Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fsi/fsi-master-gpio: Add "no-gpio-delays" option

This adds support for an optional device-tree property that
makes the driver skip all the delays around clocking the
GPIOs and set it in the device-tree of common POWER9 based
OpenPower platforms.

This useful on chips like the AST2500 where the GPIO block is
running at a fairly low clock frequency (25Mhz typically). In
this case, the delays are unnecessary and due to the low
precision of the timers, actually quite harmful in terms of
performance.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
Tested-by: Joel Stanley <joel@jms.id.au>

+19 -4
+1
arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
··· 52 52 compatible = "fsi-master-gpio", "fsi-master"; 53 53 #address-cells = <2>; 54 54 #size-cells = <0>; 55 + no-gpio-delays; 55 56 56 57 clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>; 57 58 data-gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_HIGH>;
+1
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
··· 153 153 compatible = "fsi-master-gpio", "fsi-master"; 154 154 #address-cells = <2>; 155 155 #size-cells = <0>; 156 + no-gpio-delays; 156 157 157 158 clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>; 158 159 data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>;
+1
arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
··· 91 91 compatible = "fsi-master-gpio", "fsi-master"; 92 92 #address-cells = <2>; 93 93 #size-cells = <0>; 94 + no-gpio-delays; 94 95 95 96 trans-gpios = <&gpio ASPEED_GPIO(O, 6) GPIO_ACTIVE_HIGH>; 96 97 enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
+16 -4
drivers/fsi/fsi-master-gpio.c
··· 62 62 struct gpio_desc *gpio_enable; /* FSI enable */ 63 63 struct gpio_desc *gpio_mux; /* Mux control */ 64 64 bool external_mode; 65 + bool no_delays; 65 66 }; 66 67 67 68 #define CREATE_TRACE_POINTS ··· 80 79 int i; 81 80 82 81 for (i = 0; i < count; i++) { 83 - ndelay(FSI_GPIO_STD_DLY); 82 + if (!master->no_delays) 83 + ndelay(FSI_GPIO_STD_DLY); 84 84 gpiod_set_value(master->gpio_clk, 0); 85 - ndelay(FSI_GPIO_STD_DLY); 85 + if (!master->no_delays) 86 + ndelay(FSI_GPIO_STD_DLY); 86 87 gpiod_set_value(master->gpio_clk, 1); 87 88 } 88 89 } ··· 93 90 { 94 91 int in; 95 92 96 - ndelay(FSI_GPIO_STD_DLY); 93 + if (!master->no_delays) 94 + ndelay(FSI_GPIO_STD_DLY); 97 95 gpiod_set_value(master->gpio_clk, 0); 98 96 in = gpiod_get_value(master->gpio_data); 99 - ndelay(FSI_GPIO_STD_DLY); 97 + if (!master->no_delays) 98 + ndelay(FSI_GPIO_STD_DLY); 100 99 gpiod_set_value(master->gpio_clk, 1); 101 100 return in ? 1 : 0; 102 101 } ··· 681 676 return PTR_ERR(gpio); 682 677 } 683 678 master->gpio_mux = gpio; 679 + 680 + /* 681 + * Check if GPIO block is slow enought that no extra delays 682 + * are necessary. This improves performance on ast2500 by 683 + * an order of magnitude. 684 + */ 685 + master->no_delays = device_property_present(&pdev->dev, "no-gpio-delays"); 684 686 685 687 master->master.n_links = 1; 686 688 master->master.flags = FSI_MASTER_FLAG_SWCLOCK;