From 394c6b0ff11a14400c7f8bc6d3a138f804f79586 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:50:39 +0200 Subject: [PATCH 01/16] board: s400: generate unique mac address from SoC serial Enable unique mac address generation from SoC serial on S400 board. Signed-off-by: Neil Armstrong --- board/amlogic/s400/s400.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/board/amlogic/s400/s400.c b/board/amlogic/s400/s400.c index 7e2f0cdae3..b081942dcc 100644 --- a/board/amlogic/s400/s400.c +++ b/board/amlogic/s400/s400.c @@ -18,5 +18,7 @@ int misc_init_r(void) { meson_eth_init(PHY_INTERFACE_MODE_RGMII, 0); + meson_generate_serial_ethaddr(); + return 0; } From 4e7b0a3f2a3153f2e3a2247626c91ef225de3d57 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:12 +0200 Subject: [PATCH 02/16] ARM: dts: sync amlogic AXG/GXL/GXM DT from Linux 5.8-rc1 This imports the AXG, GXL & GXM SoC and boards DT changes from the Linux commit b3a9e3b9622a ("Linux 5.8-rc1"). This change also removes GXL & GXM u-boot.dtsi hacks for USB gadget. Signed-off-by: Neil Armstrong --- arch/arm/dts/meson-axg.dtsi | 6 +- arch/arm/dts/meson-gx-libretech-pc.dtsi | 78 +++++++++++++++++- arch/arm/dts/meson-gx.dtsi | 23 ++++-- arch/arm/dts/meson-gxbb-nanopi-k2.dts | 2 +- arch/arm/dts/meson-gxbb-odroidc2.dts | 2 +- arch/arm/dts/meson-gxbb.dtsi | 23 ++++++ .../meson-gxl-s805x-libretech-ac-u-boot.dtsi | 4 - arch/arm/dts/meson-gxl-s805x-libretech-ac.dts | 73 ++++++++++++++++- .../meson-gxl-s905d-libretech-pc-u-boot.dtsi | 4 - .../meson-gxl-s905x-khadas-vim-u-boot.dtsi | 4 - arch/arm/dts/meson-gxl-s905x-khadas-vim.dts | 4 + .../meson-gxl-s905x-libretech-cc-u-boot.dtsi | 4 - arch/arm/dts/meson-gxl-s905x-libretech-cc.dts | 77 +++++++++++++++++- arch/arm/dts/meson-gxl-s905x-p212.dtsi | 3 +- arch/arm/dts/meson-gxl-u-boot.dtsi | 16 ---- arch/arm/dts/meson-gxl.dtsi | 79 ++++++++++++++----- .../arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi | 4 - arch/arm/dts/meson-gxm-khadas-vim2.dts | 3 +- .../meson-gxm-s912-libretech-pc-u-boot.dtsi | 4 - arch/arm/dts/meson-gxm.dtsi | 7 +- .../reset/amlogic,meson-gxbb-reset.h | 2 +- include/dt-bindings/sound/meson-aiu.h | 18 +++++ 22 files changed, 358 insertions(+), 82 deletions(-) create mode 100644 include/dt-bindings/sound/meson-aiu.h diff --git a/arch/arm/dts/meson-axg.dtsi b/arch/arm/dts/meson-axg.dtsi index aace3d32a3..8e6281c685 100644 --- a/arch/arm/dts/meson-axg.dtsi +++ b/arch/arm/dts/meson-axg.dtsi @@ -1735,18 +1735,18 @@ }; sram: sram@fffc0000 { - compatible = "amlogic,meson-axg-sram", "mmio-sram"; + compatible = "mmio-sram"; reg = <0x0 0xfffc0000 0x0 0x20000>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x0 0xfffc0000 0x20000>; - cpu_scp_lpri: scp-shmem@13000 { + cpu_scp_lpri: scp-sram@13000 { compatible = "amlogic,meson-axg-scp-shmem"; reg = <0x13000 0x400>; }; - cpu_scp_hpri: scp-shmem@13400 { + cpu_scp_hpri: scp-sram@13400 { compatible = "amlogic,meson-axg-scp-shmem"; reg = <0x13400 0x400>; }; diff --git a/arch/arm/dts/meson-gx-libretech-pc.dtsi b/arch/arm/dts/meson-gx-libretech-pc.dtsi index 248b018c83..c2480bab8d 100644 --- a/arch/arm/dts/meson-gx-libretech-pc.dtsi +++ b/arch/arm/dts/meson-gx-libretech-pc.dtsi @@ -8,6 +8,7 @@ #include #include +#include / { adc-keys { @@ -29,6 +30,13 @@ spi0 = &spifc; }; + dio2133: analog-amplifier { + compatible = "simple-audio-amplifier"; + sound-name-prefix = "AU2"; + VCC-supply = <&vcc5v>; + enable-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>; + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -96,14 +104,14 @@ leds { compatible = "gpio-leds"; - green { + led-green { color = ; function = LED_FUNCTION_DISK_ACTIVITY; gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; linux,default-trigger = "disk-activity"; }; - blue { + led-blue { color = ; function = LED_FUNCTION_STATUS; gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>; @@ -175,6 +183,69 @@ regulator-settling-time-up-us = <200>; regulator-settling-time-down-us = <50000>; }; + + sound { + compatible = "amlogic,gx-sound-card"; + model = "GXL-LIBRETECH-S9XX-PC"; + audio-aux-devs = <&dio2133>; + audio-widgets = "Speaker", "7J4-14 LEFT", + "Speaker", "7J4-11 RIGHT"; + audio-routing = "AU2 INL", "ACODEC LOLN", + "AU2 INR", "ACODEC LORN", + "7J4-14 LEFT", "AU2 OUTL", + "7J4-11 RIGHT", "AU2 OUTR"; + assigned-clocks = <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>; + }; + + dai-link-1 { + sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>; + dai-format = "i2s"; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&aiu AIU_HDMI CTRL_I2S>; + }; + + codec-1 { + sound-dai = <&aiu AIU_ACODEC CTRL_I2S>; + }; + }; + + dai-link-2 { + sound-dai = <&aiu AIU_HDMI CTRL_OUT>; + + codec-0 { + sound-dai = <&hdmi_tx>; + }; + }; + + dai-link-3 { + sound-dai = <&aiu AIU_ACODEC CTRL_OUT>; + + codec-0 { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddio_ao18>; + status = "okay"; +}; + +&aiu { + status = "okay"; }; &cec_AO { @@ -360,8 +431,9 @@ status = "okay"; }; -&usb0 { +&usb { status = "okay"; + dr_mode = "host"; }; &usb2_phy0 { diff --git a/arch/arm/dts/meson-gx.dtsi b/arch/arm/dts/meson-gx.dtsi index 03f79fe045..ba63c36b22 100644 --- a/arch/arm/dts/meson-gx.dtsi +++ b/arch/arm/dts/meson-gx.dtsi @@ -278,6 +278,17 @@ #reset-cells = <1>; }; + aiu: audio-controller@5400 { + compatible = "amlogic,aiu"; + #sound-dai-cells = <2>; + sound-name-prefix = "AIU"; + reg = <0x0 0x5400 0x0 0x2ac>; + interrupts = , + ; + interrupt-names = "i2s", "spdif"; + status = "disabled"; + }; + uart_A: serial@84c0 { compatible = "amlogic,meson-gx-uart"; reg = <0x0 0x84c0 0x0 0x18>; @@ -398,20 +409,20 @@ }; sram: sram@c8000000 { - compatible = "amlogic,meson-gx-sram", "amlogic,meson-gxbb-sram", "mmio-sram"; + compatible = "mmio-sram"; reg = <0x0 0xc8000000 0x0 0x14000>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x0 0xc8000000 0x14000>; - cpu_scp_lpri: scp-shmem@0 { - compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem"; + cpu_scp_lpri: scp-sram@0 { + compatible = "amlogic,meson-gxbb-scp-shmem"; reg = <0x13000 0x400>; }; - cpu_scp_hpri: scp-shmem@200 { - compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem"; + cpu_scp_hpri: scp-sram@200 { + compatible = "amlogic,meson-gxbb-scp-shmem"; reg = <0x13400 0x400>; }; }; @@ -626,6 +637,8 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; + #sound-dai-cells = <0>; + sound-name-prefix = "HDMITX"; status = "disabled"; /* VPU VENC Input */ diff --git a/arch/arm/dts/meson-gxbb-nanopi-k2.dts b/arch/arm/dts/meson-gxbb-nanopi-k2.dts index d6ca684e0e..7be3e35409 100644 --- a/arch/arm/dts/meson-gxbb-nanopi-k2.dts +++ b/arch/arm/dts/meson-gxbb-nanopi-k2.dts @@ -29,7 +29,7 @@ leds { compatible = "gpio-leds"; - stat { + led-stat { label = "nanopi-k2:blue:stat"; gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_HIGH>; default-state = "on"; diff --git a/arch/arm/dts/meson-gxbb-odroidc2.dts b/arch/arm/dts/meson-gxbb-odroidc2.dts index b46ef985bb..70fcfb7b06 100644 --- a/arch/arm/dts/meson-gxbb-odroidc2.dts +++ b/arch/arm/dts/meson-gxbb-odroidc2.dts @@ -49,7 +49,7 @@ leds { compatible = "gpio-leds"; - blue { + led-blue { label = "c2:blue:alive"; gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_LOW>; linux,default-trigger = "heartbeat"; diff --git a/arch/arm/dts/meson-gxbb.dtsi b/arch/arm/dts/meson-gxbb.dtsi index 0cb40326b0..234490d3ee 100644 --- a/arch/arm/dts/meson-gxbb.dtsi +++ b/arch/arm/dts/meson-gxbb.dtsi @@ -60,6 +60,29 @@ }; }; +&aiu { + compatible = "amlogic,aiu-gxbb", "amlogic,aiu"; + clocks = <&clkc CLKID_AIU_GLUE>, + <&clkc CLKID_I2S_OUT>, + <&clkc CLKID_AOCLK_GATE>, + <&clkc CLKID_CTS_AMCLK>, + <&clkc CLKID_MIXER_IFACE>, + <&clkc CLKID_IEC958>, + <&clkc CLKID_IEC958_GATE>, + <&clkc CLKID_CTS_MCLK_I958>, + <&clkc CLKID_CTS_I958>; + clock-names = "pclk", + "i2s_pclk", + "i2s_aoclk", + "i2s_mclk", + "i2s_mixer", + "spdif_pclk", + "spdif_aoclk", + "spdif_mclk", + "spdif_mclk_sel"; + resets = <&reset RESET_AIU>; +}; + &aobus { pinctrl_aobus: pinctrl@14 { compatible = "amlogic,meson-gxbb-aobus-pinctrl"; diff --git a/arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi b/arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi index 474a3e1604..39270ea71c 100644 --- a/arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi @@ -5,7 +5,3 @@ */ #include "meson-gxl-u-boot.dtsi" - -&dwc2 { - status = "okay"; -}; diff --git a/arch/arm/dts/meson-gxl-s805x-libretech-ac.dts b/arch/arm/dts/meson-gxl-s805x-libretech-ac.dts index 4d59494965..6a226faab1 100644 --- a/arch/arm/dts/meson-gxl-s805x-libretech-ac.dts +++ b/arch/arm/dts/meson-gxl-s805x-libretech-ac.dts @@ -8,6 +8,7 @@ /dts-v1/; #include +#include #include "meson-gxl-s905x.dtsi" @@ -97,6 +98,15 @@ regulator-always-on; }; + vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_3v3>; + regulator-always-on; + }; + vddio_boot: regulator-vddio_boot { compatible = "regulator-fixed"; regulator-name = "VDDIO_BOOT"; @@ -105,6 +115,66 @@ vin-supply = <&vcc_3v3>; regulator-always-on; }; + + sound { + compatible = "amlogic,gx-sound-card"; + model = "GXL-LIBRETECH-S805X-AC"; + audio-widgets = "Speaker", "9J5-3 LEFT", + "Speaker", "9J5-2 RIGHT"; + audio-routing = "9J5-3 LEFT", "ACODEC LOLN", + "9J5-2 RIGHT", "ACODEC LORN"; + assigned-clocks = <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>; + }; + + dai-link-1 { + sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>; + dai-format = "i2s"; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&aiu AIU_HDMI CTRL_I2S>; + }; + + codec-1 { + sound-dai = <&aiu AIU_ACODEC CTRL_I2S>; + }; + }; + + dai-link-2 { + sound-dai = <&aiu AIU_HDMI CTRL_OUT>; + + codec-0 { + sound-dai = <&hdmi_tx>; + }; + }; + + dai-link-3 { + sound-dai = <&aiu AIU_ACODEC CTRL_OUT>; + + codec-0 { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddio_ao18>; + status = "okay"; +}; + +&aiu { + status = "okay"; }; &cec_AO { @@ -243,6 +313,7 @@ pinctrl-names = "default"; }; -&usb0 { +&usb { status = "okay"; + dr_mode = "host"; }; diff --git a/arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi b/arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi index 474a3e1604..39270ea71c 100644 --- a/arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi @@ -5,7 +5,3 @@ */ #include "meson-gxl-u-boot.dtsi" - -&dwc2 { - status = "okay"; -}; diff --git a/arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi b/arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi index 474a3e1604..39270ea71c 100644 --- a/arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi @@ -5,7 +5,3 @@ */ #include "meson-gxl-u-boot.dtsi" - -&dwc2 { - status = "okay"; -}; diff --git a/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts b/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts index 440bc23c73..8bcdffdf55 100644 --- a/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts @@ -207,3 +207,7 @@ pinctrl-0 = <&uart_ao_b_pins>; pinctrl-names = "default"; }; + +&usb { + dr_mode = "peripheral"; +}; diff --git a/arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi b/arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi index 474a3e1604..39270ea71c 100644 --- a/arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi @@ -5,7 +5,3 @@ */ #include "meson-gxl-u-boot.dtsi" - -&dwc2 { - status = "okay"; -}; diff --git a/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts b/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts index e8348b2728..5ae7bb6209 100644 --- a/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts +++ b/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts @@ -8,6 +8,7 @@ /dts-v1/; #include +#include #include "meson-gxl-s905x.dtsi" @@ -21,6 +22,13 @@ ethernet0 = ðmac; }; + dio2133: analog-amplifier { + compatible = "simple-audio-amplifier"; + sound-name-prefix = "AU2"; + VCC-supply = <&hdmi_5v>; + enable-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>; + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -54,14 +62,14 @@ leds { compatible = "gpio-leds"; - system { + led-system { label = "librecomputer:system-status"; gpios = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>; default-state = "on"; panic-indicator; }; - blue { + led-blue { label = "librecomputer:blue"; gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; @@ -124,6 +132,68 @@ regulator-max-microvolt = <1800000>; vin-supply = <&vcc_3v3>; }; + + sound { + compatible = "amlogic,gx-sound-card"; + model = "GXL-LIBRETECH-S905X-CC"; + audio-aux-devs = <&dio2133>; + audio-widgets = "Line", "Lineout"; + audio-routing = "AU2 INL", "ACODEC LOLN", + "AU2 INR", "ACODEC LORN", + "Lineout", "AU2 OUTL", + "Lineout", "AU2 OUTR"; + assigned-clocks = <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>; + }; + + dai-link-1 { + sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>; + dai-format = "i2s"; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&aiu AIU_HDMI CTRL_I2S>; + }; + + codec-1 { + sound-dai = <&aiu AIU_ACODEC CTRL_I2S>; + }; + }; + + dai-link-2 { + sound-dai = <&aiu AIU_HDMI CTRL_OUT>; + + codec-0 { + sound-dai = <&hdmi_tx>; + }; + }; + + dai-link-3 { + sound-dai = <&aiu AIU_ACODEC CTRL_OUT>; + + codec-0 { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddio_ao18>; + status = "okay"; +}; + +&aiu { + status = "okay"; }; &cec_AO { @@ -272,8 +342,9 @@ pinctrl-names = "default"; }; -&usb0 { +&usb { status = "okay"; + dr_mode = "host"; }; &usb2_phy0 { diff --git a/arch/arm/dts/meson-gxl-s905x-p212.dtsi b/arch/arm/dts/meson-gxl-s905x-p212.dtsi index 6ac678f88b..05cb2f5e5c 100644 --- a/arch/arm/dts/meson-gxl-s905x-p212.dtsi +++ b/arch/arm/dts/meson-gxl-s905x-p212.dtsi @@ -195,8 +195,9 @@ pinctrl-names = "default"; }; -&usb0 { +&usb { status = "okay"; + dr_mode = "host"; }; &usb2_phy0 { diff --git a/arch/arm/dts/meson-gxl-u-boot.dtsi b/arch/arm/dts/meson-gxl-u-boot.dtsi index 9e88afd30e..c35158d7e9 100644 --- a/arch/arm/dts/meson-gxl-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-u-boot.dtsi @@ -5,19 +5,3 @@ */ #include "meson-gx-u-boot.dtsi" - -&usb0 { - dwc2: usb@c9100000 { - compatible = "snps,dwc2"; - reg = <0x0 0xc9100000 0x0 0x40000>; - interrupts = ; - clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; - clock-names = "ddr"; - phys = <&usb3_phy>, <&usb2_phy1>; - dr_mode = "peripheral"; - g-rx-fifo-size = <192>; - g-np-tx-fifo-size = <128>; - g-tx-fifo-size = <128 128 16 16 16>; - status = "disabled"; - }; -}; diff --git a/arch/arm/dts/meson-gxl.dtsi b/arch/arm/dts/meson-gxl.dtsi index 259d863993..fc59c8534c 100644 --- a/arch/arm/dts/meson-gxl.dtsi +++ b/arch/arm/dts/meson-gxl.dtsi @@ -14,29 +14,57 @@ compatible = "amlogic,meson-gxl"; soc { - usb0: usb@c9000000 { - status = "disabled"; - compatible = "amlogic,meson-gxl-dwc3"; + usb: usb@d0078080 { + compatible = "amlogic,meson-gxl-usb-ctrl"; + reg = <0x0 0xd0078080 0x0 0x20>; + interrupts = ; #address-cells = <2>; #size-cells = <2>; ranges; - clocks = <&clkc CLKID_USB>; - clock-names = "usb_general"; + clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1_DDR_BRIDGE>; + clock-names = "usb_ctrl", "ddr"; resets = <&reset RESET_USB_OTG>; - reset-names = "usb_otg"; - dwc3: dwc3@c9000000 { + dr_mode = "otg"; + + phys = <&usb2_phy0>, <&usb2_phy1>; + phy-names = "usb2-phy0", "usb2-phy1"; + + dwc2: usb@c9100000 { + compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; + reg = <0x0 0xc9100000 0x0 0x40000>; + interrupts = ; + clocks = <&clkc CLKID_USB1>; + clock-names = "otg"; + phys = <&usb2_phy1>; + dr_mode = "peripheral"; + g-rx-fifo-size = <192>; + g-np-tx-fifo-size = <128>; + g-tx-fifo-size = <128 128 16 16 16>; + }; + + dwc3: usb@c9000000 { compatible = "snps,dwc3"; reg = <0x0 0xc9000000 0x0 0x100000>; interrupts = ; dr_mode = "host"; maximum-speed = "high-speed"; snps,dis_u2_susphy_quirk; - phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>; }; }; + acodec: audio-controller@c8832000 { + compatible = "amlogic,t9015"; + reg = <0x0 0xc8832000 0x0 0x14>; + #sound-dai-cells = <0>; + sound-name-prefix = "ACODEC"; + clocks = <&clkc CLKID_ACODEC>; + clock-names = "pclk"; + resets = <&reset RESET_ACODEC>; + status = "disabled"; + }; + crypto: crypto@c883e000 { compatible = "amlogic,gxl-crypto"; reg = <0x0 0xc883e000 0x0 0x36>; @@ -49,6 +77,29 @@ }; }; +&aiu { + compatible = "amlogic,aiu-gxl", "amlogic,aiu"; + clocks = <&clkc CLKID_AIU_GLUE>, + <&clkc CLKID_I2S_OUT>, + <&clkc CLKID_AOCLK_GATE>, + <&clkc CLKID_CTS_AMCLK>, + <&clkc CLKID_MIXER_IFACE>, + <&clkc CLKID_IEC958>, + <&clkc CLKID_IEC958_GATE>, + <&clkc CLKID_CTS_MCLK_I958>, + <&clkc CLKID_CTS_I958>; + clock-names = "pclk", + "i2s_pclk", + "i2s_aoclk", + "i2s_mclk", + "i2s_mixer", + "spdif_pclk", + "spdif_aoclk", + "spdif_mclk", + "spdif_mclk_sel"; + resets = <&reset RESET_AIU>; +}; + &apb { usb2_phy0: phy@78000 { compatible = "amlogic,meson-gxl-usb2-phy"; @@ -71,18 +122,6 @@ reset-names = "phy"; status = "okay"; }; - - usb3_phy: phy@78080 { - compatible = "amlogic,meson-gxl-usb3-phy"; - #phy-cells = <0>; - reg = <0x0 0x78080 0x0 0x20>; - interrupts = ; - clocks = <&clkc CLKID_USB>, <&clkc_AO CLKID_AO_CEC_32K>; - clock-names = "phy", "peripheral"; - resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>; - reset-names = "phy", "peripheral"; - status = "okay"; - }; }; &efuse { diff --git a/arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi b/arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi index 7aecf2696b..c1763336cf 100644 --- a/arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi +++ b/arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi @@ -12,10 +12,6 @@ }; }; -&dwc2 { - status = "okay"; -}; - &sd_emmc_c { status = "okay"; pinctrl-0 = <&emmc_pins>; diff --git a/arch/arm/dts/meson-gxm-khadas-vim2.dts b/arch/arm/dts/meson-gxm-khadas-vim2.dts index 27eeab71ec..bff8ec2c1c 100644 --- a/arch/arm/dts/meson-gxm-khadas-vim2.dts +++ b/arch/arm/dts/meson-gxm-khadas-vim2.dts @@ -380,6 +380,7 @@ vref-supply = <&vddio_ao18>; }; -&usb0 { +&usb { status = "okay"; + dr_mode = "peripheral"; }; diff --git a/arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi b/arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi index 474a3e1604..39270ea71c 100644 --- a/arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi +++ b/arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi @@ -5,7 +5,3 @@ */ #include "meson-gxl-u-boot.dtsi" - -&dwc2 { - status = "okay"; -}; diff --git a/arch/arm/dts/meson-gxm.dtsi b/arch/arm/dts/meson-gxm.dtsi index b6f89f108e..40e3e123e0 100644 --- a/arch/arm/dts/meson-gxm.dtsi +++ b/arch/arm/dts/meson-gxm.dtsi @@ -169,8 +169,11 @@ compatible = "amlogic,meson-gxm-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; }; -&dwc3 { - phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; +&usb { + compatible = "amlogic,meson-gxm-usb-ctrl"; + + phy-names = "usb2-phy0", "usb2-phy1", "usb2-phy2"; + phys = <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; }; &vdec { diff --git a/include/dt-bindings/reset/amlogic,meson-gxbb-reset.h b/include/dt-bindings/reset/amlogic,meson-gxbb-reset.h index ea50586188..883bfd3bcb 100644 --- a/include/dt-bindings/reset/amlogic,meson-gxbb-reset.h +++ b/include/dt-bindings/reset/amlogic,meson-gxbb-reset.h @@ -69,7 +69,7 @@ #define RESET_SYS_CPU_L2 58 #define RESET_SYS_CPU_P 59 #define RESET_SYS_CPU_MBIST 60 -/* 61 */ +#define RESET_ACODEC 61 /* 62 */ /* 63 */ /* RESET2 */ diff --git a/include/dt-bindings/sound/meson-aiu.h b/include/dt-bindings/sound/meson-aiu.h new file mode 100644 index 0000000000..1051b8af29 --- /dev/null +++ b/include/dt-bindings/sound/meson-aiu.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_MESON_AIU_H +#define __DT_MESON_AIU_H + +#define AIU_CPU 0 +#define AIU_HDMI 1 +#define AIU_ACODEC 2 + +#define CPU_I2S_FIFO 0 +#define CPU_SPDIF_FIFO 1 +#define CPU_I2S_ENCODER 2 +#define CPU_SPDIF_ENCODER 3 + +#define CTRL_I2S 0 +#define CTRL_PCM 1 +#define CTRL_OUT 2 + +#endif /* __DT_MESON_AIU_H */ From 46eddbc58f0d038df5fb51d6c27a989ba826a620 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:13 +0200 Subject: [PATCH 03/16] usb: dwc3: add Amlogic GXL & GXL DWC3 Glue The USB support was initialy done with a set of PHYs and dwc3-of-simple because the architecture of the USB complex was not understood correctly at the time (and proper documentation was missing...). But with the G12A family, the USB complex was correctly understood and implemented correctly. This adds a proper driver for the glue, based on the G12A one, but with enough changes to require a different driver in U-Boot. Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/usb-gx.h | 2 + drivers/usb/dwc3/Kconfig | 8 + drivers/usb/dwc3/Makefile | 1 + drivers/usb/dwc3/dwc3-meson-gxl.c | 425 +++++++++++++++++++++++ 4 files changed, 436 insertions(+) create mode 100644 drivers/usb/dwc3/dwc3-meson-gxl.c diff --git a/arch/arm/include/asm/arch-meson/usb-gx.h b/arch/arm/include/asm/arch-meson/usb-gx.h index aeb8e0c673..7200a4c31a 100644 --- a/arch/arm/include/asm/arch-meson/usb-gx.h +++ b/arch/arm/include/asm/arch-meson/usb-gx.h @@ -13,4 +13,6 @@ void phy_meson_gxl_usb2_set_mode(struct phy *phy, enum usb_dr_mode mode); void phy_meson_gxl_usb3_set_mode(struct phy *phy, enum usb_dr_mode mode); +int dwc3_meson_gxl_force_mode(struct udevice *dev, enum usb_dr_mode mode); + #endif diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index c302486291..802ee508d9 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -38,6 +38,14 @@ config USB_DWC3_MESON_G12A Select this for Amlogic Meson G12A Platforms. This wrapper supports Host and Peripheral operation modes. +config USB_DWC3_MESON_GXL + bool "Amlogic Meson GXL USB wrapper" + depends on DM_USB && USB_DWC3 && ARCH_MESON + imply PHY + help + Select this for Amlogic Meson GXL and GXM Platforms. + This wrapper supports Host and Peripheral operation modes. + config USB_DWC3_UNIPHIER bool "DesignWare USB3 Host Support on UniPhier Platforms" depends on ARCH_UNIPHIER && USB_XHCI_DWC3 diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 0b652a6f36..6e3e024e97 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o +obj-$(CONFIG_USB_DWC3_MESON_GXL) += dwc3-meson-gxl.o obj-$(CONFIG_USB_DWC3_GENERIC) += dwc3-generic.o obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o diff --git a/drivers/usb/dwc3/dwc3-meson-gxl.c b/drivers/usb/dwc3/dwc3-meson-gxl.c new file mode 100644 index 0000000000..92ee0866f7 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-meson-gxl.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Amlogic GXL DWC3 Glue layer + * + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "gadget.h" +#include +#include +#include +#include +#include +#include +#include + +/* USB Glue Control Registers */ + +#define USB_R0 0x00 + #define USB_R0_P30_FSEL_MASK GENMASK(5, 0) + #define USB_R0_P30_PHY_RESET BIT(6) + #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7) + #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8) + #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9) + #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14) + #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) + #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) + #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) + #define USB_R0_U2D_ACT BIT(31) + +#define USB_R1 0x04 + #define USB_R1_U3H_BIGENDIAN_GS BIT(0) + #define USB_R1_U3H_PME_ENABLE BIT(1) + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2) + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7) + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12) + #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) + #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) + #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) + #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) + #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) + +#define USB_R2 0x08 + #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0) + #define USB_R2_P30_CR_READ BIT(16) + #define USB_R2_P30_CR_WRITE BIT(17) + #define USB_R2_P30_CR_CAP_ADDR BIT(18) + #define USB_R2_P30_CR_CAP_DATA BIT(19) + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) + +#define USB_R3 0x0c + #define USB_R3_P30_SSC_ENABLE BIT(0) + #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) + #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) + #define USB_R3_P30_REF_SSP_EN BIT(13) + #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16) + #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19) + #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24) + +#define USB_R4 0x10 + #define USB_R4_P21_PORT_RESET_0 BIT(0) + #define USB_R4_P21_SLEEP_M0 BIT(1) + #define USB_R4_MEM_PD_MASK GENMASK(3, 2) + #define USB_R4_P21_ONLY BIT(4) + +#define USB_R5 0x14 + #define USB_R5_ID_DIG_SYNC BIT(0) + #define USB_R5_ID_DIG_REG BIT(1) + #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) + #define USB_R5_ID_DIG_EN_0 BIT(4) + #define USB_R5_ID_DIG_EN_1 BIT(5) + #define USB_R5_ID_DIG_CURR BIT(6) + #define USB_R5_ID_DIG_IRQ BIT(7) + #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) + #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) + +/* read-only register */ +#define USB_R6 0x18 + #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0) + #define USB_R6_P30_CR_ACK BIT(16) + +enum { + USB2_HOST_PHY0 = 0, + USB2_OTG_PHY1, + USB2_HOST_PHY2, + PHY_COUNT, +}; + +static const char *phy_names[PHY_COUNT] = { + "usb2-phy0", "usb2-phy1", "usb2-phy2", +}; + +struct dwc3_meson_gxl { + struct udevice *dev; + struct regmap *regmap; + struct clk clk; + struct reset_ctl reset; + struct phy phys[PHY_COUNT]; + enum usb_dr_mode otg_mode; + enum usb_dr_mode otg_phy_mode; + unsigned int usb2_ports; +#if CONFIG_IS_ENABLED(DM_REGULATOR) + struct udevice *vbus_supply; +#endif +}; + +#define U2P_REG_SIZE 0x20 +#define USB_REG_OFFSET 0x80 + +#define USB2_OTG_PHY USB2_OTG_PHY1 + +static void dwc3_meson_gxl_usb2_set_mode(struct dwc3_meson_gxl *priv, enum usb_dr_mode mode) +{ + switch (mode) { + case USB_DR_MODE_HOST: + case USB_DR_MODE_OTG: + case USB_DR_MODE_UNKNOWN: + regmap_update_bits(priv->regmap, USB_R1, + USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0); + regmap_update_bits(priv->regmap, USB_R0, + USB_R0_U2D_ACT, 0); + regmap_update_bits(priv->regmap, USB_R4, + USB_R4_P21_SLEEP_M0, 0); + break; + + case USB_DR_MODE_PERIPHERAL: + regmap_update_bits(priv->regmap, USB_R0, + USB_R0_U2D_ACT, USB_R0_U2D_ACT); + regmap_update_bits(priv->regmap, USB_R0, + USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0); + regmap_update_bits(priv->regmap, USB_R4, + USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); + break; + } +} + +static int dwc3_meson_gxl_usb2_init(struct dwc3_meson_gxl *priv) +{ + int i; + + for (i = 0; i < PHY_COUNT; ++i) { + if (!priv->phys[i].dev) + continue; + + phy_meson_gxl_usb2_set_mode(&priv->phys[i], + (i == USB2_OTG_PHY) ? USB_DR_MODE_PERIPHERAL + : USB_DR_MODE_HOST); + } + + return 0; +} + +static int dwc3_meson_gxl_usb_init(struct dwc3_meson_gxl *priv) +{ + int ret; + + ret = dwc3_meson_gxl_usb2_init(priv); + if (ret) + return ret; + + regmap_update_bits(priv->regmap, USB_R1, + USB_R1_U3H_FLADJ_30MHZ_REG_MASK, + FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); + + regmap_update_bits(priv->regmap, USB_R5, + USB_R5_ID_DIG_EN_0, + USB_R5_ID_DIG_EN_0); + regmap_update_bits(priv->regmap, USB_R5, + USB_R5_ID_DIG_EN_1, + USB_R5_ID_DIG_EN_1); + regmap_update_bits(priv->regmap, USB_R5, + USB_R5_ID_DIG_TH_MASK, + FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); + + dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode); + + return 0; +} + +int dwc3_meson_gxl_force_mode(struct udevice *dev, enum usb_dr_mode mode) +{ + struct dwc3_meson_gxl *priv = dev_get_platdata(dev); + + if (!priv) + return -EINVAL; + + if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL) + return -EINVAL; + + if (!priv->phys[USB2_OTG_PHY].dev) + return -EINVAL; + + if (mode == priv->otg_phy_mode) + return 0; + + if (mode == USB_DR_MODE_HOST) + debug("%s: switching to Host Mode\n", __func__); + else + debug("%s: switching to Device Mode\n", __func__); + +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (priv->vbus_supply) { + int ret = regulator_set_enable(priv->vbus_supply, + (mode == USB_DR_MODE_PERIPHERAL)); + if (ret) + return ret; + } +#endif + priv->otg_phy_mode = mode; + + phy_meson_gxl_usb2_set_mode(&priv->phys[USB2_OTG_PHY], mode); + + dwc3_meson_gxl_usb2_set_mode(priv, mode); + + return 0; +} + +static int dwc3_meson_gxl_get_phys(struct dwc3_meson_gxl *priv) +{ + int i, ret; + + for (i = 0 ; i < PHY_COUNT ; ++i) { + ret = generic_phy_get_by_name(priv->dev, phy_names[i], + &priv->phys[i]); + if (ret == -ENOENT || ret == -ENODATA) { + priv->phys[i].dev = NULL; + continue; + } + + if (ret) + return ret; + + priv->usb2_ports++; + } + + debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports); + + return 0; +} + +static int dwc3_meson_gxl_reset_init(struct dwc3_meson_gxl *priv) +{ + int ret; + + ret = reset_get_by_index(priv->dev, 0, &priv->reset); + if (ret) + return ret; + + ret = reset_assert(&priv->reset); + udelay(1); + ret |= reset_deassert(&priv->reset); + if (ret) { + reset_free(&priv->reset); + return ret; + } + + return 0; +} + +static int dwc3_meson_gxl_clk_init(struct dwc3_meson_gxl *priv) +{ + int ret; + + ret = clk_get_by_index(priv->dev, 0, &priv->clk); + if (ret) + return ret; + +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->clk); + if (ret) { + clk_free(&priv->clk); + return ret; + } +#endif + + return 0; +} + +static int dwc3_meson_gxl_probe(struct udevice *dev) +{ + struct dwc3_meson_gxl *priv = dev_get_platdata(dev); + int ret, i; + + priv->dev = dev; + + ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); + if (ret) + return ret; + + ret = dwc3_meson_gxl_clk_init(priv); + if (ret) + return ret; + + ret = dwc3_meson_gxl_reset_init(priv); + if (ret) + return ret; + + ret = dwc3_meson_gxl_get_phys(priv); + if (ret) + return ret; + +#if CONFIG_IS_ENABLED(DM_REGULATOR) + ret = device_get_supply_regulator(dev, "vbus-supply", + &priv->vbus_supply); + if (ret && ret != -ENOENT) { + pr_err("Failed to get PHY regulator\n"); + return ret; + } + + if (priv->vbus_supply) { + ret = regulator_set_enable(priv->vbus_supply, true); + if (ret) + return ret; + } +#endif + + /* On GXL PHY must be started in device mode for DWC2 init */ + priv->otg_mode = USB_DR_MODE_PERIPHERAL; + + ret = dwc3_meson_gxl_usb_init(priv); + if (ret) + return ret; + + priv->otg_mode = usb_get_dr_mode(dev->node); + + if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) + priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL; + else + priv->otg_phy_mode = USB_DR_MODE_HOST; + + for (i = 0 ; i < PHY_COUNT ; ++i) { + if (!priv->phys[i].dev) + continue; + + ret = generic_phy_init(&priv->phys[i]); + if (ret) + goto err_phy_init; + } + + for (i = 0; i < PHY_COUNT; ++i) { + if (!priv->phys[i].dev) + continue; + + ret = generic_phy_power_on(&priv->phys[i]); + if (ret) + goto err_phy_init; + } + + if (priv->phys[USB2_OTG_PHY].dev) + phy_meson_gxl_usb2_set_mode(&priv->phys[USB2_OTG_PHY], + priv->otg_phy_mode); + + dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode); + + return 0; + +err_phy_init: + for (i = 0 ; i < PHY_COUNT ; ++i) { + if (!priv->phys[i].dev) + continue; + + generic_phy_exit(&priv->phys[i]); + } + + return ret; +} + +static int dwc3_meson_gxl_remove(struct udevice *dev) +{ + struct dwc3_meson_gxl *priv = dev_get_platdata(dev); + int i; + + reset_release_all(&priv->reset, 1); + + clk_release_all(&priv->clk, 1); + + for (i = 0; i < PHY_COUNT; ++i) { + if (!priv->phys[i].dev) + continue; + + generic_phy_power_off(&priv->phys[i]); + } + + for (i = 0 ; i < PHY_COUNT ; ++i) { + if (!priv->phys[i].dev) + continue; + + generic_phy_exit(&priv->phys[i]); + } + + return dm_scan_fdt_dev(dev); +} + +static const struct udevice_id dwc3_meson_gxl_ids[] = { + { .compatible = "amlogic,meson-gxl-usb-ctrl" }, + { .compatible = "amlogic,meson-gxm-usb-ctrl" }, + { } +}; + +U_BOOT_DRIVER(dwc3_generic_wrapper) = { + .name = "dwc3-meson-gxl", + .id = UCLASS_SIMPLE_BUS, + .of_match = dwc3_meson_gxl_ids, + .probe = dwc3_meson_gxl_probe, + .remove = dwc3_meson_gxl_remove, + .platdata_auto_alloc_size = sizeof(struct dwc3_meson_gxl), + +}; From 7ccc73773fb58efe710ccb1f9e855e73cf8b0b9d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:14 +0200 Subject: [PATCH 04/16] ARM: mach-meson: use new DWC3 glue for GXL & GXM Use the new Amlogic GXL/GXM USB Glue instead of the set of USB3 PHY and Simple DWC3 wrapper. Signed-off-by: Neil Armstrong --- arch/arm/mach-meson/board-gx.c | 129 +++++++++++++++------------ configs/khadas-vim2_defconfig | 2 +- configs/khadas-vim_defconfig | 2 +- configs/libretech-ac_defconfig | 2 +- configs/libretech-cc_defconfig | 2 +- configs/libretech-s905d-pc_defconfig | 2 +- configs/libretech-s912-pc_defconfig | 2 +- configs/p212_defconfig | 2 +- 8 files changed, 80 insertions(+), 63 deletions(-) diff --git a/arch/arm/mach-meson/board-gx.c b/arch/arm/mach-meson/board-gx.c index c4cc11f1de..7a0e703596 100644 --- a/arch/arm/mach-meson/board-gx.c +++ b/arch/arm/mach-meson/board-gx.c @@ -156,79 +156,70 @@ void meson_eth_init(phy_interface_t mode, unsigned int flags) clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK); } -#if CONFIG_IS_ENABLED(USB_XHCI_DWC3_OF_SIMPLE) && \ +#if CONFIG_IS_ENABLED(USB_DWC3_MESON_GXL) && \ CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG) static struct dwc2_plat_otg_data meson_gx_dwc2_data; -static struct phy usb_phys[2]; int board_usb_init(int index, enum usb_init_type init) { - struct ofnode_phandle_args args; - struct udevice *clk_dev; - ofnode dwc2_node; + struct fdtdec_phandle_args args; + const void *blob = gd->fdt_blob; + int node, dwc2_node; + struct udevice *dev, *clk_dev; struct clk clk; - int ret, i; - u32 val; + int ret; + + /* find the usb glue node */ + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxl-usb-ctrl"); + if (node < 0) { + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxm-usb-ctrl"); + if (node < 0) { + debug("Not found usb-control node\n"); + return -ENODEV; + } + } + + if (!fdtdec_get_is_enabled(blob, node)) { + debug("usb is disabled in the device tree\n"); + return -ENODEV; + } + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) { + debug("Not found usb-control device\n"); + return ret; + } /* find the dwc2 node */ - dwc2_node = ofnode_by_compatible(ofnode_null(), "snps,dwc2"); - if (!ofnode_valid(dwc2_node)) { + dwc2_node = fdt_node_offset_by_compatible(blob, node, + "amlogic,meson-g12a-usb"); + if (dwc2_node < 0) { debug("Not found dwc2 node\n"); return -ENODEV; } - if (!ofnode_is_available(dwc2_node)) { + if (!fdtdec_get_is_enabled(blob, dwc2_node)) { debug("dwc2 is disabled in the device tree\n"); return -ENODEV; } - /* get the PHYs */ - for (i = 0; i < 2; i++) { - ret = generic_phy_get_by_index_nodev(dwc2_node, i, - &usb_phys[i]); - if (ret && ret != -ENOENT) { - pr_err("Failed to get USB PHY%d for %s\n", - i, ofnode_get_name(dwc2_node)); - return ret; - } - } - - for (i = 0; i < 2; i++) { - ret = generic_phy_init(&usb_phys[i]); - if (ret) { - pr_err("Can't init USB PHY%d for %s\n", - i, ofnode_get_name(dwc2_node)); - return ret; - } - } - - for (i = 0; i < 2; i++) { - ret = generic_phy_power_on(&usb_phys[i]); - if (ret) { - pr_err("Can't power USB PHY%d for %s\n", - i, ofnode_get_name(dwc2_node)); - return ret; - } - } - - phy_meson_gxl_usb3_set_mode(&usb_phys[0], USB_DR_MODE_PERIPHERAL); - phy_meson_gxl_usb2_set_mode(&usb_phys[1], USB_DR_MODE_PERIPHERAL); - - meson_gx_dwc2_data.regs_otg = ofnode_get_addr(dwc2_node); + meson_gx_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg"); if (meson_gx_dwc2_data.regs_otg == FDT_ADDR_T_NONE) { debug("usbotg: can't get base address\n"); return -ENODATA; } /* Enable clock */ - ret = ofnode_parse_phandle_with_args(dwc2_node, "clocks", + ret = fdtdec_parse_phandle_with_args(blob, dwc2_node, "clocks", "#clock-cells", 0, 0, &args); if (ret) { debug("usbotg has no clocks defined in the device tree\n"); return ret; } - ret = uclass_get_device_by_ofnode(UCLASS_CLK, args.node, &clk_dev); + ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &clk_dev); if (ret) return ret; @@ -246,25 +237,51 @@ int board_usb_init(int index, enum usb_init_type init) return ret; } - ofnode_read_u32(dwc2_node, "g-rx-fifo-size", &val); - meson_gx_dwc2_data.rx_fifo_sz = val; - ofnode_read_u32(dwc2_node, "g-np-tx-fifo-size", &val); - meson_gx_dwc2_data.np_tx_fifo_sz = val; - ofnode_read_u32(dwc2_node, "g-tx-fifo-size", &val); - meson_gx_dwc2_data.tx_fifo_sz = val; + meson_gx_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-rx-fifo-size", 0); + meson_gx_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-np-tx-fifo-size", 0); + meson_gx_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-tx-fifo-size", 0); + + /* Switch to peripheral mode */ + ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_PERIPHERAL); + if (ret) + return ret; return dwc2_udc_probe(&meson_gx_dwc2_data); } int board_usb_cleanup(int index, enum usb_init_type init) { - int i; + const void *blob = gd->fdt_blob; + struct udevice *dev; + int node; + int ret; - phy_meson_gxl_usb3_set_mode(&usb_phys[0], USB_DR_MODE_HOST); - phy_meson_gxl_usb2_set_mode(&usb_phys[1], USB_DR_MODE_HOST); + /* find the usb glue node */ + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxl-usb-ctrl"); + if (node < 0) { + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxm-usb-ctrl"); + if (node < 0) { + debug("Not found usb-control node\n"); + return -ENODEV; + } + } - for (i = 0; i < 2; i++) - usb_phys[i].dev = NULL; + if (!fdtdec_get_is_enabled(blob, node)) + return -ENODEV; + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) + return ret; + + /* Switch to OTG mode */ + ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_HOST); + if (ret) + return ret; return 0; } diff --git a/configs/khadas-vim2_defconfig b/configs/khadas-vim2_defconfig index 1435781f59..31db02ef26 100644 --- a/configs/khadas-vim2_defconfig +++ b/configs/khadas-vim2_defconfig @@ -41,6 +41,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_DM_REGULATOR=y @@ -56,7 +57,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_GADGET=y diff --git a/configs/khadas-vim_defconfig b/configs/khadas-vim_defconfig index d075dd134c..65bd7f588e 100644 --- a/configs/khadas-vim_defconfig +++ b/configs/khadas-vim_defconfig @@ -37,6 +37,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_DM_REGULATOR=y @@ -49,7 +50,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_GADGET=y diff --git a/configs/libretech-ac_defconfig b/configs/libretech-ac_defconfig index e898fb147f..5e8ea0b087 100644 --- a/configs/libretech-ac_defconfig +++ b/configs/libretech-ac_defconfig @@ -49,6 +49,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_POWER_DOMAIN=y @@ -66,7 +67,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_KEYBOARD=y diff --git a/configs/libretech-cc_defconfig b/configs/libretech-cc_defconfig index 65ad7f5de4..559d674ff5 100644 --- a/configs/libretech-cc_defconfig +++ b/configs/libretech-cc_defconfig @@ -36,6 +36,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_POWER_DOMAIN=y @@ -50,7 +51,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_GADGET=y diff --git a/configs/libretech-s905d-pc_defconfig b/configs/libretech-s905d-pc_defconfig index c99a6c5971..5f8074a883 100644 --- a/configs/libretech-s905d-pc_defconfig +++ b/configs/libretech-s905d-pc_defconfig @@ -44,6 +44,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_POWER_DOMAIN=y @@ -61,7 +62,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_KEYBOARD=y diff --git a/configs/libretech-s912-pc_defconfig b/configs/libretech-s912-pc_defconfig index 7975c590b6..cbd42b4216 100644 --- a/configs/libretech-s912-pc_defconfig +++ b/configs/libretech-s912-pc_defconfig @@ -43,6 +43,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_POWER_DOMAIN=y @@ -60,7 +61,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y # CONFIG_USB_DWC3_GADGET is not set CONFIG_USB_KEYBOARD=y diff --git a/configs/p212_defconfig b/configs/p212_defconfig index 108b60889b..182321151a 100644 --- a/configs/p212_defconfig +++ b/configs/p212_defconfig @@ -34,6 +34,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_MESON_GXL_USB_PHY=y +CONFIG_USB_DWC3_MESON_GXL=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_GXL=y CONFIG_DM_REGULATOR=y @@ -46,6 +47,5 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3=y CONFIG_OF_LIBFDT_OVERLAY=y From 66d942740307e8199e0671bf667629cb9511436a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:15 +0200 Subject: [PATCH 05/16] phy: meson-gxl: remove invalid USB3 PHY driver The registers which are managed by the meson-gxl-usb3 PHY driver are actually "USB control" registers (which are "glue" registers which manage OTG detection and routing of the OTG capable port between the DWC2 peripheral-only controller and the DWC3 host-only controller). Drop the meson-gxl-usb3 PHY driver now that the dwc3-meson-gxl-usb driver supports the USB control registers on GXL and GXM SoCs (these were previously managed by the meson-gxl-usb3 PHY driver). Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/usb-gx.h | 1 - drivers/phy/Makefile | 2 +- drivers/phy/meson-gxl-usb3.c | 219 ----------------------- 3 files changed, 1 insertion(+), 221 deletions(-) delete mode 100644 drivers/phy/meson-gxl-usb3.c diff --git a/arch/arm/include/asm/arch-meson/usb-gx.h b/arch/arm/include/asm/arch-meson/usb-gx.h index 7200a4c31a..61f1809df9 100644 --- a/arch/arm/include/asm/arch-meson/usb-gx.h +++ b/arch/arm/include/asm/arch-meson/usb-gx.h @@ -11,7 +11,6 @@ /* TOFIX add set_mode to struct phy_ops */ void phy_meson_gxl_usb2_set_mode(struct phy *phy, enum usb_dr_mode mode); -void phy_meson_gxl_usb3_set_mode(struct phy *phy, enum usb_dr_mode mode); int dwc3_meson_gxl_force_mode(struct udevice *dev, enum usb_dr_mode mode); diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 74e8d931d3..c839c250bd 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o obj-$(CONFIG_MESON_GXBB_USB_PHY) += meson-gxbb-usb2.o -obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o +obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o obj-$(CONFIG_MESON_G12A_USB_PHY) += meson-g12a-usb2.o meson-g12a-usb3-pcie.o obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c deleted file mode 100644 index 9de55bb5df..0000000000 --- a/drivers/phy/meson-gxl-usb3.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Meson GXL USB3 PHY driver - * - * Copyright (C) 2018 Martin Blumenstingl - * Copyright (C) 2018 BayLibre, SAS - * Author: Neil Armstrong - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#define USB_R0 0x00 - #define USB_R0_P30_FSEL_MASK GENMASK(5, 0) - #define USB_R0_P30_PHY_RESET BIT(6) - #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7) - #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8) - #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9) - #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14) - #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) - #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) - #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) - #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) - #define USB_R0_U2D_ACT BIT(31) - -#define USB_R1 0x04 - #define USB_R1_U3H_BIGENDIAN_GS BIT(0) - #define USB_R1_U3H_PME_ENABLE BIT(1) - #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2) - #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7) - #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12) - #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) - #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) - #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) - #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) - #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) - -#define USB_R2 0x08 - #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0) - #define USB_R2_P30_CR_READ BIT(16) - #define USB_R2_P30_CR_WRITE BIT(17) - #define USB_R2_P30_CR_CAP_ADDR BIT(18) - #define USB_R2_P30_CR_CAP_DATA BIT(19) - #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) - #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) - -#define USB_R3 0x0c - #define USB_R3_P30_SSC_ENABLE BIT(0) - #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) - #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) - #define USB_R3_P30_REF_SSP_EN BIT(13) - #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16) - #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19) - #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24) - -#define USB_R4 0x10 - #define USB_R4_P21_PORT_RESET_0 BIT(0) - #define USB_R4_P21_SLEEP_M0 BIT(1) - #define USB_R4_MEM_PD_MASK GENMASK(3, 2) - #define USB_R4_P21_ONLY BIT(4) - -#define USB_R5 0x14 - #define USB_R5_ID_DIG_SYNC BIT(0) - #define USB_R5_ID_DIG_REG BIT(1) - #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) - #define USB_R5_ID_DIG_EN_0 BIT(4) - #define USB_R5_ID_DIG_EN_1 BIT(5) - #define USB_R5_ID_DIG_CURR BIT(6) - #define USB_R5_ID_DIG_IRQ BIT(7) - #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) - #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) - -/* read-only register */ -#define USB_R6 0x18 - #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0) - #define USB_R6_P30_CR_ACK BIT(16) - -struct phy_meson_gxl_usb3_priv { - struct regmap *regmap; -#if CONFIG_IS_ENABLED(CLK) - struct clk clk; -#endif -}; - -void phy_meson_gxl_usb3_set_mode(struct phy *phy, enum usb_dr_mode mode) -{ - struct udevice *dev = phy->dev; - struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); - uint val; - - switch (mode) { - case USB_DR_MODE_UNKNOWN: - case USB_DR_MODE_HOST: - case USB_DR_MODE_OTG: - regmap_read(priv->regmap, USB_R0, &val); - val &= ~USB_R0_U2D_ACT; - regmap_write(priv->regmap, USB_R0, val); - - regmap_read(priv->regmap, USB_R4, &val); - val &= ~USB_R4_P21_SLEEP_M0; - regmap_write(priv->regmap, USB_R4, val); - break; - - case USB_DR_MODE_PERIPHERAL: - regmap_read(priv->regmap, USB_R0, &val); - val |= USB_R0_U2D_ACT; - regmap_write(priv->regmap, USB_R0, val); - - regmap_read(priv->regmap, USB_R4, &val); - val |= USB_R4_P21_SLEEP_M0; - regmap_write(priv->regmap, USB_R4, val); - break; - } -} - -static int phy_meson_gxl_usb3_power_on(struct phy *phy) -{ - struct udevice *dev = phy->dev; - struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); - uint val; - - regmap_read(priv->regmap, USB_R5, &val); - val |= USB_R5_ID_DIG_EN_0; - val |= USB_R5_ID_DIG_EN_1; - val &= ~USB_R5_ID_DIG_TH_MASK; - val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff); - regmap_write(priv->regmap, USB_R5, val); - - phy_meson_gxl_usb3_set_mode(phy, USB_DR_MODE_HOST); - - return 0; -} - -static int phy_meson_gxl_usb3_power_off(struct phy *phy) -{ - struct udevice *dev = phy->dev; - struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); - uint val; - - regmap_read(priv->regmap, USB_R5, &val); - val &= ~USB_R5_ID_DIG_EN_0; - val &= ~USB_R5_ID_DIG_EN_1; - regmap_write(priv->regmap, USB_R5, val); - - return 0; -} - -static int phy_meson_gxl_usb3_init(struct phy *phy) -{ - struct udevice *dev = phy->dev; - struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); - uint val; - - regmap_read(priv->regmap, USB_R1, &val); - val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK; - val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20); - regmap_write(priv->regmap, USB_R1, val); - - return 0; -} - -struct phy_ops meson_gxl_usb3_phy_ops = { - .init = phy_meson_gxl_usb3_init, - .power_on = phy_meson_gxl_usb3_power_on, - .power_off = phy_meson_gxl_usb3_power_off, -}; - -int meson_gxl_usb3_phy_probe(struct udevice *dev) -{ - struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev); - int ret; - - ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); - if (ret) - return ret; - -#if CONFIG_IS_ENABLED(CLK) - ret = clk_get_by_index(dev, 0, &priv->clk); - if (ret < 0) - return ret; - - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { - pr_err("failed to enable PHY clock\n"); - clk_free(&priv->clk); - return ret; - } -#endif - - return 0; -} - -static const struct udevice_id meson_gxl_usb3_phy_ids[] = { - { .compatible = "amlogic,meson-gxl-usb3-phy" }, - { } -}; - -U_BOOT_DRIVER(meson_gxl_usb3_phy) = { - .name = "meson_gxl_usb3_phy", - .id = UCLASS_PHY, - .of_match = meson_gxl_usb3_phy_ids, - .probe = meson_gxl_usb3_phy_probe, - .ops = &meson_gxl_usb3_phy_ops, - .priv_auto_alloc_size = sizeof(struct phy_meson_gxl_usb3_priv), -}; From 0ae8724d7e64f814fb77d2caef6214fc1bc52991 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:16 +0200 Subject: [PATCH 06/16] phy: meson-gxl-usb: depend on Meson AXG aswell Enable build of meson-gxl-usb PHY for the AXG architecture aswell. Signed-off-by: Neil Armstrong --- drivers/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 9c775107e9..912e29f7b5 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -164,7 +164,7 @@ config MESON_GXBB_USB_PHY config MESON_GXL_USB_PHY bool "Amlogic Meson GXL USB PHYs" - depends on PHY && ARCH_MESON && (MESON_GXL || MESON_GXM) + depends on PHY && ARCH_MESON && (MESON_GXL || MESON_GXM || MESON_AXG) imply REGMAP help This is the generic phy driver for the Amlogic Meson GXL From e9d29b98e3e16387f5b03140d0b3aba7b0a2c530 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:17 +0200 Subject: [PATCH 07/16] arm: meson-axg: add board_usb_init()/cleanup() for USB gadget Add the board_usb_init()/cleanup() for USB gadget for AXG based on the code for the G12A architecture. Signed-off-by: Neil Armstrong --- arch/arm/mach-meson/board-axg.c | 128 ++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/arch/arm/mach-meson/board-axg.c b/arch/arm/mach-meson/board-axg.c index 5e0b3f6cb5..0d4eda93b8 100644 --- a/arch/arm/mach-meson/board-axg.c +++ b/arch/arm/mach-meson/board-axg.c @@ -14,6 +14,11 @@ #include #include #include +#include +#include +#include +#include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -118,3 +123,126 @@ void meson_eth_init(phy_interface_t mode, unsigned int flags) /* Enable power gate */ clrbits_le32(AXG_MEM_PD_REG_0, AXG_MEM_PD_REG_0_ETH_MASK); } + +#if CONFIG_IS_ENABLED(USB_DWC3_MESON_GXL) && \ + CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG) +static struct dwc2_plat_otg_data meson_gx_dwc2_data; + +int board_usb_init(int index, enum usb_init_type init) +{ + struct fdtdec_phandle_args args; + const void *blob = gd->fdt_blob; + int node, dwc2_node; + struct udevice *dev, *clk_dev; + struct clk clk; + int ret; + + /* find the usb glue node */ + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxl-usb-ctrl"); + if (node < 0) { + debug("Not found usb-control node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, node)) { + debug("usb is disabled in the device tree\n"); + return -ENODEV; + } + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) { + debug("Not found usb-control device\n"); + return ret; + } + + /* find the dwc2 node */ + dwc2_node = fdt_node_offset_by_compatible(blob, node, + "amlogic,meson-g12a-usb"); + if (dwc2_node < 0) { + debug("Not found dwc2 node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, dwc2_node)) { + debug("dwc2 is disabled in the device tree\n"); + return -ENODEV; + } + + meson_gx_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg"); + if (meson_gx_dwc2_data.regs_otg == FDT_ADDR_T_NONE) { + debug("usbotg: can't get base address\n"); + return -ENODATA; + } + + /* Enable clock */ + ret = fdtdec_parse_phandle_with_args(blob, dwc2_node, "clocks", + "#clock-cells", 0, 0, &args); + if (ret) { + debug("usbotg has no clocks defined in the device tree\n"); + return ret; + } + + ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &clk_dev); + if (ret) + return ret; + + if (args.args_count != 1) { + debug("Can't find clock ID in the device tree\n"); + return -ENODATA; + } + + clk.dev = clk_dev; + clk.id = args.args[0]; + + ret = clk_enable(&clk); + if (ret) { + debug("Failed to enable usbotg clock\n"); + return ret; + } + + meson_gx_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-rx-fifo-size", 0); + meson_gx_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-np-tx-fifo-size", 0); + meson_gx_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-tx-fifo-size", 0); + + /* Switch to peripheral mode */ + ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_PERIPHERAL); + if (ret) + return ret; + + return dwc2_udc_probe(&meson_gx_dwc2_data); +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + const void *blob = gd->fdt_blob; + struct udevice *dev; + int node; + int ret; + + /* find the usb glue node */ + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-gxl-usb-ctrl"); + if (node < 0) { + debug("Not found usb-control node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, node)) + return -ENODEV; + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) + return ret; + + /* Switch to OTG mode */ + ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_HOST); + if (ret) + return ret; + + return 0; +} +#endif From 85a034c275910d9c48474d32c9303bf29dd98a31 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:18 +0200 Subject: [PATCH 08/16] ARM: dts: meson-axg: add USB nodes for S400 Add the correcly architectured USB Glue node for Meson AXG and the S400 board in -u-boot.dtsi until support in upstream Linux then backported. Signed-off-by: Neil Armstrong --- arch/arm/dts/meson-axg-s400-u-boot.dtsi | 12 +++++ arch/arm/dts/meson-axg-u-boot.dtsi | 62 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 arch/arm/dts/meson-axg-u-boot.dtsi diff --git a/arch/arm/dts/meson-axg-s400-u-boot.dtsi b/arch/arm/dts/meson-axg-s400-u-boot.dtsi index c46eb3f38d..2c4b06f140 100644 --- a/arch/arm/dts/meson-axg-s400-u-boot.dtsi +++ b/arch/arm/dts/meson-axg-s400-u-boot.dtsi @@ -3,6 +3,8 @@ * Copyright (c) 2017 Amlogic, Inc. All rights reserved. */ +#include "meson-axg-u-boot.dtsi" + /* wifi module */ &sd_emmc_b { status = "disabled"; @@ -12,3 +14,13 @@ &sd_emmc_c { status = "okay"; }; + +&usb { + status = "okay"; + dr_mode = "otg"; + vbus-supply = <&usb_pwr>; +}; + +&usb2_phy1 { + phy-supply = <&vcc_5v>; +}; diff --git a/arch/arm/dts/meson-axg-u-boot.dtsi b/arch/arm/dts/meson-axg-u-boot.dtsi new file mode 100644 index 0000000000..cb1c71e78c --- /dev/null +++ b/arch/arm/dts/meson-axg-u-boot.dtsi @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 BayLibre, SAS. + * Author: Neil Armstrong + */ + +/ { + soc { + usb: usb@ffe09080 { + compatible = "amlogic,meson-gxl-usb-ctrl"; + reg = <0x0 0xffe09080 0x0 0x20>; + interrupts = ; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1_DDR_BRIDGE>; + clock-names = "usb_ctrl", "ddr"; + resets = <&reset RESET_USB_OTG>; + + dr_mode = "otg"; + + phys = <&usb2_phy1>; + phy-names = "usb2-phy1"; + + dwc2: usb@ff400000 { + compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; + reg = <0x0 0xff400000 0x0 0x40000>; + interrupts = ; + clocks = <&clkc CLKID_USB1>; + clock-names = "otg"; + phys = <&usb2_phy1>; + dr_mode = "peripheral"; + g-rx-fifo-size = <192>; + g-np-tx-fifo-size = <128>; + g-tx-fifo-size = <128 128 16 16 16>; + }; + + dwc3: usb@ff500000 { + compatible = "snps,dwc3"; + reg = <0x0 0xff500000 0x0 0x100000>; + interrupts = ; + dr_mode = "host"; + maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; + }; + }; + }; +}; + +&apb { + usb2_phy1: phy@9020 { + compatible = "amlogic,meson-gxl-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0x9020 0x0 0x20>; + clocks = <&clkc CLKID_USB>; + clock-names = "phy"; + resets = <&reset RESET_USB_OTG>; + reset-names = "phy"; + status = "okay"; + }; +}; From 7570ad6b6ecaa737c1063f985fd083d849f4e8d6 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 10 Sep 2020 10:48:19 +0200 Subject: [PATCH 09/16] configs: s400: enable USB Enable USB Host & Gadget on the Amlogic S400 board. Signed-off-by: Neil Armstrong --- configs/s400_defconfig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/configs/s400_defconfig b/configs/s400_defconfig index 3c9509411b..16c162434b 100644 --- a/configs/s400_defconfig +++ b/configs/s400_defconfig @@ -18,6 +18,8 @@ CONFIG_MISC_INIT_R=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y @@ -28,6 +30,7 @@ CONFIG_MMC_MESON_GX=y CONFIG_PHY_REALTEK=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y +CONFIG_MESON_GXL_USB_PHY=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MESON_AXG=y CONFIG_DM_REGULATOR=y @@ -36,4 +39,16 @@ CONFIG_DM_RESET=y CONFIG_DEBUG_UART_ANNOUNCE=y CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DWC3=y +CONFIG_USB_DWC3=y +# CONFIG_USB_DWC3_GADGET is not set +CONFIG_USB_DWC3_MESON_GXL=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VENDOR_NUM=0x1b8e +CONFIG_USB_GADGET_PRODUCT_NUM=0xfada +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_OF_LIBFDT_OVERLAY=y From 1110e49e3435d4c6d5654aa925365b3084099aca Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2020 09:34:12 +0200 Subject: [PATCH 10/16] ARM: dts: sync amlogic G12A/SM1 DT from Linux 5.9-rc1 This imports the G12A & SM1 SoC and boards DT changes from the Linux commit 9123e3a74ec7 ("Linux 5.9-rc1"). Signed-off-by: Neil Armstrong Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Neil Armstrong --- arch/arm/dts/meson-g12-common.dtsi | 55 ++++--- arch/arm/dts/meson-g12b-odroid-n2.dts | 136 +++++++++++++++++- arch/arm/dts/meson-khadas-vim3.dtsi | 26 +++- arch/arm/dts/meson-sm1-khadas-vim3l.dts | 92 ++++++++++++ arch/arm/dts/meson-sm1-odroid-c4.dts | 88 ++++++++++++ include/dt-bindings/clock/g12a-clkc.h | 2 + .../dt-bindings/sound/meson-g12a-toacodec.h | 10 ++ 7 files changed, 385 insertions(+), 24 deletions(-) create mode 100644 include/dt-bindings/sound/meson-g12a-toacodec.h diff --git a/arch/arm/dts/meson-g12-common.dtsi b/arch/arm/dts/meson-g12-common.dtsi index 593a006f4b..1e83ec5b8c 100644 --- a/arch/arm/dts/meson-g12-common.dtsi +++ b/arch/arm/dts/meson-g12-common.dtsi @@ -52,6 +52,39 @@ secure-monitor = <&sm>; }; + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-124999998 { + opp-hz = /bits/ 64 <124999998>; + opp-microvolt = <800000>; + }; + opp-249999996 { + opp-hz = /bits/ 64 <249999996>; + opp-microvolt = <800000>; + }; + opp-285714281 { + opp-hz = /bits/ 64 <285714281>; + opp-microvolt = <800000>; + }; + opp-399999994 { + opp-hz = /bits/ 64 <399999994>; + opp-microvolt = <800000>; + }; + opp-499999992 { + opp-hz = /bits/ 64 <499999992>; + opp-microvolt = <800000>; + }; + opp-666666656 { + opp-hz = /bits/ 64 <666666656>; + opp-microvolt = <800000>; + }; + opp-799999987 { + opp-hz = /bits/ 64 <799999987>; + opp-microvolt = <800000>; + }; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -185,8 +218,10 @@ interrupt-names = "macirq"; clocks = <&clkc CLKID_ETH>, <&clkc CLKID_FCLK_DIV2>, - <&clkc CLKID_MPLL2>; - clock-names = "stmmaceth", "clkin0", "clkin1"; + <&clkc CLKID_MPLL2>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "stmmaceth", "clkin0", "clkin1", + "timing-adjustment"; rx-fifo-depth = <4096>; tx-fifo-depth = <2048>; status = "disabled"; @@ -2360,21 +2395,7 @@ interrupt-names = "job", "mmu", "gpu"; clocks = <&clkc CLKID_MALI>; resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; - - /* - * Mali clocking is provided by two identical clock paths - * MALI_0 and MALI_1 muxed to a single clock by a glitch - * free mux to safely change frequency while running. - */ - assigned-clocks = <&clkc CLKID_MALI_0_SEL>, - <&clkc CLKID_MALI_0>, - <&clkc CLKID_MALI>; /* Glitch free mux */ - assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, - <0>, /* Do Nothing */ - <&clkc CLKID_MALI_0>; - assigned-clock-rates = <0>, /* Do Nothing */ - <800000000>, - <0>; /* Do Nothing */ + operating-points-v2 = <&gpu_opp_table>; #cooling-cells = <2>; }; }; diff --git a/arch/arm/dts/meson-g12b-odroid-n2.dts b/arch/arm/dts/meson-g12b-odroid-n2.dts index 169ea283d4..34fffa6d85 100644 --- a/arch/arm/dts/meson-g12b-odroid-n2.dts +++ b/arch/arm/dts/meson-g12b-odroid-n2.dts @@ -9,6 +9,7 @@ #include "meson-g12b-s922x.dtsi" #include #include +#include #include / { @@ -20,6 +21,14 @@ ethernet0 = ðmac; }; + dioo2133: audio-amplifier-0 { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; + VCC-supply = <&vcc_5v>; + sound-name-prefix = "U19"; + status = "okay"; + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -209,11 +218,42 @@ sound { compatible = "amlogic,axg-sound-card"; model = "G12B-ODROID-N2"; - audio-aux-devs = <&tdmout_b>; + audio-widgets = "Line", "Lineout"; + audio-aux-devs = <&tdmout_b>, <&tdmout_c>, <&tdmin_a>, + <&tdmin_b>, <&tdmin_c>, <&tdmin_lb>, + <&dioo2133>; audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", "TDMOUT_B IN 1", "FRDDR_B OUT 1", "TDMOUT_B IN 2", "FRDDR_C OUT 1", - "TDM_B Playback", "TDMOUT_B OUT"; + "TDM_B Playback", "TDMOUT_B OUT", + "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "TDMOUT_C IN 1", "FRDDR_B OUT 2", + "TDMOUT_C IN 2", "FRDDR_C OUT 2", + "TDM_C Playback", "TDMOUT_C OUT", + "TDMIN_A IN 4", "TDM_B Loopback", + "TDMIN_B IN 4", "TDM_B Loopback", + "TDMIN_C IN 4", "TDM_B Loopback", + "TDMIN_LB IN 1", "TDM_B Loopback", + "TDMIN_A IN 5", "TDM_C Loopback", + "TDMIN_B IN 5", "TDM_C Loopback", + "TDMIN_C IN 5", "TDM_C Loopback", + "TDMIN_LB IN 2", "TDM_C Loopback", + "TODDR_A IN 0", "TDMIN_A OUT", + "TODDR_B IN 0", "TDMIN_A OUT", + "TODDR_C IN 0", "TDMIN_A OUT", + "TODDR_A IN 1", "TDMIN_B OUT", + "TODDR_B IN 1", "TDMIN_B OUT", + "TODDR_C IN 1", "TDMIN_B OUT", + "TODDR_A IN 2", "TDMIN_C OUT", + "TODDR_B IN 2", "TDMIN_C OUT", + "TODDR_C IN 2", "TDMIN_C OUT", + "TODDR_A IN 6", "TDMIN_LB OUT", + "TODDR_B IN 6", "TDMIN_LB OUT", + "TODDR_C IN 6", "TDMIN_LB OUT", + "U19 INL", "ACODEC LOLP", + "U19 INR", "ACODEC LORP", + "Lineout", "U19 OUTL", + "Lineout", "U19 OUTR"; assigned-clocks = <&clkc CLKID_MPLL2>, <&clkc CLKID_MPLL0>, @@ -236,8 +276,20 @@ sound-dai = <&frddr_c>; }; - /* 8ch hdmi interface */ dai-link-3 { + sound-dai = <&toddr_a>; + }; + + dai-link-4 { + sound-dai = <&toddr_b>; + }; + + dai-link-5 { + sound-dai = <&toddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-6 { sound-dai = <&tdmif_b>; dai-format = "i2s"; dai-tdm-slot-tx-mask-0 = <1 1>; @@ -246,22 +298,56 @@ dai-tdm-slot-tx-mask-3 = <1 1>; mclk-fs = <256>; - codec { + codec-0 { sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_B>; + }; + }; + + /* i2s jack output interface */ + dai-link-7 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>; + }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_C>; + }; }; /* hdmi glue */ - dai-link-4 { + dai-link-8 { sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; codec { sound-dai = <&hdmi_tx>; }; }; + + /* acodec glue */ + dai-link-9 { + sound-dai = <&toacodec TOACODEC_OUT>; + + codec { + sound-dai = <&acodec>; + }; + }; }; }; +&acodec { + AVDD-supply = <&vddao_1v8>; + status = "okay"; +}; + &arb { status = "okay"; }; @@ -476,14 +562,54 @@ status = "okay"; }; +&tdmif_c { + status = "okay"; +}; + +&tdmin_a { + status = "okay"; +}; + +&tdmin_b { + status = "okay"; +}; + +&tdmin_c { + status = "okay"; +}; + +&tdmin_lb { + status = "okay"; +}; + &tdmout_b { status = "okay"; }; +&tdmout_c { + status = "okay"; +}; + +&toacodec { + status = "okay"; +}; + &tohdmitx { status = "okay"; }; +&toddr_a { + status = "okay"; +}; + +&toddr_b { + status = "okay"; +}; + +&toddr_c { + status = "okay"; +}; + &uart_AO { status = "okay"; pinctrl-0 = <&uart_ao_a_pins>; diff --git a/arch/arm/dts/meson-khadas-vim3.dtsi b/arch/arm/dts/meson-khadas-vim3.dtsi index 1ef1e3672b..94f75b4465 100644 --- a/arch/arm/dts/meson-khadas-vim3.dtsi +++ b/arch/arm/dts/meson-khadas-vim3.dtsi @@ -183,6 +183,23 @@ hdmi-phandle = <&hdmi_tx>; }; +&cpu_thermal { + trips { + cpu_active: cpu-active { + temperature = <80000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "active"; + }; + }; + + cooling-maps { + map { + trip = <&cpu_active>; + cooling-device = <&khadas_mcu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; +}; + &ext_mdio { external_phy: ethernet-phy@0 { /* Realtek RTL8211F (0x001cc916) */ @@ -222,6 +239,12 @@ pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>; pinctrl-names = "default"; + khadas_mcu: system-controller@18 { + compatible = "khadas,mcu"; + reg = <0x18>; + #cooling-cells = <2>; + }; + gpio_expander: gpio-controller@20 { compatible = "ti,tca6408"; reg = <0x20>; @@ -270,7 +293,6 @@ bus-width = <4>; cap-sd-highspeed; - sd-uhs-sdr50; max-frequency = <100000000>; non-removable; @@ -337,7 +359,7 @@ pinctrl-0 = <&nor_pins>; pinctrl-names = "default"; - w25q32: spi-flash@0 { + w25q128: spi-flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "winbond,w25q128fw", "jedec,spi-nor"; diff --git a/arch/arm/dts/meson-sm1-khadas-vim3l.dts b/arch/arm/dts/meson-sm1-khadas-vim3l.dts index dbbf29a0db..0da56c051a 100644 --- a/arch/arm/dts/meson-sm1-khadas-vim3l.dts +++ b/arch/arm/dts/meson-sm1-khadas-vim3l.dts @@ -8,6 +8,7 @@ #include "meson-sm1.dtsi" #include "meson-khadas-vim3.dtsi" +#include / { compatible = "khadas,vim3l", "amlogic,sm1"; @@ -31,6 +32,69 @@ regulator-boot-on; regulator-always-on; }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "SM1-KHADAS-VIM3L"; + audio-aux-devs = <&tdmout_a>; + audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", + "TDMOUT_A IN 1", "FRDDR_B OUT 0", + "TDMOUT_A IN 2", "FRDDR_C OUT 0", + "TDM_A Playback", "TDMOUT_A OUT"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-3 { + sound-dai = <&tdmif_a>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>; + }; + }; + + /* hdmi glue */ + dai-link-4 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + }; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; }; &cpu0 { @@ -61,6 +125,18 @@ clock-latency = <50000>; }; +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + &pwm_AO_cd { pinctrl-0 = <&pwm_ao_d_e_pins>; pinctrl-names = "default"; @@ -88,8 +164,24 @@ status = "okay"; }; +&sd_emmc_a { + sd-uhs-sdr50; +}; + &usb { phys = <&usb2_phy0>, <&usb2_phy1>; phy-names = "usb2-phy0", "usb2-phy1"; }; */ + +&tdmif_a { + status = "okay"; +}; + +&tdmout_a { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; diff --git a/arch/arm/dts/meson-sm1-odroid-c4.dts b/arch/arm/dts/meson-sm1-odroid-c4.dts index 00d90b30f8..cf5a98f0e4 100644 --- a/arch/arm/dts/meson-sm1-odroid-c4.dts +++ b/arch/arm/dts/meson-sm1-odroid-c4.dts @@ -8,6 +8,7 @@ #include "meson-sm1.dtsi" #include #include +#include / { compatible = "hardkernel,odroid-c4", "amlogic,sm1"; @@ -186,6 +187,69 @@ }; }; }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "SM1-ODROID-C4"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-3 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + }; + + /* hdmi glue */ + dai-link-4 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + }; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; }; &cpu0 { @@ -237,6 +301,18 @@ amlogic,tx-delay-ns = <2>; }; +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + &gpio { gpio-line-names = /* GPIOZ */ @@ -381,6 +457,18 @@ vqmmc-supply = <&flash_1v8>; }; +&tdmif_b { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + &uart_AO { status = "okay"; pinctrl-0 = <&uart_ao_a_pins>; diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h index b0d65d73db..40d49940d8 100644 --- a/include/dt-bindings/clock/g12a-clkc.h +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -145,5 +145,7 @@ #define CLKID_CPU3_CLK 255 #define CLKID_SPICC0_SCLK 258 #define CLKID_SPICC1_SCLK 261 +#define CLKID_NNA_AXI_CLK 264 +#define CLKID_NNA_CORE_CLK 267 #endif /* __G12A_CLKC_H */ diff --git a/include/dt-bindings/sound/meson-g12a-toacodec.h b/include/dt-bindings/sound/meson-g12a-toacodec.h new file mode 100644 index 0000000000..69d7a75592 --- /dev/null +++ b/include/dt-bindings/sound/meson-g12a-toacodec.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_MESON_G12A_TOACODEC_H +#define __DT_MESON_G12A_TOACODEC_H + +#define TOACODEC_IN_A 0 +#define TOACODEC_IN_B 1 +#define TOACODEC_IN_C 2 +#define TOACODEC_OUT 3 + +#endif /* __DT_MESON_G12A_TOACODEC_H */ From 5aeecbcf819055c68173f3e57700f11033c3186b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2020 09:34:13 +0200 Subject: [PATCH 11/16] board: amlogic: add a vim3 specific board support The VIM3 will need a specific code to enable PCIe if enabled in the MCU, thus add a specific board support for VIM3 & VIM3L. Signed-off-by: Neil Armstrong Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Neil Armstrong --- board/amlogic/vim3/MAINTAINERS | 9 +++++++++ board/amlogic/vim3/Makefile | 6 ++++++ board/amlogic/vim3/vim3.c | 20 ++++++++++++++++++++ board/amlogic/w400/MAINTAINERS | 4 ---- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 board/amlogic/vim3/MAINTAINERS create mode 100644 board/amlogic/vim3/Makefile create mode 100644 board/amlogic/vim3/vim3.c diff --git a/board/amlogic/vim3/MAINTAINERS b/board/amlogic/vim3/MAINTAINERS new file mode 100644 index 0000000000..92b426f66d --- /dev/null +++ b/board/amlogic/vim3/MAINTAINERS @@ -0,0 +1,9 @@ +VIM3 +M: Neil Armstrong +S: Maintained +L: u-boot-amlogic@groups.io +F: board/amlogic/vim3/ +F: configs/khadas-vim3_defconfig +F: configs/khadas-vim3l_defconfig +F: doc/board/amlogic/khadas-vim3.rst +F: doc/board/amlogic/khadas-vim3l.rst diff --git a/board/amlogic/vim3/Makefile b/board/amlogic/vim3/Makefile new file mode 100644 index 0000000000..c515077302 --- /dev/null +++ b/board/amlogic/vim3/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2020 BayLibre, SAS +# Author: Neil Armstrong + +obj-y := vim3.o diff --git a/board/amlogic/vim3/vim3.c b/board/amlogic/vim3/vim3.c new file mode 100644 index 0000000000..02d8cd0ce0 --- /dev/null +++ b/board/amlogic/vim3/vim3.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include + +int misc_init_r(void) +{ + meson_eth_init(PHY_INTERFACE_MODE_RGMII, 0); + + return 0; +} diff --git a/board/amlogic/w400/MAINTAINERS b/board/amlogic/w400/MAINTAINERS index a1b0ac8636..991590d9f2 100644 --- a/board/amlogic/w400/MAINTAINERS +++ b/board/amlogic/w400/MAINTAINERS @@ -3,8 +3,4 @@ M: Neil Armstrong S: Maintained L: u-boot-amlogic@groups.io F: board/amlogic/w400/ -F: configs/khadas-vim3_defconfig -F: configs/khadas-vim3l_defconfig F: doc/board/amlogic/w400.rst -F: doc/board/amlogic/khadas-vim3.rst -F: doc/board/amlogic/khadas-vim3l.rst From cb4a7feb54b5143905f720afb582e2aeef4937ef Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2020 09:34:14 +0200 Subject: [PATCH 12/16] configs: vim3: use the vim3 board support Use the newly added VIM3 board support instead of the generic W400. Signed-off-by: Neil Armstrong Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Neil Armstrong --- configs/khadas-vim3_defconfig | 2 +- configs/khadas-vim3l_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/khadas-vim3_defconfig b/configs/khadas-vim3_defconfig index a39e0f9c9f..ee5990426d 100644 --- a/configs/khadas-vim3_defconfig +++ b/configs/khadas-vim3_defconfig @@ -1,5 +1,5 @@ CONFIG_ARM=y -CONFIG_SYS_BOARD="w400" +CONFIG_SYS_BOARD="vim3" CONFIG_ARCH_MESON=y CONFIG_SYS_TEXT_BASE=0x01000000 CONFIG_NR_DRAM_BANKS=1 diff --git a/configs/khadas-vim3l_defconfig b/configs/khadas-vim3l_defconfig index 57cc383b9d..5729d339e9 100644 --- a/configs/khadas-vim3l_defconfig +++ b/configs/khadas-vim3l_defconfig @@ -1,5 +1,5 @@ CONFIG_ARM=y -CONFIG_SYS_BOARD="w400" +CONFIG_SYS_BOARD="vim3" CONFIG_ARCH_MESON=y CONFIG_SYS_TEXT_BASE=0x01000000 CONFIG_NR_DRAM_BANKS=1 From adbff64af7b7cee3e0007b75df2644090edaafcb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 21 Sep 2020 09:34:15 +0200 Subject: [PATCH 13/16] board: amlogic: vim3: add support for dynamic PCIe enable The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between an USB3.0 Type A connector and a M.2 Key M slot. The PHY driving these differential lines is shared between the USB3.0 controller and the PCIe Controller, thus only a single controller can use it. This adds this dynamic switching right before booting Linux and the configuration steps in the boards documentation. Signed-off-by: Neil Armstrong Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman [narmstrong: fixed warning by replacing min() by min_t()] --- board/amlogic/vim3/khadas-mcu.h | 81 ++++++++++++++++++++ board/amlogic/vim3/vim3.c | 117 +++++++++++++++++++++++++++++ configs/khadas-vim3_defconfig | 3 + configs/khadas-vim3l_defconfig | 3 + doc/board/amlogic/khadas-vim3.rst | 27 +++++++ doc/board/amlogic/khadas-vim3l.rst | 27 +++++++ 6 files changed, 258 insertions(+) create mode 100644 board/amlogic/vim3/khadas-mcu.h diff --git a/board/amlogic/vim3/khadas-mcu.h b/board/amlogic/vim3/khadas-mcu.h new file mode 100644 index 0000000000..de3758cafe --- /dev/null +++ b/board/amlogic/vim3/khadas-mcu.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Khadas System control Microcontroller Register map + * + * Copyright (C) 2020 BayLibre SAS + * + * Author(s): Neil Armstrong + */ + +#ifndef MFD_KHADAS_MCU_H +#define MFD_KHADAS_MCU_H + +#define KHADAS_MCU_PASSWD_VEN_0_REG 0x00 /* RO */ +#define KHADAS_MCU_PASSWD_VEN_1_REG 0x01 /* RO */ +#define KHADAS_MCU_PASSWD_VEN_2_REG 0x02 /* RO */ +#define KHADAS_MCU_PASSWD_VEN_3_REG 0x03 /* RO */ +#define KHADAS_MCU_PASSWD_VEN_4_REG 0x04 /* RO */ +#define KHADAS_MCU_PASSWD_VEN_5_REG 0x05 /* RO */ +#define KHADAS_MCU_MAC_0_REG 0x06 /* RO */ +#define KHADAS_MCU_MAC_1_REG 0x07 /* RO */ +#define KHADAS_MCU_MAC_2_REG 0x08 /* RO */ +#define KHADAS_MCU_MAC_3_REG 0x09 /* RO */ +#define KHADAS_MCU_MAC_4_REG 0x0a /* RO */ +#define KHADAS_MCU_MAC_5_REG 0x0b /* RO */ +#define KHADAS_MCU_USID_0_REG 0x0c /* RO */ +#define KHADAS_MCU_USID_1_REG 0x0d /* RO */ +#define KHADAS_MCU_USID_2_REG 0x0e /* RO */ +#define KHADAS_MCU_USID_3_REG 0x0f /* RO */ +#define KHADAS_MCU_USID_4_REG 0x10 /* RO */ +#define KHADAS_MCU_USID_5_REG 0x11 /* RO */ +#define KHADAS_MCU_VERSION_0_REG 0x12 /* RO */ +#define KHADAS_MCU_VERSION_1_REG 0x13 /* RO */ +#define KHADAS_MCU_DEVICE_NO_0_REG 0x14 /* RO */ +#define KHADAS_MCU_DEVICE_NO_1_REG 0x15 /* RO */ +#define KHADAS_MCU_FACTORY_TEST_REG 0x16 /* R */ +#define KHADAS_MCU_BOOT_MODE_REG 0x20 /* RW */ +#define KHADAS_MCU_BOOT_EN_WOL_REG 0x21 /* RW */ +#define KHADAS_MCU_BOOT_EN_RTC_REG 0x22 /* RW */ +#define KHADAS_MCU_BOOT_EN_EXP_REG 0x23 /* RW */ +#define KHADAS_MCU_BOOT_EN_IR_REG 0x24 /* RW */ +#define KHADAS_MCU_BOOT_EN_DCIN_REG 0x25 /* RW */ +#define KHADAS_MCU_BOOT_EN_KEY_REG 0x26 /* RW */ +#define KHADAS_MCU_KEY_MODE_REG 0x27 /* RW */ +#define KHADAS_MCU_LED_MODE_ON_REG 0x28 /* RW */ +#define KHADAS_MCU_LED_MODE_OFF_REG 0x29 /* RW */ +#define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c /* RW */ +#define KHADAS_MCU_MAC_SWITCH_REG 0x2d /* RW */ +#define KHADAS_MCU_MCU_SLEEP_MODE_REG 0x2e /* RW */ +#define KHADAS_MCU_IR_CODE1_0_REG 0x2f /* RW */ +#define KHADAS_MCU_IR_CODE1_1_REG 0x30 /* RW */ +#define KHADAS_MCU_IR_CODE1_2_REG 0x31 /* RW */ +#define KHADAS_MCU_IR_CODE1_3_REG 0x32 /* RW */ +#define KHADAS_MCU_USB_PCIE_SWITCH_REG 0x33 /* RW */ +#define KHADAS_MCU_IR_CODE2_0_REG 0x34 /* RW */ +#define KHADAS_MCU_IR_CODE2_1_REG 0x35 /* RW */ +#define KHADAS_MCU_IR_CODE2_2_REG 0x36 /* RW */ +#define KHADAS_MCU_IR_CODE2_3_REG 0x37 /* RW */ +#define KHADAS_MCU_PASSWD_USER_0_REG 0x40 /* RW */ +#define KHADAS_MCU_PASSWD_USER_1_REG 0x41 /* RW */ +#define KHADAS_MCU_PASSWD_USER_2_REG 0x42 /* RW */ +#define KHADAS_MCU_PASSWD_USER_3_REG 0x43 /* RW */ +#define KHADAS_MCU_PASSWD_USER_4_REG 0x44 /* RW */ +#define KHADAS_MCU_PASSWD_USER_5_REG 0x45 /* RW */ +#define KHADAS_MCU_USER_DATA_0_REG 0x46 /* RW 56 bytes */ +#define KHADAS_MCU_PWR_OFF_CMD_REG 0x80 /* WO */ +#define KHADAS_MCU_PASSWD_START_REG 0x81 /* WO */ +#define KHADAS_MCU_CHECK_VEN_PASSWD_REG 0x82 /* WO */ +#define KHADAS_MCU_CHECK_USER_PASSWD_REG 0x83 /* WO */ +#define KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG 0x86 /* RO */ +#define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */ +#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */ + +enum { + KHADAS_BOARD_VIM1 = 0x1, + KHADAS_BOARD_VIM2, + KHADAS_BOARD_VIM3, + KHADAS_BOARD_EDGE = 0x11, + KHADAS_BOARD_EDGE_V, +}; + +#endif /* MFD_KHADAS_MCU_H */ diff --git a/board/amlogic/vim3/vim3.c b/board/amlogic/vim3/vim3.c index 02d8cd0ce0..09ef39ff30 100644 --- a/board/amlogic/vim3/vim3.c +++ b/board/amlogic/vim3/vim3.c @@ -11,6 +11,123 @@ #include #include #include +#include +#include "khadas-mcu.h" + +/* + * The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential + * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between + * an USB3.0 Type A connector and a M.2 Key M slot. + * The PHY driving these differential lines is shared between + * the USB3.0 controller and the PCIe Controller, thus only + * a single controller can use it. + */ +int meson_ft_board_setup(void *blob, struct bd_info *bd) +{ + struct udevice *bus, *dev; + int node, i2c_node, ret; + unsigned int i2c_addr; + u32 *val; + + /* Find I2C device */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "khadas,mcu"); + if (node < 0) { + printf("vim3: cannot find khadas,mcu node\n"); + return 0; + } + + /* Get addr */ + val = (u32 *)fdt_getprop(gd->fdt_blob, node, "reg", NULL); + if (!val) { + printf("vim3: cannot find khadas,mcu node i2c addr\n"); + return 0; + } + i2c_addr = fdt32_to_cpu(*val); + + /* Get i2c device */ + i2c_node = fdt_parent_offset(gd->fdt_blob, node); + if (node < 0) { + printf("vim3: cannot find khadas,mcu i2c node\n"); + return 0; + } + + ret = uclass_get_device_by_of_offset(UCLASS_I2C, i2c_node, &bus); + if (ret < 0) { + printf("vim3: cannot find i2c bus (%d)\n", ret); + return 0; + } + + ret = i2c_get_chip(bus, i2c_addr, 1, &dev); + if (ret < 0) { + printf("vim3: cannot find i2c chip (%d)\n", ret); + return 0; + } + + /* Read USB_PCIE_SWITCH_REG */ + ret = dm_i2c_reg_read(dev, KHADAS_MCU_USB_PCIE_SWITCH_REG); + if (ret < 0) { + printf("vim3: failed to read i2c reg (%d)\n", ret); + return 0; + } + debug("MCU_USB_PCIE_SWITCH_REG: %d\n", ret); + + /* + * If in PCIe mode, alter DT + * 0:Enable USB3.0,Disable PCIE, 1:Disable USB3.0, Enable PCIE + */ + if (ret > 0) { + static char data[32] __aligned(4); + const void *ptmp; + int len; + + /* Find USB node */ + node = fdt_node_offset_by_compatible(blob, -1, "amlogic,meson-g12a-usb-ctrl"); + if (node < 0) { + printf("vim3: cannot find amlogic,meson-g12a-usb-ctrl node\n"); + return 0; + } + + /* Update PHY names (mandatory to disable USB3.0) */ + len = strlcpy(data, "usb2-phy0", 32) + 1; + len += strlcpy(&data[len], "usb2-phy1", 32 - len) + 1; + ret = fdt_setprop(blob, node, "phy-names", data, len); + if (ret < 0) { + printf("vim3: failed to update usb phy names property (%d)\n", ret); + return 0; + } + + /* Update PHY list, by keeping the 2 first entries (optional) */ + ptmp = fdt_getprop(blob, node, "phys", &len); + if (ptmp) { + memcpy(data, ptmp, min_t(unsigned int, 2 * sizeof(u32), len)); + + ret = fdt_setprop(blob, node, "phys", data, + min_t(unsigned int, 2 * sizeof(u32), len)); + if (ret < 0) + printf("vim3: failed to update usb phys property (%d)\n", ret); + } else + printf("vim3: cannot find usb node phys property\n"); + + /* Find PCIe node */ + node = fdt_node_offset_by_compatible(blob, -1, "amlogic,g12a-pcie"); + if (node < 0) { + printf("vim3: cannot find amlogic,g12a-pcie node\n"); + return 0; + } + + /* Enable PCIe */ + len = strlcpy(data, "okay", 32); + ret = fdt_setprop(blob, node, "status", data, len); + if (ret < 0) { + printf("vim3: failed to enable pcie node (%d)\n", ret); + return 0; + } + + printf("vim3: successfully enabled PCIe\n"); + } + + return 0; +} int misc_init_r(void) { diff --git a/configs/khadas-vim3_defconfig b/configs/khadas-vim3_defconfig index ee5990426d..df2d5bda5b 100644 --- a/configs/khadas-vim3_defconfig +++ b/configs/khadas-vim3_defconfig @@ -17,6 +17,7 @@ CONFIG_MISC_INIT_R=y # CONFIG_CMD_BDI is not set # CONFIG_CMD_IMI is not set CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y CONFIG_CMD_SF_TEST=y @@ -28,6 +29,8 @@ CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MESON=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_MTD=y diff --git a/configs/khadas-vim3l_defconfig b/configs/khadas-vim3l_defconfig index 5729d339e9..39e74c3ccb 100644 --- a/configs/khadas-vim3l_defconfig +++ b/configs/khadas-vim3l_defconfig @@ -17,6 +17,7 @@ CONFIG_MISC_INIT_R=y # CONFIG_CMD_BDI is not set # CONFIG_CMD_IMI is not set CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y CONFIG_CMD_SF_TEST=y @@ -28,6 +29,8 @@ CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MESON=y CONFIG_DM_MMC=y CONFIG_MMC_MESON_GX=y CONFIG_MTD=y diff --git a/doc/board/amlogic/khadas-vim3.rst b/doc/board/amlogic/khadas-vim3.rst index c1c03212d2..d6a9642ad6 100644 --- a/doc/board/amlogic/khadas-vim3.rst +++ b/doc/board/amlogic/khadas-vim3.rst @@ -18,6 +18,33 @@ Technology Co., Ltd. with the following specifications: Schematics are available on the manufacturer website. +PCIe Setup +---------- +The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential +lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between +an USB3.0 Type A connector and a M.2 Key M slot. +The PHY driving these differential lines is shared between +the USB3.0 controller and the PCIe Controller, thus only +a single controller can use it. + +To setup for PCIe, run the following commands from U-Boot: + +.. code-block:: none + + i2c dev i2c@5000 + i2c mw 0x18 0x33 1 + +Then power-cycle the board. + +To set back to USB3.0, run the following commands from U-Boot: + +.. code-block:: none + + i2c dev i2c@5000 + i2c mw 0x18 0x33 0 + +Then power-cycle the board. + U-Boot compilation ------------------ diff --git a/doc/board/amlogic/khadas-vim3l.rst b/doc/board/amlogic/khadas-vim3l.rst index b380c17456..3c0a415a87 100644 --- a/doc/board/amlogic/khadas-vim3l.rst +++ b/doc/board/amlogic/khadas-vim3l.rst @@ -18,6 +18,33 @@ Technology Co., Ltd. with the following specifications: Schematics are available on the manufacturer website. +PCIe Setup +---------- +The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential +lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between +an USB3.0 Type A connector and a M.2 Key M slot. +The PHY driving these differential lines is shared between +the USB3.0 controller and the PCIe Controller, thus only +a single controller can use it. + +To setup for PCIe, run the following commands from U-Boot: + +.. code-block:: none + + i2c dev i2c@5000 + i2c mw 0x18 0x33 1 + +Then power-cycle the board. + +To set back to USB3.0, run the following commands from U-Boot: + +.. code-block:: none + + i2c dev i2c@5000 + i2c mw 0x18 0x33 0 + +Then power-cycle the board. + U-Boot compilation ------------------ From 0f6bef4a95672f9497067e90bd2b6441810644f7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 2 Oct 2020 09:31:46 +0200 Subject: [PATCH 14/16] pinctrl: meson-axg-pmx: fix gpio request The AXG pmx driver gpio request offset needs the pin base to have the correct pin number. Signed-off-by: Neil Armstrong Reviewed-by: Mark Kettenis --- drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c index c6cb941d0a..cfe94cf9e1 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c @@ -165,7 +165,10 @@ const struct pinctrl_ops meson_axg_pinctrl_ops = { static int meson_axg_gpio_request(struct udevice *dev, unsigned int offset, const char *label) { - return meson_axg_pmx_update_function(dev->parent, offset, 0); + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + + return meson_axg_pmx_update_function(dev->parent, + offset + priv->data->pin_base, 0); } static const struct dm_gpio_ops meson_axg_gpio_ops = { From 38c1c6f8163334521def945a379e7fca231f4b62 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 2 Oct 2020 09:32:12 +0200 Subject: [PATCH 15/16] pinctrl: meson-axg: add missing GPIOA_18 Add the missing GPIOA_18 from the missing EE gpio list. Signed-off-by: Neil Armstrong --- drivers/pinctrl/meson/pinctrl-meson-axg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c index 8f23c8cef1..11809b29f3 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -298,6 +298,7 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = { GPIO_GROUP(GPIOA_15, EE_OFF), GPIO_GROUP(GPIOA_16, EE_OFF), GPIO_GROUP(GPIOA_17, EE_OFF), + GPIO_GROUP(GPIOA_18, EE_OFF), GPIO_GROUP(GPIOA_19, EE_OFF), GPIO_GROUP(GPIOA_20, EE_OFF), From 2d481b2e3e22f7be854d381a7bafd92a65e18b23 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 1 Oct 2020 10:04:56 +0200 Subject: [PATCH 16/16] pwm: Add driver for Amlogic Meson PWM controller This adds the driver for the PWM controller found in the Amlogic SoCs. This PWM is only a set of Gates, Dividers and Counters: PWM output is achieved by calculating a clock that permits calculating two periods (low and high). The counter then has to be set to switch after N cycles for the first half period. The hardware has no "polarity" setting. This driver reverses the period cycles (the low length is inverted with the high length) for PWM_POLARITY_INVERSED. Disabling the PWM stops the output immediately (without waiting for the current period to complete first). Signed-off-by: Neil Armstrong --- drivers/pwm/Kconfig | 7 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-meson.c | 528 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 drivers/pwm/pwm-meson.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 61eb468cde..b3bd5c6bb7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -23,6 +23,13 @@ config PWM_IMX help This PWM is found i.MX27 and later i.MX SoCs. +config PWM_MESON + bool "Enable support for Amlogic Meson SoCs PWM" + depends on DM_PWM + help + This PWM is found on Amlogic Meson SoCs. It supports a + programmable period and duty cycle for 2 independant channels. + config PWM_MTK bool "Enable support for MediaTek PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 0f4e84b04d..f21ae7d76e 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o +obj-$(CONFIG_PWM_MESON) += pwm-meson.o obj-$(CONFIG_PWM_MTK) += pwm-mtk.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c new file mode 100644 index 0000000000..cafb571f16 --- /dev/null +++ b/drivers/pwm/pwm-meson.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2020 BayLibre, SAS. + * Author: Neil Armstrong + * Copyright (C) 2014 Amlogic, Inc. + * + * This PWM is only a set of Gates, Dividers and Counters: + * PWM output is achieved by calculating a clock that permits calculating + * two periods (low and high). The counter then has to be set to switch after + * N cycles for the first half period. + * The hardware has no "polarity" setting. This driver reverses the period + * cycles (the low length is inverted with the high length) for + * PWM_POLARITY_INVERSED. + * Setting the polarity will disable and re-enable the PWM output. + * Disabling the PWM stops the output immediately (without waiting for the + * current period to complete first). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NSEC_PER_SEC 1000000000L + +#define REG_PWM_A 0x0 +#define REG_PWM_B 0x4 +#define PWM_LOW_MASK GENMASK(15, 0) +#define PWM_HIGH_MASK GENMASK(31, 16) + +#define REG_MISC_AB 0x8 +#define MISC_B_CLK_EN BIT(23) +#define MISC_A_CLK_EN BIT(15) +#define MISC_CLK_DIV_MASK 0x7f +#define MISC_B_CLK_DIV_SHIFT 16 +#define MISC_A_CLK_DIV_SHIFT 8 +#define MISC_B_CLK_SEL_SHIFT 6 +#define MISC_A_CLK_SEL_SHIFT 4 +#define MISC_CLK_SEL_MASK 0x3 +#define MISC_B_EN BIT(1) +#define MISC_A_EN BIT(0) + +#define MESON_NUM_PWMS 2 + +static struct meson_pwm_channel_data { + u8 reg_offset; + u8 clk_sel_shift; + u8 clk_div_shift; + u32 clk_en_mask; + u32 pwm_en_mask; +} meson_pwm_per_channel_data[MESON_NUM_PWMS] = { + { + .reg_offset = REG_PWM_A, + .clk_sel_shift = MISC_A_CLK_SEL_SHIFT, + .clk_div_shift = MISC_A_CLK_DIV_SHIFT, + .clk_en_mask = MISC_A_CLK_EN, + .pwm_en_mask = MISC_A_EN, + }, + { + .reg_offset = REG_PWM_B, + .clk_sel_shift = MISC_B_CLK_SEL_SHIFT, + .clk_div_shift = MISC_B_CLK_DIV_SHIFT, + .clk_en_mask = MISC_B_CLK_EN, + .pwm_en_mask = MISC_B_EN, + } +}; + +struct meson_pwm_channel { + unsigned int hi; + unsigned int lo; + u8 pre_div; + uint period_ns; + uint duty_ns; + bool configured; + bool enabled; + bool polarity; + struct clk clk; +}; + +struct meson_pwm_data { + const long *parent_ids; + unsigned int num_parents; +}; + +struct meson_pwm { + const struct meson_pwm_data *data; + struct meson_pwm_channel channels[MESON_NUM_PWMS]; + void __iomem *base; +}; + +static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable); + +static int meson_pwm_set_config(struct udevice *dev, uint channeln, + uint period_ns, uint duty_ns) +{ + struct meson_pwm *priv = dev_get_priv(dev); + struct meson_pwm_channel *channel; + struct meson_pwm_channel_data *channel_data; + unsigned int duty, period, pre_div, cnt, duty_cnt; + unsigned long fin_freq; + + if (channeln >= MESON_NUM_PWMS) + return -ENODEV; + + channel = &priv->channels[channeln]; + channel_data = &meson_pwm_per_channel_data[channeln]; + + period = period_ns; + if (channel->polarity) + duty = period_ns - duty_ns; + else + duty = duty_ns; + + debug("%s%d: polarity %s duty %d period %d\n", __func__, channeln, + channel->polarity ? "true" : "false", duty, period); + + fin_freq = clk_get_rate(&channel->clk); + if (fin_freq == 0) { + printf("%s%d: invalid source clock frequency\n", __func__, channeln); + return -EINVAL; + } + + debug("%s%d: fin_freq: %lu Hz\n", __func__, channeln, fin_freq); + + pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL); + if (pre_div > MISC_CLK_DIV_MASK) { + printf("%s%d: unable to get period pre_div\n", __func__, channeln); + return -EINVAL; + } + + cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1)); + if (cnt > 0xffff) { + printf("%s%d: unable to get period cnt\n", __func__, channeln); + return -EINVAL; + } + + debug("%s%d: period=%u pre_div=%u cnt=%u\n", __func__, channeln, period, pre_div, cnt); + + if (duty == period) { + channel->pre_div = pre_div; + channel->hi = cnt; + channel->lo = 0; + } else if (duty == 0) { + channel->pre_div = pre_div; + channel->hi = 0; + channel->lo = cnt; + } else { + /* Then check is we can have the duty with the same pre_div */ + duty_cnt = div64_u64(fin_freq * (u64)duty, NSEC_PER_SEC * (pre_div + 1)); + if (duty_cnt > 0xffff) { + printf("%s%d: unable to get duty cycle\n", __func__, channeln); + return -EINVAL; + } + + debug("%s%d: duty=%u pre_div=%u duty_cnt=%u\n", + __func__, channeln, duty, pre_div, duty_cnt); + + channel->pre_div = pre_div; + channel->hi = duty_cnt; + channel->lo = cnt - duty_cnt; + } + + channel->period_ns = period_ns; + channel->duty_ns = duty_ns; + channel->configured = true; + + if (channel->enabled) { + meson_pwm_set_enable(dev, channeln, false); + meson_pwm_set_enable(dev, channeln, true); + } + + return 0; +} + +static int meson_pwm_set_enable(struct udevice *dev, uint channeln, bool enable) +{ + struct meson_pwm *priv = dev_get_priv(dev); + struct meson_pwm_channel *channel; + struct meson_pwm_channel_data *channel_data; + u32 value; + + if (channeln >= MESON_NUM_PWMS) + return -ENODEV; + + channel = &priv->channels[channeln]; + channel_data = &meson_pwm_per_channel_data[channeln]; + + if (!channel->configured) + return -EINVAL; + + if (enable) { + if (channel->enabled) + return 0; + + value = readl(priv->base + REG_MISC_AB); + value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift); + value |= channel->pre_div << channel_data->clk_div_shift; + value |= channel_data->clk_en_mask; + writel(value, priv->base + REG_MISC_AB); + + value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) | + FIELD_PREP(PWM_LOW_MASK, channel->lo); + writel(value, priv->base + channel_data->reg_offset); + + value = readl(priv->base + REG_MISC_AB); + value |= channel_data->pwm_en_mask; + writel(value, priv->base + REG_MISC_AB); + + debug("%s%d: enabled\n", __func__, channeln); + channel->enabled = true; + } else { + if (!channel->enabled) + return 0; + + value = readl(priv->base + REG_MISC_AB); + value &= channel_data->pwm_en_mask; + writel(value, priv->base + REG_MISC_AB); + + debug("%s%d: disabled\n", __func__, channeln); + channel->enabled = false; + } + + return 0; +} + +static int meson_pwm_set_invert(struct udevice *dev, uint channeln, bool polarity) +{ + struct meson_pwm *priv = dev_get_priv(dev); + struct meson_pwm_channel *channel; + + if (channeln >= MESON_NUM_PWMS) + return -ENODEV; + + debug("%s%d: set invert %s\n", __func__, channeln, polarity ? "true" : "false"); + + channel = &priv->channels[channeln]; + + channel->polarity = polarity; + + if (!channel->configured) + return 0; + + return meson_pwm_set_config(dev, channeln, channel->period_ns, channel->duty_ns); +} + +static int meson_pwm_ofdata_to_platdata(struct udevice *dev) +{ + struct meson_pwm *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + + return 0; +} + +static int meson_pwm_probe(struct udevice *dev) +{ + struct meson_pwm *priv = dev_get_priv(dev); + struct meson_pwm_data *data; + unsigned int i, p; + char name[255]; + int err; + u32 reg; + + data = (struct meson_pwm_data *)dev_get_driver_data(dev); + if (!data) + return -EINVAL; + + for (i = 0; i < MESON_NUM_PWMS; i++) { + struct meson_pwm_channel *channel = &priv->channels[i]; + struct meson_pwm_channel_data *channel_data = &meson_pwm_per_channel_data[i]; + + snprintf(name, sizeof(name), "clkin%u", i); + + err = clk_get_by_name(dev, name, &channel->clk); + /* If clock is not specified, use the already set clock */ + if (err == -ENODATA) { + struct udevice *cdev; + struct uclass *uc; + + /* Get parent from mux */ + p = (readl(priv->base + REG_MISC_AB) >> channel_data->clk_sel_shift) & + MISC_CLK_SEL_MASK; + + if (p >= data->num_parents) { + printf("%s%d: hw parent is invalid\n", __func__, i); + return -EINVAL; + } + + if (data->parent_ids[p] == -1) { + /* Search for xtal clk */ + const char *str; + + err = uclass_get(UCLASS_CLK, &uc); + if (err) + return err; + + uclass_foreach_dev(cdev, uc) { + if (strcmp(cdev->driver->name, "fixed_rate_clock")) + continue; + + str = ofnode_read_string(cdev->node, "clock-output-names"); + if (!str) + continue; + + if (!strcmp(str, "xtal")) { + err = uclass_get_device_by_ofnode(UCLASS_CLK, + cdev->node, + &cdev); + if (err) { + printf("%s%d: Failed to get xtal clk\n", __func__, i); + return err; + } + + break; + } + } + + if (!cdev) { + printf("%s%d: Failed to find xtal clk device\n", __func__, i); + return -EINVAL; + } + + channel->clk.dev = cdev; + channel->clk.id = 0; + channel->clk.data = 0; + } else { + /* Look for parent clock */ + err = uclass_get(UCLASS_CLK, &uc); + if (err) + return err; + + uclass_foreach_dev(cdev, uc) { + if (strstr(cdev->driver->name, "meson_clk")) + break; + } + + if (!cdev) { + printf("%s%d: Failed to find clk device\n", __func__, i); + return -EINVAL; + } + + err = uclass_get_device_by_ofnode(UCLASS_CLK, cdev->node, &cdev); + if (err) { + printf("%s%d: Failed to get clk controller\n", __func__, i); + return err; + } + + channel->clk.dev = cdev; + channel->clk.id = data->parent_ids[p]; + channel->clk.data = 0; + } + + /* We have our source clock, do not alter HW clock mux */ + continue; + } else + return err; + + /* Get id in list */ + for (p = 0 ; p < data->num_parents ; ++p) { + if (!strcmp(channel->clk.dev->driver->name, "fixed_rate_clock")) { + if (data->parent_ids[p] == -1) + break; + } else { + if (data->parent_ids[p] == channel->clk.id) + break; + } + } + + /* Invalid clock ID */ + if (p == data->num_parents) { + printf("%s%d: source clock is invalid\n", __func__, i); + return -EINVAL; + } + + /* switch parent in mux */ + reg = readl(priv->base + REG_MISC_AB); + + debug("%s%d: switching parent %d to %d\n", __func__, i, + (reg >> channel_data->clk_sel_shift) & MISC_CLK_SEL_MASK, p); + + reg &= MISC_CLK_SEL_MASK << channel_data->clk_sel_shift; + reg |= (p & MISC_CLK_SEL_MASK) << channel_data->clk_sel_shift; + writel(reg, priv->base + REG_MISC_AB); + } + + return 0; +} + +static const struct pwm_ops meson_pwm_ops = { + .set_config = meson_pwm_set_config, + .set_enable = meson_pwm_set_enable, + .set_invert = meson_pwm_set_invert, +}; + +#define XTAL -1 + +/* Local clock ids aliases to avoid define conflicts */ +#define GXBB_CLKID_HDMI_PLL 2 +#define GXBB_CLKID_FCLK_DIV3 5 +#define GXBB_CLKID_FCLK_DIV4 6 +#define GXBB_CLKID_CLK81 12 + +static const long pwm_gxbb_parent_ids[] = { + XTAL, GXBB_CLKID_HDMI_PLL, GXBB_CLKID_FCLK_DIV4, GXBB_CLKID_FCLK_DIV3 +}; + +static const struct meson_pwm_data pwm_gxbb_data = { + .parent_ids = pwm_gxbb_parent_ids, + .num_parents = ARRAY_SIZE(pwm_gxbb_parent_ids), +}; + +/* + * Only the 2 first inputs of the GXBB AO PWMs are valid + * The last 2 are grounded + */ +static const long pwm_gxbb_ao_parent_ids[] = { + XTAL, GXBB_CLKID_CLK81 +}; + +static const struct meson_pwm_data pwm_gxbb_ao_data = { + .parent_ids = pwm_gxbb_ao_parent_ids, + .num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_ids), +}; + +/* Local clock ids aliases to avoid define conflicts */ +#define AXG_CLKID_FCLK_DIV3 3 +#define AXG_CLKID_FCLK_DIV4 4 +#define AXG_CLKID_FCLK_DIV5 5 +#define AXG_CLKID_CLK81 10 + +static const long pwm_axg_ee_parent_ids[] = { + XTAL, AXG_CLKID_FCLK_DIV5, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV3 +}; + +static const struct meson_pwm_data pwm_axg_ee_data = { + .parent_ids = pwm_axg_ee_parent_ids, + .num_parents = ARRAY_SIZE(pwm_axg_ee_parent_ids), +}; + +static const long pwm_axg_ao_parent_ids[] = { + AXG_CLKID_CLK81, XTAL, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV5 +}; + +static const struct meson_pwm_data pwm_axg_ao_data = { + .parent_ids = pwm_axg_ao_parent_ids, + .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_ids), +}; + +/* Local clock ids aliases to avoid define conflicts */ +#define G12A_CLKID_FCLK_DIV3 3 +#define G12A_CLKID_FCLK_DIV4 4 +#define G12A_CLKID_FCLK_DIV5 5 +#define G12A_CLKID_CLK81 10 +#define G12A_CLKID_HDMI_PLL 128 + +static const long pwm_g12a_ao_ab_parent_ids[] = { + XTAL, G12A_CLKID_CLK81, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV5 +}; + +static const struct meson_pwm_data pwm_g12a_ao_ab_data = { + .parent_ids = pwm_g12a_ao_ab_parent_ids, + .num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_ids), +}; + +static const long pwm_g12a_ao_cd_parent_ids[] = { + XTAL, G12A_CLKID_CLK81, +}; + +static const struct meson_pwm_data pwm_g12a_ao_cd_data = { + .parent_ids = pwm_g12a_ao_cd_parent_ids, + .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_ids), +}; + +static const long pwm_g12a_ee_parent_ids[] = { + XTAL, G12A_CLKID_HDMI_PLL, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV3 +}; + +static const struct meson_pwm_data pwm_g12a_ee_data = { + .parent_ids = pwm_g12a_ee_parent_ids, + .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_ids), +}; + +static const struct udevice_id meson_pwm_ids[] = { + { + .compatible = "amlogic,meson-gxbb-pwm", + .data = (ulong)&pwm_gxbb_data + }, + { + .compatible = "amlogic,meson-gxbb-ao-pwm", + .data = (ulong)&pwm_gxbb_ao_data + }, + { + .compatible = "amlogic,meson-axg-ee-pwm", + .data = (ulong)&pwm_axg_ee_data + }, + { + .compatible = "amlogic,meson-axg-ao-pwm", + .data = (ulong)&pwm_axg_ao_data + }, + { + .compatible = "amlogic,meson-g12a-ee-pwm", + .data = (ulong)&pwm_g12a_ee_data + }, + { + .compatible = "amlogic,meson-g12a-ao-pwm-ab", + .data = (ulong)&pwm_g12a_ao_ab_data + }, + { + .compatible = "amlogic,meson-g12a-ao-pwm-cd", + .data = (ulong)&pwm_g12a_ao_cd_data + }, +}; + +U_BOOT_DRIVER(meson_pwm) = { + .name = "meson_pwm", + .id = UCLASS_PWM, + .of_match = meson_pwm_ids, + .ops = &meson_pwm_ops, + .ofdata_to_platdata = meson_pwm_ofdata_to_platdata, + .probe = meson_pwm_probe, + .priv_auto_alloc_size = sizeof(struct meson_pwm), +};