* [PATCH] ARM: dts: aspeed: Add Mihawk BMC platform
From: Andrew Jeffery @ 2019-07-31 0:51 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190730060029.25268-1-Ben_Pai@wistron.com>
Hello Ben,
Thanks for the patch! Some minor comments below.
On Tue, 30 Jul 2019, at 15:30, Ben Pai wrote:
> The Mihawk BMC is an ASPEED ast2500 based BMC that is part of an
> OpenPower Power9 server.
>
> This adds the device tree description for most upstream components. It
> is a squashed commit from the OpenBMC kernel tree.
That it's a squashed commit isn't relevant, neither is the mention of the OpenBMC
kernel tree. I'd drop both from the commit message.
>
> Signed-off-by: Ben Pai <Ben_Pai@wistron.com>
> ---
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts | 922 ++++++++++++++++++++
> 2 files changed, 923 insertions(+)
> create mode 100755 arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
>
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index eb6de52c1936..262345544359 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -1281,5 +1281,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
> aspeed-bmc-opp-vesnin.dtb \
> aspeed-bmc-opp-witherspoon.dtb \
> aspeed-bmc-opp-zaius.dtb \
> + aspeed-bmc-opp-mihawk.dtb \
> aspeed-bmc-portwell-neptune.dtb \
> aspeed-bmc-quanta-q71l.dtb
> diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> new file mode 100755
> index 000000000000..cfa20e0b2939
> --- /dev/null
> +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> @@ -0,0 +1,922 @@
> +/dts-v1/;
> +
> +#include "aspeed-g5.dtsi"
> +#include <dt-bindings/gpio/aspeed-gpio.h>
> +#include <dt-bindings/leds/leds-pca955x.h>
> +
> +/ {
> + model = "Mihawk BMC";
> + compatible = "ibm,mihawk-bmc", "aspeed,ast2500";
I think this should be "ips,mihawk-bmc". You may also need to add "ips" to the
vendor-prefixes list.
> +
> +
> + chosen {
> + stdout-path = &uart5;
> + bootargs = "console=ttyS4,115200 earlyprintk";
> + };
> +
> + memory at 80000000 {
> + reg = <0x80000000 0x20000000>; /* address and size of RAM(512MB) */
> + };
> +
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> +
> + flash_memory: region at 98000000 {
> + no-map;
> + reg = <0x98000000 0x04000000>; /* 64M */
> + };
> +
> + gfx_memory: framebuffer {
> + size = <0x01000000>;
> + alignment = <0x01000000>;
> + compatible = "shared-dma-pool";
> + reusable;
> + };
> +
> + video_engine_memory: jpegbuffer {
> + size = <0x02000000>; /* 32MM */
> + alignment = <0x01000000>;
> + compatible = "shared-dma-pool";
> + reusable;
> + };
> + };
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> +
> + air-water {
> + label = "air-water";
> + gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(F, 6)>;
> + };
> +
> + checkstop {
> + label = "checkstop";
> + gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(J, 2)>;
> + };
> +
> + ps0-presence {
> + label = "ps0-presence";
> + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(Z, 2)>;
> + };
> +
> + ps1-presence {
> + label = "ps1-presence";
> + gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(Z, 0)>;
> + };
> + id-button {
> + label = "id-button";
> + gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(F, 1)>;
> + };
> + };
> +
> + gpio-keys-polled {
> + compatible = "gpio-keys-polled";
> + #address-cells = <1>;
> + #size-cells = <0>;
Please remove the #address-cells and #size-cells properties, they aren't
relevant for gpio-keys-polled.
> + poll-interval = <1000>;
> +
> + fan0-presence {
> + label = "fan0-presence";
> + gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
> + linux,code = <9>;
> + };
> +
> + fan1-presence {
> + label = "fan1-presence";
> + gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
> + linux,code = <10>;
> + };
> +
> + fan2-presence {
> + label = "fan2-presence";
> + gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
> + linux,code = <11>;
> + };
> +
> + fan3-presence {
> + label = "fan3-presence";
> + gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
> + linux,code = <12>;
> + };
> +
> + fan4-presence {
> + label = "fan4-presence";
> + gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
> + linux,code = <13>;
> + };
> +
> + fan5-presence {
> + label = "fan5-presence";
> + gpios = <&pca9552 14 GPIO_ACTIVE_LOW>;
> + linux,code = <14>;
> + };
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> +
> + fault {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
> + };
> +
> + power {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-id {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-g {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 4) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-ok {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(Y, 0) GPIO_ACTIVE_LOW>;
> + };
> +
> + fan0 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 0 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan1 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 1 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan2 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 2 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan3 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 3 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan4 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 4 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan5 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 5 GPIO_ACTIVE_LOW>;
> + };
> + };
> +
> + fsi: gpio-fsi {
> + compatible = "fsi-master-gpio", "fsi-master";
> + #address-cells = <2>;
> + #size-cells = <0>;
> + no-gpio-delays;
> +
> + clock-gpios = <&gpio ASPEED_GPIO(E, 6) GPIO_ACTIVE_HIGH>;
> + data-gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_HIGH>;
> + mux-gpios = <&gpio ASPEED_GPIO(E, 5) GPIO_ACTIVE_HIGH>;
> + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
> + trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
> + };
> + iio-hwmon-12v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 0>;
> + };
> +
> + iio-hwmon-5v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 1>;
> + };
> +
> + iio-hwmon-3v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 2>;
> + };
> +
> + iio-hwmon-vdd0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 3>;
> + };
> +
> + iio-hwmon-vdd1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 4>;
> + };
> +
> + iio-hwmon-vcs0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 5>;
> + };
> +
> + iio-hwmon-vcs1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 6>;
> + };
> +
> + iio-hwmon-vdn0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 7>;
> + };
> +
> + iio-hwmon-vdn1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 8>;
> + };
> +
> + iio-hwmon-vio0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 9>;
> + };
> +
> + iio-hwmon-vio1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 10>;
> + };
> +
> + iio-hwmon-vddra {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 11>;
> + };
> +
> + iio-hwmon-vddrb {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 13>;
> + };
> +
> + iio-hwmon-vddrc {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 14>;
> + };
> +
> + iio-hwmon-vddrd {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 15>;
> + };
> +
> + iio-hwmon-battery {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 12>;
> + };
> +};
> +
> +&pwm_tacho {
> + status = "okay";
> + /*compatible = "aspeed,ast2500-pwm-tacho";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x1e786000 0x1000>;
> + clocks = <&pwm_tacho_fixed_clk>;*/
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
> + &pinctrl_pwm2_default &pinctrl_pwm3_default
> + &pinctrl_pwm4_default &pinctrl_pwm5_default>;
> +
> + fan at 0 {
> + reg = <0x00>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x00>;
> + };
> +
> + fan at 1 {
> + reg = <0x01>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x01>;
> + };
> +
> + fan at 2 {
> + reg = <0x02>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x02>;
> + };
> +
> + fan at 3 {
> + reg = <0x03>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x03>;
> + };
> +
> + fan at 4 {
> + reg = <0x04>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x04>;
> + };
> +
> + fan at 5 {
> + reg = <0x05>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x05>;
> + };
> +
> + fan at 6 {
> + reg = <0x00>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x06>;
> + };
> +
> + fan at 7 {
> + reg = <0x01>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x07>;
> + };
> +
> + fan at 8 {
> + reg = <0x02>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x08>;
> + };
> +
> + fan at 9 {
> + reg = <0x03>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x09>;
> + };
> +
> + fan at 10 {
> + reg = <0x04>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x0a>;
> + };
> +
> + fan at 11 {
> + reg = <0x05>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x0b>;
> + };
> +};
> +
> +&fmc {
> + status = "okay";
> + flash at 0 {
> + status = "okay";
> + label = "bmc";
> + m25p,fast-read;
> + spi-max-frequency = <50000000>;
> + partitions {
> + #address-cells = < 1 >;
> + #size-cells = < 1 >;
> + compatible = "fixed-partitions";
> + u-boot at 0 {
> + reg = < 0 0x60000 >;
> + label = "u-boot";
> + };
> + u-boot-env at 60000 {
> + reg = < 0x60000 0x20000 >;
> + label = "u-boot-env";
> + };
> + obmc-ubi at 80000 {
> + reg = < 0x80000 0x1F80000 >;
> + label = "obmc-ubi";
> + };
> + };
> + };
> + flash at 1 {
> + status = "okay";
> + label = "alt-bmc";
> + m25p,fast-read;
> + spi-max-frequency = <50000000>;
> + partitions {
> + #address-cells = < 1 >;
> + #size-cells = < 1 >;
> + compatible = "fixed-partitions";
> + u-boot at 0 {
> + reg = < 0 0x60000 >;
> + label = "alt-u-boot";
> + };
> + u-boot-env at 60000 {
> + reg = < 0x60000 0x20000 >;
> + label = "alt-u-boot-env";
> + };
> + obmc-ubi at 80000 {
> + reg = < 0x80000 0x1F80000 >;
> + label = "alt-obmc-ubi";
> + };
> + };
> + };
> +};
> +
> +&spi1 {
> + status = "okay";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_spi1_default>;
> +
> + flash at 0 {
> + status = "okay";
> + label = "pnor";
> + m25p,fast-read;
> + spi-max-frequency = <100000000>;
> + };
> +};
> +
> +&lpc_ctrl {
> + status = "okay";
> + memory-region = <&flash_memory>;
> + flash = <&spi1>;
> +};
> +
> +&uart1 {
> + /* Rear RS-232 connector */
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_txd1_default
> + &pinctrl_rxd1_default
> + &pinctrl_nrts1_default
> + &pinctrl_ndtr1_default
> + &pinctrl_ndsr1_default
> + &pinctrl_ncts1_default
> + &pinctrl_ndcd1_default
> + &pinctrl_nri1_default>;
> +};
> +
> +&uart2 {
> + /* APSS */
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
> +};
> +
> +&uart5 {
> + status = "okay";
> +};
> +
> +&mac0 {
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_rmii1_default>;
> + use-ncsi;
> +};
> +
> +&mac1 {
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
> +};
> +
> +&i2c0 {
> + status = "disabled";
> +};
> +
> +&i2c1 {
> + status = "disabled";
> +};
> +
> +&i2c2 {
> + status = "okay";
> +
> + /* SAMTEC P0 */
> + /* SAMTEC P1 */
> +
> +};
> +
> +&i2c3 {
> + status = "okay";
> +
> + /* APSS */
> + /* CPLD */
> +
> + /* PCA9516 (repeater) ->
> + * CLK Buffer 9FGS9092
> + * CLK Buffer 9DBL0651BKILFT
> + * CLK Buffer 9DBL0651BKILFT
> + * Power Supply 0
> + * Power Supply 1
> + * PCA 9552 LED
> + */
> +
> + power-supply at 58 {
> + compatible = "ibm,cffps1";
> + reg = <0x58>;
> + };
> +
> + power-supply at 5b {
> + compatible = "ibm,cffps1";
> + reg = <0x5b>;
> + };
> +
> + pca9552: pca9552 at 60 {
> + compatible = "nxp,pca9552";
> + reg = <0x60>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + gpio-controller;
> + #gpio-cells = <2>;
> +
> + gpio at 0 {
> + reg = <0>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 1 {
> + reg = <1>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 2 {
> + reg = <2>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 3 {
> + reg = <3>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 4 {
> + reg = <4>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 5 {
> + reg = <5>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 6 {
> + reg = <6>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 7 {
> + reg = <7>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 8 {
> + reg = <8>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 9 {
> + reg = <9>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 10 {
> + reg = <10>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 11 {
> + reg = <11>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 12 {
> + reg = <12>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 13 {
> + reg = <13>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 14 {
> + reg = <14>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio at 15 {
> + reg = <15>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> +
> + };
> +
> +};
> +
> +&i2c4 {
> + status = "okay";
> +
> + /* CP0 VDD & VCS : IR35221 */
> + /* CP0 VDN : IR35221 */
> + /* CP0 VIO : IR38064 */
> + /* CP0 VDDR : PXM1330 */
> +
> + ir35221 at 70 {
> + compatible = "infineon,ir35221";
> + reg = <0x70>;
> + };
> +
> + ir35221 at 72 {
> + compatible = "infineon,ir35221";
> + reg = <0x72>;
> + };
> +
> +};
> +
> +&i2c5 {
> + status = "okay";
> +
> + /* CP0 VDD & VCS : IR35221 */
> + /* CP0 VDN : IR35221 */
> + /* CP0 VIO : IR38064 */
> + /* CP0 VDDR : PXM1330 */
> +
> + ir35221 at 70 {
> + compatible = "infineon,ir35221";
> + reg = <0x70>;
> + };
> +
> + ir35221 at 72 {
> + compatible = "infineon,ir35221";
> + reg = <0x72>;
> + };
> +
> +};
> +
> +&i2c6 {
> + status = "okay";
> +
> + /* pca9548 -> NVMe1 to 8 */
> +
> + pca9548 at 70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +
> +};
> +
> +&i2c7 {
> + status = "okay";
> +
> + /* pca9548 -> NVMe9 to 16 */
> +
> + pca9548 at 70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +
> +};
> +
> +&i2c8 {
> + status = "okay";
> +
> + /* FSI CLK/DAT */
This comment doesn't make sense?
> + eeprom at 50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> +};
> +
> +&i2c9 {
> + status = "okay";
> +
> + /* pca9545 Riser ->
> + * PCIe x8 Slot3
> + * PCIe x16 slot4
> + * PCIe x8 slot5
> + * I2C BMC RISER PCA9554
> + * BMC SCL/SDA PCA9554
> + * PCA9554
> + */
> +
> + /* pca9545 ->
> + * PCIe x16 Slot1
> + * PCIe x8 slot2
> + * PEX8748
> + */
> +
> + pca9545riser at 70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + /*interrupt-parent = <&ipic>;*/
> + /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +
> + pca9545 at 71 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x71>;
> +
> + /*interrupt-parent = <&ipic>;*/
> + /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +};
> +
> +&i2c10 {
> + status = "okay";
> +
> + /* pca9545 Riser ->
> + * PCIe x8 Slot8
> + * PCIe x16 slot9
> + * PCIe x8 slot10
> + * I2C BMC RISER PCA9554
> + * BMC SCL/SDA PCA9554
> + * PCA9554
> + */
> +
> + /* pca9545 ->
> + * PCIe x16 Slot1
> + * PCIe x8 slot2
> + * PEX8748
> + */
> +
> + pca9545riser at 70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + /*interrupt-parent = <&ipic>;*/
> + /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
Remove the commented properties.
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +
> + pca9545 at 71 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x71>;
> +
> + /*interrupt-parent = <&ipic>;*/
> + /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
Again here.
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +};
> +
> +&i2c11 {
> + status = "okay";
> +
> + /* TPM */
> + /* RTC RX8900CE */
> + /* FPGA for power sequence */
> + /* TMP275A */
> + /* TMP275A */
> + /* EMC1462 */
> +
> + tpm at 57 {
> + compatible = "infineon,slb9645tt";
> + reg = <0x57>;
> + };
> +
> + rtc at 32 {
> + compatible = "epson,rx8900";
> + reg = <0x32>;
> + };
> +
> + tmp275 at 48 {
> + compatible = "ti,tmp275";
> + reg = <0x48>;
> + };
> +
> + tmp275 at 49 {
> + compatible = "ti,tmp275";
> + reg = <0x49>;
> + };
> +
> + /* chip emc1462 use emc1403 driver */
> + emc1403 at 4c {
> + compatible = "smsc,emc1403";
> + reg = <0x4c>;
> + };
> +
> +};
> +
> +&i2c12 {
> + status = "okay";
> +
> + /* pca9545 ->
> + * SAS BP1
> + * SAS BP2
> + * NVMe BP
> + * M.2 riser
> + */
> +
> + pca9545 at 70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + /*interrupt-parent = <&ipic>;*/
> + /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
> + interrupt-controller;
> + #interrupt-cells = <2>;
> +
> + i2c at 0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0>;
> +
> + eeprom at 50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c at 1 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <1>;
> +
> + eeprom at 50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c at 2 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <2>;
> +
> + eeprom at 50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c at 3 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <3>;
> +
> + tmp275 at 48 {
> + compatible = "ti,tmp275";
> + reg = <0x48>;
> + };
> + };
> +
> + };
> +
> +};
> +
> +&i2c13 {
> + status = "okay";
> +
> + /* pca9548 ->
> + * NVMe BP
> + * NVMe HDD17 to 24
> + */
> +
> + pca9548 at 70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +};
> +
> +&vuart {
> + status = "okay";
> +};
> +
> +&gfx {
> + status = "okay";
> + memory-region = <&gfx_memory>;
> +};
> +
> +&pinctrl {
> + aspeed,external-nodes = <&gfx &lhc>;
This is already provided by aspeed-g5.dtsi, please drop it.
> +};
> +
> +&adc {
> + status = "okay";
Please add the pinmux properties to mux the ADC lines that you're using
> +};
> +
> +&wdt1 {
> + aspeed,reset-type = "none";
> + aspeed,external-signal;
> + aspeed,ext-push-pull;
> + aspeed,ext-active-high;
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_wdtrst1_default>;
> +};
> +
> +&wdt2 {
> + aspeed,alt-boot;
> +};
> +
> +&ibt {
> + status = "okay";
> +};
> +
> +&vhub {
> + status = "okay";
> +};
> +
> +&video {
> + status = "okay";
> + memory-region = <&video_engine_memory>;
> +};
> +
> +#include "ibm-power9-dual.dtsi"
> \ No newline at end of file
Add a newline here to avoid the warning.
> --
> 2.17.1
>
>
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------
> This email contains confidential or legally privileged information and
> is for the sole use of its intended recipient.
> Any unauthorized review, use, copying or distribution of this email or
> the content of this email is strictly prohibited.
> If you are not the intended recipient, you may reply to the sender and
> should delete this e-mail immediately.
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------
>
Please try to avoid posting footers like this to public mailing lists.
Cheers,
Andrew
^ permalink raw reply
* [v6 2/2] gpio: aspeed: Add SGPIO driver
From: Andrew Jeffery @ 2019-07-31 0:19 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1564500268-2627-3-git-send-email-hongweiz@ami.com>
On Wed, 31 Jul 2019, at 00:55, Hongwei Zhang wrote:
> Add SGPIO driver support for Aspeed AST2500 SoC.
>
> Signed-off-by: Hongwei Zhang <hongweiz@ami.com>
> ---
> drivers/gpio/sgpio-aspeed.c | 521 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 521 insertions(+)
> create mode 100644 drivers/gpio/sgpio-aspeed.c
>
> diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
> new file mode 100644
> index 0000000..9a17b1a
> --- /dev/null
> +++ b/drivers/gpio/sgpio-aspeed.c
> @@ -0,0 +1,521 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright 2019 American Megatrends International LLC.
> + *
> + * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/hashtable.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +
> +#define MAX_NR_SGPIO 80
> +
> +#define ASPEED_SGPIO_CTRL 0x54
> +
> +#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
> +#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
> +#define ASPEED_SGPIO_ENABLE BIT(0)
> +
> +struct aspeed_sgpio {
> + struct gpio_chip chip;
> + struct clk *pclk;
> + spinlock_t lock;
> + void __iomem *base;
> + uint32_t dir_in[3];
> + int irq;
> +};
> +
> +struct aspeed_sgpio_bank {
> + uint16_t val_regs;
> + uint16_t rdata_reg;
> + uint16_t irq_regs;
> + const char names[4][3];
> +};
> +
> +/*
> + * Note: The "value" register returns the input value when the GPIO is
> + * configured as an input.
> + *
> + * The "rdata" register returns the output value when the GPIO is
> + * configured as an output.
> + */
> +static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
> + {
> + .val_regs = 0x0000,
> + .rdata_reg = 0x0070,
> + .irq_regs = 0x0004,
> + .names = { "A", "B", "C", "D" },
> + },
> + {
> + .val_regs = 0x001C,
> + .rdata_reg = 0x0074,
> + .irq_regs = 0x0020,
> + .names = { "E", "F", "G", "H" },
> + },
> + {
> + .val_regs = 0x0038,
> + .rdata_reg = 0x0078,
> + .irq_regs = 0x003C,
> + .names = { "I", "J" },
> + },
> +};
> +
> +enum aspeed_sgpio_reg {
> + reg_val,
> + reg_rdata,
> + reg_irq_enable,
> + reg_irq_type0,
> + reg_irq_type1,
> + reg_irq_type2,
> + reg_irq_status,
> +};
> +
> +#define GPIO_VAL_VALUE 0x00
> +#define GPIO_IRQ_ENABLE 0x00
> +#define GPIO_IRQ_TYPE0 0x04
> +#define GPIO_IRQ_TYPE1 0x08
> +#define GPIO_IRQ_TYPE2 0x0C
> +#define GPIO_IRQ_STATUS 0x10
> +
> +static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
> + const struct aspeed_sgpio_bank *bank,
> + const enum aspeed_sgpio_reg reg)
> +{
> + switch (reg) {
> + case reg_val:
> + return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
> + case reg_rdata:
> + return gpio->base + bank->rdata_reg;
> + case reg_irq_enable:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
> + case reg_irq_type0:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
> + case reg_irq_type1:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
> + case reg_irq_type2:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
> + case reg_irq_status:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
> + default:
> + /* acturally if code runs to here, it's an error case */
> + BUG_ON(1);
> + }
> +}
> +
> +#define GPIO_BANK(x) ((x) >> 5)
> +#define GPIO_OFFSET(x) ((x) & 0x1f)
> +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
> +
> +static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
> +{
> + unsigned int bank = GPIO_BANK(offset);
> +
> + WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
> + return &aspeed_sgpio_banks[bank];
> +}
> +
> +static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + const struct aspeed_sgpio_bank *bank = to_bank(offset);
> + unsigned long flags;
> + enum aspeed_sgpio_reg reg;
> + bool is_input;
> + int rc = 0;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
> + reg = is_input ? reg_val : reg_rdata;
> + rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return rc;
> +}
> +
> +static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int
> offset, int val)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + const struct aspeed_sgpio_bank *bank = to_bank(offset);
> + unsigned long flags;
> + void __iomem *addr;
> + u32 reg = 0;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + addr = bank_reg(gpio, bank, reg_val);
> +
> + if (val)
> + reg |= GPIO_BIT(offset);
> + else
> + reg &= ~GPIO_BIT(offset);
reg is zero-initialised above and you haven't read from addr to assign to reg, so
the else branch is redundant (reg is already zeroed). This path has a bug - you're
clearing the state of all GPIOs associated with addr rather than just the GPIO
associated with offset.
> +
> + iowrite32(reg, addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int
> offset)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> + gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return 0;
> +}
> +
> +static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int
> offset, int val)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> + gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + aspeed_sgpio_set(gc, offset, val);
In this case you should probably have an unlocked variant of aspeed_sgpio_set()
so you can call it inside the the critical section above instead of needing to
acquire/release the lock twice (once above and again in aspeed_sgpio_set()
as it stands).
Cheers,
Andrew
> +
> + return 0;
> +}
> +
> +static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned
> int offset)
> +{
> + int dir_status;
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> + dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return dir_status;
> +
> +}
> +
> +static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
> + struct aspeed_sgpio **gpio,
> + const struct aspeed_sgpio_bank **bank,
> + u32 *bit, int *offset)
> +{
> + struct aspeed_sgpio *internal;
> +
> + *offset = irqd_to_hwirq(d);
> + internal = irq_data_get_irq_chip_data(d);
> + WARN_ON(!internal);
> +
> + *gpio = internal;
> + *bank = to_bank(*offset);
> + *bit = GPIO_BIT(*offset);
> +}
> +
> +static void aspeed_sgpio_irq_ack(struct irq_data *d)
> +{
> + const struct aspeed_sgpio_bank *bank;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + void __iomem *status_addr;
> + int offset;
> + u32 bit;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> +
> + status_addr = bank_reg(gpio, bank, reg_irq_status);
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + iowrite32(bit, status_addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
> +{
> + const struct aspeed_sgpio_bank *bank;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + u32 reg, bit;
> + void __iomem *addr;
> + int offset;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> + addr = bank_reg(gpio, bank, reg_irq_enable);
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + reg = ioread32(addr);
> + if (set)
> + reg |= bit;
> + else
> + reg &= ~bit;
> +
> + iowrite32(reg, addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static void aspeed_sgpio_irq_mask(struct irq_data *d)
> +{
> + aspeed_sgpio_irq_set_mask(d, false);
> +}
> +
> +static void aspeed_sgpio_irq_unmask(struct irq_data *d)
> +{
> + aspeed_sgpio_irq_set_mask(d, true);
> +}
> +
> +static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
> +{
> + u32 type0 = 0;
> + u32 type1 = 0;
> + u32 type2 = 0;
> + u32 bit, reg;
> + const struct aspeed_sgpio_bank *bank;
> + irq_flow_handler_t handler;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + void __iomem *addr;
> + int offset;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> +
> + switch (type & IRQ_TYPE_SENSE_MASK) {
> + case IRQ_TYPE_EDGE_BOTH:
> + type2 |= bit;
> + /* fall through */
> + case IRQ_TYPE_EDGE_RISING:
> + type0 |= bit;
> + /* fall through */
> + case IRQ_TYPE_EDGE_FALLING:
> + handler = handle_edge_irq;
> + break;
> + case IRQ_TYPE_LEVEL_HIGH:
> + type0 |= bit;
> + /* fall through */
> + case IRQ_TYPE_LEVEL_LOW:
> + type1 |= bit;
> + handler = handle_level_irq;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type0);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type0;
> + iowrite32(reg, addr);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type1);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type1;
> + iowrite32(reg, addr);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type2);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type2;
> + iowrite32(reg, addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + irq_set_handler_locked(d, handler);
> +
> + return 0;
> +}
> +
> +static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
> +{
> + struct gpio_chip *gc = irq_desc_get_handler_data(desc);
> + struct irq_chip *ic = irq_desc_get_chip(desc);
> + struct aspeed_sgpio *data = gpiochip_get_data(gc);
> + unsigned int i, p, girq;
> + unsigned long reg;
> +
> + chained_irq_enter(ic, desc);
> +
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
> +
> + reg = ioread32(bank_reg(data, bank, reg_irq_status));
> +
> + for_each_set_bit(p, ®, 32) {
> + girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
> + generic_handle_irq(girq);
> + }
> +
> + }
> +
> + chained_irq_exit(ic, desc);
> +}
> +
> +static struct irq_chip aspeed_sgpio_irqchip = {
> + .name = "aspeed-sgpio",
> + .irq_ack = aspeed_sgpio_irq_ack,
> + .irq_mask = aspeed_sgpio_irq_mask,
> + .irq_unmask = aspeed_sgpio_irq_unmask,
> + .irq_set_type = aspeed_sgpio_set_type,
> +};
> +
> +static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
> + struct platform_device *pdev)
> +{
> + int rc, i;
> + const struct aspeed_sgpio_bank *bank;
> +
> + rc = platform_get_irq(pdev, 0);
> + if (rc < 0)
> + return rc;
> +
> + gpio->irq = rc;
> +
> + /* Disable IRQ and clear Interrupt status registers for all SPGIO
> Pins. */
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + bank = &aspeed_sgpio_banks[i];
> + /* disable irq enable bits */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
> + /* clear status bits */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
> + }
> +
> + rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip,
> + 0, handle_bad_irq, IRQ_TYPE_NONE);
> + if (rc) {
> + dev_info(&pdev->dev, "Could not add irqchip\n");
> + return rc;
> + }
> +
> + gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip,
> + gpio->irq, aspeed_sgpio_irq_handler);
> +
> + /* set IRQ settings and Enable Interrupt */
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + bank = &aspeed_sgpio_banks[i];
> + /* set falling or level-low irq */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
> + /* trigger type is edge */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
> + /* dual edge trigger mode. */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
> + /* enable irq */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
> + }
> +
> + return 0;
> +}
> +
> +static const struct of_device_id aspeed_sgpio_of_table[] = {
> + { .compatible = "aspeed,ast2400-sgpio" },
> + { .compatible = "aspeed,ast2500-sgpio" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
> +
> +static int __init aspeed_sgpio_probe(struct platform_device *pdev)
> +{
> + struct aspeed_sgpio *gpio;
> + u32 nr_gpios, sgpio_freq, sgpio_clk_div;
> + int rc;
> + unsigned long apb_freq;
> +
> + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
> + if (!gpio)
> + return -ENOMEM;
> +
> + gpio->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(gpio->base))
> + return PTR_ERR(gpio->base);
> +
> + rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
> + if (rc < 0) {
> + dev_err(&pdev->dev, "Could not read ngpios property\n");
> + return -EINVAL;
> + } else if (nr_gpios > MAX_NR_SGPIO) {
> + dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d:
> %d\n",
> + MAX_NR_SGPIO, nr_gpios);
> + return -EINVAL;
> + }
> +
> + rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency",
> &sgpio_freq);
> + if (rc < 0) {
> + dev_err(&pdev->dev, "Could not read bus-frequency property\n");
> + return -EINVAL;
> + }
> +
> + gpio->pclk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(gpio->pclk)) {
> + dev_err(&pdev->dev, "devm_clk_get failed\n");
> + return PTR_ERR(gpio->pclk);
> + }
> +
> + apb_freq = clk_get_rate(gpio->pclk);
> +
> + /*
> + * From the datasheet,
> + * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
> + * period = 2 * (GPIO254[31:16] + 1) / PCLK
> + * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
> + * frequency = PCLK / (2 * (GPIO254[31:16] + 1))
> + * frequency * 2 * (GPIO254[31:16] + 1) = PCLK
> + * GPIO254[31:16] = PCLK / (frequency * 2) - 1
> + */
> + if (sgpio_freq == 0)
> + return -EINVAL;
> +
> + sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
> +
> + if (sgpio_clk_div > (1 << 16) - 1)
> + return -EINVAL;
> +
> + iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
> + FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
> + ASPEED_SGPIO_ENABLE,
> + gpio->base + ASPEED_SGPIO_CTRL);
> +
> + spin_lock_init(&gpio->lock);
> +
> + gpio->chip.parent = &pdev->dev;
> + gpio->chip.ngpio = nr_gpios;
> + gpio->chip.direction_input = aspeed_sgpio_dir_in;
> + gpio->chip.direction_output = aspeed_sgpio_dir_out;
> + gpio->chip.get_direction = aspeed_sgpio_get_direction;
> + gpio->chip.request = NULL;
> + gpio->chip.free = NULL;
> + gpio->chip.get = aspeed_sgpio_get;
> + gpio->chip.set = aspeed_sgpio_set;
> + gpio->chip.set_config = NULL;
> + gpio->chip.label = dev_name(&pdev->dev);
> + gpio->chip.base = -1;
> +
> + /* set all SGPIO pins as input (1). */
> + memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
> +
> + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
> + if (rc < 0)
> + return rc;
> +
> + return aspeed_sgpio_setup_irqs(gpio, pdev);
> +}
> +
> +static struct platform_driver aspeed_sgpio_driver = {
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .of_match_table = aspeed_sgpio_of_table,
> + },
> +};
> +
> +module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
> +MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.7.4
>
>
^ permalink raw reply
* [v6 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
From: Andrew Jeffery @ 2019-07-30 23:58 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1564500268-2627-2-git-send-email-hongweiz@ami.com>
On Wed, 31 Jul 2019, at 00:55, Hongwei Zhang wrote:
> Add bindings to support SGPIO on AST2400 or AST2500.
>
> Signed-off-by: Hongwei Zhang <hongweiz@ami.com>
> ---
> .../devicetree/bindings/gpio/sgpio-aspeed.txt | 55 ++++++++++++++++++++++
> 1 file changed, 55 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
>
> diff --git a/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
> b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
> new file mode 100644
> index 0000000..f9ed438
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
> @@ -0,0 +1,55 @@
> +Aspeed SGPIO controller Device Tree Bindings
> +-------------------------------------------
> +
> +This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80
> full
> +featured Serial GPIOs. Each of the Serial GPIO pins can be programmed
> to
> +support the following options:
> +- Support interrupt option for each input port and various interrupt
> + sensitivity option (level-high, level-low, edge-high, edge-low)
> +- Support reset tolerance option for each output port
> +- Directly connected to APB bus and its shift clock is from APB bus
> clock
> + divided by a programmable value.
> +- Co-work with external signal-chained TTL components (74LV165/74LV595)
> +
> +
> +Required properties:
> +
> +- compatible : Either "aspeed,ast2400-sgpio" or "aspeed,ast2500-sgpio"
> +
> +- #gpio-cells : Should be two
> + - First cell is the GPIO line number
> + - Second cell is used to specify optional
> + parameters (unused)
> +
> +- reg : Address and length of the register set for the device
> +- gpio-controller : Marks the device node as a GPIO controller
> +- interrupts : Interrupt specifier (see interrupt bindings for
> + details)
> +
> +- interrupt-controller : Mark the GPIO controller as an
> interrupt-controller
> +
> +- ngpios : number of GPIO pins to serialise.
> + (should be multiple of 8, up to 80 pins)
> +
> +- clocks : A phandle to the APB clock for SGPM clock
> division
> +
> +- bus-frequency : SGPM CLK frequency
> +
> +
> +The sgpio and interrupt properties are further described in their
> respective bindings documentation:
> +
> +- Documentation/devicetree/bindings/sgpio/gpio.txt
This isn't a file? This one is (s/sgpio/gpio/):
Documentation/devicetree/bindings/gpio/gpio.txt
I assume this was the result of a stray search/replace?
With that fixed you can add: Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Andrew
> +- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
> +
> + Example:
> + sgpio: sgpio at 1e780200 {
> + #gpio-cells = <2>;
> + compatible = "aspeed,ast2500-sgpio";
> + gpio-controller;
> + interrupts = <40>;
> + reg = <0x1e780200 0x0100>;
> + clocks = <&syscon ASPEED_CLK_APB>;
> + interrupt-controller;
> + ngpios = <8>;
> + bus-frequency = <12000000>;
> + };
> --
> 2.7.4
>
>
^ permalink raw reply
* [v5 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
From: Hongwei Zhang @ 2019-07-30 19:25 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1563564291-9692-2-git-send-email-hongweiz@ami.com>
Hello Linus and Andrew,
Thanks for your detailed comments, I just submitted v6 of our update:
_http://patchwork.ozlabs.org/cover/1139035/
_http://patchwork.ozlabs.org/patch/1139038/
_http://patchwork.ozlabs.org/patch/1139040/
please ignore my previous patches sent on 07/28, they does not have proper serial
title and one of the patch is missing.
--Hongwei
> From: Linus Walleij <linus.walleij@linaro.org>
> Sent: Monday, July 29, 2019 5:57 PM
> To: Andrew Jeffery
> Cc: Hongwei Zhang; open list:GPIO SUBSYSTEM; Joel Stanley; open list:OPEN FIRMWARE AND
> FLATTENED DEVICE TREE BINDINGS; linux-aspeed; Bartosz Golaszewski; Rob Herring; Mark Rutland;
> linux-kernel at vger.kernel.org; Linux ARM
> Subject: Re: [v5 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
>
> On Mon, Jul 29, 2019 at 2:19 AM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> > The behaviour is to periodically emit the state of all enabled GPIOs
> > (i.e. the ngpios value), one per bus clock cycle. There's no explicit
> > addressing scheme, the protocol encodes the value for a given GPIO by
> > its position in the data stream relative to a pulse on the "load data"
> > (LD) line, whose envelope covers the clock cycle for the last GPIO in
> > the sequence. Similar to SPI the bus has both out and in lines, which
> > cater to output/input GPIOs.
> >
> > A rough timing diagram for a 16-GPIO configuration looks like what
> > I've pasted here:
> >
> > https://gist.github.com/amboar/c9543af1957854474b8c05ab357f0675
>
> OK that is complex. I agree we need to keep this driver together.
>
> Yours,
> Linus Walleij
^ permalink raw reply
* [patch v4 1/5] AST2500 DMA UART driver
From: Greg KH @ 2019-07-30 15:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1564147640-30753-2-git-send-email-open.sudheer@gmail.com>
On Fri, Jul 26, 2019 at 06:57:16PM +0530, sudheer.v wrote:
> From: sudheer veliseti <sudheer.open@gmail.com>
>
> UART driver for Aspeed's bmc chip AST2500
>
> Design approch:
> AST2500 has dedicated Uart DMA controller which has 12 sets of Tx and RX channels
> connected to UART controller directly.
> Since the DMA controller have dedicated buffers and registers,
> there would be little benifit in adding DMA framework overhead.
> So the software for DMA controller is included within the UART driver itself.
>
> implementation details:
> 'struct ast_uart_port' is populated and registered with uart_core.
> code is organised into two layers UART-layer and DMA-Layer,both of them are
> in the same file.UART-layer requests Rx and Tx dma channels
> and registers callbacks with DMA controller software Layer
> Interrupt service routine for DMA controller is the crucial one for Handling all
> the tx and rx data. ISRs installed for individual uarts are just dummy,and are helpful
> only to report any spurious interrupts in hardware.
>
>
> Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
> ---
>
> Changes from v3->v4:
> - per port uart structures are registerd directly with uart core
> Instead of registering through 8250 Frame work,
> ast_uart_port is registered using uart_add_one_port
> -SDMA_RX_FIX macro replaced with CONFIG_AST_UART_DMA_RX_INTERRUPT
> -ast_uart_sdma_isr : DMA interrupt handler code is improvised
> -replaced pr_debug with ftrace wherever appropriate
> -dev_err is used in all error return cases
> -uart driver structure ast25xx_uart_reg is modified
> -driver name changed to ast2500-uart-dma-drv
> -rx_timer initialisation and callback fn modified
>
> Changes from v2->v3:
> -custom debug replaced by in kerenl dynamic debug: pr_debug
> -change-logs added
>
>
> .../tty/serial/8250/8250_ast2500_uart_dma.c | 1901 +++++++++++++++++
> 1 file changed, 1901 insertions(+)
> create mode 100644 drivers/tty/serial/8250/8250_ast2500_uart_dma.c
>
> diff --git a/drivers/tty/serial/8250/8250_ast2500_uart_dma.c b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> new file mode 100644
> index 000000000000..bc830d605372
> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> @@ -0,0 +1,1901 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * DMA UART Driver for ASPEED BMC chip: AST2500
> + *
> + * Copyright (C) 2019 sudheer Kumar veliseti, Aspeed technology Inc.
> + * <open.sudheer@gmail.com>
What was the copyright on the file you copied? Please properly
attribute that here.
> + *
> + */
> +#include <linux/clk.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include "8250.h"
> +
> +#define SERIAL8250_CONSOLE NULL
> +#define TTY_AST_MAJOR 204
> +#define TTY_AST_MINOR 68
Where did you get this minor number from?
> +
> +#define DMA_BUFF_SIZE 0x1000
> +#define SDMA_RX_BUFF_SIZE 0x10000
> +#define PASS_LIMIT 256
> +#define UART_DMA_NR CONFIG_AST_NR_DMA_UARTS
> +#define AST_UART_SDMA_CH 12
> +
> +/* enum ast_uart_chan_op
> + * operation codes passed to the DMA code by the user, and also used
> + * to inform the current channel owner of any changes to the system state
> + */
> +enum ast_uart_chan_op {
> + AST_UART_DMAOP_TRIGGER,
> + AST_UART_DMAOP_STOP,
> + AST_UART_DMAOP_PAUSE,
> +};
> +
> +/* ast_uart_dma_cbfn: buffer callback routinei type */
> +typedef void (*ast_uart_dma_cbfn)(void *dev_id, u16 len);
> +
> +struct ast_sdma_info {
> + u8 ch_no;
> + u8 direction;
> + u8 enable;
> + void *priv;
> + char *sdma_virt_addr;
> + dma_addr_t dma_phy_addr;
> + /* cdriver callbacks */
> + ast_uart_dma_cbfn callback_fn; /* buffer done callback */
> +};
> +
> +struct ast_sdma_ch {
> + struct ast_sdma_info tx_dma_info[AST_UART_SDMA_CH];
> + struct ast_sdma_info rx_dma_info[AST_UART_SDMA_CH];
> +};
> +
> +struct ast_sdma {
> + void __iomem *reg_base;
> + int dma_irq;
> + struct ast_sdma_ch *dma_ch;
> + struct regmap *map;
> +};
> +
> +#define UART_TX_SDMA_EN 0x00
> +#define UART_RX_SDMA_EN 0x04
> +#define UART_SDMA_CONF 0x08 /* Misc, Buffer size */
> +#define UART_SDMA_TIMER 0x0C
> +#define UART_TX_SDMA_REST 0x20
> +#define UART_RX_SDMA_REST 0x24
> +#define UART_TX_SDMA_IER 0x30
> +#define UART_TX_SDMA_ISR 0x34
> +#define UART_RX_SDMA_IER 0x38
> +#define UART_RX_SDMA_ISR 0x3C
> +#define UART_TX_R_POINT(x) (0x40 + ((x) * 0x20))
> +#define UART_TX_W_POINT(x) (0x44 + ((x) * 0x20))
> +#define UART_TX_SDMA_ADDR(x) (0x48 + ((x) * 0x20))
> +#define UART_RX_R_POINT(x) (0x50 + ((x) * 0x20))
> +#define UART_RX_W_POINT(x) (0x54 + ((x) * 0x20))
> +#define UART_RX_SDMA_ADDR(x) (0x58 + ((x) * 0x20))
> +#define SDMA_CH_EN(x) BIT(x)
> +
> +#define SDMA_TX_BUFF_SIZE_MASK (0x3)
> +#define SDMA_SET_TX_BUFF_SIZE(x)(x)
> +#define SDMA_BUFF_SIZE_1KB (0x0)
> +#define SDMA_BUFF_SIZE_4KB (0x1)
> +#define SDMA_BUFF_SIZE_16KB (0x2)
> +#define SDMA_BUFF_SIZE_64KB (0x3)
> +#define SDMA_RX_BUFF_SIZE_MASK (0x3 << 2)
> +#define SDMA_SET_RX_BUFF_SIZE(x)((x) << 2)
> +#define SDMA_TIMEOUT_DIS BIT(4)
> +
> +#define UART_SDMA11_INT BIT(11)
> +#define UART_SDMA10_INT BIT(10)
> +#define UART_SDMA9_INT BIT(9)
> +#define UART_SDMA8_INT BIT(8)
> +#define UART_SDMA7_INT BIT(7)
> +#define UART_SDMA6_INT BIT(6)
> +#define UART_SDMA5_INT BIT(5)
> +#define UART_SDMA4_INT BIT(4)
> +#define UART_SDMA3_INT BIT(3)
> +#define UART_SDMA2_INT BIT(2)
> +#define UART_SDMA1_INT BIT(1)
> +#define UART_SDMA0_INT BIT(0)
> +
> +/*
> + * Configuration:
> + * share_irqs - whether we pass IRQF_SHARED to request_irq().
> + * This option is unsafe when used on edge-triggered interrupts.
> + */
> +static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
> +
> +static unsigned int nr_uarts = CONFIG_AST_RUNTIME_DMA_UARTS;
> +
> +struct ast_uart_port {
> + struct uart_port port;
> + unsigned short capabilities; /* port capabilities */
> + unsigned short bugs; /* port bugs */
> + unsigned int tx_loadsz; /* transmit fifo load size */
> + unsigned char acr;
> + unsigned char ier;
> + unsigned char lcr;
> + unsigned char mcr;
> + unsigned char mcr_mask; /* mask of user bits */
> + unsigned char mcr_force; /* mask of forced bits */
> + struct circ_buf rx_dma_buf;
> + struct circ_buf tx_dma_buf;
> + unsigned char dma_channel;
> + dma_addr_t dma_rx_addr; /* Mapped ADMA descr. table */
> + dma_addr_t dma_tx_addr; /* Mapped ADMA descr. table */
> +#ifdef CONFIG_AST_UART_DMA_RX_INTERRUPT
> + struct tasklet_struct rx_tasklet;
> +#else
> + struct timer_list rx_timer;
> + unsigned int workaround;
> +#endif
> + struct tasklet_struct tx_tasklet;
> + spinlock_t lock;
> + int tx_done;
> + int tx_count;
> + struct platform_device *ast_uart_pdev;
> +/*
> + * Some bits in registers are cleared on a read, so they must
> + * be saved whenever the register is read but the bits will not
> + * be immediately processed.
> + */
> +#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
> + unsigned char lsr_saved_flags;
> +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
> + unsigned char msr_saved_flags;
> +
> + /*
> + * We provide a per-port pm hook.
> + */
> + void (*pm)(struct uart_port *port, unsigned int state,
> + unsigned int old);
> +};
> +
> +static struct ast_uart_port ast_uart_ports[UART_DMA_NR];
> +
> +#define GET_DEV(ast_uart_port_priv_ptr)\
> + (ast_uart_port_priv_ptr->ast_uart_pdev->dev)
> +
> +static inline struct ast_uart_port *
> +to_ast_dma_uart_port(struct uart_port *uart) {
> + return container_of(uart, struct ast_uart_port, port);
> +}
> +
> +struct irq_info {
> + spinlock_t lock;
> + struct ast_uart_port *up;
> +};
> +
> +static struct irq_info ast_uart_irq[1];
> +static DEFINE_MUTEX(ast_uart_mutex);
> +
> +/*
> + * Here we define the default xmit fifo size used for each type of UART.
> + */
> +static const struct serial8250_config uart_config[] = {
> + [PORT_UNKNOWN] = {
> + .name = "unknown",
> + .fifo_size = 1,
> + .tx_loadsz = 1,
> + },
> + [PORT_8250] = {
> + .name = "8250",
> + .fifo_size = 1,
> + .tx_loadsz = 1,
> + },
> + [PORT_16450] = {
> + .name = "16450",
> + .fifo_size = 1,
> + .tx_loadsz = 1,
> + },
> + [PORT_16550] = {
> + .name = "16550",
> + .fifo_size = 1,
> + .tx_loadsz = 1,
> + },
> + [PORT_16550A] = {
> + .name = "16550A",
> + .fifo_size = 16,
> + .tx_loadsz = 16,
> + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10
> + | UART_FCR_DMA_SELECT,
> + .flags = UART_CAP_FIFO,
> + },
> +};
I doubt you need all of these port types, right? You only have one type
of device, please strip out _ALL_ of the unneeded code in here. You did
a wholesale copy of the old driver, to get away with that you then need
to customize it to work properly with your hardware _AND_ take away all
code that is not needed for your hardware.
Lots of this file can be removed, please do so.
thanks,
greg k-h
^ permalink raw reply
* [v6 2/2] gpio: aspeed: Add SGPIO driver
From: Hongwei Zhang @ 2019-07-30 15:24 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1564500268-2627-1-git-send-email-hongweiz@ami.com>
Add SGPIO driver support for Aspeed AST2500 SoC.
Signed-off-by: Hongwei Zhang <hongweiz@ami.com>
---
drivers/gpio/sgpio-aspeed.c | 521 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 521 insertions(+)
create mode 100644 drivers/gpio/sgpio-aspeed.c
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
new file mode 100644
index 0000000..9a17b1a
--- /dev/null
+++ b/drivers/gpio/sgpio-aspeed.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 American Megatrends International LLC.
+ *
+ * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#define MAX_NR_SGPIO 80
+
+#define ASPEED_SGPIO_CTRL 0x54
+
+#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
+#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
+#define ASPEED_SGPIO_ENABLE BIT(0)
+
+struct aspeed_sgpio {
+ struct gpio_chip chip;
+ struct clk *pclk;
+ spinlock_t lock;
+ void __iomem *base;
+ uint32_t dir_in[3];
+ int irq;
+};
+
+struct aspeed_sgpio_bank {
+ uint16_t val_regs;
+ uint16_t rdata_reg;
+ uint16_t irq_regs;
+ const char names[4][3];
+};
+
+/*
+ * Note: The "value" register returns the input value when the GPIO is
+ * configured as an input.
+ *
+ * The "rdata" register returns the output value when the GPIO is
+ * configured as an output.
+ */
+static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
+ {
+ .val_regs = 0x0000,
+ .rdata_reg = 0x0070,
+ .irq_regs = 0x0004,
+ .names = { "A", "B", "C", "D" },
+ },
+ {
+ .val_regs = 0x001C,
+ .rdata_reg = 0x0074,
+ .irq_regs = 0x0020,
+ .names = { "E", "F", "G", "H" },
+ },
+ {
+ .val_regs = 0x0038,
+ .rdata_reg = 0x0078,
+ .irq_regs = 0x003C,
+ .names = { "I", "J" },
+ },
+};
+
+enum aspeed_sgpio_reg {
+ reg_val,
+ reg_rdata,
+ reg_irq_enable,
+ reg_irq_type0,
+ reg_irq_type1,
+ reg_irq_type2,
+ reg_irq_status,
+};
+
+#define GPIO_VAL_VALUE 0x00
+#define GPIO_IRQ_ENABLE 0x00
+#define GPIO_IRQ_TYPE0 0x04
+#define GPIO_IRQ_TYPE1 0x08
+#define GPIO_IRQ_TYPE2 0x0C
+#define GPIO_IRQ_STATUS 0x10
+
+static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
+ const struct aspeed_sgpio_bank *bank,
+ const enum aspeed_sgpio_reg reg)
+{
+ switch (reg) {
+ case reg_val:
+ return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
+ case reg_rdata:
+ return gpio->base + bank->rdata_reg;
+ case reg_irq_enable:
+ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
+ case reg_irq_type0:
+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
+ case reg_irq_type1:
+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
+ case reg_irq_type2:
+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
+ case reg_irq_status:
+ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
+ default:
+ /* acturally if code runs to here, it's an error case */
+ BUG_ON(1);
+ }
+}
+
+#define GPIO_BANK(x) ((x) >> 5)
+#define GPIO_OFFSET(x) ((x) & 0x1f)
+#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
+
+static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
+{
+ unsigned int bank = GPIO_BANK(offset);
+
+ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
+ return &aspeed_sgpio_banks[bank];
+}
+
+static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ const struct aspeed_sgpio_bank *bank = to_bank(offset);
+ unsigned long flags;
+ enum aspeed_sgpio_reg reg;
+ bool is_input;
+ int rc = 0;
+
+ spin_lock_irqsave(&gpio->lock, flags);
+
+ is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+ reg = is_input ? reg_val : reg_rdata;
+ rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
+
+ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ return rc;
+}
+
+static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ const struct aspeed_sgpio_bank *bank = to_bank(offset);
+ unsigned long flags;
+ void __iomem *addr;
+ u32 reg = 0;
+
+ spin_lock_irqsave(&gpio->lock, flags);
+
+ addr = bank_reg(gpio, bank, reg_val);
+
+ if (val)
+ reg |= GPIO_BIT(offset);
+ else
+ reg &= ~GPIO_BIT(offset);
+
+ iowrite32(reg, addr);
+
+ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
+{
+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio->lock, flags);
+ gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
+ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ return 0;
+}
+
+static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio->lock, flags);
+ gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
+ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ aspeed_sgpio_set(gc, offset, val);
+
+ return 0;
+}
+
+static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ int dir_status;
+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio->lock, flags);
+ dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ return dir_status;
+
+}
+
+static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
+ struct aspeed_sgpio **gpio,
+ const struct aspeed_sgpio_bank **bank,
+ u32 *bit, int *offset)
+{
+ struct aspeed_sgpio *internal;
+
+ *offset = irqd_to_hwirq(d);
+ internal = irq_data_get_irq_chip_data(d);
+ WARN_ON(!internal);
+
+ *gpio = internal;
+ *bank = to_bank(*offset);
+ *bit = GPIO_BIT(*offset);
+}
+
+static void aspeed_sgpio_irq_ack(struct irq_data *d)
+{
+ const struct aspeed_sgpio_bank *bank;
+ struct aspeed_sgpio *gpio;
+ unsigned long flags;
+ void __iomem *status_addr;
+ int offset;
+ u32 bit;
+
+ irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+ status_addr = bank_reg(gpio, bank, reg_irq_status);
+
+ spin_lock_irqsave(&gpio->lock, flags);
+
+ iowrite32(bit, status_addr);
+
+ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
+{
+ const struct aspeed_sgpio_bank *bank;
+ struct aspeed_sgpio *gpio;
+ unsigned long flags;
+ u32 reg, bit;
+ void __iomem *addr;
+ int offset;
+
+ irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+ addr = bank_reg(gpio, bank, reg_irq_enable);
+
+ spin_lock_irqsave(&gpio->lock, flags);
+
+ reg = ioread32(addr);
+ if (set)
+ reg |= bit;
+ else
+ reg &= ~bit;
+
+ iowrite32(reg, addr);
+
+ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_mask(struct irq_data *d)
+{
+ aspeed_sgpio_irq_set_mask(d, false);
+}
+
+static void aspeed_sgpio_irq_unmask(struct irq_data *d)
+{
+ aspeed_sgpio_irq_set_mask(d, true);
+}
+
+static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
+{
+ u32 type0 = 0;
+ u32 type1 = 0;
+ u32 type2 = 0;
+ u32 bit, reg;
+ const struct aspeed_sgpio_bank *bank;
+ irq_flow_handler_t handler;
+ struct aspeed_sgpio *gpio;
+ unsigned long flags;
+ void __iomem *addr;
+ int offset;
+
+ irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_BOTH:
+ type2 |= bit;
+ /* fall through */
+ case IRQ_TYPE_EDGE_RISING:
+ type0 |= bit;
+ /* fall through */
+ case IRQ_TYPE_EDGE_FALLING:
+ handler = handle_edge_irq;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ type0 |= bit;
+ /* fall through */
+ case IRQ_TYPE_LEVEL_LOW:
+ type1 |= bit;
+ handler = handle_level_irq;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&gpio->lock, flags);
+
+ addr = bank_reg(gpio, bank, reg_irq_type0);
+ reg = ioread32(addr);
+ reg = (reg & ~bit) | type0;
+ iowrite32(reg, addr);
+
+ addr = bank_reg(gpio, bank, reg_irq_type1);
+ reg = ioread32(addr);
+ reg = (reg & ~bit) | type1;
+ iowrite32(reg, addr);
+
+ addr = bank_reg(gpio, bank, reg_irq_type2);
+ reg = ioread32(addr);
+ reg = (reg & ~bit) | type2;
+ iowrite32(reg, addr);
+
+ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ irq_set_handler_locked(d, handler);
+
+ return 0;
+}
+
+static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct irq_chip *ic = irq_desc_get_chip(desc);
+ struct aspeed_sgpio *data = gpiochip_get_data(gc);
+ unsigned int i, p, girq;
+ unsigned long reg;
+
+ chained_irq_enter(ic, desc);
+
+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
+
+ reg = ioread32(bank_reg(data, bank, reg_irq_status));
+
+ for_each_set_bit(p, ®, 32) {
+ girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
+ generic_handle_irq(girq);
+ }
+
+ }
+
+ chained_irq_exit(ic, desc);
+}
+
+static struct irq_chip aspeed_sgpio_irqchip = {
+ .name = "aspeed-sgpio",
+ .irq_ack = aspeed_sgpio_irq_ack,
+ .irq_mask = aspeed_sgpio_irq_mask,
+ .irq_unmask = aspeed_sgpio_irq_unmask,
+ .irq_set_type = aspeed_sgpio_set_type,
+};
+
+static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
+ struct platform_device *pdev)
+{
+ int rc, i;
+ const struct aspeed_sgpio_bank *bank;
+
+ rc = platform_get_irq(pdev, 0);
+ if (rc < 0)
+ return rc;
+
+ gpio->irq = rc;
+
+ /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */
+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+ bank = &aspeed_sgpio_banks[i];
+ /* disable irq enable bits */
+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
+ /* clear status bits */
+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
+ }
+
+ rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip,
+ 0, handle_bad_irq, IRQ_TYPE_NONE);
+ if (rc) {
+ dev_info(&pdev->dev, "Could not add irqchip\n");
+ return rc;
+ }
+
+ gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip,
+ gpio->irq, aspeed_sgpio_irq_handler);
+
+ /* set IRQ settings and Enable Interrupt */
+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+ bank = &aspeed_sgpio_banks[i];
+ /* set falling or level-low irq */
+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
+ /* trigger type is edge */
+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
+ /* dual edge trigger mode. */
+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
+ /* enable irq */
+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+ }
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_sgpio_of_table[] = {
+ { .compatible = "aspeed,ast2400-sgpio" },
+ { .compatible = "aspeed,ast2500-sgpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
+
+static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+{
+ struct aspeed_sgpio *gpio;
+ u32 nr_gpios, sgpio_freq, sgpio_clk_div;
+ int rc;
+ unsigned long apb_freq;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ gpio->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(gpio->base))
+ return PTR_ERR(gpio->base);
+
+ rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Could not read ngpios property\n");
+ return -EINVAL;
+ } else if (nr_gpios > MAX_NR_SGPIO) {
+ dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
+ MAX_NR_SGPIO, nr_gpios);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Could not read bus-frequency property\n");
+ return -EINVAL;
+ }
+
+ gpio->pclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(gpio->pclk)) {
+ dev_err(&pdev->dev, "devm_clk_get failed\n");
+ return PTR_ERR(gpio->pclk);
+ }
+
+ apb_freq = clk_get_rate(gpio->pclk);
+
+ /*
+ * From the datasheet,
+ * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
+ * period = 2 * (GPIO254[31:16] + 1) / PCLK
+ * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
+ * frequency = PCLK / (2 * (GPIO254[31:16] + 1))
+ * frequency * 2 * (GPIO254[31:16] + 1) = PCLK
+ * GPIO254[31:16] = PCLK / (frequency * 2) - 1
+ */
+ if (sgpio_freq == 0)
+ return -EINVAL;
+
+ sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
+
+ if (sgpio_clk_div > (1 << 16) - 1)
+ return -EINVAL;
+
+ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
+ FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
+ ASPEED_SGPIO_ENABLE,
+ gpio->base + ASPEED_SGPIO_CTRL);
+
+ spin_lock_init(&gpio->lock);
+
+ gpio->chip.parent = &pdev->dev;
+ gpio->chip.ngpio = nr_gpios;
+ gpio->chip.direction_input = aspeed_sgpio_dir_in;
+ gpio->chip.direction_output = aspeed_sgpio_dir_out;
+ gpio->chip.get_direction = aspeed_sgpio_get_direction;
+ gpio->chip.request = NULL;
+ gpio->chip.free = NULL;
+ gpio->chip.get = aspeed_sgpio_get;
+ gpio->chip.set = aspeed_sgpio_set;
+ gpio->chip.set_config = NULL;
+ gpio->chip.label = dev_name(&pdev->dev);
+ gpio->chip.base = -1;
+
+ /* set all SGPIO pins as input (1). */
+ memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
+
+ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+ if (rc < 0)
+ return rc;
+
+ return aspeed_sgpio_setup_irqs(gpio, pdev);
+}
+
+static struct platform_driver aspeed_sgpio_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = aspeed_sgpio_of_table,
+ },
+};
+
+module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
+MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
+MODULE_LICENSE("GPL");
--
2.7.4
^ permalink raw reply related
* [v6 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
From: Hongwei Zhang @ 2019-07-30 15:24 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <1564500268-2627-1-git-send-email-hongweiz@ami.com>
Add bindings to support SGPIO on AST2400 or AST2500.
Signed-off-by: Hongwei Zhang <hongweiz@ami.com>
---
.../devicetree/bindings/gpio/sgpio-aspeed.txt | 55 ++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
diff --git a/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
new file mode 100644
index 0000000..f9ed438
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
@@ -0,0 +1,55 @@
+Aspeed SGPIO controller Device Tree Bindings
+-------------------------------------------
+
+This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80 full
+featured Serial GPIOs. Each of the Serial GPIO pins can be programmed to
+support the following options:
+- Support interrupt option for each input port and various interrupt
+ sensitivity option (level-high, level-low, edge-high, edge-low)
+- Support reset tolerance option for each output port
+- Directly connected to APB bus and its shift clock is from APB bus clock
+ divided by a programmable value.
+- Co-work with external signal-chained TTL components (74LV165/74LV595)
+
+
+Required properties:
+
+- compatible : Either "aspeed,ast2400-sgpio" or "aspeed,ast2500-sgpio"
+
+- #gpio-cells : Should be two
+ - First cell is the GPIO line number
+ - Second cell is used to specify optional
+ parameters (unused)
+
+- reg : Address and length of the register set for the device
+- gpio-controller : Marks the device node as a GPIO controller
+- interrupts : Interrupt specifier (see interrupt bindings for
+ details)
+
+- interrupt-controller : Mark the GPIO controller as an interrupt-controller
+
+- ngpios : number of GPIO pins to serialise.
+ (should be multiple of 8, up to 80 pins)
+
+- clocks : A phandle to the APB clock for SGPM clock division
+
+- bus-frequency : SGPM CLK frequency
+
+
+The sgpio and interrupt properties are further described in their respective bindings documentation:
+
+- Documentation/devicetree/bindings/sgpio/gpio.txt
+- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+ Example:
+ sgpio: sgpio at 1e780200 {
+ #gpio-cells = <2>;
+ compatible = "aspeed,ast2500-sgpio";
+ gpio-controller;
+ interrupts = <40>;
+ reg = <0x1e780200 0x0100>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+ ngpios = <8>;
+ bus-frequency = <12000000>;
+ };
--
2.7.4
^ permalink raw reply related
* [v6 0/2] gpio: aspeed: Add SGPIO driver
From: Hongwei Zhang @ 2019-07-30 15:24 UTC (permalink / raw)
To: linux-aspeed
Hello,
This short series introduce dt-binding document and a driver for the
Aspeed AST2500 SGPIO controller. Please review.
[v6]: Changes between v5 and v6:
- fix a bug in aspeed_sgpio_dir_out()
- v5 feedback updates, some comments cleanup
The related SGPM pinmux dt-binding document, dts, and pinctrl driver
updates have been accepted and merged:
_http://patchwork.ozlabs.org/patch/1110210/
Hongwei Zhang (2):
dt-bindings: gpio: aspeed: Add SGPIO support
gpio: aspeed: Add SGPIO driver
.../devicetree/bindings/gpio/sgpio-aspeed.txt | 55 +++
drivers/gpio/sgpio-aspeed.c | 521 +++++++++++++++++++++
2 files changed, 576 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
create mode 100644 drivers/gpio/sgpio-aspeed.c
--
2.7.4
^ permalink raw reply
* [PATCH v3 2/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-30 6:23 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190730062316.32037-1-andrew@aj.id.au>
Add a minimal driver for ASPEED's SD controller, which exposes two
SDHCIs.
The ASPEED design implements a common register set for the SDHCIs, and
moves some of the standard configuration elements out to this common
area (e.g. 8-bit mode, and card detect configuration which is not
currently supported).
The SD controller has a dedicated hardware interrupt that is shared
between the slots. The common register set exposes information on which
slot triggered the interrupt; early revisions of the patch introduced an
irqchip for the register, but reality is it doesn't behave as an
irqchip, and the result fits awkwardly into the irqchip APIs. Instead
I've taken the simple approach of using the IRQ as a shared IRQ with
some minor performance impact for the second slot.
Ryan was the original author of the patch - I've taken his work and
massaged it to drop the irqchip support and rework the devicetree
integration. The driver has been smoke tested under qemu against a
minimal SD controller model and lightly tested on an ast2500-evb.
Signed-off-by: Ryan Chen <ryanchen.aspeed@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
v3:
* Add AST2600 compatible
* Drop SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN
* Ensure slot number is valid
* Fix build with CONFIG_MODULES
* Fix module license string
* Non-PCI devices won't die
* Rename aspeed_sdc_configure_8bit_mode()
* Rename aspeed_sdhci_pdata
* Switch to sdhci_enable_clk()
* Use PTR_ERR() on the right `struct platform_device *`
---
drivers/mmc/host/Kconfig | 12 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-aspeed.c | 328 +++++++++++++++++++++++++++++
3 files changed, 341 insertions(+)
create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 14d89a108edd..0f8a230de2f3 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -154,6 +154,18 @@ config MMC_SDHCI_OF_ARASAN
If unsure, say N.
+config MMC_SDHCI_OF_ASPEED
+ tristate "SDHCI OF support for the ASPEED SDHCI controller"
+ depends on MMC_SDHCI_PLTFM
+ depends on OF
+ help
+ This selects the ASPEED Secure Digital Host Controller Interface.
+
+ If you have a controller with this interface, say Y or M here. You
+ also need to enable an appropriate bus interface.
+
+ If unsure, say N.
+
config MMC_SDHCI_OF_AT91
tristate "SDHCI OF support for the Atmel SDMMC controller"
depends on MMC_SDHCI_PLTFM
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..390ee162fe71 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
+obj-$(CONFIG_MMC_SDHCI_OF_ASPEED) += sdhci-of-aspeed.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
new file mode 100644
index 000000000000..d31785ec90d7
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2019 ASPEED Technology Inc. */
+/* Copyright (C) 2019 IBM Corp. */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "sdhci-pltfm.h"
+
+#define ASPEED_SDC_INFO 0x00
+#define ASPEED_SDC_S1MMC8 BIT(25)
+#define ASPEED_SDC_S0MMC8 BIT(24)
+
+struct aspeed_sdc {
+ struct clk *clk;
+ struct resource *res;
+
+ spinlock_t lock;
+ void __iomem *regs;
+};
+
+struct aspeed_sdhci {
+ struct aspeed_sdc *parent;
+ u32 width_mask;
+};
+
+static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc,
+ struct aspeed_sdhci *sdhci,
+ bool bus8)
+{
+ u32 info;
+
+ /* Set/clear 8 bit mode */
+ spin_lock(&sdc->lock);
+ info = readl(sdc->regs + ASPEED_SDC_INFO);
+ if (bus8)
+ info |= sdhci->width_mask;
+ else
+ info &= ~sdhci->width_mask;
+ writel(info, sdc->regs + ASPEED_SDC_INFO);
+ spin_unlock(&sdc->lock);
+}
+
+static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ int div;
+ u16 clk;
+
+ if (clock == host->clock)
+ return;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ if (clock == 0)
+ goto out;
+
+ for (div = 1; div < 256; div *= 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ div >>= 1;
+
+ clk = div << SDHCI_DIVIDER_SHIFT;
+
+ sdhci_enable_clk(host, clk);
+
+out:
+ host->clock = clock;
+}
+
+static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+ struct sdhci_pltfm_host *pltfm_priv;
+ struct aspeed_sdhci *aspeed_sdhci;
+ struct aspeed_sdc *aspeed_sdc;
+ u8 ctrl;
+
+ pltfm_priv = sdhci_priv(host);
+ aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv);
+ aspeed_sdc = aspeed_sdhci->parent;
+
+ /* Set/clear 8-bit mode */
+ aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci,
+ width == MMC_BUS_WIDTH_8);
+
+ /* Set/clear 1 or 4 bit mode */
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+static const struct sdhci_ops aspeed_sdhci_ops = {
+ .set_clock = aspeed_sdhci_set_clock,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = aspeed_sdhci_set_bus_width,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .reset = sdhci_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data aspeed_sdhci_pdata = {
+ .ops = &aspeed_sdhci_ops,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+};
+
+static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
+ struct resource *res)
+{
+ resource_size_t delta;
+
+ if (!res || resource_type(res) != IORESOURCE_MEM)
+ return -EINVAL;
+
+ if (res->start < dev->parent->res->start)
+ return -EINVAL;
+
+ delta = res->start - dev->parent->res->start;
+ if (delta & (0x100 - 1))
+ return -EINVAL;
+
+ return (delta / 0x100) - 1;
+}
+
+static int aspeed_sdhci_probe(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct aspeed_sdhci *dev;
+ struct sdhci_host *host;
+ struct resource *res;
+ int slot;
+ int ret;
+
+ host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+ dev = sdhci_pltfm_priv(pltfm_host);
+ dev->parent = dev_get_drvdata(pdev->dev.parent);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ slot = aspeed_sdhci_calculate_slot(dev, res);
+
+ if (slot < 0)
+ return slot;
+ else if (slot >= 2)
+ return -EINVAL;
+
+ dev_info(&pdev->dev, "Configuring for slot %d\n", slot);
+ dev->width_mask = !slot ? ASPEED_SDC_S0MMC8 : ASPEED_SDC_S1MMC8;
+
+ sdhci_get_of_property(pdev);
+
+ pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pltfm_host->clk))
+ return PTR_ERR(pltfm_host->clk);
+
+ ret = clk_prepare_enable(pltfm_host->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable SDIO clock\n");
+ goto err_pltfm_free;
+ }
+
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err_sdhci_add;
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ goto err_sdhci_add;
+
+ return 0;
+
+err_sdhci_add:
+ clk_disable_unprepare(pltfm_host->clk);
+err_pltfm_free:
+ sdhci_pltfm_free(pdev);
+ return ret;
+}
+
+static int aspeed_sdhci_remove(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_host *host;
+ int dead = 0;
+
+ host = platform_get_drvdata(pdev);
+ pltfm_host = sdhci_priv(host);
+
+ sdhci_remove_host(host, dead);
+
+ clk_disable_unprepare(pltfm_host->clk);
+
+ sdhci_pltfm_free(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_sdhci_of_match[] = {
+ { .compatible = "aspeed,ast2400-sdhci", },
+ { .compatible = "aspeed,ast2500-sdhci", },
+ { .compatible = "aspeed,ast2600-sdhci", },
+ { }
+};
+
+static struct platform_driver aspeed_sdhci_driver = {
+ .driver = {
+ .name = "sdhci-aspeed",
+ .of_match_table = aspeed_sdhci_of_match,
+ },
+ .probe = aspeed_sdhci_probe,
+ .remove = aspeed_sdhci_remove,
+};
+
+static int aspeed_sdc_probe(struct platform_device *pdev)
+
+{
+ struct device_node *parent, *child;
+ struct aspeed_sdc *sdc;
+ int ret;
+
+ sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
+ if (!sdc)
+ return -ENOMEM;
+
+ spin_lock_init(&sdc->lock);
+
+ sdc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sdc->clk))
+ return PTR_ERR(sdc->clk);
+
+ ret = clk_prepare_enable(sdc->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable SDCLK\n");
+ return ret;
+ }
+
+ sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res);
+ if (IS_ERR(sdc->regs)) {
+ ret = PTR_ERR(sdc->regs);
+ goto err_clk;
+ }
+
+ dev_set_drvdata(&pdev->dev, sdc);
+
+ parent = pdev->dev.of_node;
+ for_each_available_child_of_node(parent, child) {
+ struct platform_device *cpdev;
+
+ cpdev = of_platform_device_create(child, NULL, &pdev->dev);
+ if (IS_ERR(cpdev)) {
+ of_node_put(child);
+ ret = PTR_ERR(cpdev);
+ goto err_clk;
+ }
+ }
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(sdc->clk);
+ return ret;
+}
+
+static int aspeed_sdc_remove(struct platform_device *pdev)
+{
+ struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(sdc->clk);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_sdc_of_match[] = {
+ { .compatible = "aspeed,ast2400-sd-controller", },
+ { .compatible = "aspeed,ast2500-sd-controller", },
+ { .compatible = "aspeed,ast2600-sd-controller", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
+
+static struct platform_driver aspeed_sdc_driver = {
+ .driver = {
+ .name = "sd-controller-aspeed",
+ .pm = &sdhci_pltfm_pmops,
+ .of_match_table = aspeed_sdc_of_match,
+ },
+ .probe = aspeed_sdc_probe,
+ .remove = aspeed_sdc_remove,
+};
+
+static int __init aspeed_sdc_init(void)
+{
+ int rc;
+
+ rc = platform_driver_register(&aspeed_sdhci_driver);
+ if (rc < 0)
+ return rc;
+
+ return platform_driver_register(&aspeed_sdc_driver);
+}
+module_init(aspeed_sdc_init);
+
+static void __exit aspeed_sdc_exit(void)
+{
+ platform_driver_unregister(&aspeed_sdc_driver);
+ platform_driver_unregister(&aspeed_sdhci_driver);
+}
+module_exit(aspeed_sdc_exit);
+
+MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_LICENSE("GPL");
--
2.20.1
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: mmc: Document Aspeed SD controller
From: Andrew Jeffery @ 2019-07-30 6:23 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190730062316.32037-1-andrew@aj.id.au>
The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the
SDIO Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit
data bus if only a single slot is enabled.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
v3:
* Fix compatible enums
* Add AST2600 compatibles
* Describe #address-cells / #size-cells
---
.../devicetree/bindings/mmc/aspeed,sdhci.yaml | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
new file mode 100644
index 000000000000..dd2a00c59641
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/aspeed,sdhci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED SD/SDIO/eMMC Controller
+
+maintainers:
+ - Andrew Jeffery <andrew@aj.id.au>
+ - Ryan Chen <ryanchen.aspeed@gmail.com>
+
+description: |+
+ The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO
+ Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if
+ only a single slot is enabled.
+
+ The two slots are supported by a common configuration area. As the SDHCIs for
+ the slots are dependent on the common configuration area, they are described
+ as child nodes.
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2400-sd-controller
+ - aspeed,ast2500-sd-controller
+ - aspeed,ast2600-sd-controller
+ reg:
+ maxItems: 1
+ description: Common configuration registers
+ "#address-cells":
+ const: 1
+ "#size-cells":
+ const: 1
+ ranges: true
+ clocks:
+ maxItems: 1
+ description: The SD/SDIO controller clock gate
+
+patternProperties:
+ "^sdhci@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ enum:
+ - aspeed,ast2400-sdhci
+ - aspeed,ast2500-sdhci
+ - aspeed,ast2600-sdhci
+ reg:
+ maxItems: 1
+ description: The SDHCI registers
+ clocks:
+ maxItems: 1
+ description: The SD bus clock
+ interrupts:
+ maxItems: 1
+ description: The SD interrupt shared between both slots
+ required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+ - clocks
+
+examples:
+ - |
+ #include <dt-bindings/clock/aspeed-clock.h>
+ sdc at 1e740000 {
+ compatible = "aspeed,ast2500-sd-controller";
+ reg = <0x1e740000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x1e740000 0x10000>;
+ clocks = <&syscon ASPEED_CLK_GATE_SDCLK>;
+
+ sdhci0: sdhci at 100 {
+ compatible = "aspeed,ast2500-sdhci";
+ reg = <0x100 0x100>;
+ interrupts = <26>;
+ sdhci,auto-cmd12;
+ clocks = <&syscon ASPEED_CLK_SDIO>;
+ };
+
+ sdhci1: sdhci at 200 {
+ compatible = "aspeed,ast2500-sdhci";
+ reg = <0x200 0x100>;
+ interrupts = <26>;
+ sdhci,auto-cmd12;
+ clocks = <&syscon ASPEED_CLK_SDIO>;
+ };
+ };
--
2.20.1
^ permalink raw reply related
* [PATCH v3 0/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-30 6:23 UTC (permalink / raw)
To: linux-aspeed
Hello,
v3 of the ASPEED SDHCI driver makes a bunch of fixes to the driver and the
devicetree binding, including the addition of the AST2600 compatible string.
v2 can be found here:
https://lists.ozlabs.org/pipermail/linux-aspeed/2019-July/002013.html
Please review!
Andrew
Andrew Jeffery (2):
dt-bindings: mmc: Document Aspeed SD controller
mmc: Add support for the ASPEED SD controller
.../devicetree/bindings/mmc/aspeed,sdhci.yaml | 100 ++++++
drivers/mmc/host/Kconfig | 12 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-aspeed.c | 328 ++++++++++++++++++
4 files changed, 441 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c
--
2.20.1
^ permalink raw reply
* [PATCH] ARM: dts: aspeed: Add Mihawk BMC platform
From: Ben Pai @ 2019-07-30 6:00 UTC (permalink / raw)
To: linux-aspeed
The Mihawk BMC is an ASPEED ast2500 based BMC that is part of an
OpenPower Power9 server.
This adds the device tree description for most upstream components. It
is a squashed commit from the OpenBMC kernel tree.
Signed-off-by: Ben Pai <Ben_Pai@wistron.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts | 922 ++++++++++++++++++++
2 files changed, 923 insertions(+)
create mode 100755 arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index eb6de52c1936..262345544359 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -1281,5 +1281,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-opp-vesnin.dtb \
aspeed-bmc-opp-witherspoon.dtb \
aspeed-bmc-opp-zaius.dtb \
+ aspeed-bmc-opp-mihawk.dtb \
aspeed-bmc-portwell-neptune.dtb \
aspeed-bmc-quanta-q71l.dtb
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
new file mode 100755
index 000000000000..cfa20e0b2939
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
@@ -0,0 +1,922 @@
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+ model = "Mihawk BMC";
+ compatible = "ibm,mihawk-bmc", "aspeed,ast2500";
+
+
+ chosen {
+ stdout-path = &uart5;
+ bootargs = "console=ttyS4,115200 earlyprintk";
+ };
+
+ memory at 80000000 {
+ reg = <0x80000000 0x20000000>; /* address and size of RAM(512MB) */
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ flash_memory: region at 98000000 {
+ no-map;
+ reg = <0x98000000 0x04000000>; /* 64M */
+ };
+
+ gfx_memory: framebuffer {
+ size = <0x01000000>;
+ alignment = <0x01000000>;
+ compatible = "shared-dma-pool";
+ reusable;
+ };
+
+ video_engine_memory: jpegbuffer {
+ size = <0x02000000>; /* 32MM */
+ alignment = <0x01000000>;
+ compatible = "shared-dma-pool";
+ reusable;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ air-water {
+ label = "air-water";
+ gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(F, 6)>;
+ };
+
+ checkstop {
+ label = "checkstop";
+ gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(J, 2)>;
+ };
+
+ ps0-presence {
+ label = "ps0-presence";
+ gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(Z, 2)>;
+ };
+
+ ps1-presence {
+ label = "ps1-presence";
+ gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(Z, 0)>;
+ };
+ id-button {
+ label = "id-button";
+ gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(F, 1)>;
+ };
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <1000>;
+
+ fan0-presence {
+ label = "fan0-presence";
+ gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
+ linux,code = <9>;
+ };
+
+ fan1-presence {
+ label = "fan1-presence";
+ gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
+ linux,code = <10>;
+ };
+
+ fan2-presence {
+ label = "fan2-presence";
+ gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
+ linux,code = <11>;
+ };
+
+ fan3-presence {
+ label = "fan3-presence";
+ gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
+ linux,code = <12>;
+ };
+
+ fan4-presence {
+ label = "fan4-presence";
+ gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
+ linux,code = <13>;
+ };
+
+ fan5-presence {
+ label = "fan5-presence";
+ gpios = <&pca9552 14 GPIO_ACTIVE_LOW>;
+ linux,code = <14>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ fault {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
+ };
+
+ power {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>;
+ };
+
+ rear-id {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>;
+ };
+
+ rear-g {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&gpio ASPEED_GPIO(AA, 4) GPIO_ACTIVE_LOW>;
+ };
+
+ rear-ok {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&gpio ASPEED_GPIO(Y, 0) GPIO_ACTIVE_LOW>;
+ };
+
+ fan0 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 0 GPIO_ACTIVE_LOW>;
+ };
+
+ fan1 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 1 GPIO_ACTIVE_LOW>;
+ };
+
+ fan2 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 2 GPIO_ACTIVE_LOW>;
+ };
+
+ fan3 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 3 GPIO_ACTIVE_LOW>;
+ };
+
+ fan4 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 4 GPIO_ACTIVE_LOW>;
+ };
+
+ fan5 {
+ retain-state-shutdown;
+ default-state = "keep";
+ gpios = <&pca9552 5 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ fsi: gpio-fsi {
+ compatible = "fsi-master-gpio", "fsi-master";
+ #address-cells = <2>;
+ #size-cells = <0>;
+ no-gpio-delays;
+
+ clock-gpios = <&gpio ASPEED_GPIO(E, 6) GPIO_ACTIVE_HIGH>;
+ data-gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_HIGH>;
+ mux-gpios = <&gpio ASPEED_GPIO(E, 5) GPIO_ACTIVE_HIGH>;
+ enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
+ trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+ };
+ iio-hwmon-12v {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 0>;
+ };
+
+ iio-hwmon-5v {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 1>;
+ };
+
+ iio-hwmon-3v {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 2>;
+ };
+
+ iio-hwmon-vdd0 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 3>;
+ };
+
+ iio-hwmon-vdd1 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 4>;
+ };
+
+ iio-hwmon-vcs0 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 5>;
+ };
+
+ iio-hwmon-vcs1 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 6>;
+ };
+
+ iio-hwmon-vdn0 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 7>;
+ };
+
+ iio-hwmon-vdn1 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 8>;
+ };
+
+ iio-hwmon-vio0 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 9>;
+ };
+
+ iio-hwmon-vio1 {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 10>;
+ };
+
+ iio-hwmon-vddra {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 11>;
+ };
+
+ iio-hwmon-vddrb {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 13>;
+ };
+
+ iio-hwmon-vddrc {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 14>;
+ };
+
+ iio-hwmon-vddrd {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 15>;
+ };
+
+ iio-hwmon-battery {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 12>;
+ };
+};
+
+&pwm_tacho {
+ status = "okay";
+ /*compatible = "aspeed,ast2500-pwm-tacho";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1e786000 0x1000>;
+ clocks = <&pwm_tacho_fixed_clk>;*/
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
+ &pinctrl_pwm2_default &pinctrl_pwm3_default
+ &pinctrl_pwm4_default &pinctrl_pwm5_default>;
+
+ fan at 0 {
+ reg = <0x00>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x00>;
+ };
+
+ fan at 1 {
+ reg = <0x01>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x01>;
+ };
+
+ fan at 2 {
+ reg = <0x02>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x02>;
+ };
+
+ fan at 3 {
+ reg = <0x03>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x03>;
+ };
+
+ fan at 4 {
+ reg = <0x04>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x04>;
+ };
+
+ fan at 5 {
+ reg = <0x05>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x05>;
+ };
+
+ fan at 6 {
+ reg = <0x00>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x06>;
+ };
+
+ fan at 7 {
+ reg = <0x01>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x07>;
+ };
+
+ fan at 8 {
+ reg = <0x02>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x08>;
+ };
+
+ fan at 9 {
+ reg = <0x03>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x09>;
+ };
+
+ fan at 10 {
+ reg = <0x04>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x0a>;
+ };
+
+ fan at 11 {
+ reg = <0x05>;
+ aspeed,fan-tach-ch = /bits/ 8 <0x0b>;
+ };
+};
+
+&fmc {
+ status = "okay";
+ flash at 0 {
+ status = "okay";
+ label = "bmc";
+ m25p,fast-read;
+ spi-max-frequency = <50000000>;
+ partitions {
+ #address-cells = < 1 >;
+ #size-cells = < 1 >;
+ compatible = "fixed-partitions";
+ u-boot at 0 {
+ reg = < 0 0x60000 >;
+ label = "u-boot";
+ };
+ u-boot-env at 60000 {
+ reg = < 0x60000 0x20000 >;
+ label = "u-boot-env";
+ };
+ obmc-ubi at 80000 {
+ reg = < 0x80000 0x1F80000 >;
+ label = "obmc-ubi";
+ };
+ };
+ };
+ flash at 1 {
+ status = "okay";
+ label = "alt-bmc";
+ m25p,fast-read;
+ spi-max-frequency = <50000000>;
+ partitions {
+ #address-cells = < 1 >;
+ #size-cells = < 1 >;
+ compatible = "fixed-partitions";
+ u-boot at 0 {
+ reg = < 0 0x60000 >;
+ label = "alt-u-boot";
+ };
+ u-boot-env at 60000 {
+ reg = < 0x60000 0x20000 >;
+ label = "alt-u-boot-env";
+ };
+ obmc-ubi at 80000 {
+ reg = < 0x80000 0x1F80000 >;
+ label = "alt-obmc-ubi";
+ };
+ };
+ };
+};
+
+&spi1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
+
+ flash at 0 {
+ status = "okay";
+ label = "pnor";
+ m25p,fast-read;
+ spi-max-frequency = <100000000>;
+ };
+};
+
+&lpc_ctrl {
+ status = "okay";
+ memory-region = <&flash_memory>;
+ flash = <&spi1>;
+};
+
+&uart1 {
+ /* Rear RS-232 connector */
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default
+ &pinctrl_rxd1_default
+ &pinctrl_nrts1_default
+ &pinctrl_ndtr1_default
+ &pinctrl_ndsr1_default
+ &pinctrl_ncts1_default
+ &pinctrl_ndcd1_default
+ &pinctrl_nri1_default>;
+};
+
+&uart2 {
+ /* APSS */
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+};
+
+&uart5 {
+ status = "okay";
+};
+
+&mac0 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii1_default>;
+ use-ncsi;
+};
+
+&mac1 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&i2c0 {
+ status = "disabled";
+};
+
+&i2c1 {
+ status = "disabled";
+};
+
+&i2c2 {
+ status = "okay";
+
+ /* SAMTEC P0 */
+ /* SAMTEC P1 */
+
+};
+
+&i2c3 {
+ status = "okay";
+
+ /* APSS */
+ /* CPLD */
+
+ /* PCA9516 (repeater) ->
+ * CLK Buffer 9FGS9092
+ * CLK Buffer 9DBL0651BKILFT
+ * CLK Buffer 9DBL0651BKILFT
+ * Power Supply 0
+ * Power Supply 1
+ * PCA 9552 LED
+ */
+
+ power-supply at 58 {
+ compatible = "ibm,cffps1";
+ reg = <0x58>;
+ };
+
+ power-supply at 5b {
+ compatible = "ibm,cffps1";
+ reg = <0x5b>;
+ };
+
+ pca9552: pca9552 at 60 {
+ compatible = "nxp,pca9552";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio at 0 {
+ reg = <0>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 1 {
+ reg = <1>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 2 {
+ reg = <2>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 3 {
+ reg = <3>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 4 {
+ reg = <4>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 5 {
+ reg = <5>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 6 {
+ reg = <6>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 7 {
+ reg = <7>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 8 {
+ reg = <8>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 9 {
+ reg = <9>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 10 {
+ reg = <10>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 11 {
+ reg = <11>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 12 {
+ reg = <12>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 13 {
+ reg = <13>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 14 {
+ reg = <14>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ gpio at 15 {
+ reg = <15>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ };
+
+};
+
+&i2c4 {
+ status = "okay";
+
+ /* CP0 VDD & VCS : IR35221 */
+ /* CP0 VDN : IR35221 */
+ /* CP0 VIO : IR38064 */
+ /* CP0 VDDR : PXM1330 */
+
+ ir35221 at 70 {
+ compatible = "infineon,ir35221";
+ reg = <0x70>;
+ };
+
+ ir35221 at 72 {
+ compatible = "infineon,ir35221";
+ reg = <0x72>;
+ };
+
+};
+
+&i2c5 {
+ status = "okay";
+
+ /* CP0 VDD & VCS : IR35221 */
+ /* CP0 VDN : IR35221 */
+ /* CP0 VIO : IR38064 */
+ /* CP0 VDDR : PXM1330 */
+
+ ir35221 at 70 {
+ compatible = "infineon,ir35221";
+ reg = <0x70>;
+ };
+
+ ir35221 at 72 {
+ compatible = "infineon,ir35221";
+ reg = <0x72>;
+ };
+
+};
+
+&i2c6 {
+ status = "okay";
+
+ /* pca9548 -> NVMe1 to 8 */
+
+ pca9548 at 70 {
+ compatible = "nxp,pca9548";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ };
+
+};
+
+&i2c7 {
+ status = "okay";
+
+ /* pca9548 -> NVMe9 to 16 */
+
+ pca9548 at 70 {
+ compatible = "nxp,pca9548";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ };
+
+};
+
+&i2c8 {
+ status = "okay";
+
+ /* FSI CLK/DAT */
+ eeprom at 50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+};
+
+&i2c9 {
+ status = "okay";
+
+ /* pca9545 Riser ->
+ * PCIe x8 Slot3
+ * PCIe x16 slot4
+ * PCIe x8 slot5
+ * I2C BMC RISER PCA9554
+ * BMC SCL/SDA PCA9554
+ * PCA9554
+ */
+
+ /* pca9545 ->
+ * PCIe x16 Slot1
+ * PCIe x8 slot2
+ * PEX8748
+ */
+
+ pca9545riser at 70 {
+ compatible = "nxp,pca9545";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+
+ /*interrupt-parent = <&ipic>;*/
+ /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
+ i2c-mux-idle-disconnect;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pca9545 at 71 {
+ compatible = "nxp,pca9545";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x71>;
+
+ /*interrupt-parent = <&ipic>;*/
+ /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
+ i2c-mux-idle-disconnect;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+
+ /* pca9545 Riser ->
+ * PCIe x8 Slot8
+ * PCIe x16 slot9
+ * PCIe x8 slot10
+ * I2C BMC RISER PCA9554
+ * BMC SCL/SDA PCA9554
+ * PCA9554
+ */
+
+ /* pca9545 ->
+ * PCIe x16 Slot1
+ * PCIe x8 slot2
+ * PEX8748
+ */
+
+ pca9545riser at 70 {
+ compatible = "nxp,pca9545";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+
+ /*interrupt-parent = <&ipic>;*/
+ /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
+ i2c-mux-idle-disconnect;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pca9545 at 71 {
+ compatible = "nxp,pca9545";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x71>;
+
+ /*interrupt-parent = <&ipic>;*/
+ /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
+ i2c-mux-idle-disconnect;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
+
+&i2c11 {
+ status = "okay";
+
+ /* TPM */
+ /* RTC RX8900CE */
+ /* FPGA for power sequence */
+ /* TMP275A */
+ /* TMP275A */
+ /* EMC1462 */
+
+ tpm at 57 {
+ compatible = "infineon,slb9645tt";
+ reg = <0x57>;
+ };
+
+ rtc at 32 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+
+ tmp275 at 48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275 at 49 {
+ compatible = "ti,tmp275";
+ reg = <0x49>;
+ };
+
+ /* chip emc1462 use emc1403 driver */
+ emc1403 at 4c {
+ compatible = "smsc,emc1403";
+ reg = <0x4c>;
+ };
+
+};
+
+&i2c12 {
+ status = "okay";
+
+ /* pca9545 ->
+ * SAS BP1
+ * SAS BP2
+ * NVMe BP
+ * M.2 riser
+ */
+
+ pca9545 at 70 {
+ compatible = "nxp,pca9545";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+
+ /*interrupt-parent = <&ipic>;*/
+ /*interrupts = <17 IRQ_TYPE_LEVEL_LOW>;*/
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ i2c at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ eeprom at 50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+ };
+
+ i2c at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ eeprom at 50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+ };
+
+ i2c at 2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ eeprom at 50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+ };
+
+ i2c at 3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ tmp275 at 48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+ };
+
+ };
+
+};
+
+&i2c13 {
+ status = "okay";
+
+ /* pca9548 ->
+ * NVMe BP
+ * NVMe HDD17 to 24
+ */
+
+ pca9548 at 70 {
+ compatible = "nxp,pca9548";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ };
+};
+
+&vuart {
+ status = "okay";
+};
+
+&gfx {
+ status = "okay";
+ memory-region = <&gfx_memory>;
+};
+
+&pinctrl {
+ aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&adc {
+ status = "okay";
+};
+
+&wdt1 {
+ aspeed,reset-type = "none";
+ aspeed,external-signal;
+ aspeed,ext-push-pull;
+ aspeed,ext-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&wdt2 {
+ aspeed,alt-boot;
+};
+
+&ibt {
+ status = "okay";
+};
+
+&vhub {
+ status = "okay";
+};
+
+&video {
+ status = "okay";
+ memory-region = <&video_engine_memory>;
+};
+
+#include "ibm-power9-dual.dtsi"
\ No newline at end of file
--
2.17.1
---------------------------------------------------------------------------------------------------------------------------------------------------------------
This email contains confidential or legally privileged information and is for the sole use of its intended recipient.
Any unauthorized review, use, copying or distribution of this email or the content of this email is strictly prohibited.
If you are not the intended recipient, you may reply to the sender and should delete this e-mail immediately.
---------------------------------------------------------------------------------------------------------------------------------------------------------------
^ permalink raw reply related
* [PATCH 2/4] net: phy: Add mdio-aspeed
From: Andrew Jeffery @ 2019-07-30 2:23 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190729133250.GB4110@lunn.ch>
On Mon, 29 Jul 2019, at 23:03, Andrew Lunn wrote:
> On Mon, Jul 29, 2019 at 02:09:24PM +0930, Andrew Jeffery wrote:
> > The AST2600 design separates the MDIO controllers from the MAC, which is
> > where they were placed in the AST2400 and AST2500. Further, the register
> > interface is reworked again, so now we have three possible different
> > interface implementations, however this driver only supports the
> > interface provided by the AST2600. The AST2400 and AST2500 will continue
> > to be supported by the MDIO support embedded in the FTGMAC100 driver.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > drivers/net/phy/Kconfig | 13 +++
> > drivers/net/phy/Makefile | 1 +
> > drivers/net/phy/mdio-aspeed.c | 159 ++++++++++++++++++++++++++++++++++
> > 3 files changed, 173 insertions(+)
> > create mode 100644 drivers/net/phy/mdio-aspeed.c
> >
> > diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> > index 20f14c5fbb7e..206d8650ee7f 100644
> > --- a/drivers/net/phy/Kconfig
> > +++ b/drivers/net/phy/Kconfig
> > @@ -21,6 +21,19 @@ config MDIO_BUS
> >
> > if MDIO_BUS
> >
> > +config MDIO_ASPEED
> > + tristate "ASPEED MDIO bus controller"
> > + depends on ARCH_ASPEED || COMPILE_TEST
> > + depends on OF_MDIO && HAS_IOMEM
> > + help
> > + This module provides a driver for the independent MDIO bus
> > + controllers found in the ASPEED AST2600 SoC. This is a driver for the
> > + third revision of the ASPEED MDIO register interface - the first two
> > + revisions are the "old" and "new" interfaces found in the AST2400 and
> > + AST2500, embedded in the MAC. For legacy reasons, FTGMAC100 driver
> > + continues to drive the embedded MDIO controller for the AST2400 and
> > + AST2500 SoCs, so say N if AST2600 support is not required.
> > +
> > config MDIO_BCM_IPROC
> > tristate "Broadcom iProc MDIO bus controller"
> > depends on ARCH_BCM_IPROC || COMPILE_TEST
> > diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> > index 839acb292c38..ba07c27e4208 100644
> > --- a/drivers/net/phy/Makefile
> > +++ b/drivers/net/phy/Makefile
> > @@ -22,6 +22,7 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o
> > obj-$(CONFIG_PHYLINK) += phylink.o
> > obj-$(CONFIG_PHYLIB) += libphy.o
> >
> > +obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o
> > obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
> > obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
> > obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
> > diff --git a/drivers/net/phy/mdio-aspeed.c b/drivers/net/phy/mdio-aspeed.c
> > new file mode 100644
> > index 000000000000..71496a9ff54a
> > --- /dev/null
> > +++ b/drivers/net/phy/mdio-aspeed.c
> > @@ -0,0 +1,159 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/* Copyright (C) 2019 IBM Corp. */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/delay.h>
> > +#include <linux/mdio.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_mdio.h>
> > +#include <linux/phy.h>
> > +#include <linux/platform_device.h>
> > +
> > +#define DRV_NAME "mdio-aspeed"
> > +
> > +#define ASPEED_MDIO_CTRL 0x0
> > +#define ASPEED_MDIO_CTRL_FIRE BIT(31)
> > +#define ASPEED_MDIO_CTRL_ST BIT(28)
> > +#define ASPEED_MDIO_CTRL_ST_C45 0
> > +#define ASPEED_MDIO_CTRL_ST_C22 1
> > +#define ASPEED_MDIO_CTRL_OP GENMASK(27, 26)
> > +#define MDIO_C22_OP_WRITE 0b01
> > +#define MDIO_C22_OP_READ 0b10
> > +#define ASPEED_MDIO_CTRL_PHYAD GENMASK(25, 21)
> > +#define ASPEED_MDIO_CTRL_REGAD GENMASK(20, 16)
> > +#define ASPEED_MDIO_CTRL_MIIWDATA GENMASK(15, 0)
> > +
> > +#define ASPEED_MDIO_DATA 0x4
> > +#define ASPEED_MDIO_DATA_MDC_THRES GENMASK(31, 24)
> > +#define ASPEED_MDIO_DATA_MDIO_EDGE BIT(23)
> > +#define ASPEED_MDIO_DATA_MDIO_LATCH GENMASK(22, 20)
> > +#define ASPEED_MDIO_DATA_IDLE BIT(16)
> > +#define ASPEED_MDIO_DATA_MIIRDATA GENMASK(15, 0)
> > +
> > +#define ASPEED_MDIO_RETRIES 10
> > +
> > +struct aspeed_mdio {
> > + void __iomem *base;
> > +};
> > +
> > +static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum)
> > +{
> > + struct aspeed_mdio *ctx = bus->priv;
> > + u32 ctrl;
> > + int i;
> > +
> > + dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d\n", __func__, addr,
> > + regnum);
> > +
> > + /* Just clause 22 for the moment */
> > + ctrl = ASPEED_MDIO_CTRL_FIRE
>
> Hi Andrew
>
> In the binding, you say C45 is supported. Here you don't. It would be
> nice to be consistent.
Right - but the bindings describe the hardware, and the hardware is capable.
Just that the driver as it stands can't drive it that way.
Having said that I do need to do more digging to understand how to cater to
C45 PHYs wrt the read/write calls.
>
>
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum);
> > +
> > + iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> > +
> > + for (i = 0; i < ASPEED_MDIO_RETRIES; i++) {
> > + u32 data;
> > +
> > + data = ioread32(ctx->base + ASPEED_MDIO_DATA);
> > + if (data & ASPEED_MDIO_DATA_IDLE)
> > + return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
> > +
> > + udelay(100);
> > + }
>
> One of the readx_poll_timeout functions could be used.
Thanks, I'll take a look.
>
> > +
> > + dev_err(&bus->dev, "MDIO read failed\n");
> > + return -EIO;
> > +}
> > +
> > +static int aspeed_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
> > +{
> > + struct aspeed_mdio *ctx = bus->priv;
> > + u32 ctrl;
> > + int i;
> > +
> > + dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d, val: 0x%x\n",
> > + __func__, addr, regnum, val);
> > +
> > + /* Just clause 22 for the moment */
> > + ctrl = ASPEED_MDIO_CTRL_FIRE
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
> > +
> > + iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> > +
> > + for (i = 0; i < ASPEED_MDIO_RETRIES; i++) {
> > + ctrl = ioread32(ctx->base + ASPEED_MDIO_CTRL);
> > + if (!(ctrl & ASPEED_MDIO_CTRL_FIRE))
> > + return 0;
> > +
> > + udelay(100);
> > + }
>
> readx_poll_timeout() here as well.
>
> Otherwise this looks good.
Thanks for the review!
Andrew
^ permalink raw reply
* [PATCH v2 3/3] ARM: dts: aspeed: Add uart-routing node
From: Oskar Senft @ 2019-07-30 1:49 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190730014955.34059-1-osk@google.com>
Add a node for the aspeed-uart-routing module. This node, when enabled
will provide control of the Aspeed UART routing via sysfs.
Signed-off-by: Oskar Senft <osk@google.com>
---
Changes since v1:
Added AST2400.
arch/arm/boot/dts/aspeed-g4.dtsi | 6 ++++++
arch/arm/boot/dts/aspeed-g5.dtsi | 6 ++++++
2 files changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index dd4b0b15afcf..d855bc19d677 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -326,6 +326,12 @@
status = "disabled";
};
};
+
+ uart_routing: uart_routing at 9c {
+ compatible = "aspeed,ast2400-uart-routing";
+ reg = <0x9c 0x4>;
+ status = "disabled";
+ };
};
uart2: serial at 1e78d000 {
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 7149ff3b6fb3..9e561504042a 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -440,6 +440,12 @@
status = "disabled";
};
};
+
+ uart_routing: uart_routing at 9c {
+ compatible = "aspeed,ast2500-uart-routing";
+ reg = <0x9c 0x4>;
+ status = "disabled";
+ };
};
uart2: serial at 1e78d000 {
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [PATCH v2 2/3] dt-bindings: misc: Bindings doc for aspeed-uart-routing
From: Oskar Senft @ 2019-07-30 1:49 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190730014955.34059-1-osk@google.com>
Device tree bindings documentation for the aspeed-uart-routing driver.
Signed-off-by: Oskar Senft <osk@google.com>
---
Changes since v1:
Split out bindings documentation from driver commit.
Added bindings for AST2400.
.../bindings/misc/aspeed-uart-routing.txt | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/aspeed-uart-routing.txt
diff --git a/Documentation/devicetree/bindings/misc/aspeed-uart-routing.txt b/Documentation/devicetree/bindings/misc/aspeed-uart-routing.txt
new file mode 100644
index 000000000000..bb9ce689d56b
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/aspeed-uart-routing.txt
@@ -0,0 +1,39 @@
+======================================================================
+Device tree bindings for Aspeed AST2400/AST2500 UART Routing Control Driver
+======================================================================
+
+The Aspeed AST2500 allows to dynamically route the inputs for the built-in
+UARTS and physical serial I/O ports.
+
+Required properties:
+===================
+
+ - compatible: must be one of:
+ - "aspeed,ast2400-uart-routing"
+ - "aspeed,ast2500-uart-routing"
+
+Optional properties:
+===================
+
+The uart-routing node should be the child of a lpc node with the required
+property:
+
+- compatible : Should be one of the following:
+ "aspeed,ast2400-lpc", "simple-mfd"
+ "aspeed,ast2500-lpc", "simple-mfd"
+
+Example
+===================
+
+g5 Example
+----------
+
+lpc: lpc at 1e789000 {
+ compatible = "aspeed,ast2500-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+
+ uart_routing: uart_routing at 9c {
+ compatible = "aspeed,ast2500-uart-routing";
+ reg = <0x9c 0x4>;
+ };
+};
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [PATCH v2 1/3] misc: aspeed: Add Aspeed UART routing control driver.
From: Oskar Senft @ 2019-07-30 1:49 UTC (permalink / raw)
To: linux-aspeed
This driver adds sysfs files that allow the BMC userspace to configure
how UARTs and physical serial I/O ports are routed.
Tested: Checked correct behavior (both read & write) on TYAN S7106
board by manually changing routing settings and confirming that bits
flow as expected. Tested for UART1 and UART3 as this board doesn't have
the other UARTs wired up in a testable way.
Signed-off-by: Oskar Senft <osk@google.com>
---
Changes since v1:
Moved from drivers/misc into drivers/soc.
Added support for AST2400.
.../stable/sysfs-driver-aspeed-uart-routing | 14 +
.../misc-devices/aspeed-uart-routing.txt | 50 +++
drivers/soc/aspeed/Kconfig | 7 +
drivers/soc/aspeed/Makefile | 7 +-
drivers/soc/aspeed/aspeed-uart-routing.c | 385 ++++++++++++++++++
5 files changed, 460 insertions(+), 3 deletions(-)
create mode 100644 Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
create mode 100644 Documentation/misc-devices/aspeed-uart-routing.txt
create mode 100644 drivers/soc/aspeed/aspeed-uart-routing.c
diff --git a/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
new file mode 100644
index 000000000000..5068737d9c12
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
@@ -0,0 +1,14 @@
+What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io*
+Date: August 2018
+Contact: Oskar Senft <osk@google.com>
+Description: Configures the input source for the specific physical
+ serial I/O port.
+Users: OpenBMC. Proposed changes should be mailed to
+ openbmc at lists.ozlabs.org
+
+What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart*
+Date: August 2018
+Contact: Oskar Senft <osk@google.com>
+Description: Configures the input source for the specific UART.
+Users: OpenBMC. Proposed changes should be mailed to
+ openbmc at lists.ozlabs.org
diff --git a/Documentation/misc-devices/aspeed-uart-routing.txt b/Documentation/misc-devices/aspeed-uart-routing.txt
new file mode 100644
index 000000000000..dcfdf90a6b6b
--- /dev/null
+++ b/Documentation/misc-devices/aspeed-uart-routing.txt
@@ -0,0 +1,50 @@
+Kernel driver aspeed-uart-routing
+=================================
+
+Supported chips:
+Aspeed AST24xx
+Aspeed AST25xx
+
+Author:
+Google LLC
+
+Description
+-----------
+
+The Aspeed AST24xx/AST25xx allow to dynamically route the inputs for the
+built-in UARTS and physical serial I/O ports.
+
+This allows, for example, to connect the output of UART to another UART.
+This can be used to enable host<->BMC communication via UARTs, e.g. to allow
+access to the host's serial console.
+
+This driver is for the BMC side. The sysfs files allow the BMC userspace
+which owns the system configuration policy, to configure how UARTs and
+physical serial I/O ports are routed.
+
+The driver provides the following files in sysfs:
+uart1 Configure the input signal to UART1.
+uart2 Configure the input signal to UART2.
+uart3 Configure the input signal to UART3.
+uart4 Configure the input signal to UART4.
+uart5 Configure the input signal to UART5.
+io1 Configure the input signal to physical serial port 1.
+io2 Configure the input signal to physical serial port 2.
+io3 Configure the input signal to physical serial port 3.
+io4 Configure the input signal to physical serial port 4.
+io5 Configure the input signal to physical serial port 5.
+
+When read, each file shows the list of available options with the currently
+selected option marked by square brackets "[]". The list of available options
+depends on the selected file.
+
+Example:
+$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
+[io1] io2 io3 io4 uart2 uart3 uart4 io6
+
+In this case, UART1 gets its input signal from IO1 (physical serial port 1).
+
+$ echo -n "uart3" \
+ >/sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
+$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
+io1 io2 io3 io4 uart2 [uart3] uart4 io6
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
index 323e177aa74d..ab11dd81c752 100644
--- a/drivers/soc/aspeed/Kconfig
+++ b/drivers/soc/aspeed/Kconfig
@@ -29,4 +29,11 @@ config ASPEED_P2A_CTRL
ioctl()s, the driver also provides an interface for userspace mappings to
a pre-defined region.
+config ASPEED_UART_ROUTING
+ depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+ tristate "Aspeed ast2400/2500 UART routing control"
+ help
+ Control Aspeed ast2400/ast2500 UART routing via sysfs. This enables UART
+ and I/O components to be dynamically connected at runtime.
+
endmenu
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
index b64be47f2b1f..2fb979dec443 100644
--- a/drivers/soc/aspeed/Makefile
+++ b/drivers/soc/aspeed/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
-obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
-obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c
new file mode 100644
index 000000000000..937191bfc740
--- /dev/null
+++ b/drivers/soc/aspeed/aspeed-uart-routing.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * UART Routing driver for Aspeed AST24xx/AST25xx
+ *
+ * Copyright (c) 2018 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+/* The Aspeed AST24xx/AST25xx allow to dynamically route the inputs for the
+ * built-in UARTS and physical serial I/O ports.
+ *
+ * This allows, for example, to connect the output of UART to another UART.
+ * This can be used to enable host<->BMC communication via UARTs, e.g. to allow
+ * access to the host's serial console.
+ *
+ * This driver is for the BMC side. The sysfs files allow the BMC userspace
+ * which owns the system configuration policy, to configure how UARTs and
+ * physical serial I/O ports are routed.
+ */
+
+#define ASPEED_HICRA_IO1 "io1"
+#define ASPEED_HICRA_IO2 "io2"
+#define ASPEED_HICRA_IO3 "io3"
+#define ASPEED_HICRA_IO4 "io4"
+#define ASPEED_HICRA_IO5 "io5"
+#define ASPEED_HICRA_IO6 "io6"
+#define ASPEED_HICRA_UART1 "uart1"
+#define ASPEED_HICRA_UART2 "uart2"
+#define ASPEED_HICRA_UART3 "uart3"
+#define ASPEED_HICRA_UART4 "uart4"
+#define ASPEED_HICRA_UART5 "uart5"
+
+struct aspeed_uart_routing {
+ struct device *dev;
+ void __iomem *regs;
+ spinlock_t lock;
+};
+
+struct aspeed_uart_routing_selector {
+ struct device_attribute dev_attr;
+ int shift;
+ int mask;
+ const char * const options[];
+};
+
+#define to_routing_selector(_dev_attr) \
+ container_of(_dev_attr, struct aspeed_uart_routing_selector, dev_attr)
+
+
+static ssize_t aspeed_uart_routing_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static ssize_t aspeed_uart_routing_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+#define ROUTING_ATTR(_name) { \
+ .attr = {.name = _name, \
+ .mode = VERIFY_OCTAL_PERMISSIONS(0644) }, \
+ .show = aspeed_uart_routing_show, \
+ .store = aspeed_uart_routing_store, \
+}
+
+static struct aspeed_uart_routing_selector uart5_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART5),
+ .shift = 28,
+ .mask = 0xf,
+ .options = {
+ ASPEED_HICRA_IO5, // 0
+ ASPEED_HICRA_IO1, // 1
+ ASPEED_HICRA_IO2, // 2
+ ASPEED_HICRA_IO3, // 3
+ ASPEED_HICRA_IO4, // 4
+ ASPEED_HICRA_UART1, // 5
+ ASPEED_HICRA_UART2, // 6
+ ASPEED_HICRA_UART3, // 7
+ ASPEED_HICRA_UART4, // 8
+ ASPEED_HICRA_IO6, // 9
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector uart4_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART4),
+ .shift = 25,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_IO4, // 0
+ ASPEED_HICRA_IO1, // 1
+ ASPEED_HICRA_IO2, // 2
+ ASPEED_HICRA_IO3, // 3
+ ASPEED_HICRA_UART1, // 4
+ ASPEED_HICRA_UART2, // 5
+ ASPEED_HICRA_UART3, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector uart3_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART3),
+ .shift = 22,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_IO3, // 0
+ ASPEED_HICRA_IO4, // 1
+ ASPEED_HICRA_IO1, // 2
+ ASPEED_HICRA_IO2, // 3
+ ASPEED_HICRA_UART4, // 4
+ ASPEED_HICRA_UART1, // 5
+ ASPEED_HICRA_UART2, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector uart2_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART2),
+ .shift = 19,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_IO2, // 0
+ ASPEED_HICRA_IO3, // 1
+ ASPEED_HICRA_IO4, // 2
+ ASPEED_HICRA_IO1, // 3
+ ASPEED_HICRA_UART3, // 4
+ ASPEED_HICRA_UART4, // 5
+ ASPEED_HICRA_UART1, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector uart1_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART1),
+ .shift = 16,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_IO1, // 0
+ ASPEED_HICRA_IO2, // 1
+ ASPEED_HICRA_IO3, // 2
+ ASPEED_HICRA_IO4, // 3
+ ASPEED_HICRA_UART2, // 4
+ ASPEED_HICRA_UART3, // 5
+ ASPEED_HICRA_UART4, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector io5_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO5),
+ .shift = 12,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_UART5, // 0
+ ASPEED_HICRA_UART1, // 1
+ ASPEED_HICRA_UART2, // 2
+ ASPEED_HICRA_UART3, // 3
+ ASPEED_HICRA_UART4, // 4
+ ASPEED_HICRA_IO1, // 5
+ ASPEED_HICRA_IO3, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector io4_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO4),
+ .shift = 9,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_UART4, // 0
+ ASPEED_HICRA_UART5, // 1
+ ASPEED_HICRA_UART1, // 2
+ ASPEED_HICRA_UART2, // 3
+ ASPEED_HICRA_UART3, // 4
+ ASPEED_HICRA_IO1, // 5
+ ASPEED_HICRA_IO2, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector io3_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO3),
+ .shift = 6,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_UART3, // 0
+ ASPEED_HICRA_UART4, // 1
+ ASPEED_HICRA_UART5, // 2
+ ASPEED_HICRA_UART1, // 3
+ ASPEED_HICRA_UART2, // 4
+ ASPEED_HICRA_IO1, // 5
+ ASPEED_HICRA_IO2, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector io2_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO2),
+ .shift = 3,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_UART2, // 0
+ ASPEED_HICRA_UART3, // 1
+ ASPEED_HICRA_UART4, // 2
+ ASPEED_HICRA_UART5, // 3
+ ASPEED_HICRA_UART1, // 4
+ ASPEED_HICRA_IO3, // 5
+ ASPEED_HICRA_IO4, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+static struct aspeed_uart_routing_selector io1_sel = {
+ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO1),
+ .shift = 0,
+ .mask = 0x7,
+ .options = {
+ ASPEED_HICRA_UART1, // 0
+ ASPEED_HICRA_UART2, // 1
+ ASPEED_HICRA_UART3, // 2
+ ASPEED_HICRA_UART4, // 3
+ ASPEED_HICRA_UART5, // 4
+ ASPEED_HICRA_IO3, // 5
+ ASPEED_HICRA_IO4, // 6
+ ASPEED_HICRA_IO6, // 7
+ NULL, // NULL termination
+ },
+};
+
+
+static struct attribute *aspeed_uart_routing_attrs[] = {
+ &uart1_sel.dev_attr.attr,
+ &uart2_sel.dev_attr.attr,
+ &uart3_sel.dev_attr.attr,
+ &uart4_sel.dev_attr.attr,
+ &uart5_sel.dev_attr.attr,
+ &io1_sel.dev_attr.attr,
+ &io2_sel.dev_attr.attr,
+ &io3_sel.dev_attr.attr,
+ &io4_sel.dev_attr.attr,
+ &io5_sel.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group aspeed_uart_routing_attr_group = {
+ .attrs = aspeed_uart_routing_attrs,
+};
+
+static ssize_t aspeed_uart_routing_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
+ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
+ int val, pos, len;
+
+ val = (readl(uart_routing->regs) >> sel->shift) & sel->mask;
+
+ len = 0;
+ for (pos = 0; sel->options[pos] != NULL; ++pos) {
+ if (pos == val) {
+ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
+ "[%s] ", sel->options[pos]);
+ } else {
+ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
+ "%s ", sel->options[pos]);
+ }
+ }
+
+ if (val >= pos) {
+ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
+ "[unknown(%d)]", val);
+ }
+
+ len += snprintf(buf + len, PAGE_SIZE - 1 - len, "\n");
+
+ return len;
+}
+
+static ssize_t aspeed_uart_routing_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
+ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
+ int val;
+ u32 reg;
+
+ val = match_string(sel->options, -1, buf);
+ if (val < 0) {
+ dev_err(dev, "invalid value \"%s\"\n", buf);
+ return -EINVAL;
+ }
+
+ spin_lock(&uart_routing->lock);
+ reg = readl(uart_routing->regs);
+ // Zero out existing value in specified bits.
+ reg &= ~(sel->mask << sel->shift);
+ // Set new value in specified bits.
+ reg |= (val & sel->mask) << sel->shift;
+ writel(reg, uart_routing->regs);
+ spin_unlock(&uart_routing->lock);
+
+ return count;
+}
+
+static int aspeed_uart_routing_probe(struct platform_device *pdev)
+{
+ struct aspeed_uart_routing *uart_routing;
+ struct resource *res;
+ int rc;
+
+ uart_routing = devm_kzalloc(&pdev->dev,
+ sizeof(*uart_routing),
+ GFP_KERNEL);
+ if (!uart_routing)
+ return -ENOMEM;
+
+ spin_lock_init(&uart_routing->lock);
+ uart_routing->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ uart_routing->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(uart_routing->regs))
+ return PTR_ERR(uart_routing->regs);
+
+ rc = sysfs_create_group(&uart_routing->dev->kobj,
+ &aspeed_uart_routing_attr_group);
+ if (rc < 0)
+ return rc;
+
+ platform_set_drvdata(pdev, uart_routing);
+
+ return 0;
+}
+
+static int aspeed_uart_routing_remove(struct platform_device *pdev)
+{
+ struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
+
+ sysfs_remove_group(&uart_routing->dev->kobj,
+ &aspeed_uart_routing_attr_group);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_uart_routing_table[] = {
+ { .compatible = "aspeed,ast2400-uart-routing" },
+ { .compatible = "aspeed,ast2500-uart-routing" },
+ { },
+};
+
+static struct platform_driver aspeed_uart_routing_driver = {
+ .driver = {
+ .name = "aspeed-uart-routing",
+ .of_match_table = aspeed_uart_routing_table,
+ },
+ .probe = aspeed_uart_routing_probe,
+ .remove = aspeed_uart_routing_remove,
+};
+
+module_platform_driver(aspeed_uart_routing_driver);
+
+MODULE_AUTHOR("Oskar Senft <osk@google.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Driver to configure Aspeed UART routing");
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [RFC-ish PATCH 00/17] Clean up ASPEED devicetree warnings
From: Andrew Jeffery @ 2019-07-30 1:09 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <CAL_JsqJ+sFDG8eKbV3gvmqVHx+otWbki4dY213apzXgfhbXXEw@mail.gmail.com>
On Tue, 30 Jul 2019, at 10:23, Rob Herring wrote:
> On Thu, Jul 25, 2019 at 11:40 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > Hello,
> >
> > The aim of this series is to minimise/eliminate all the warnings from the
> > ASPEED devicetrees. It mostly achieves its goal, as outlined below.
> >
> > Using `aspeed_g5_defconfig` we started with the follow warning count:
> >
> > $ make dtbs 2>&1 >/dev/null | wc -l
> > 218
> >
> > and after the full series is applied we have:
> >
> > $ make dtbs 2>&1 >/dev/null | wc -l
> > 2
> >
> > for a 100x reduction.
> >
> > Getting there though isn't without some potential controversy, which I've saved
> > for the last half of the series. The following patches I think are in pretty
> > good shape:
> >
> > ARM: dts: aspeed-g5: Move EDAC node to APB
> > ARM: dts: aspeed-g5: Use recommended generic node name for SDMC
> > ARM: dts: aspeed-g5: Fix aspeed,external-nodes description
> > ARM: dts: vesnin: Add unit address for memory node
> > ARM: dts: fp5280g2: Cleanup gpio-keys-polled properties
> > ARM: dts: swift: Cleanup gpio-keys-polled properties
> > ARM: dts: witherspoon: Cleanup gpio-keys-polled properties
> > ARM: dts: aspeed: Cleanup lpc-ctrl and snoop regs
> > ARM: dts: ibm-power9-dual: Add a unit address for OCC nodes
> >
> > With these patches applied we get to:
> >
> > $ make dtbs 2>&1 >/dev/null | wc -l
> > 144
> >
> > So they make a dent, but fail to clean up the bulk of the issues. From here
> > I've mixed in some binding and driver changes with subsequent updates to the
> > devicetrees:
> >
> > dt-bindings: pinctrl: aspeed: Add reg property as a hint
> > dt-bindings: misc: Document reg for aspeed,p2a-ctrl nodes
> > ARM: dts: aspeed: Add reg hints to syscon children
> > dt-bindings: ipmi: aspeed: Introduce a v2 binding for KCS
> > ipmi: kcs: Finish configuring ASPEED KCS device before enable
> > ipmi: kcs: aspeed: Implement v2 bindings
> > ARM: dts: aspeed-g5: Change KCS nodes to v2 binding
> > ARM: dts: aspeed-g5: Sort LPC child nodes by unit address
> >
> > By `dt-bindings: ipmi: aspeed: Introduce a v2 binding for KCS` the warnings are
> > reduced to:
> >
> > $ make dtbs 2>&1 >/dev/null | wc -l
> > 125
> >
> > The bang-for-buck is in fixing up the KCS bindings which removes all-but-two of
> > the remaining warnings (which we can't feasibly remove), but doing so forces
> > code changes (which I'd avoided up until this point).
> >
> > Reflecting broadly on the fixes, I think I've made a mistake way back by using
> > syscon/simple-mfds to expose the innards of the SCU and LPC controllers in the
> > devicetree. This series cleans up what's currently there, but I have half a
> > mind to rev the SCU and LPC bindings to not use simple-mfd and instead have a
> > driver implementation that uses `platform_device_register_full()` or similar to
> > deal with the mess.
> >
> > Rob - I'm looking for your thoughts here and on the series, I've never felt
> > entirely comfortable with what I cooked up. Your advice would be appreciated.
>
> The series generally looks fine to me from a quick scan. As far as
> dropping 'simple-mfd', having less fine grained description in DT is
> generally my preference. It comes down to whether what you have
> defined is maintainable. As most of it is just additions, I think what
> you have is fine. Maybe keep all this in mind for the next chip
> depending how the SCU and LPC change.
Okay, I think the timing of that suggestion is good given where things are with
the AST2600. I'll keep that in mind.
Consensus so far seems to be that the series is fine. I'll split it up and send out
the sub-series to the relevant lists with the acks accumulated here.
Thanks all for taking a look.
Andrew
^ permalink raw reply
* [PATCH 0/3] ARM: dts: aspeed: Deprecate g[45]-style compatibles
From: Andrew Jeffery @ 2019-07-30 0:57 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <CACRpkdapypySGPrLgSMSNy1fzkca2BfMUGzf3koFWQZ-M5VOvg@mail.gmail.com>
On Tue, 30 Jul 2019, at 07:23, Linus Walleij wrote:
> On Wed, Jul 24, 2019 at 10:13 AM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> > It's probably best if we push the three patches all through one tree rather
> > than fragmenting. Is everyone happy if Joel applies them to the aspeed tree?
>
> If you are sure it will not collide with parallell work in the
> pinctrl tree, yes.
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
>
> (If it does collide I'd prefer to take the pinctrl patches and fix the
> conflicts in my tree.)
Fair enough, I don't know the answer so I'll poke around. I don't really mind
where the series goes in, I just want to avoid landing only part of it if I split it up.
Andrew
^ permalink raw reply
* [RFC-ish PATCH 00/17] Clean up ASPEED devicetree warnings
From: Rob Herring @ 2019-07-30 0:53 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190726053959.2003-1-andrew@aj.id.au>
On Thu, Jul 25, 2019 at 11:40 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> Hello,
>
> The aim of this series is to minimise/eliminate all the warnings from the
> ASPEED devicetrees. It mostly achieves its goal, as outlined below.
>
> Using `aspeed_g5_defconfig` we started with the follow warning count:
>
> $ make dtbs 2>&1 >/dev/null | wc -l
> 218
>
> and after the full series is applied we have:
>
> $ make dtbs 2>&1 >/dev/null | wc -l
> 2
>
> for a 100x reduction.
>
> Getting there though isn't without some potential controversy, which I've saved
> for the last half of the series. The following patches I think are in pretty
> good shape:
>
> ARM: dts: aspeed-g5: Move EDAC node to APB
> ARM: dts: aspeed-g5: Use recommended generic node name for SDMC
> ARM: dts: aspeed-g5: Fix aspeed,external-nodes description
> ARM: dts: vesnin: Add unit address for memory node
> ARM: dts: fp5280g2: Cleanup gpio-keys-polled properties
> ARM: dts: swift: Cleanup gpio-keys-polled properties
> ARM: dts: witherspoon: Cleanup gpio-keys-polled properties
> ARM: dts: aspeed: Cleanup lpc-ctrl and snoop regs
> ARM: dts: ibm-power9-dual: Add a unit address for OCC nodes
>
> With these patches applied we get to:
>
> $ make dtbs 2>&1 >/dev/null | wc -l
> 144
>
> So they make a dent, but fail to clean up the bulk of the issues. From here
> I've mixed in some binding and driver changes with subsequent updates to the
> devicetrees:
>
> dt-bindings: pinctrl: aspeed: Add reg property as a hint
> dt-bindings: misc: Document reg for aspeed,p2a-ctrl nodes
> ARM: dts: aspeed: Add reg hints to syscon children
> dt-bindings: ipmi: aspeed: Introduce a v2 binding for KCS
> ipmi: kcs: Finish configuring ASPEED KCS device before enable
> ipmi: kcs: aspeed: Implement v2 bindings
> ARM: dts: aspeed-g5: Change KCS nodes to v2 binding
> ARM: dts: aspeed-g5: Sort LPC child nodes by unit address
>
> By `dt-bindings: ipmi: aspeed: Introduce a v2 binding for KCS` the warnings are
> reduced to:
>
> $ make dtbs 2>&1 >/dev/null | wc -l
> 125
>
> The bang-for-buck is in fixing up the KCS bindings which removes all-but-two of
> the remaining warnings (which we can't feasibly remove), but doing so forces
> code changes (which I'd avoided up until this point).
>
> Reflecting broadly on the fixes, I think I've made a mistake way back by using
> syscon/simple-mfds to expose the innards of the SCU and LPC controllers in the
> devicetree. This series cleans up what's currently there, but I have half a
> mind to rev the SCU and LPC bindings to not use simple-mfd and instead have a
> driver implementation that uses `platform_device_register_full()` or similar to
> deal with the mess.
>
> Rob - I'm looking for your thoughts here and on the series, I've never felt
> entirely comfortable with what I cooked up. Your advice would be appreciated.
The series generally looks fine to me from a quick scan. As far as
dropping 'simple-mfd', having less fine grained description in DT is
generally my preference. It comes down to whether what you have
defined is maintainable. As most of it is just additions, I think what
you have is fine. Maybe keep all this in mind for the next chip
depending how the SCU and LPC change.
Rob
^ permalink raw reply
* [RFC-ish PATCH 00/17] Clean up ASPEED devicetree warnings
From: Andrew Jeffery @ 2019-07-30 0:49 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <CACRpkdZVVgqdt=+YYEauChoxjqKk6=LNKzj-40u3CFLxJr0D7Q@mail.gmail.com>
On Tue, 30 Jul 2019, at 07:25, Linus Walleij wrote:
> On Fri, Jul 26, 2019 at 7:40 AM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> > The aim of this series is to minimise/eliminate all the warnings from the
> > ASPEED devicetrees. It mostly achieves its goal, as outlined below.
>
> I suppose it will all be merged in the Aspeed tree?
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
Yeah, if you're happy for that. Thanks.
Andrew
^ permalink raw reply
* [PATCH 1/4] dt-bindings: net: Add aspeed,ast2600-mdio binding
From: Andrew Jeffery @ 2019-07-30 0:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <CAL_JsqLytwfsoyS6TSnpPgTjRTOR0TeQwroX21AHqj3A1mPJ5Q@mail.gmail.com>
On Tue, 30 Jul 2019, at 09:07, Rob Herring wrote:
> On Sun, Jul 28, 2019 at 10:39 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > The AST2600 splits out the MDIO bus controller from the MAC into its own
> > IP block and rearranges the register layout. Add a new binding to
> > describe the new hardware.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > .../bindings/net/aspeed,ast2600-mdio.yaml | 61 +++++++++++++++++++
> > 1 file changed, 61 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> > new file mode 100644
> > index 000000000000..fa86f6438473
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> > @@ -0,0 +1,61 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/net/aspeed,ast2600-mdio.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ASPEED AST2600 MDIO Controller
> > +
> > +maintainers:
> > + - Andrew Jeffery <andrew@aj.id.au>
> > +
> > +description: |+
> > + The ASPEED AST2600 MDIO controller is the third iteration of ASPEED's MDIO
> > + bus register interface, this time also separating out the controller from the
> > + MAC.
> > +
>
> Should have a:
>
> allOf:
> - $ref: "mdio.yaml#"
Ack.
>
> > +properties:
> > + compatible:
> > + const: aspeed,ast2600-mdio
> > + reg:
> > + maxItems: 1
> > + description: The register range of the MDIO controller instance
>
> > + "#address-cells":
> > + const: 1
> > + "#size-cells":
> > + const: 0
>
> Then you can drop these 2.
Great.
>
> > +
> > +patternProperties:
> > + "^ethernet-phy@[a-f0-9]$":
> > + properties:
> > + reg:
> > + description:
> > + The MDIO bus index of the PHY
>
> And this.
>
> > + compatible:
> > + enum:
> > + - ethernet-phy-ieee802.3-c22
> > + - ethernet-phy-ieee802.3-c45
>
> This isn't specific to ASpeed either and is already covered by
> ethernet-phy.yaml.
>
> So that means none of the child node schema is needed here.
Bah, I'd developed the patches on v5.2 while waiting for v5.3-rc1 to come
out.
>
> > + required:
> > + - reg
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - "#address-cells"
> > + - "#size-cells"
> > +
> > +examples:
> > + - |
> > + mdio0: mdio at 1e650000 {
> > + compatible = "aspeed,ast2600-mdio";
> > + reg = <0x1e650000 0x8>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + status = "okay";
>
> Don't show status in examples.
Sorry, copy/paste at fault.
Thanks for the feedback.
Andrew
>
> > +
> > + ethphy0: ethernet-phy at 0 {
> > + compatible = "ethernet-phy-ieee802.3-c22";
> > + reg = <0>;
> > + };
> > + };
> > --
> > 2.20.1
> >
>
^ permalink raw reply
* [PATCH v2 1/6] dt-bindings: pinctrl: aspeed: Document AST2600 pinmux
From: Rob Herring @ 2019-07-29 23:40 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190729055604.13239-2-andrew@aj.id.au>
On Sun, Jul 28, 2019 at 11:56 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> The AST260 differs from the 2400 and 2500 in that it supports multiple
> groups for a subset of functions.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
>
> ---
> v2:
> * Avoid patternProperties for fixed strings
> * Don't needlessly quote strings
> ---
> .../pinctrl/aspeed,ast2600-pinctrl.yaml | 115 ++++++++++++++++++
> 1 file changed, 115 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH 1/4] dt-bindings: net: Add aspeed,ast2600-mdio binding
From: Rob Herring @ 2019-07-29 23:37 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190729043926.32679-2-andrew@aj.id.au>
On Sun, Jul 28, 2019 at 10:39 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> The AST2600 splits out the MDIO bus controller from the MAC into its own
> IP block and rearranges the register layout. Add a new binding to
> describe the new hardware.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> ---
> .../bindings/net/aspeed,ast2600-mdio.yaml | 61 +++++++++++++++++++
> 1 file changed, 61 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
>
> diff --git a/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> new file mode 100644
> index 000000000000..fa86f6438473
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> @@ -0,0 +1,61 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/aspeed,ast2600-mdio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ASPEED AST2600 MDIO Controller
> +
> +maintainers:
> + - Andrew Jeffery <andrew@aj.id.au>
> +
> +description: |+
> + The ASPEED AST2600 MDIO controller is the third iteration of ASPEED's MDIO
> + bus register interface, this time also separating out the controller from the
> + MAC.
> +
Should have a:
allOf:
- $ref: "mdio.yaml#"
> +properties:
> + compatible:
> + const: aspeed,ast2600-mdio
> + reg:
> + maxItems: 1
> + description: The register range of the MDIO controller instance
> + "#address-cells":
> + const: 1
> + "#size-cells":
> + const: 0
Then you can drop these 2.
> +
> +patternProperties:
> + "^ethernet-phy@[a-f0-9]$":
> + properties:
> + reg:
> + description:
> + The MDIO bus index of the PHY
And this.
> + compatible:
> + enum:
> + - ethernet-phy-ieee802.3-c22
> + - ethernet-phy-ieee802.3-c45
This isn't specific to ASpeed either and is already covered by
ethernet-phy.yaml.
So that means none of the child node schema is needed here.
> + required:
> + - reg
> +
> +required:
> + - compatible
> + - reg
> + - "#address-cells"
> + - "#size-cells"
> +
> +examples:
> + - |
> + mdio0: mdio at 1e650000 {
> + compatible = "aspeed,ast2600-mdio";
> + reg = <0x1e650000 0x8>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + status = "okay";
Don't show status in examples.
> +
> + ethphy0: ethernet-phy at 0 {
> + compatible = "ethernet-phy-ieee802.3-c22";
> + reg = <0>;
> + };
> + };
> --
> 2.20.1
>
^ permalink raw reply
* [v5 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
From: Linus Walleij @ 2019-07-29 21:57 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <f2875111-9ba9-43b7-b2a4-d00c8725f5a0@www.fastmail.com>
On Mon, Jul 29, 2019 at 2:19 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> The behaviour is to periodically emit the state of all enabled GPIOs
> (i.e. the ngpios value), one per bus clock cycle. There's no explicit
> addressing scheme, the protocol encodes the value for a given GPIO
> by its position in the data stream relative to a pulse on the "load data"
> (LD) line, whose envelope covers the clock cycle for the last GPIO in
> the sequence. Similar to SPI the bus has both out and in lines, which
> cater to output/input GPIOs.
>
> A rough timing diagram for a 16-GPIO configuration looks like what
> I've pasted here:
>
> https://gist.github.com/amboar/c9543af1957854474b8c05ab357f0675
OK that is complex. I agree we need to keep this driver together.
Yours,
Linus Walleij
^ permalink raw reply
* [RFC-ish PATCH 00/17] Clean up ASPEED devicetree warnings
From: Linus Walleij @ 2019-07-29 21:55 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20190726053959.2003-1-andrew@aj.id.au>
On Fri, Jul 26, 2019 at 7:40 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> The aim of this series is to minimise/eliminate all the warnings from the
> ASPEED devicetrees. It mostly achieves its goal, as outlined below.
I suppose it will all be merged in the Aspeed tree?
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox