Browse Source

Merge tag 'u-boot-amlogic-20201005' of https://gitlab.denx.de/u-boot/custodians/u-boot-amlogic

- generate unique mac address from SoC serial on S400 board
- Add USB support for GXL and AXG SoCs
- Update Gadget code to use the new GXL and AXG USB glue driver
- Add a VIM3 board support to add dynamic PCIe enable in OS DT
- Fix AXG pinmux with requesting GPIOs
- Add missing GPIOA_18 for AXG pinctrl
- Add Amlogic PWM driver
Tom Rini 3 years ago
parent
commit
987ab49366
63 changed files with 2315 additions and 397 deletions
  1. 12 0
      arch/arm/dts/meson-axg-s400-u-boot.dtsi
  2. 62 0
      arch/arm/dts/meson-axg-u-boot.dtsi
  3. 3 3
      arch/arm/dts/meson-axg.dtsi
  4. 38 17
      arch/arm/dts/meson-g12-common.dtsi
  5. 131 5
      arch/arm/dts/meson-g12b-odroid-n2.dts
  6. 75 3
      arch/arm/dts/meson-gx-libretech-pc.dtsi
  7. 18 5
      arch/arm/dts/meson-gx.dtsi
  8. 1 1
      arch/arm/dts/meson-gxbb-nanopi-k2.dts
  9. 1 1
      arch/arm/dts/meson-gxbb-odroidc2.dts
  10. 23 0
      arch/arm/dts/meson-gxbb.dtsi
  11. 0 4
      arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi
  12. 72 1
      arch/arm/dts/meson-gxl-s805x-libretech-ac.dts
  13. 0 4
      arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi
  14. 0 4
      arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi
  15. 4 0
      arch/arm/dts/meson-gxl-s905x-khadas-vim.dts
  16. 0 4
      arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi
  17. 74 3
      arch/arm/dts/meson-gxl-s905x-libretech-cc.dts
  18. 2 1
      arch/arm/dts/meson-gxl-s905x-p212.dtsi
  19. 0 16
      arch/arm/dts/meson-gxl-u-boot.dtsi
  20. 59 20
      arch/arm/dts/meson-gxl.dtsi
  21. 0 4
      arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi
  22. 2 1
      arch/arm/dts/meson-gxm-khadas-vim2.dts
  23. 0 4
      arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi
  24. 5 2
      arch/arm/dts/meson-gxm.dtsi
  25. 24 2
      arch/arm/dts/meson-khadas-vim3.dtsi
  26. 92 0
      arch/arm/dts/meson-sm1-khadas-vim3l.dts
  27. 88 0
      arch/arm/dts/meson-sm1-odroid-c4.dts
  28. 2 1
      arch/arm/include/asm/arch-meson/usb-gx.h
  29. 128 0
      arch/arm/mach-meson/board-axg.c
  30. 72 55
      arch/arm/mach-meson/board-gx.c
  31. 2 0
      board/amlogic/s400/s400.c
  32. 9 0
      board/amlogic/vim3/MAINTAINERS
  33. 6 0
      board/amlogic/vim3/Makefile
  34. 81 0
      board/amlogic/vim3/khadas-mcu.h
  35. 137 0
      board/amlogic/vim3/vim3.c
  36. 0 4
      board/amlogic/w400/MAINTAINERS
  37. 1 1
      configs/khadas-vim2_defconfig
  38. 4 1
      configs/khadas-vim3_defconfig
  39. 4 1
      configs/khadas-vim3l_defconfig
  40. 1 1
      configs/khadas-vim_defconfig
  41. 1 1
      configs/libretech-ac_defconfig
  42. 1 1
      configs/libretech-cc_defconfig
  43. 1 1
      configs/libretech-s905d-pc_defconfig
  44. 1 1
      configs/libretech-s912-pc_defconfig
  45. 1 1
      configs/p212_defconfig
  46. 15 0
      configs/s400_defconfig
  47. 27 0
      doc/board/amlogic/khadas-vim3.rst
  48. 27 0
      doc/board/amlogic/khadas-vim3l.rst
  49. 1 1
      drivers/phy/Kconfig
  50. 1 1
      drivers/phy/Makefile
  51. 0 219
      drivers/phy/meson-gxl-usb3.c
  52. 4 1
      drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c
  53. 1 0
      drivers/pinctrl/meson/pinctrl-meson-axg.c
  54. 7 0
      drivers/pwm/Kconfig
  55. 1 0
      drivers/pwm/Makefile
  56. 528 0
      drivers/pwm/pwm-meson.c
  57. 8 0
      drivers/usb/dwc3/Kconfig
  58. 1 0
      drivers/usb/dwc3/Makefile
  59. 425 0
      drivers/usb/dwc3/dwc3-meson-gxl.c
  60. 2 0
      include/dt-bindings/clock/g12a-clkc.h
  61. 1 1
      include/dt-bindings/reset/amlogic,meson-gxbb-reset.h
  62. 18 0
      include/dt-bindings/sound/meson-aiu.h
  63. 10 0
      include/dt-bindings/sound/meson-g12a-toacodec.h

+ 12 - 0
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>;
+};

+ 62 - 0
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 <narmstrong@baylibre.com>
+ */
+
+/ {
+	soc {
+		usb: usb@ffe09080 {
+			compatible = "amlogic,meson-gxl-usb-ctrl";
+			reg = <0x0 0xffe09080 0x0 0x20>;
+			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+			#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 = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+				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 = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+				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";
+	};
+};

+ 3 - 3
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>;
 			};

+ 38 - 17
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>;
 		};
 	};

+ 131 - 5
arch/arm/dts/meson-g12b-odroid-n2.dts

@@ -9,6 +9,7 @@
 #include "meson-g12b-s922x.dtsi"
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-toacodec.h>
 #include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
@@ -20,6 +21,14 @@
 		ethernet0 = &ethmac;
 	};
 
+	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>;

+ 75 - 3
arch/arm/dts/meson-gx-libretech-pc.dtsi

@@ -8,6 +8,7 @@
 
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
+#include <dt-bindings/sound/meson-aiu.h>
 
 / {
 	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 = <LED_COLOR_ID_GREEN>;
 			function = LED_FUNCTION_DISK_ACTIVITY;
 			gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "disk-activity";
 		};
 
-		blue {
+		led-blue {
 			color = <LED_COLOR_ID_BLUE>;
 			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 {

+ 18 - 5
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 = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>,
+					     <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+				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 = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			#sound-dai-cells = <0>;
+			sound-name-prefix = "HDMITX";
 			status = "disabled";
 
 			/* VPU VENC Input */

+ 1 - 1
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";

+ 1 - 1
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";

+ 23 - 0
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";

+ 0 - 4
arch/arm/dts/meson-gxl-s805x-libretech-ac-u-boot.dtsi

@@ -5,7 +5,3 @@
  */
 
 #include "meson-gxl-u-boot.dtsi"
-
-&dwc2 {
-	status = "okay";
-};

+ 72 - 1
arch/arm/dts/meson-gxl-s805x-libretech-ac.dts

@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/sound/meson-aiu.h>
 
 #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";
 };

+ 0 - 4
arch/arm/dts/meson-gxl-s905d-libretech-pc-u-boot.dtsi

@@ -5,7 +5,3 @@
  */
 
 #include "meson-gxl-u-boot.dtsi"
-
-&dwc2 {
-	status = "okay";
-};

+ 0 - 4
arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi

@@ -5,7 +5,3 @@
  */
 
 #include "meson-gxl-u-boot.dtsi"
-
-&dwc2 {
-	status = "okay";
-};

+ 4 - 0
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";
+};

+ 0 - 4
arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi

@@ -5,7 +5,3 @@
  */
 
 #include "meson-gxl-u-boot.dtsi"
-
-&dwc2 {
-	status = "okay";
-};

+ 74 - 3
arch/arm/dts/meson-gxl-s905x-libretech-cc.dts

@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/sound/meson-aiu.h>
 
 #include "meson-gxl-s905x.dtsi"
 
@@ -21,6 +22,13 @@
 		ethernet0 = &ethmac;
 	};
 
+	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 {

+ 2 - 1
arch/arm/dts/meson-gxl-s905x-p212.dtsi

@@ -195,8 +195,9 @@
 	pinctrl-names = "default";
 };
 
-&usb0 {
+&usb {
 	status = "okay";
+	dr_mode = "host";
 };
 
 &usb2_phy0 {

+ 0 - 16
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 = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		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";
-	};
-};

+ 59 - 20
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 = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
 			#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 = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+				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 = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 				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 = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
-		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 {

+ 0 - 4
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>;

+ 2 - 1
arch/arm/dts/meson-gxm-khadas-vim2.dts

@@ -380,6 +380,7 @@
 	vref-supply = <&vddio_ao18>;
 };
 
-&usb0 {
+&usb {
 	status = "okay";
+	dr_mode = "peripheral";
 };

+ 0 - 4
arch/arm/dts/meson-gxm-s912-libretech-pc-u-boot.dtsi

@@ -5,7 +5,3 @@
  */
 
 #include "meson-gxl-u-boot.dtsi"
-
-&dwc2 {
-	status = "okay";
-};

+ 5 - 2
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 {

+ 24 - 2
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";

+ 92 - 0
arch/arm/dts/meson-sm1-khadas-vim3l.dts

@@ -8,6 +8,7 @@
 
 #include "meson-sm1.dtsi"
 #include "meson-khadas-vim3.dtsi"
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
 	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";
+};

+ 88 - 0
arch/arm/dts/meson-sm1-odroid-c4.dts

@@ -8,6 +8,7 @@
 #include "meson-sm1.dtsi"
 #include <dt-bindings/gpio/meson-g12a-gpio.h>
 #include <dt-bindings/leds/common.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
 	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>;

+ 2 - 1
arch/arm/include/asm/arch-meson/usb-gx.h

@@ -11,6 +11,7 @@
 
 /* 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);
 
 #endif

+ 128 - 0
arch/arm/mach-meson/board-axg.c

@@ -14,6 +14,11 @@
 #include <asm/io.h>
 #include <asm/armv8/mmu.h>
 #include <linux/sizes.h>
+#include <usb.h>
+#include <linux/usb/otg.h>
+#include <asm/arch/usb-gx.h>
+#include <usb/dwc2_udc.h>
+#include <clk.h>
 #include <phy.h>
 
 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

+ 72 - 55
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;
-
-	/* find the dwc2 node */
-	dwc2_node = ofnode_by_compatible(ofnode_null(), "snps,dwc2");
-	if (!ofnode_valid(dwc2_node)) {
-		debug("Not found dwc2 node\n");
-		return -ENODEV;
+	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 (!ofnode_is_available(dwc2_node)) {
-		debug("dwc2 is disabled in the device tree\n");
+	if (!fdtdec_get_is_enabled(blob, node)) {
+		debug("usb 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;
-		}
+	ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+	if (ret) {
+		debug("Not found usb-control device\n");
+		return ret;
 	}
 
-	for (i = 0; i < 2; i++) {
-		ret = generic_phy_init(&usb_phys[i]);
-		if (ret) {
-			pr_debug("Can't init USB PHY%d for %s\n",
-				 i, ofnode_get_name(dwc2_node));
-			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;
 	}
 
-	for (i = 0; i < 2; i++) {
-		ret = generic_phy_power_on(&usb_phys[i]);
-		if (ret) {
-			pr_debug("Can't power USB PHY%d for %s\n",
-				 i, ofnode_get_name(dwc2_node));
-			return ret;
-		}
+	if (!fdtdec_get_is_enabled(blob, dwc2_node)) {
+		debug("dwc2 is disabled in the device tree\n");
+		return -ENODEV;
 	}
 
-	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;
+
+	/* 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;
+		}
+	}
 
-	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);
+	if (!fdtdec_get_is_enabled(blob, node))
+		return -ENODEV;
 
-	for (i = 0; i < 2; i++)
-		usb_phys[i].dev = NULL;
+	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;
 }

+ 2 - 0
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;
 }

+ 9 - 0
board/amlogic/vim3/MAINTAINERS

@@ -0,0 +1,9 @@
+VIM3
+M:	Neil Armstrong <narmstrong@baylibre.com>
+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

+ 6 - 0
board/amlogic/vim3/Makefile

@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2020 BayLibre, SAS
+# Author: Neil Armstrong <narmstrong@baylibre.com>
+
+obj-y	:= vim3.o

+ 81 - 0
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 <narmstrong@baylibre.com>
+ */
+
+#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 */

+ 137 - 0
board/amlogic/vim3/vim3.c

@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <env_internal.h>
+#include <init.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/arch/eth.h>
+#include <i2c.h>
+#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)
+{
+	meson_eth_init(PHY_INTERFACE_MODE_RGMII, 0);
+
+	return 0;
+}

+ 0 - 4
board/amlogic/w400/MAINTAINERS

@@ -3,8 +3,4 @@ M:	Neil Armstrong <narmstrong@baylibre.com>
 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

+ 1 - 1
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

+ 4 - 1
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
@@ -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

+ 4 - 1
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
@@ -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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 15 - 0
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

+ 27 - 0
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
 ------------------
 

+ 27 - 0
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
 ------------------
 

+ 1 - 1
drivers/phy/Kconfig

@@ -177,7 +177,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

+ 1 - 1
drivers/phy/Makefile

@@ -19,7 +19,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

+ 0 - 219
drivers/phy/meson-gxl-usb3.c

@@ -1,219 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Meson GXL USB3 PHY driver
- *
- * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
- * Copyright (C) 2018 BayLibre, SAS
- * Author: Neil Armstrong <narmstron@baylibre.com>
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <bitfield.h>
-#include <dm.h>
-#include <errno.h>
-#include <generic-phy.h>
-#include <regmap.h>
-#include <clk.h>
-#include <linux/usb/otg.h>
-
-#include <asm/arch/usb-gx.h>
-
-#include <linux/bitops.h>
-#include <linux/compat.h>
-#include <linux/bitfield.h>
-
-#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),
-};

+ 4 - 1
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 = {

+ 1 - 0
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),
 

+ 7 - 0
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

+ 1 - 0
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

+ 528 - 0
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 <narmstrong@baylibre.com>
+ * 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 <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <pwm.h>
+#include <regmap.h>
+#include <linux/io.h>
+#include <linux/math64.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+
+#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),
+};

+ 8 - 0
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

+ 1 - 0
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

+ 425 - 0
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 <narmstrong@baylibre.com>
+ */
+
+#define DEBUG
+#include <common.h>
+#include <asm-generic/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dwc3-uboot.h>
+#include <generic-phy.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <regmap.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include <reset.h>
+#include <clk.h>
+#include <power/regulator.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <asm/arch/usb-gx.h>
+
+/* 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),
+
+};

+ 2 - 0
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 */

+ 1 - 1
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					*/

+ 18 - 0
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 */

+ 10 - 0
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 */