Merge tag 'u-boot-stm32-20201021' of https://gitlab.denx.de/u-boot/custodians/u-boot-stm
authorTom Rini <trini@konsulko.com>
Thu, 22 Oct 2020 12:25:41 +0000 (08:25 -0400)
committerTom Rini <trini@konsulko.com>
Thu, 22 Oct 2020 12:25:41 +0000 (08:25 -0400)
- Activate CMD_EXPORTENV/CMD_IMPORTENV/CMD_ELF for STM32MP15 defconfig
- Fix stm32prog command: parsing of FlashLayout without partition
- Update MAINTAINERS for ARM STM STM32MP
- Manage eth1addr on dh board with KS8851
- Limit size of cacheable DDR in pre-reloc stage in stm32mp1
- Use mmc_of_parse() to read host capabilities in mmc:sdmmc2 driver

43 files changed:
MAINTAINERS
Makefile
arch/arm/dts/mt8512-bm1-emmc.dts
arch/arm/dts/mt8512.dtsi
arch/arm/dts/r8a774c0.dtsi [new file with mode: 0644]
arch/arm/mach-rmobile/Kconfig.64
arch/arm/mach-socfpga/include/mach/system_manager_gen5.h
common/spl/spl_fit.c
configs/mt8512_bm1_emmc_defconfig
doc/device-tree-bindings/usb/generic.txt [new file with mode: 0644]
doc/device-tree-bindings/usb/mediatek,mtu3.txt [new file with mode: 0644]
drivers/clk/renesas/Kconfig
drivers/clk/renesas/Makefile
drivers/clk/renesas/r8a774a1-cpg-mssr.c
drivers/clk/renesas/r8a774b1-cpg-mssr.c [new file with mode: 0644]
drivers/clk/renesas/r8a774c0-cpg-mssr.c [new file with mode: 0644]
drivers/clk/renesas/r8a774e1-cpg-mssr.c [new file with mode: 0644]
drivers/pinctrl/renesas/pfc-r8a77990.c
drivers/spi/renesas_rpc_spi.c
drivers/usb/Kconfig
drivers/usb/common/common.c
drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/host/xhci-mem.c
drivers/usb/mtu3/Kconfig [new file with mode: 0644]
drivers/usb/mtu3/Makefile [new file with mode: 0644]
drivers/usb/mtu3/mtu3.h [new file with mode: 0644]
drivers/usb/mtu3/mtu3_core.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_dr.h [new file with mode: 0644]
drivers/usb/mtu3/mtu3_gadget.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_gadget_ep0.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_host.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_hw_regs.h [new file with mode: 0644]
drivers/usb/mtu3/mtu3_plat.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_qmu.c [new file with mode: 0644]
drivers/usb/mtu3/mtu3_qmu.h [new file with mode: 0644]
drivers/usb/musb-new/musb_dsps.c
include/dt-bindings/clock/r8a774c0-cpg-mssr.h [new file with mode: 0644]
include/dt-bindings/power/r8a774c0-sysc.h [new file with mode: 0644]
include/linux/usb/ch9.h
include/net.h
lib/efi_loader/efi_net.c
net/eth-uclass.c

index d89ffe1..196d635 100644 (file)
@@ -266,6 +266,7 @@ F:  arch/arm/include/asm/arch-pxa/
 ARM MEDIATEK
 M:     Ryder Lee <ryder.lee@mediatek.com>
 M:     Weijie Gao <weijie.gao@mediatek.com>
+M:     Chunfeng Yun <chunfeng.yun@mediatek.com>
 R:     GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com>
 S:     Maintained
 F:     arch/arm/mach-mediatek/
@@ -282,6 +283,8 @@ F:  drivers/power/domain/mtk-power-domain.c
 F:     drivers/ram/mediatek/
 F:     drivers/spi/mtk_snfi_spi.c
 F:     drivers/timer/mtk_timer.c
+F:     drivers/usb/host/xhci-mtk.c
+F:     drivers/usb/mtu3/
 F:     drivers/watchdog/mtk_wdt.c
 F:     drivers/net/mtk_eth.c
 F:     drivers/reset/reset-mediatek.c
index 28c9f31..6c3a953 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -795,6 +795,7 @@ libs-y += drivers/usb/eth/
 libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/
 libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc/
 libs-y += drivers/usb/host/
+libs-y += drivers/usb/mtu3/
 libs-y += drivers/usb/musb/
 libs-y += drivers/usb/musb-new/
 libs-y += drivers/usb/phy/
index 296ed93..12511b5 100644 (file)
                regulator-boot-on;
                regulator-always-on;
        };
+
+       usb_p0_vbus: regulator@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "p0_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio 27 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       usb_p1_vbus: regulator@1 {
+               compatible = "regulator-fixed";
+               regulator-name = "p1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio 32 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
 };
 
 &mmc0 {
                };
 };
 
+&ssusb {
+       dr_mode = "peripheral";
+       maximum-speed = "high-speed";
+       status = "okay";
+};
+
+&usb3 {
+       vbus-supply = <&usb_p0_vbus>;
+       status = "okay";
+};
+
+&u3phy {
+       status = "okay";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pins>;
index 01a02a7..bdb84f8 100644 (file)
@@ -9,6 +9,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
        compatible = "mediatek,mt8512";
                status = "disabled";
        };
 
+       usb3: usb@11213e00 {
+               compatible = "mediatek,mt8512-mtu3", "mediatek,mtu3";
+               reg = <0x11213e00 0x0100>;
+               reg-names = "ippc";
+               phys = <&u2port0 PHY_TYPE_USB2>, <&u2port1 PHY_TYPE_USB2>;
+               clocks = <&infracfg CLK_INFRA_USB_SYS>,
+                        <&topckgen CLK_TOP_SSUSB_TOP_CK_EN>,
+                        <&infracfg CLK_INFRA_ICUSB>;
+               clock-names = "sys_ck", "ref_ck", "mcu_ck";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               status = "disabled";
+
+               ssusb: usb@11210000 {
+                       compatible = "mediatek,ssusb";
+                       reg = <0x11210000 0x3e00>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_LOW>;
+                       reg-names = "mac";
+                       status = "disabled";
+               };
+       };
+
+       u3phy: usb-phy@11cc0000 {
+               compatible = "mediatek,mt8512-tphy",
+                            "mediatek,generic-tphy-v2";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               status = "disabled";
+
+               u2port0: usb-phy@11cc0000 {
+                       reg = <0x11cc0000 0x400>;
+                       clocks = <&topckgen CLK_TOP_USB20_48M_EN>;
+                       clock-names = "ref";
+                       #phy-cells = <1>;
+                       status = "okay";
+               };
+
+               u2port1: usb-phy@11c40000 {
+                       reg = <0x11c40000 0x400>;
+                       #phy-cells = <1>;
+                       status = "okay";
+               };
+       };
+
        mmc0: mmc@11230000 {
                compatible = "mediatek,mt8512-mmc";
                reg = <0x11230000 0x1000>,
                status = "disabled";
        };
 
-};
\ No newline at end of file
+};
diff --git a/arch/arm/dts/r8a774c0.dtsi b/arch/arm/dts/r8a774c0.dtsi
new file mode 100644 (file)
index 0000000..e14db4d
--- /dev/null
@@ -0,0 +1,1960 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the RZ/G2E (R8A774C0) SoC
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/r8a774c0-sysc.h>
+
+/ {
+       compatible = "renesas,r8a774c0";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       /*
+        * The external audio clocks are configured as 0 Hz fixed frequency
+        * clocks by default.
+        * Boards that provide audio clocks should override them.
+        */
+       audio_clk_a: audio_clk_a {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_b: audio_clk_b {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       audio_clk_c: audio_clk_c {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       /* External CAN clock - to be overridden by boards that provide it */
+       can_clk: can {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       cluster1_opp: opp_table10 {
+               compatible = "operating-points-v2";
+               opp-shared;
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+                       opp-suspend;
+               };
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               a53_0: cpu@0 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0>;
+                       device_type = "cpu";
+                       #cooling-cells = <2>;
+                       power-domains = <&sysc R8A774C0_PD_CA53_CPU0>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       dynamic-power-coefficient = <277>;
+                       clocks = <&cpg CPG_CORE R8A774C0_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+               };
+
+               a53_1: cpu@1 {
+                       compatible = "arm,cortex-a53";
+                       reg = <1>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A774C0_PD_CA53_CPU1>;
+                       next-level-cache = <&L2_CA53>;
+                       enable-method = "psci";
+                       clocks = <&cpg CPG_CORE R8A774C0_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+               };
+
+               L2_CA53: cache-controller-0 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A774C0_PD_CA53_SCU>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+       };
+
+       extal_clk: extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       /* External PCIe clock - can be overridden by the board */
+       pcie_bus_clk: pcie_bus {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       pmu_a53 {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts-extended = <&gic GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                                     <&gic GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&a53_0>, <&a53_1>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
+       /* External SCIF clock - to be overridden by boards that provide it */
+       scif_clk: scif {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       soc: soc {
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               rwdt: watchdog@e6020000 {
+                       compatible = "renesas,r8a774c0-wdt",
+                                    "renesas,rcar-gen3-wdt";
+                       reg = <0 0xe6020000 0 0x0c>;
+                       clocks = <&cpg CPG_MOD 402>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 402>;
+                       status = "disabled";
+               };
+
+               gpio0: gpio@e6050000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6050000 0 0x50>;
+                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 0 18>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 912>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 912>;
+               };
+
+               gpio1: gpio@e6051000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6051000 0 0x50>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 32 23>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 911>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 911>;
+               };
+
+               gpio2: gpio@e6052000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6052000 0 0x50>;
+                       interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 64 26>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 910>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 910>;
+               };
+
+               gpio3: gpio@e6053000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6053000 0 0x50>;
+                       interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 96 16>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 909>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 909>;
+               };
+
+               gpio4: gpio@e6054000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6054000 0 0x50>;
+                       interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 128 11>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 908>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 908>;
+               };
+
+               gpio5: gpio@e6055000 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6055000 0 0x50>;
+                       interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 160 20>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 907>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 907>;
+               };
+
+               gpio6: gpio@e6055400 {
+                       compatible = "renesas,gpio-r8a774c0",
+                                    "renesas,rcar-gen3-gpio";
+                       reg = <0 0xe6055400 0 0x50>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 192 18>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 906>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 906>;
+               };
+
+               pfc: pin-controller@e6060000 {
+                       compatible = "renesas,pfc-r8a774c0";
+                       reg = <0 0xe6060000 0 0x508>;
+               };
+
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a774c0-cmt0",
+                                    "renesas,rcar-gen3-cmt0";
+                       reg = <0 0xe60f0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 303>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a774c0-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 302>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a774c0-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6140000 0 0x1004>;
+                       interrupts = <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 301>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a774c0-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6148000 0 0x1004>;
+                       interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 300>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
+               cpg: clock-controller@e6150000 {
+                       compatible = "renesas,r8a774c0-cpg-mssr";
+                       reg = <0 0xe6150000 0 0x1000>;
+                       clocks = <&extal_clk>;
+                       clock-names = "extal";
+                       #clock-cells = <2>;
+                       #power-domain-cells = <0>;
+                       #reset-cells = <1>;
+               };
+
+               rst: reset-controller@e6160000 {
+                       compatible = "renesas,r8a774c0-rst";
+                       reg = <0 0xe6160000 0 0x0200>;
+               };
+
+               sysc: system-controller@e6180000 {
+                       compatible = "renesas,r8a774c0-sysc";
+                       reg = <0 0xe6180000 0 0x0400>;
+                       #power-domain-cells = <1>;
+               };
+
+               thermal: thermal@e6190000 {
+                       compatible = "renesas,thermal-r8a774c0";
+                       reg = <0 0xe6190000 0 0x10>, <0 0xe6190100 0 0x38>;
+                       interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 522>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 522>;
+                       #thermal-sensor-cells = <0>;
+               };
+
+               intc_ex: interrupt-controller@e61c0000 {
+                       compatible = "renesas,intc-ex-r8a774c0", "renesas,irqc";
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       reg = <0 0xe61c0000 0 0x200>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 407>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 407>;
+               };
+
+               tmu0: timer@e61e0000 {
+                       compatible = "renesas,tmu-r8a774c0", "renesas,tmu";
+                       reg = <0 0xe61e0000 0 0x30>;
+                       interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 125>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 125>;
+                       status = "disabled";
+               };
+
+               tmu1: timer@e6fc0000 {
+                       compatible = "renesas,tmu-r8a774c0", "renesas,tmu";
+                       reg = <0 0xe6fc0000 0 0x30>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 124>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 124>;
+                       status = "disabled";
+               };
+
+               tmu2: timer@e6fd0000 {
+                       compatible = "renesas,tmu-r8a774c0", "renesas,tmu";
+                       reg = <0 0xe6fd0000 0 0x30>;
+                       interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 123>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 123>;
+                       status = "disabled";
+               };
+
+               tmu3: timer@e6fe0000 {
+                       compatible = "renesas,tmu-r8a774c0", "renesas,tmu";
+                       reg = <0 0xe6fe0000 0 0x30>;
+                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 122>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 122>;
+                       status = "disabled";
+               };
+
+               tmu4: timer@ffc00000 {
+                       compatible = "renesas,tmu-r8a774c0", "renesas,tmu";
+                       reg = <0 0xffc00000 0 0x30>;
+                       interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 121>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 121>;
+                       status = "disabled";
+               };
+
+               i2c0: i2c@e6500000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6500000 0 0x40>;
+                       interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 931>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 931>;
+                       dmas = <&dmac1 0x91>, <&dmac1 0x90>,
+                              <&dmac2 0x91>, <&dmac2 0x90>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@e6508000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6508000 0 0x40>;
+                       interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 930>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 930>;
+                       dmas = <&dmac1 0x93>, <&dmac1 0x92>,
+                              <&dmac2 0x93>, <&dmac2 0x92>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@e6510000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6510000 0 0x40>;
+                       interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 929>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 929>;
+                       dmas = <&dmac1 0x95>, <&dmac1 0x94>,
+                              <&dmac2 0x95>, <&dmac2 0x94>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@e66d0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66d0000 0 0x40>;
+                       interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 928>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 928>;
+                       dmas = <&dmac0 0x97>, <&dmac0 0x96>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       status = "disabled";
+               };
+
+               i2c4: i2c@e66d8000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66d8000 0 0x40>;
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 927>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 927>;
+                       dmas = <&dmac0 0x99>, <&dmac0 0x98>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c5: i2c@e66e0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66e0000 0 0x40>;
+                       interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 919>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 919>;
+                       dmas = <&dmac0 0x9b>, <&dmac0 0x9a>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c6: i2c@e66e8000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe66e8000 0 0x40>;
+                       interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 918>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 918>;
+                       dmas = <&dmac0 0x9d>, <&dmac0 0x9c>;
+                       dma-names = "tx", "rx";
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c7: i2c@e6690000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,i2c-r8a774c0",
+                                    "renesas,rcar-gen3-i2c";
+                       reg = <0 0xe6690000 0 0x40>;
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 1003>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 1003>;
+                       i2c-scl-internal-delay-ns = <6>;
+                       status = "disabled";
+               };
+
+               i2c_dvfs: i2c@e60b0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,iic-r8a774c0";
+                       reg = <0 0xe60b0000 0 0x15>;
+                       interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 926>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 926>;
+                       dmas = <&dmac0 0x11>, <&dmac0 0x10>;
+                       dma-names = "tx", "rx";
+                       status = "disabled";
+               };
+
+               hscif0: serial@e6540000 {
+                       compatible = "renesas,hscif-r8a774c0",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6540000 0 0x60>;
+                       interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 520>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x31>, <&dmac1 0x30>,
+                              <&dmac2 0x31>, <&dmac2 0x30>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 520>;
+                       status = "disabled";
+               };
+
+               hscif1: serial@e6550000 {
+                       compatible = "renesas,hscif-r8a774c0",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6550000 0 0x60>;
+                       interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 519>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x33>, <&dmac1 0x32>,
+                              <&dmac2 0x33>, <&dmac2 0x32>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 519>;
+                       status = "disabled";
+               };
+
+               hscif2: serial@e6560000 {
+                       compatible = "renesas,hscif-r8a774c0",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe6560000 0 0x60>;
+                       interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 518>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x35>, <&dmac1 0x34>,
+                              <&dmac2 0x35>, <&dmac2 0x34>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 518>;
+                       status = "disabled";
+               };
+
+               hscif3: serial@e66a0000 {
+                       compatible = "renesas,hscif-r8a774c0",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe66a0000 0 0x60>;
+                       interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 517>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x37>, <&dmac0 0x36>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 517>;
+                       status = "disabled";
+               };
+
+               hscif4: serial@e66b0000 {
+                       compatible = "renesas,hscif-r8a774c0",
+                                    "renesas,rcar-gen3-hscif",
+                                    "renesas,hscif";
+                       reg = <0 0xe66b0000 0 0x60>;
+                       interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 516>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x39>, <&dmac0 0x38>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 516>;
+                       status = "disabled";
+               };
+
+               hsusb: usb@e6590000 {
+                       compatible = "renesas,usbhs-r8a774c0",
+                                    "renesas,rcar-gen3-usbhs";
+                       reg = <0 0xe6590000 0 0x200>;
+                       interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 704>, <&cpg CPG_MOD 703>;
+                       dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+                              <&usb_dmac1 0>, <&usb_dmac1 1>;
+                       dma-names = "ch0", "ch1", "ch2", "ch3";
+                       renesas,buswait = <11>;
+                       phys = <&usb2_phy0 3>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 704>, <&cpg 703>;
+                       status = "disabled";
+               };
+
+               usb_dmac0: dma-controller@e65a0000 {
+                       compatible = "renesas,r8a774c0-usb-dmac",
+                                    "renesas,usb-dmac";
+                       reg = <0 0xe65a0000 0 0x100>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1";
+                       clocks = <&cpg CPG_MOD 330>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 330>;
+                       #dma-cells = <1>;
+                       dma-channels = <2>;
+               };
+
+               usb_dmac1: dma-controller@e65b0000 {
+                       compatible = "renesas,r8a774c0-usb-dmac",
+                                    "renesas,usb-dmac";
+                       reg = <0 0xe65b0000 0 0x100>;
+                       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1";
+                       clocks = <&cpg CPG_MOD 331>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 331>;
+                       #dma-cells = <1>;
+                       dma-channels = <2>;
+               };
+
+               dmac0: dma-controller@e6700000 {
+                       compatible = "renesas,dmac-r8a774c0",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe6700000 0 0x10000>;
+                       interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 219>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 219>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds0 0>, <&ipmmu_ds0 1>,
+                              <&ipmmu_ds0 2>, <&ipmmu_ds0 3>,
+                              <&ipmmu_ds0 4>, <&ipmmu_ds0 5>,
+                              <&ipmmu_ds0 6>, <&ipmmu_ds0 7>,
+                              <&ipmmu_ds0 8>, <&ipmmu_ds0 9>,
+                              <&ipmmu_ds0 10>, <&ipmmu_ds0 11>,
+                              <&ipmmu_ds0 12>, <&ipmmu_ds0 13>,
+                              <&ipmmu_ds0 14>, <&ipmmu_ds0 15>;
+               };
+
+               dmac1: dma-controller@e7300000 {
+                       compatible = "renesas,dmac-r8a774c0",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe7300000 0 0x10000>;
+                       interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 218>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 218>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 0>, <&ipmmu_ds1 1>,
+                              <&ipmmu_ds1 2>, <&ipmmu_ds1 3>,
+                              <&ipmmu_ds1 4>, <&ipmmu_ds1 5>,
+                              <&ipmmu_ds1 6>, <&ipmmu_ds1 7>,
+                              <&ipmmu_ds1 8>, <&ipmmu_ds1 9>,
+                              <&ipmmu_ds1 10>, <&ipmmu_ds1 11>,
+                              <&ipmmu_ds1 12>, <&ipmmu_ds1 13>,
+                              <&ipmmu_ds1 14>, <&ipmmu_ds1 15>;
+               };
+
+               dmac2: dma-controller@e7310000 {
+                       compatible = "renesas,dmac-r8a774c0",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xe7310000 0 0x10000>;
+                       interrupts = <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 217>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 217>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 16>, <&ipmmu_ds1 17>,
+                              <&ipmmu_ds1 18>, <&ipmmu_ds1 19>,
+                              <&ipmmu_ds1 20>, <&ipmmu_ds1 21>,
+                              <&ipmmu_ds1 22>, <&ipmmu_ds1 23>,
+                              <&ipmmu_ds1 24>, <&ipmmu_ds1 25>,
+                              <&ipmmu_ds1 26>, <&ipmmu_ds1 27>,
+                              <&ipmmu_ds1 28>, <&ipmmu_ds1 29>,
+                              <&ipmmu_ds1 30>, <&ipmmu_ds1 31>;
+               };
+
+               ipmmu_ds0: iommu@e6740000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xe6740000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 0>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_ds1: iommu@e7740000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xe7740000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 1>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_hc: iommu@e6570000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xe6570000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 2>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_mm: iommu@e67b0000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xe67b0000 0 0x1000>;
+                       interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_mp: iommu@ec670000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xec670000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 4>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_pv0: iommu@fd800000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xfd800000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 6>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vc0: iommu@fe6b0000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xfe6b0000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 12>;
+                       power-domains = <&sysc R8A774C0_PD_A3VC>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vi0: iommu@febd0000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xfebd0000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 14>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_vp0: iommu@fe990000 {
+                       compatible = "renesas,ipmmu-r8a774c0";
+                       reg = <0 0xfe990000 0 0x1000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 16>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               avb: ethernet@e6800000 {
+                       compatible = "renesas,etheravb-r8a774c0",
+                                    "renesas,etheravb-rcar-gen3";
+                       reg = <0 0xe6800000 0 0x800>;
+                       interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "ch22", "ch23",
+                                         "ch24";
+                       clocks = <&cpg CPG_MOD 812>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 812>;
+                       phy-mode = "rgmii";
+                       iommus = <&ipmmu_ds0 16>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               can0: can@e6c30000 {
+                       compatible = "renesas,can-r8a774c0",
+                                    "renesas,rcar-gen3-can";
+                       reg = <0 0xe6c30000 0 0x1000>;
+                       interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 916>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 916>;
+                       status = "disabled";
+               };
+
+               can1: can@e6c38000 {
+                       compatible = "renesas,can-r8a774c0",
+                                    "renesas,rcar-gen3-can";
+                       reg = <0 0xe6c38000 0 0x1000>;
+                       interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 915>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 915>;
+                       status = "disabled";
+               };
+
+               canfd: can@e66c0000 {
+                       compatible = "renesas,r8a774c0-canfd",
+                                    "renesas,rcar-gen3-canfd";
+                       reg = <0 0xe66c0000 0 0x8000>;
+                       interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 914>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "fck", "canfd", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 914>;
+                       status = "disabled";
+
+                       channel0 {
+                               status = "disabled";
+                       };
+
+                       channel1 {
+                               status = "disabled";
+                       };
+               };
+
+               pwm0: pwm@e6e30000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e30000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm1: pwm@e6e31000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e31000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm2: pwm@e6e32000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e32000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm3: pwm@e6e33000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e33000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm4: pwm@e6e34000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e34000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm5: pwm@e6e35000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e35000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm6: pwm@e6e36000 {
+                       compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
+                       reg = <0 0xe6e36000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               scif0: serial@e6e60000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e60000 0 64>;
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 207>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x51>, <&dmac1 0x50>,
+                              <&dmac2 0x51>, <&dmac2 0x50>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 207>;
+                       status = "disabled";
+               };
+
+               scif1: serial@e6e68000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e68000 0 64>;
+                       interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 206>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x53>, <&dmac1 0x52>,
+                              <&dmac2 0x53>, <&dmac2 0x52>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 206>;
+                       status = "disabled";
+               };
+
+               scif2: serial@e6e88000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6e88000 0 64>;
+                       interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 310>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac1 0x13>, <&dmac1 0x12>,
+                              <&dmac2 0x13>, <&dmac2 0x12>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 310>;
+                       status = "disabled";
+               };
+
+               scif3: serial@e6c50000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6c50000 0 64>;
+                       interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 204>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x57>, <&dmac0 0x56>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 204>;
+                       status = "disabled";
+               };
+
+               scif4: serial@e6c40000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6c40000 0 64>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 203>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x59>, <&dmac0 0x58>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 203>;
+                       status = "disabled";
+               };
+
+               scif5: serial@e6f30000 {
+                       compatible = "renesas,scif-r8a774c0",
+                                    "renesas,rcar-gen3-scif", "renesas,scif";
+                       reg = <0 0xe6f30000 0 64>;
+                       interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 202>,
+                                <&cpg CPG_CORE R8A774C0_CLK_S3D1C>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x5b>, <&dmac0 0x5a>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 202>;
+                       status = "disabled";
+               };
+
+               msiof0: spi@e6e90000 {
+                       compatible = "renesas,msiof-r8a774c0",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6e90000 0 0x0064>;
+                       interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 211>;
+                       dmas = <&dmac1 0x41>, <&dmac1 0x40>,
+                              <&dmac2 0x41>, <&dmac2 0x40>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 211>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof1: spi@e6ea0000 {
+                       compatible = "renesas,msiof-r8a774c0",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6ea0000 0 0x0064>;
+                       interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 210>;
+                       dmas = <&dmac1 0x43>, <&dmac1 0x42>,
+                              <&dmac2 0x43>, <&dmac2 0x42>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 210>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof2: spi@e6c00000 {
+                       compatible = "renesas,msiof-r8a774c0",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6c00000 0 0x0064>;
+                       interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 209>;
+                       dmas = <&dmac0 0x45>, <&dmac0 0x44>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 209>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               msiof3: spi@e6c10000 {
+                       compatible = "renesas,msiof-r8a774c0",
+                                    "renesas,rcar-gen3-msiof";
+                       reg = <0 0xe6c10000 0 0x0064>;
+                       interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 208>;
+                       dmas = <&dmac0 0x47>, <&dmac0 0x46>;
+                       dma-names = "tx", "rx";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 208>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               vin4: video@e6ef4000 {
+                       compatible = "renesas,vin-r8a774c0";
+                       reg = <0 0xe6ef4000 0 0x1000>;
+                       interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 807>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 807>;
+                       renesas,id = <4>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin4csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint= <&csi40vin4>;
+                                       };
+                               };
+                       };
+               };
+
+               vin5: video@e6ef5000 {
+                       compatible = "renesas,vin-r8a774c0";
+                       reg = <0 0xe6ef5000 0 0x1000>;
+                       interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 806>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 806>;
+                       renesas,id = <5>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       vin5csi40: endpoint@2 {
+                                               reg = <2>;
+                                               remote-endpoint= <&csi40vin5>;
+                                       };
+                               };
+                       };
+               };
+
+               rcar_sound: sound@ec500000 {
+                       /*
+                        * #sound-dai-cells is required
+                        *
+                        * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+                        * Multi  DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+                        */
+                       /*
+                        * #clock-cells is required for audio_clkout0/1/2/3
+                        *
+                        * clkout       : #clock-cells = <0>;   <&rcar_sound>;
+                        * clkout0/1/2/3: #clock-cells = <1>;   <&rcar_sound N>;
+                        */
+                       compatible = "renesas,rcar_sound-r8a774c0",
+                                    "renesas,rcar_sound-gen3";
+                       reg =   <0 0xec500000 0 0x1000>, /* SCU */
+                               <0 0xec5a0000 0 0x100>,  /* ADG */
+                               <0 0xec540000 0 0x1000>, /* SSIU */
+                               <0 0xec541000 0 0x280>,  /* SSI */
+                               <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
+                       reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+                       clocks = <&cpg CPG_MOD 1005>,
+                                <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+                                <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+                                <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+                                <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+                                <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+                                <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+                                <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+                                <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+                                <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+                                <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+                                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+                                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+                                <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+                                <&audio_clk_a>, <&audio_clk_b>,
+                                <&audio_clk_c>,
+                                <&cpg CPG_CORE R8A774C0_CLK_ZA2>;
+                       clock-names = "ssi-all",
+                                     "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+                                     "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+                                     "ssi.1", "ssi.0",
+                                     "src.9", "src.8", "src.7", "src.6",
+                                     "src.5", "src.4", "src.3", "src.2",
+                                     "src.1", "src.0",
+                                     "mix.1", "mix.0",
+                                     "ctu.1", "ctu.0",
+                                     "dvc.0", "dvc.1",
+                                     "clk_a", "clk_b", "clk_c", "clk_i";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 1005>,
+                                <&cpg 1006>, <&cpg 1007>,
+                                <&cpg 1008>, <&cpg 1009>,
+                                <&cpg 1010>, <&cpg 1011>,
+                                <&cpg 1012>, <&cpg 1013>,
+                                <&cpg 1014>, <&cpg 1015>;
+                       reset-names = "ssi-all",
+                                     "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+                                     "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+                                     "ssi.1", "ssi.0";
+                       status = "disabled";
+
+                       rcar_sound,ctu {
+                               ctu00: ctu-0 { };
+                               ctu01: ctu-1 { };
+                               ctu02: ctu-2 { };
+                               ctu03: ctu-3 { };
+                               ctu10: ctu-4 { };
+                               ctu11: ctu-5 { };
+                               ctu12: ctu-6 { };
+                               ctu13: ctu-7 { };
+                       };
+
+                       rcar_sound,dvc {
+                               dvc0: dvc-0 {
+                                       dmas = <&audma0 0xbc>;
+                                       dma-names = "tx";
+                               };
+                               dvc1: dvc-1 {
+                                       dmas = <&audma0 0xbe>;
+                                       dma-names = "tx";
+                               };
+                       };
+
+                       rcar_sound,mix {
+                               mix0: mix-0 { };
+                               mix1: mix-1 { };
+                       };
+
+                       rcar_sound,src {
+                               src0: src-0 {
+                                       interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x85>, <&audma0 0x9a>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src1: src-1 {
+                                       interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x87>, <&audma0 0x9c>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src2: src-2 {
+                                       interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x89>, <&audma0 0x9e>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src3: src-3 {
+                                       interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8b>, <&audma0 0xa0>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src4: src-4 {
+                                       interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8d>, <&audma0 0xb0>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src5: src-5 {
+                                       interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x8f>, <&audma0 0xb2>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src6: src-6 {
+                                       interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x91>, <&audma0 0xb4>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src7: src-7 {
+                                       interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x93>, <&audma0 0xb6>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src8: src-8 {
+                                       interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x95>, <&audma0 0xb8>;
+                                       dma-names = "rx", "tx";
+                               };
+                               src9: src-9 {
+                                       interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x97>, <&audma0 0xba>;
+                                       dma-names = "rx", "tx";
+                               };
+                       };
+
+                       rcar_sound,ssi {
+                               ssi0: ssi-0 {
+                                       interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x01>, <&audma0 0x02>,
+                                              <&audma0 0x15>, <&audma0 0x16>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi1: ssi-1 {
+                                       interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x03>, <&audma0 0x04>,
+                                              <&audma0 0x49>, <&audma0 0x4a>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi2: ssi-2 {
+                                       interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x05>, <&audma0 0x06>,
+                                              <&audma0 0x63>, <&audma0 0x64>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi3: ssi-3 {
+                                       interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x07>, <&audma0 0x08>,
+                                              <&audma0 0x6f>, <&audma0 0x70>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi4: ssi-4 {
+                                       interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x09>, <&audma0 0x0a>,
+                                              <&audma0 0x71>, <&audma0 0x72>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi5: ssi-5 {
+                                       interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x0b>, <&audma0 0x0c>,
+                                              <&audma0 0x73>, <&audma0 0x74>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi6: ssi-6 {
+                                       interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x0d>, <&audma0 0x0e>,
+                                              <&audma0 0x75>, <&audma0 0x76>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi7: ssi-7 {
+                                       interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x0f>, <&audma0 0x10>,
+                                              <&audma0 0x79>, <&audma0 0x7a>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi8: ssi-8 {
+                                       interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x11>, <&audma0 0x12>,
+                                              <&audma0 0x7b>, <&audma0 0x7c>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                               ssi9: ssi-9 {
+                                       interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+                                       dmas = <&audma0 0x13>, <&audma0 0x14>,
+                                              <&audma0 0x7d>, <&audma0 0x7e>;
+                                       dma-names = "rx", "tx", "rxu", "txu";
+                               };
+                       };
+               };
+
+               audma0: dma-controller@ec700000 {
+                       compatible = "renesas,dmac-r8a774c0",
+                                    "renesas,rcar-dmac";
+                       reg = <0 0xec700000 0 0x10000>;
+                       interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                       "ch0", "ch1", "ch2", "ch3",
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 502>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 502>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       iommus = <&ipmmu_mp 0>, <&ipmmu_mp 1>,
+                                <&ipmmu_mp 2>, <&ipmmu_mp 3>,
+                                <&ipmmu_mp 4>, <&ipmmu_mp 5>,
+                                <&ipmmu_mp 6>, <&ipmmu_mp 7>,
+                                <&ipmmu_mp 8>, <&ipmmu_mp 9>,
+                                <&ipmmu_mp 10>, <&ipmmu_mp 11>,
+                                <&ipmmu_mp 12>, <&ipmmu_mp 13>,
+                                <&ipmmu_mp 14>, <&ipmmu_mp 15>;
+               };
+
+               xhci0: usb@ee000000 {
+                       compatible = "renesas,xhci-r8a774c0",
+                                    "renesas,rcar-gen3-xhci";
+                       reg = <0 0xee000000 0 0xc00>;
+                       interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 328>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 328>;
+                       status = "disabled";
+               };
+
+               usb3_peri0: usb@ee020000 {
+                       compatible = "renesas,r8a774c0-usb3-peri",
+                                    "renesas,rcar-gen3-usb3-peri";
+                       reg = <0 0xee020000 0 0x400>;
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 328>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 328>;
+                       status = "disabled";
+               };
+
+               ohci0: usb@ee080000 {
+                       compatible = "generic-ohci";
+                       reg = <0 0xee080000 0 0x100>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 1>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       status = "disabled";
+               };
+
+               ehci0: usb@ee080100 {
+                       compatible = "generic-ehci";
+                       reg = <0 0xee080100 0 0x100>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 2>;
+                       phy-names = "usb";
+                       companion = <&ohci0>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       status = "disabled";
+               };
+
+               usb2_phy0: usb-phy@ee080200 {
+                       compatible = "renesas,usb2-phy-r8a774c0",
+                                    "renesas,rcar-gen3-usb2-phy";
+                       reg = <0 0xee080200 0 0x700>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               sdhi0: mmc@ee100000 {
+                       compatible = "renesas,sdhi-r8a774c0",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee100000 0 0x2000>;
+                       interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 314>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 314>;
+                       status = "disabled";
+               };
+
+               sdhi1: mmc@ee120000 {
+                       compatible = "renesas,sdhi-r8a774c0",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee120000 0 0x2000>;
+                       interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 313>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 313>;
+                       status = "disabled";
+               };
+
+               sdhi3: mmc@ee160000 {
+                       compatible = "renesas,sdhi-r8a774c0",
+                                    "renesas,rcar-gen3-sdhi";
+                       reg = <0 0xee160000 0 0x2000>;
+                       interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 311>;
+                       max-frequency = <200000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 311>;
+                       status = "disabled";
+               };
+
+               gic: interrupt-controller@f1010000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x0 0xf1010000 0 0x1000>,
+                             <0x0 0xf1020000 0 0x20000>,
+                             <0x0 0xf1040000 0 0x20000>,
+                             <0x0 0xf1060000 0 0x20000>;
+                       interrupts = <GIC_PPI 9
+                                       (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+                       clocks = <&cpg CPG_MOD 408>;
+                       clock-names = "clk";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 408>;
+               };
+
+               pciec0: pcie@fe000000 {
+                       compatible = "renesas,pcie-r8a774c0",
+                                    "renesas,pcie-rcar-gen3";
+                       reg = <0 0xfe000000 0 0x80000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       device_type = "pci";
+                       ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>,
+                                <0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>,
+                                <0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>,
+                                <0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+                       /* Map all possible DDR as inbound ranges */
+                       dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>;
+                       interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+                       clock-names = "pcie", "pcie_bus";
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 319>;
+                       status = "disabled";
+               };
+
+               vspb0: vsp@fe960000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe960000 0 0x8000>;
+                       interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 626>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 626>;
+                       renesas,fcp = <&fcpvb0>;
+               };
+
+               vspd0: vsp@fea20000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea20000 0 0x7000>;
+                       interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 623>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 623>;
+                       renesas,fcp = <&fcpvd0>;
+               };
+
+               vspd1: vsp@fea28000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea28000 0 0x7000>;
+                       interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 622>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 622>;
+                       renesas,fcp = <&fcpvd1>;
+               };
+
+               vspi0: vsp@fe9a0000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe9a0000 0 0x8000>;
+                       interrupts = <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 631>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 631>;
+                       renesas,fcp = <&fcpvi0>;
+               };
+
+               fcpvb0: fcp@fe96f000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfe96f000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 607>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 607>;
+                       iommus = <&ipmmu_vp0 5>;
+               };
+
+               fcpvd0: fcp@fea27000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfea27000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 603>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 603>;
+                       iommus = <&ipmmu_vi0 8>;
+               };
+
+               fcpvd1: fcp@fea2f000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfea2f000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 602>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 602>;
+                       iommus = <&ipmmu_vi0 9>;
+               };
+
+               fcpvi0: fcp@fe9af000 {
+                       compatible = "renesas,fcpv";
+                       reg = <0 0xfe9af000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 611>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 611>;
+                       iommus = <&ipmmu_vp0 8>;
+               };
+
+               csi40: csi2@feaa0000 {
+                       compatible = "renesas,r8a774c0-csi2";
+                       reg = <0 0xfeaa0000 0 0x10000>;
+                       interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 716>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 716>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       reg = <1>;
+
+                                       csi40vin4: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&vin4csi40>;
+                                       };
+                                       csi40vin5: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&vin5csi40>;
+                                       };
+                               };
+                       };
+               };
+
+               du: display@feb00000 {
+                       compatible = "renesas,du-r8a774c0";
+                       reg = <0 0xfeb00000 0 0x40000>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
+                       clock-names = "du.0", "du.1";
+                       resets = <&cpg 724>;
+                       reset-names = "du.0";
+                       renesas,vsps = <&vspd0 0>, <&vspd1 0>;
+
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_rgb: endpoint {
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       du_out_lvds0: endpoint {
+                                               remote-endpoint = <&lvds0_in>;
+                                       };
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       du_out_lvds1: endpoint {
+                                               remote-endpoint = <&lvds1_in>;
+                                       };
+                               };
+                       };
+               };
+
+               lvds0: lvds-encoder@feb90000 {
+                       compatible = "renesas,r8a774c0-lvds";
+                       reg = <0 0xfeb90000 0 0x20>;
+                       clocks = <&cpg CPG_MOD 727>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 727>;
+                       status = "disabled";
+
+                       renesas,companion = <&lvds1>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       lvds0_in: endpoint {
+                                               remote-endpoint = <&du_out_lvds0>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       lvds0_out: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               lvds1: lvds-encoder@feb90100 {
+                       compatible = "renesas,r8a774c0-lvds";
+                       reg = <0 0xfeb90100 0 0x20>;
+                       clocks = <&cpg CPG_MOD 727>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 726>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       lvds1_in: endpoint {
+                                               remote-endpoint = <&du_out_lvds1>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       lvds1_out: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               prr: chipid@fff00044 {
+                       compatible = "renesas,prr";
+                       reg = <0 0xfff00044 0 4>;
+               };
+       };
+
+       thermal-zones {
+               cpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&thermal 0>;
+                       sustainable-power = <717>;
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
+                               };
+                       };
+
+                       trips {
+                               sensor1_crit: sensor1-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+
+                               target: trip-point1 {
+                                       temperature = <100000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       /* External USB clocks - can be overridden by the board */
+       usb3s0_clk: usb3s0 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       usb_extal_clk: usb_extal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+};
index 07f607d..be3ea3c 100644 (file)
@@ -3,7 +3,19 @@ if RCAR_GEN3
 menu "Select Target SoC"
 
 config R8A774A1
-        bool "Renesas SoC R8A774A1"
+       bool "Renesas SoC R8A774A1"
+
+config R8A774B1
+       bool "Renesas SoC R8A774B1"
+       imply CLK_R8A774B1
+
+config R8A774C0
+       bool "Renesas SoC R8A774C0"
+       imply CLK_R8A774C0
+
+config R8A774E1
+       bool "Renesas SoC R8A774E1"
+       imply CLK_R8A774E1
 
 config R8A7795
        bool "Renesas SoC R8A7795"
index 90cb465..a63a4ee 100644 (file)
@@ -26,9 +26,9 @@ void sysmgr_get_pinmux_table(const u8 **table, unsigned int *table_len);
 #define SYSMGR_GEN5_ECCGRP_OCRAM               0x144
 #define SYSMGR_GEN5_EMACIO                     0x400
 #define SYSMGR_GEN5_NAND_USEFPGA               0x6f0
-#define SYSMGR_GEN5_RGMII0_USEFPGA             0x6f8
+#define SYSMGR_GEN5_RGMII1_USEFPGA             0x6f8
 #define SYSMGR_GEN5_SDMMC_USEFPGA              0x708
-#define SYSMGR_GEN5_RGMII1_USEFPGA             0x704
+#define SYSMGR_GEN5_RGMII0_USEFPGA             0x714
 #define SYSMGR_GEN5_SPIM1_USEFPGA              0x730
 #define SYSMGR_GEN5_SPIM0_USEFPGA              0x738
 
index 0e27ad1..a90d821 100644 (file)
@@ -349,12 +349,9 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
 
        /*
         * Use the address following the image as target address for the
-        * device tree. Load address is aligned to 8 bytes to match the required
-        * alignment specified for linux arm [1] and arm 64 [2] booting
-        * [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm/booting.rst#n126
-        * [2]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/booting.rst#n45
+        * device tree.
         */
-       image_info.load_addr = ALIGN(spl_image->load_addr + spl_image->size, 8);
+       image_info.load_addr = spl_image->load_addr + spl_image->size;
 
        /* Figure out which device tree the board wants to use */
        node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, index++);
index 950507f..aaf59f5 100644 (file)
@@ -9,11 +9,16 @@ CONFIG_DM_GPIO=y
 CONFIG_TARGET_MT8512=y
 CONFIG_DEFAULT_DEVICE_TREE="mt8512-bm1-emmc"
 CONFIG_FIT=y
+CONFIG_EFI_PARTITION=y
 CONFIG_FIT_SIGNATURE=y
 CONFIG_DEFAULT_FDT_FILE="mt8512-bm1-emmc.dtb"
 CONFIG_SYS_PROMPT="MT8512> "
 CONFIG_CMD_BOOTMENU=y
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+# CONFIG_DOS_PARTITION is not set
 CONFIG_ENV_OVERWRITE=y
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y
@@ -26,6 +31,16 @@ CONFIG_PINCONF=y
 CONFIG_PINCTRL_MT8512=y
 CONFIG_RAM=y
 CONFIG_BAUDRATE=921600
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x56000000
+CONFIG_FASTBOOT_BUF_SIZE=0x1e00000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y
+CONFIG_PHY=y
+CONFIG_PHY_MTK_TPHY=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_SERIAL=y
 CONFIG_MTK_SERIAL=y
 CONFIG_TIMER=y
@@ -33,3 +48,14 @@ CONFIG_MTK_TIMER=y
 CONFIG_WDT=y
 CONFIG_WDT_MTK=y
 CONFIG_LZO=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_MTU3=y
+# CONFIG_USB_MTU3_HOST is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="MediaTek"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d
+CONFIG_USB_GADGET_PRODUCT_NUM=0x201c
diff --git a/doc/device-tree-bindings/usb/generic.txt b/doc/device-tree-bindings/usb/generic.txt
new file mode 100644 (file)
index 0000000..a02a198
--- /dev/null
@@ -0,0 +1,31 @@
+Generic USB Properties
+
+Optional properties:
+ - maximum-speed: tells USB controllers we want to work up to a certain
+                       speed. Valid arguments are "super-speed-plus",
+                       "super-speed", "high-speed", "full-speed" and
+                       "low-speed". In case this isn't passed via DT, USB
+                       controllers should default to their maximum HW
+                       capability.
+ - dr_mode: tells Dual-Role USB controllers that we want to work on a
+                       particular mode. Valid arguments are "host",
+                       "peripheral" and "otg". In case this attribute isn't
+                       passed via DT, USB DRD controllers should default to
+                       OTG.
+ - phy_type: tells USB controllers that we want to configure the core to support
+                       a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is
+                       selected. Valid arguments are "utmi" and "utmi_wide".
+                       In case this isn't passed via DT, USB controllers should
+                       default to HW capability.
+
+This is an attribute to a USB controller such as:
+
+dwc3@4a030000 {
+       compatible = "synopsys,dwc3";
+       reg = <0x4a030000 0xcfff>;
+       interrupts = <0 92 4>
+       usb-phy = <&usb2_phy>, <&usb3,phy>;
+       maximum-speed = "super-speed";
+       dr_mode = "otg";
+       phy_type = "utmi_wide";
+};
diff --git a/doc/device-tree-bindings/usb/mediatek,mtu3.txt b/doc/device-tree-bindings/usb/mediatek,mtu3.txt
new file mode 100644 (file)
index 0000000..ab877bf
--- /dev/null
@@ -0,0 +1,79 @@
+The device node for Mediatek USB3 DRD controller
+
+Required properties:
+ - compatible : should be "mediatek,<soc-model>-mtu3", "mediatek,mtu3",
+       soc-model is the name of SoC, such as mt8512 etc,
+       when using "mediatek,mtu3" compatible string, you need SoC specific
+       ones in addition, one of:
+       - "mediatek,mt8512-mtu3"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be
+       - "ippc" : IP Port Control
+ - power-domains : a phandle to USB power domain node to control USB's MTCMOS
+ - clocks : a list of phandle + clock-specifier pairs, one for each
+       entry in clock-names
+ - clock-names : must contain "sys_ck" for clock of controller,
+       the following clocks are optional:
+       "ref_ck", "mcu_ck", "dma_ck" and "xhci_ck";
+ - phys : list of all the USB PHYs on this HCD
+ - #address-cells, #size-cells : used for sub-nodes with 'reg' property
+ - ranges : allows valid 1:1 translation between child's address space and
+       parent's address space
+
+Optional properties:
+ - vusb33-supply : regulator of USB AVDD3.3v
+ - vbus-supply : regulator of VBUS 5v, needed when supports host mode.
+
+Sub-nodes:
+Required properties:
+ - compatible : should be "mediatek,ssusb"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be
+       - "mac" : SSUSB MAC, include xHCI and device
+ - interrupts : interrupt used by xHCI or device
+ - dr_mode : should be one of "host" or "peripheral",
+       see : usb/generic.txt
+
+Optional properties:
+ - pinctrl-names : a pinctrl state named "default" is optional
+ - pinctrl-0 : pin control group
+       See: pinctrl/pinctrl-bindings.txt
+
+ - device mode:
+   - maximum-speed : valid arguments are "full-speed", "high-speed",
+       "super-speed" and "super-speed-plus",
+       see: usb/generic.txt
+   - mediatek,force-vbus : force vbus as valid by SW
+
+ - host mode (dr_mode is "host"):
+   - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
+       bit1 for u3port1, ... etc;
+
+Example:
+usb3: usb@11213e00 {
+       compatible = "mediatek,mt8512-mtu3", "mediatek,mtu3";
+       reg = <0x11213e00 0x0100>;
+       reg-names = "ippc";
+       phys = <&u2port0 PHY_TYPE_USB2>, <&u2port1 PHY_TYPE_USB2>;
+       power-domains = <&scpsys MT8512_POWER_DOMAIN_USB>;
+       clocks = <&infracfg CLK_INFRA_USB_SYS>,
+                <&topckgen CLK_TOP_SSUSB_TOP_CK_EN>,
+                <&infracfg CLK_INFRA_ICUSB>;
+       clock-names = "sys_ck", "ref_ck", "mcu_ck";
+       vusb33-supply = <reg_3p3v>;
+       vbus-supply = <&usb_p0_vbus>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+       status = "disabled";
+
+       ssusb: usb@11210000 {
+               compatible = "mediatek,ssusb";
+               reg = <0x11210000 0x3e00>;
+               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_LOW>;
+               reg-names = "mac";
+               dr_mode = "peripheral";
+               maximum-speed = "high-speed";
+               status = "disabled";
+       };
+};
index 284e213..0c8b9eb 100644 (file)
@@ -55,6 +55,24 @@ config CLK_R8A774A1
         help
           Enable this to support the clocks on Renesas R8A774A1 SoC.
 
+config CLK_R8A774B1
+       bool "Renesas R8A774B1 clock driver"
+       depends on CLK_RCAR_GEN3
+       help
+         Enable this to support the clocks on Renesas R8A774B1 SoC.
+
+config CLK_R8A774C0
+       bool "Renesas R8A774C0 clock driver"
+       depends on CLK_RCAR_GEN3
+       help
+         Enable this to support the clocks on Renesas R8A774C0 SoC.
+
+config CLK_R8A774E1
+       bool "Renesas R8A774E1 clock driver"
+       depends on CLK_RCAR_GEN3
+       help
+         Enable this to support the clocks on Renesas R8A774E1 SoC.
+
 config CLK_R8A7795
        bool "Renesas R8A7795 clock driver"
        depends on CLK_RCAR_GEN3
index dd599b7..ed1a125 100644 (file)
@@ -1,6 +1,9 @@
 obj-$(CONFIG_CLK_RENESAS) += renesas-cpg-mssr.o
 obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o
 obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A774B1) += r8a774b1-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A774C0) += r8a774c0-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A774E1) += r8a774e1-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7790) += r8a7790-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7791) += r8a7791-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o
index 8935667..6997054 100644 (file)
@@ -41,6 +41,7 @@ enum clk_ids {
        CLK_S2,
        CLK_S3,
        CLK_SDSRC,
+       CLK_RPCSRC,
        CLK_RINT,
 
        /* Module Clocks */
@@ -67,6 +68,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] = {
        DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
        DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
        DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED(".rpcsrc",    CLK_RPCSRC,        CLK_PLL1,       2, 1),
 
        DEF_GEN3_OSC(".r",      CLK_RINT,          CLK_EXTAL,      32),
 
@@ -97,6 +99,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] = {
        DEF_GEN3_SD("sd1",      R8A774A1_CLK_SD1,   CLK_SDSRC,     0x078),
        DEF_GEN3_SD("sd2",      R8A774A1_CLK_SD2,   CLK_SDSRC,     0x268),
        DEF_GEN3_SD("sd3",      R8A774A1_CLK_SD3,   CLK_SDSRC,     0x26c),
+       DEF_GEN3_RPC("rpc",     R8A774A1_CLK_RPC,   CLK_RPCSRC,    0x238),
 
        DEF_FIXED("cl",         R8A774A1_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
        DEF_FIXED("cp",         R8A774A1_CLK_CP,    CLK_EXTAL,      2, 1),
@@ -200,6 +203,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] = {
        DEF_MOD("can-fd",                914,   R8A774A1_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774A1_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774A1_CLK_S3D4),
+       DEF_MOD("rpc",                   917,   R8A774A1_CLK_RPC),
        DEF_MOD("i2c6",                  918,   R8A774A1_CLK_S0D6),
        DEF_MOD("i2c5",                  919,   R8A774A1_CLK_S0D6),
        DEF_MOD("i2c-dvfs",              926,   R8A774A1_CLK_CP),
diff --git a/drivers/clk/renesas/r8a774b1-cpg-mssr.c b/drivers/clk/renesas/r8a774b1-cpg-mssr.c
new file mode 100644 (file)
index 0000000..7b6947b
--- /dev/null
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * r8a774b1 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ *
+ * Based on r8a7796-cpg-mssr.c
+ *
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+
+#include <dt-bindings/clock/r8a774b1-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+       /* Core Clock Outputs exported to DT */
+       LAST_DT_CORE_CLK = R8A774B1_CLK_CANFD,
+
+       /* External Input Clocks */
+       CLK_EXTAL,
+       CLK_EXTALR,
+
+       /* Internal Core Clocks */
+       CLK_MAIN,
+       CLK_PLL0,
+       CLK_PLL1,
+       CLK_PLL3,
+       CLK_PLL4,
+       CLK_PLL1_DIV2,
+       CLK_PLL1_DIV4,
+       CLK_S0,
+       CLK_S1,
+       CLK_S2,
+       CLK_S3,
+       CLK_SDSRC,
+       CLK_RINT,
+
+       /* Module Clocks */
+       MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a774b1_core_clks[] = {
+       /* External Clock Inputs */
+       DEF_INPUT("extal",      CLK_EXTAL),
+       DEF_INPUT("extalr",     CLK_EXTALR),
+
+       /* Internal Core Clocks */
+       DEF_BASE(".main",       CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+       DEF_BASE(".pll0",       CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+       DEF_BASE(".pll1",       CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+       DEF_BASE(".pll3",       CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+       DEF_BASE(".pll4",       CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+       DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2,     CLK_PLL1,       2, 1),
+       DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4,     CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED(".s0",        CLK_S0,            CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED(".s1",        CLK_S1,            CLK_PLL1_DIV2,  3, 1),
+       DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
+       DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
+       DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+
+       DEF_GEN3_OSC(".r",      CLK_RINT,          CLK_EXTAL,      32),
+
+       /* Core Clock Outputs */
+       DEF_GEN3_Z("z",         R8A774B1_CLK_Z,     CLK_TYPE_GEN3_Z,  CLK_PLL0, 2, 8),
+       DEF_FIXED("ztr",        R8A774B1_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
+       DEF_FIXED("ztrd2",      R8A774B1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+       DEF_FIXED("zt",         R8A774B1_CLK_ZT,    CLK_PLL1_DIV2,  4, 1),
+       DEF_FIXED("zx",         R8A774B1_CLK_ZX,    CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED("s0d1",       R8A774B1_CLK_S0D1,  CLK_S0,         1, 1),
+       DEF_FIXED("s0d2",       R8A774B1_CLK_S0D2,  CLK_S0,         2, 1),
+       DEF_FIXED("s0d3",       R8A774B1_CLK_S0D3,  CLK_S0,         3, 1),
+       DEF_FIXED("s0d4",       R8A774B1_CLK_S0D4,  CLK_S0,         4, 1),
+       DEF_FIXED("s0d6",       R8A774B1_CLK_S0D6,  CLK_S0,         6, 1),
+       DEF_FIXED("s0d8",       R8A774B1_CLK_S0D8,  CLK_S0,         8, 1),
+       DEF_FIXED("s0d12",      R8A774B1_CLK_S0D12, CLK_S0,        12, 1),
+       DEF_FIXED("s1d2",       R8A774B1_CLK_S1D2,  CLK_S1,         2, 1),
+       DEF_FIXED("s1d4",       R8A774B1_CLK_S1D4,  CLK_S1,         4, 1),
+       DEF_FIXED("s2d1",       R8A774B1_CLK_S2D1,  CLK_S2,         1, 1),
+       DEF_FIXED("s2d2",       R8A774B1_CLK_S2D2,  CLK_S2,         2, 1),
+       DEF_FIXED("s2d4",       R8A774B1_CLK_S2D4,  CLK_S2,         4, 1),
+       DEF_FIXED("s3d1",       R8A774B1_CLK_S3D1,  CLK_S3,         1, 1),
+       DEF_FIXED("s3d2",       R8A774B1_CLK_S3D2,  CLK_S3,         2, 1),
+       DEF_FIXED("s3d4",       R8A774B1_CLK_S3D4,  CLK_S3,         4, 1),
+
+       DEF_GEN3_SD("sd0",      R8A774B1_CLK_SD0,   CLK_SDSRC,     0x074),
+       DEF_GEN3_SD("sd1",      R8A774B1_CLK_SD1,   CLK_SDSRC,     0x078),
+       DEF_GEN3_SD("sd2",      R8A774B1_CLK_SD2,   CLK_SDSRC,     0x268),
+       DEF_GEN3_SD("sd3",      R8A774B1_CLK_SD3,   CLK_SDSRC,     0x26c),
+
+       DEF_FIXED("cl",         R8A774B1_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
+       DEF_FIXED("cp",         R8A774B1_CLK_CP,    CLK_EXTAL,      2, 1),
+       DEF_FIXED("cpex",       R8A774B1_CLK_CPEX,  CLK_EXTAL,      2, 1),
+
+       DEF_DIV6P1("canfd",     R8A774B1_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
+       DEF_DIV6P1("csi0",      R8A774B1_CLK_CSI0,  CLK_PLL1_DIV4, 0x00c),
+       DEF_DIV6P1("mso",       R8A774B1_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
+       DEF_DIV6P1("hdmi",      R8A774B1_CLK_HDMI,  CLK_PLL1_DIV4, 0x250),
+
+       DEF_GEN3_OSC("osc",     R8A774B1_CLK_OSC,   CLK_EXTAL,     8),
+
+       DEF_BASE("r",           R8A774B1_CLK_R,     CLK_TYPE_GEN3_R, CLK_RINT),
+};
+
+static const struct mssr_mod_clk r8a774b1_mod_clks[] = {
+       DEF_MOD("tmu4",                  121,   R8A774B1_CLK_S0D6),
+       DEF_MOD("tmu3",                  122,   R8A774B1_CLK_S3D2),
+       DEF_MOD("tmu2",                  123,   R8A774B1_CLK_S3D2),
+       DEF_MOD("tmu1",                  124,   R8A774B1_CLK_S3D2),
+       DEF_MOD("tmu0",                  125,   R8A774B1_CLK_CP),
+       DEF_MOD("fdp1-0",                119,   R8A774B1_CLK_S0D1),
+       DEF_MOD("scif5",                 202,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scif4",                 203,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scif3",                 204,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scif1",                 206,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scif0",                 207,   R8A774B1_CLK_S3D4),
+       DEF_MOD("msiof3",                208,   R8A774B1_CLK_MSO),
+       DEF_MOD("msiof2",                209,   R8A774B1_CLK_MSO),
+       DEF_MOD("msiof1",                210,   R8A774B1_CLK_MSO),
+       DEF_MOD("msiof0",                211,   R8A774B1_CLK_MSO),
+       DEF_MOD("sys-dmac2",             217,   R8A774B1_CLK_S3D1),
+       DEF_MOD("sys-dmac1",             218,   R8A774B1_CLK_S3D1),
+       DEF_MOD("sys-dmac0",             219,   R8A774B1_CLK_S0D3),
+       DEF_MOD("cmt3",                  300,   R8A774B1_CLK_R),
+       DEF_MOD("cmt2",                  301,   R8A774B1_CLK_R),
+       DEF_MOD("cmt1",                  302,   R8A774B1_CLK_R),
+       DEF_MOD("cmt0",                  303,   R8A774B1_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scif2",                 310,   R8A774B1_CLK_S3D4),
+       DEF_MOD("sdif3",                 311,   R8A774B1_CLK_SD3),
+       DEF_MOD("sdif2",                 312,   R8A774B1_CLK_SD2),
+       DEF_MOD("sdif1",                 313,   R8A774B1_CLK_SD1),
+       DEF_MOD("sdif0",                 314,   R8A774B1_CLK_SD0),
+       DEF_MOD("pcie1",                 318,   R8A774B1_CLK_S3D1),
+       DEF_MOD("pcie0",                 319,   R8A774B1_CLK_S3D1),
+       DEF_MOD("usb3-if0",              328,   R8A774B1_CLK_S3D1),
+       DEF_MOD("usb-dmac0",             330,   R8A774B1_CLK_S3D1),
+       DEF_MOD("usb-dmac1",             331,   R8A774B1_CLK_S3D1),
+       DEF_MOD("rwdt",                  402,   R8A774B1_CLK_R),
+       DEF_MOD("intc-ex",               407,   R8A774B1_CLK_CP),
+       DEF_MOD("intc-ap",               408,   R8A774B1_CLK_S0D3),
+       DEF_MOD("audmac1",               501,   R8A774B1_CLK_S1D2),
+       DEF_MOD("audmac0",               502,   R8A774B1_CLK_S1D2),
+       DEF_MOD("hscif4",                516,   R8A774B1_CLK_S3D1),
+       DEF_MOD("hscif3",                517,   R8A774B1_CLK_S3D1),
+       DEF_MOD("hscif2",                518,   R8A774B1_CLK_S3D1),
+       DEF_MOD("hscif1",                519,   R8A774B1_CLK_S3D1),
+       DEF_MOD("hscif0",                520,   R8A774B1_CLK_S3D1),
+       DEF_MOD("thermal",               522,   R8A774B1_CLK_CP),
+       DEF_MOD("pwm",                   523,   R8A774B1_CLK_S0D12),
+       DEF_MOD("fcpvd1",                602,   R8A774B1_CLK_S0D2),
+       DEF_MOD("fcpvd0",                603,   R8A774B1_CLK_S0D2),
+       DEF_MOD("fcpvb0",                607,   R8A774B1_CLK_S0D1),
+       DEF_MOD("fcpvi0",                611,   R8A774B1_CLK_S0D1),
+       DEF_MOD("fcpf0",                 615,   R8A774B1_CLK_S0D1),
+       DEF_MOD("fcpcs",                 619,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vspd1",                 622,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vspd0",                 623,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vspb",                  626,   R8A774B1_CLK_S0D1),
+       DEF_MOD("vspi0",                 631,   R8A774B1_CLK_S0D1),
+       DEF_MOD("ehci1",                 702,   R8A774B1_CLK_S3D2),
+       DEF_MOD("ehci0",                 703,   R8A774B1_CLK_S3D2),
+       DEF_MOD("hsusb",                 704,   R8A774B1_CLK_S3D2),
+       DEF_MOD("csi20",                 714,   R8A774B1_CLK_CSI0),
+       DEF_MOD("csi40",                 716,   R8A774B1_CLK_CSI0),
+       DEF_MOD("du3",                   721,   R8A774B1_CLK_S2D1),
+       DEF_MOD("du1",                   723,   R8A774B1_CLK_S2D1),
+       DEF_MOD("du0",                   724,   R8A774B1_CLK_S2D1),
+       DEF_MOD("lvds",                  727,   R8A774B1_CLK_S2D1),
+       DEF_MOD("hdmi0",                 729,   R8A774B1_CLK_HDMI),
+       DEF_MOD("vin7",                  804,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin6",                  805,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin5",                  806,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin4",                  807,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin3",                  808,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin2",                  809,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin1",                  810,   R8A774B1_CLK_S0D2),
+       DEF_MOD("vin0",                  811,   R8A774B1_CLK_S0D2),
+       DEF_MOD("etheravb",              812,   R8A774B1_CLK_S0D6),
+       DEF_MOD("sata0",                 815,   R8A774B1_CLK_S3D2),
+       DEF_MOD("gpio7",                 905,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio6",                 906,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio5",                 907,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio4",                 908,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio3",                 909,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio2",                 910,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio1",                 911,   R8A774B1_CLK_S3D4),
+       DEF_MOD("gpio0",                 912,   R8A774B1_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A774B1_CLK_S3D2),
+       DEF_MOD("can-if1",               915,   R8A774B1_CLK_S3D4),
+       DEF_MOD("can-if0",               916,   R8A774B1_CLK_S3D4),
+       DEF_MOD("i2c6",                  918,   R8A774B1_CLK_S0D6),
+       DEF_MOD("i2c5",                  919,   R8A774B1_CLK_S0D6),
+       DEF_MOD("i2c-dvfs",              926,   R8A774B1_CLK_CP),
+       DEF_MOD("i2c4",                  927,   R8A774B1_CLK_S0D6),
+       DEF_MOD("i2c3",                  928,   R8A774B1_CLK_S0D6),
+       DEF_MOD("i2c2",                  929,   R8A774B1_CLK_S3D2),
+       DEF_MOD("i2c1",                  930,   R8A774B1_CLK_S3D2),
+       DEF_MOD("i2c0",                  931,   R8A774B1_CLK_S3D2),
+       DEF_MOD("ssi-all",              1005,   R8A774B1_CLK_S3D4),
+       DEF_MOD("ssi9",                 1006,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi8",                 1007,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi7",                 1008,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi6",                 1009,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi5",                 1010,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi4",                 1011,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi3",                 1012,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi2",                 1013,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi1",                 1014,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi0",                 1015,   MOD_CLK_ID(1005)),
+       DEF_MOD("scu-all",              1017,   R8A774B1_CLK_S3D4),
+       DEF_MOD("scu-dvc1",             1018,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-dvc0",             1019,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu1-mix1",        1020,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu0-mix0",        1021,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src9",             1022,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src8",             1023,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src7",             1024,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src6",             1025,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src5",             1026,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src4",             1027,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src3",             1028,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src2",             1029,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src1",             1030,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src0",             1031,   MOD_CLK_ID(1017)),
+};
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ *   MD                EXTAL           PLL0    PLL1    PLL3    PLL4    OSC
+ * 14 13 19 17 (MHz)
+ *-----------------------------------------------------------------
+ * 0  0  0  0  16.66 x 1       x180    x192    x192    x144    /16
+ * 0  0  0  1  16.66 x 1       x180    x192    x128    x144    /16
+ * 0  0  1  0  Prohibited setting
+ * 0  0  1  1  16.66 x 1       x180    x192    x192    x144    /16
+ * 0  1  0  0  20    x 1       x150    x160    x160    x120    /19
+ * 0  1  0  1  20    x 1       x150    x160    x106    x120    /19
+ * 0  1  1  0  Prohibited setting
+ * 0  1  1  1  20    x 1       x150    x160    x160    x120    /19
+ * 1  0  0  0  25    x 1       x120    x128    x128    x96     /24
+ * 1  0  0  1  25    x 1       x120    x128    x84     x96     /24
+ * 1  0  1  0  Prohibited setting
+ * 1  0  1  1  25    x 1       x120    x128    x128    x96     /24
+ * 1  1  0  0  33.33 / 2       x180    x192    x192    x144    /32
+ * 1  1  0  1  33.33 / 2       x180    x192    x128    x144    /32
+ * 1  1  1  0  Prohibited setting
+ * 1  1  1  1  33.33 / 2       x180    x192    x192    x144    /32
+ */
+#define CPG_PLL_CONFIG_INDEX(md)       ((((md) & BIT(14)) >> 11) | \
+                                        (((md) & BIT(13)) >> 11) | \
+                                        (((md) & BIT(19)) >> 18) | \
+                                        (((md) & BIT(17)) >> 17))
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] = {
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div   OSC prediv */
+       { 1,            192,    1,      192,    1,      16,     },
+       { 1,            192,    1,      128,    1,      16,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            192,    1,      192,    1,      16,     },
+       { 1,            160,    1,      160,    1,      19,     },
+       { 1,            160,    1,      106,    1,      19,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            160,    1,      160,    1,      19,     },
+       { 1,            128,    1,      128,    1,      24,     },
+       { 1,            128,    1,      84,     1,      24,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            128,    1,      128,    1,      24,     },
+       { 2,            192,    1,      192,    1,      32,     },
+       { 2,            192,    1,      128,    1,      32,     },
+       { 0, /* Prohibited setting */                           },
+       { 2,            192,    1,      192,    1,      32,     },
+};
+
+/* RMSTPCR[0-11] is not present on RZ/G2N */
+static const struct mstp_stop_table r8a774b1_mstp_table[] = {
+       { 0x00200000, 0x0, 0x0, 0 },
+       { 0xFFFFFFFF, 0x0, 0x0, 0 },
+       { 0x340E2FDC, 0x2040, 0x0, 0 },
+       { 0xFFFFFFDF, 0x400, 0x0, 0 },
+       { 0x80000184, 0x180, 0x0, 0 },
+       { 0xC3FFFFFF, 0x0, 0x0, 0 },
+       { 0xFFFFFFFF, 0x0, 0x0, 0 },
+       { 0xFFFFFFFF, 0x0, 0x0, 0 },
+       { 0x01F1FFF7, 0x0, 0x0, 0 },
+       { 0xFFFFFFFE, 0x0, 0x0, 0 },
+       { 0xFFFEFFE0, 0x0, 0x0, 0 },
+       { 0x000000B7, 0x0, 0x0, 0 },
+};
+
+static const void *r8a774b1_get_pll_config(const u32 cpg_mode)
+{
+       return &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+}
+
+static const struct cpg_mssr_info r8a774b1_cpg_mssr_info = {
+       .core_clk               = r8a774b1_core_clks,
+       .core_clk_size          = ARRAY_SIZE(r8a774b1_core_clks),
+       .mod_clk                = r8a774b1_mod_clks,
+       .mod_clk_size           = ARRAY_SIZE(r8a774b1_mod_clks),
+       .mstp_table             = r8a774b1_mstp_table,
+       .mstp_table_size        = ARRAY_SIZE(r8a774b1_mstp_table),
+       .reset_node             = "renesas,r8a774b1-rst",
+       .extalr_node            = "extalr",
+       .mod_clk_base           = MOD_CLK_BASE,
+       .clk_extal_id           = CLK_EXTAL,
+       .clk_extalr_id          = CLK_EXTALR,
+       .get_pll_config         = r8a774b1_get_pll_config,
+};
+
+static const struct udevice_id r8a774b1_clk_ids[] = {
+       {
+               .compatible     = "renesas,r8a774b1-cpg-mssr",
+               .data           = (ulong)&r8a774b1_cpg_mssr_info,
+       },
+       { }
+};
+
+U_BOOT_DRIVER(clk_r8a774b1) = {
+       .name           = "clk_r8a774b1",
+       .id             = UCLASS_CLK,
+       .of_match       = r8a774b1_clk_ids,
+       .priv_auto_alloc_size = sizeof(struct gen3_clk_priv),
+       .ops            = &gen3_clk_ops,
+       .probe          = gen3_clk_probe,
+       .remove         = gen3_clk_remove,
+};
diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c
new file mode 100644 (file)
index 0000000..c9f0f72
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * r8a774c0 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ *
+ * Based on r8a77990-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/bitops.h>
+
+#include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+       /* Core Clock Outputs exported to DT */
+       LAST_DT_CORE_CLK = R8A774C0_CLK_CANFD,
+
+       /* External Input Clocks */
+       CLK_EXTAL,
+
+       /* Internal Core Clocks */
+       CLK_MAIN,
+       CLK_PLL0,
+       CLK_PLL1,
+       CLK_PLL3,
+       CLK_PLL0D4,
+       CLK_PLL0D6,
+       CLK_PLL0D8,
+       CLK_PLL0D20,
+       CLK_PLL0D24,
+       CLK_PLL1D2,
+       CLK_PE,
+       CLK_S0,
+       CLK_S1,
+       CLK_S2,
+       CLK_S3,
+       CLK_SDSRC,
+       CLK_RINT,
+       CLK_OCO,
+
+       /* Module Clocks */
+       MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a774c0_core_clks[] = {
+       /* External Clock Inputs */
+       DEF_INPUT("extal",     CLK_EXTAL),
+
+       /* Internal Core Clocks */
+       DEF_BASE(".main",      CLK_MAIN, CLK_TYPE_GEN3_MAIN,       CLK_EXTAL),
+       DEF_BASE(".pll1",      CLK_PLL1, CLK_TYPE_GEN3_PLL1,       CLK_MAIN),
+       DEF_BASE(".pll3",      CLK_PLL3, CLK_TYPE_GEN3_PLL3,       CLK_MAIN),
+
+       DEF_FIXED(".pll0",     CLK_PLL0,           CLK_MAIN,       1, 100),
+       DEF_FIXED(".pll0d4",   CLK_PLL0D4,         CLK_PLL0,       4, 1),
+       DEF_FIXED(".pll0d6",   CLK_PLL0D6,         CLK_PLL0,       6, 1),
+       DEF_FIXED(".pll0d8",   CLK_PLL0D8,         CLK_PLL0,       8, 1),
+       DEF_FIXED(".pll0d20",  CLK_PLL0D20,        CLK_PLL0,      20, 1),
+       DEF_FIXED(".pll0d24",  CLK_PLL0D24,        CLK_PLL0,      24, 1),
+       DEF_FIXED(".pll1d2",   CLK_PLL1D2,         CLK_PLL1,       2, 1),
+       DEF_FIXED(".pe",       CLK_PE,             CLK_PLL0D20,    1, 1),
+       DEF_FIXED(".s0",       CLK_S0,             CLK_PLL1,       2, 1),
+       DEF_FIXED(".s1",       CLK_S1,             CLK_PLL1,       3, 1),
+       DEF_FIXED(".s2",       CLK_S2,             CLK_PLL1,       4, 1),
+       DEF_FIXED(".s3",       CLK_S3,             CLK_PLL1,       6, 1),
+       DEF_FIXED(".sdsrc",    CLK_SDSRC,          CLK_PLL1,       2, 1),
+
+       DEF_DIV6_RO(".r",      CLK_RINT,           CLK_EXTAL, CPG_RCKCR, 32),
+
+       DEF_RATE(".oco",       CLK_OCO,            8 * 1000 * 1000),
+
+       /* Core Clock Outputs */
+       DEF_FIXED("za2",       R8A774C0_CLK_ZA2,   CLK_PLL0D24,    1, 1),
+       DEF_FIXED("za8",       R8A774C0_CLK_ZA8,   CLK_PLL0D8,     1, 1),
+       DEF_GEN3_Z("z2",       R8A774C0_CLK_Z2,    CLK_TYPE_GEN3_Z, CLK_PLL0, 4, 8),
+       DEF_FIXED("ztr",       R8A774C0_CLK_ZTR,   CLK_PLL1,       6, 1),
+       DEF_FIXED("zt",        R8A774C0_CLK_ZT,    CLK_PLL1,       4, 1),
+       DEF_FIXED("zx",        R8A774C0_CLK_ZX,    CLK_PLL1,       3, 1),
+       DEF_FIXED("s0d1",      R8A774C0_CLK_S0D1,  CLK_S0,         1, 1),
+       DEF_FIXED("s0d3",      R8A774C0_CLK_S0D3,  CLK_S0,         3, 1),
+       DEF_FIXED("s0d6",      R8A774C0_CLK_S0D6,  CLK_S0,         6, 1),
+       DEF_FIXED("s0d12",     R8A774C0_CLK_S0D12, CLK_S0,        12, 1),
+       DEF_FIXED("s0d24",     R8A774C0_CLK_S0D24, CLK_S0,        24, 1),
+       DEF_FIXED("s1d1",      R8A774C0_CLK_S1D1,  CLK_S1,         1, 1),
+       DEF_FIXED("s1d2",      R8A774C0_CLK_S1D2,  CLK_S1,         2, 1),
+       DEF_FIXED("s1d4",      R8A774C0_CLK_S1D4,  CLK_S1,         4, 1),
+       DEF_FIXED("s2d1",      R8A774C0_CLK_S2D1,  CLK_S2,         1, 1),
+       DEF_FIXED("s2d2",      R8A774C0_CLK_S2D2,  CLK_S2,         2, 1),
+       DEF_FIXED("s2d4",      R8A774C0_CLK_S2D4,  CLK_S2,         4, 1),
+       DEF_FIXED("s3d1",      R8A774C0_CLK_S3D1,  CLK_S3,         1, 1),
+       DEF_FIXED("s3d2",      R8A774C0_CLK_S3D2,  CLK_S3,         2, 1),
+       DEF_FIXED("s3d4",      R8A774C0_CLK_S3D4,  CLK_S3,         4, 1),
+
+       DEF_GEN3_SD("sd0",     R8A774C0_CLK_SD0,   CLK_SDSRC,     0x0074),
+       DEF_GEN3_SD("sd1",     R8A774C0_CLK_SD1,   CLK_SDSRC,     0x0078),
+       DEF_GEN3_SD("sd3",     R8A774C0_CLK_SD3,   CLK_SDSRC,     0x026c),
+
+       DEF_FIXED("cl",        R8A774C0_CLK_CL,    CLK_PLL1,      48, 1),
+       DEF_FIXED("cp",        R8A774C0_CLK_CP,    CLK_EXTAL,      2, 1),
+       DEF_FIXED("cpex",      R8A774C0_CLK_CPEX,  CLK_EXTAL,      4, 1),
+
+       DEF_DIV6_RO("osc",     R8A774C0_CLK_OSC,   CLK_EXTAL, CPG_RCKCR,  8),
+
+       DEF_GEN3_PE("s0d6c",   R8A774C0_CLK_S0D6C, CLK_S0, 6, CLK_PE, 2),
+       DEF_GEN3_PE("s3d1c",   R8A774C0_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
+       DEF_GEN3_PE("s3d2c",   R8A774C0_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
+       DEF_GEN3_PE("s3d4c",   R8A774C0_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
+
+       DEF_DIV6P1("canfd",    R8A774C0_CLK_CANFD, CLK_PLL0D6, 0x244),
+       DEF_DIV6P1("csi0",     R8A774C0_CLK_CSI0,  CLK_PLL1D2, 0x00c),
+       DEF_DIV6P1("mso",      R8A774C0_CLK_MSO,   CLK_PLL1D2, 0x014),
+
+       DEF_GEN3_RCKSEL("r",   R8A774C0_CLK_R, CLK_RINT, 1, CLK_OCO, 61 * 4),
+};
+
+static const struct mssr_mod_clk r8a774c0_mod_clks[] = {
+       DEF_MOD("tmu4",                  121,   R8A774C0_CLK_S0D6C),
+       DEF_MOD("tmu3",                  122,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu2",                  123,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu1",                  124,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu0",                  125,   R8A774C0_CLK_CP),
+       DEF_MOD("scif5",                 202,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("scif4",                 203,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("scif3",                 204,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("scif1",                 206,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("scif0",                 207,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("msiof3",                208,   R8A774C0_CLK_MSO),
+       DEF_MOD("msiof2",                209,   R8A774C0_CLK_MSO),
+       DEF_MOD("msiof1",                210,   R8A774C0_CLK_MSO),
+       DEF_MOD("msiof0",                211,   R8A774C0_CLK_MSO),
+       DEF_MOD("sys-dmac2",             217,   R8A774C0_CLK_S3D1),
+       DEF_MOD("sys-dmac1",             218,   R8A774C0_CLK_S3D1),
+       DEF_MOD("sys-dmac0",             219,   R8A774C0_CLK_S3D1),
+
+       DEF_MOD("cmt3",                  300,   R8A774C0_CLK_R),
+       DEF_MOD("cmt2",                  301,   R8A774C0_CLK_R),
+       DEF_MOD("cmt1",                  302,   R8A774C0_CLK_R),
+       DEF_MOD("cmt0",                  303,   R8A774C0_CLK_R),
+       DEF_MOD("scif2",                 310,   R8A774C0_CLK_S3D4C),
+       DEF_MOD("sdif3",                 311,   R8A774C0_CLK_SD3),
+       DEF_MOD("sdif1",                 313,   R8A774C0_CLK_SD1),
+       DEF_MOD("sdif0",                 314,   R8A774C0_CLK_SD0),
+       DEF_MOD("pcie0",                 319,   R8A774C0_CLK_S3D1),
+       DEF_MOD("usb3-if0",              328,   R8A774C0_CLK_S3D1),
+       DEF_MOD("usb-dmac0",             330,   R8A774C0_CLK_S3D1),
+       DEF_MOD("usb-dmac1",             331,   R8A774C0_CLK_S3D1),
+
+       DEF_MOD("rwdt",                  402,   R8A774C0_CLK_R),
+       DEF_MOD("intc-ex",               407,   R8A774C0_CLK_CP),
+       DEF_MOD("intc-ap",               408,   R8A774C0_CLK_S0D3),
+
+       DEF_MOD("audmac0",               502,   R8A774C0_CLK_S1D2),
+       DEF_MOD("hscif4",                516,   R8A774C0_CLK_S3D1C),
+       DEF_MOD("hscif3",                517,   R8A774C0_CLK_S3D1C),
+       DEF_MOD("hscif2",                518,   R8A774C0_CLK_S3D1C),
+       DEF_MOD("hscif1",                519,   R8A774C0_CLK_S3D1C),
+       DEF_MOD("hscif0",                520,   R8A774C0_CLK_S3D1C),
+       DEF_MOD("thermal",               522,   R8A774C0_CLK_CP),
+       DEF_MOD("pwm",                   523,   R8A774C0_CLK_S3D4C),
+
+       DEF_MOD("fcpvd1",                602,   R8A774C0_CLK_S1D2),
+       DEF_MOD("fcpvd0",                603,   R8A774C0_CLK_S1D2),
+       DEF_MOD("fcpvb0",                607,   R8A774C0_CLK_S0D1),
+       DEF_MOD("fcpvi0",                611,   R8A774C0_CLK_S0D1),
+       DEF_MOD("fcpf0",                 615,   R8A774C0_CLK_S0D1),
+       DEF_MOD("fcpcs",                 619,   R8A774C0_CLK_S0D1),
+       DEF_MOD("vspd1",                 622,   R8A774C0_CLK_S1D2),
+       DEF_MOD("vspd0",                 623,   R8A774C0_CLK_S1D2),
+       DEF_MOD("vspb",                  626,   R8A774C0_CLK_S0D1),
+       DEF_MOD("vspi0",                 631,   R8A774C0_CLK_S0D1),
+
+       DEF_MOD("ehci0",                 703,   R8A774C0_CLK_S3D2),
+       DEF_MOD("hsusb",                 704,   R8A774C0_CLK_S3D2),
+       DEF_MOD("csi40",                 716,   R8A774C0_CLK_CSI0),
+       DEF_MOD("du1",                   723,   R8A774C0_CLK_S1D1),
+       DEF_MOD("du0",                   724,   R8A774C0_CLK_S1D1),
+       DEF_MOD("lvds",                  727,   R8A774C0_CLK_S2D1),
+
+       DEF_MOD("vin5",                  806,   R8A774C0_CLK_S1D2),
+       DEF_MOD("vin4",                  807,   R8A774C0_CLK_S1D2),
+       DEF_MOD("etheravb",              812,   R8A774C0_CLK_S3D2),
+
+       DEF_MOD("gpio6",                 906,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio5",                 907,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio4",                 908,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio3",                 909,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio2",                 910,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio1",                 911,   R8A774C0_CLK_S3D4),
+       DEF_MOD("gpio0",                 912,   R8A774C0_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A774C0_CLK_S3D2),
+       DEF_MOD("can-if1",               915,   R8A774C0_CLK_S3D4),
+       DEF_MOD("can-if0",               916,   R8A774C0_CLK_S3D4),
+       DEF_MOD("i2c6",                  918,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c5",                  919,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c-dvfs",              926,   R8A774C0_CLK_CP),
+       DEF_MOD("i2c4",                  927,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c3",                  928,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c2",                  929,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c1",                  930,   R8A774C0_CLK_S3D2),
+       DEF_MOD("i2c0",                  931,   R8A774C0_CLK_S3D2),
+
+       DEF_MOD("i2c7",                 1003,   R8A774C0_CLK_S3D2),
+       DEF_MOD("ssi-all",              1005,   R8A774C0_CLK_S3D4),
+       DEF_MOD("ssi9",                 1006,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi8",                 1007,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi7",                 1008,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi6",                 1009,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi5",                 1010,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi4",                 1011,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi3",                 1012,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi2",                 1013,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi1",                 1014,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi0",                 1015,   MOD_CLK_ID(1005)),
+       DEF_MOD("scu-all",              1017,   R8A774C0_CLK_S3D4),
+       DEF_MOD("scu-dvc1",             1018,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-dvc0",             1019,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu1-mix1",        1020,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu0-mix0",        1021,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src9",             1022,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src8",             1023,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src7",             1024,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src6",             1025,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src5",             1026,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src4",             1027,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src3",             1028,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src2",             1029,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src1",             1030,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src0",             1031,   MOD_CLK_ID(1017)),
+};
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD19                EXTAL (MHz)     PLL0            PLL1            PLL3
+ *--------------------------------------------------------------------
+ * 0           48 x 1          x100/1          x100/3          x100/3
+ * 1           48 x 1          x100/1          x100/3           x58/3
+ */
+#define CPG_PLL_CONFIG_INDEX(md)       (((md) & BIT(19)) >> 19)
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[2] = {
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div */
+       { 1,            100,    3,      100,    3,      },
+       { 1,            100,    3,       58,    3,      },
+};
+
+static const struct mstp_stop_table r8a774c0_mstp_table[] = {
+       { 0x00200000, 0x0, 0x00200000, 0 },
+       { 0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0 },
+       { 0x340E2FDC, 0x2040, 0x340E2FDC, 0 },
+       { 0xFFFFFFDF, 0x400, 0xFFFFFFDF, 0 },
+       { 0x80000184, 0x180, 0x80000184, 0 },
+       { 0xC3FFFFFF, 0x0, 0xC3FFFFFF, 0 },
+       { 0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0 },
+       { 0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0 },
+       { 0x01F1FFF7, 0x0, 0x01F1FFF7, 0 },
+       { 0xFFFFFFFE, 0x0, 0xFFFFFFFE, 0 },
+       { 0xFFFEFFE0, 0x0, 0xFFFEFFE0, 0 },
+       { 0x000000B7, 0x0, 0x000000B7, 0 },
+};
+
+static const void *r8a774c0_get_pll_config(const u32 cpg_mode)
+{
+       return &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+}
+
+const struct cpg_mssr_info r8a774c0_cpg_mssr_info = {
+       .core_clk               = r8a774c0_core_clks,
+       .core_clk_size          = ARRAY_SIZE(r8a774c0_core_clks),
+       .mod_clk                = r8a774c0_mod_clks,
+       .mod_clk_size           = ARRAY_SIZE(r8a774c0_mod_clks),
+       .mstp_table             = r8a774c0_mstp_table,
+       .mstp_table_size        = ARRAY_SIZE(r8a774c0_mstp_table),
+       .reset_node             = "renesas,r8a774c0-rst",
+       .mod_clk_base           = MOD_CLK_BASE,
+       .clk_extal_id           = CLK_EXTAL,
+       .clk_extalr_id          = ~0,
+       .get_pll_config         = r8a774c0_get_pll_config,
+};
+
+static const struct udevice_id r8a774c0_clk_ids[] = {
+       {
+               .compatible     = "renesas,r8a774c0-cpg-mssr",
+               .data           = (ulong)&r8a774c0_cpg_mssr_info
+       },
+       { }
+};
+
+U_BOOT_DRIVER(clk_r8a774c0) = {
+       .name           = "clk_r8a774c0",
+       .id             = UCLASS_CLK,
+       .of_match       = r8a774c0_clk_ids,
+       .priv_auto_alloc_size = sizeof(struct gen3_clk_priv),
+       .ops            = &gen3_clk_ops,
+       .probe          = gen3_clk_probe,
+       .remove         = gen3_clk_remove,
+};
diff --git a/drivers/clk/renesas/r8a774e1-cpg-mssr.c b/drivers/clk/renesas/r8a774e1-cpg-mssr.c
new file mode 100644 (file)
index 0000000..6cce007
--- /dev/null
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * r8a774e1 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ *
+ * Based on r8a7795-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/bitops.h>
+
+#include <dt-bindings/clock/r8a774e1-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+       /* Core Clock Outputs exported to DT */
+       LAST_DT_CORE_CLK = R8A774E1_CLK_CANFD,
+
+       /* External Input Clocks */
+       CLK_EXTAL,
+       CLK_EXTALR,
+
+       /* Internal Core Clocks */
+       CLK_MAIN,
+       CLK_PLL0,
+       CLK_PLL1,
+       CLK_PLL2,
+       CLK_PLL3,
+       CLK_PLL4,
+       CLK_PLL1_DIV2,
+       CLK_PLL1_DIV4,
+       CLK_S0,
+       CLK_S1,
+       CLK_S2,
+       CLK_S3,
+       CLK_SDSRC,
+       CLK_RPCSRC,
+       CLK_RINT,
+
+       /* Module Clocks */
+       MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a774e1_core_clks[] = {
+       /* External Clock Inputs */
+       DEF_INPUT("extal",      CLK_EXTAL),
+       DEF_INPUT("extalr",     CLK_EXTALR),
+
+       /* Internal Core Clocks */
+       DEF_BASE(".main",       CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+       DEF_BASE(".pll0",       CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+       DEF_BASE(".pll1",       CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+       DEF_BASE(".pll2",       CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+       DEF_BASE(".pll3",       CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+       DEF_BASE(".pll4",       CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+       DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2,     CLK_PLL1,       2, 1),
+       DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4,     CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED(".s0",        CLK_S0,            CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED(".s1",        CLK_S1,            CLK_PLL1_DIV2,  3, 1),
+       DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
+       DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
+       DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+       DEF_BASE(".rpcsrc",     CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+       DEF_BASE("rpc",         R8A774E1_CLK_RPC, CLK_TYPE_GEN3_RPC,
+                CLK_RPCSRC),
+       DEF_BASE("rpcd2",       R8A774E1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
+                R8A774E1_CLK_RPC),
+
+       DEF_GEN3_OSC(".r",      CLK_RINT,          CLK_EXTAL,      32),
+
+       /* Core Clock Outputs */
+       DEF_GEN3_Z("z",         R8A774E1_CLK_Z,     CLK_TYPE_GEN3_Z,  CLK_PLL0, 2, 8),
+       DEF_GEN3_Z("z2",        R8A774E1_CLK_Z2,    CLK_TYPE_GEN3_Z,  CLK_PLL2, 2, 0),
+       DEF_FIXED("ztr",        R8A774E1_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
+       DEF_FIXED("ztrd2",      R8A774E1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+       DEF_FIXED("zt",         R8A774E1_CLK_ZT,    CLK_PLL1_DIV2,  4, 1),
+       DEF_FIXED("zx",         R8A774E1_CLK_ZX,    CLK_PLL1_DIV2,  2, 1),
+       DEF_FIXED("s0d1",       R8A774E1_CLK_S0D1,  CLK_S0,         1, 1),
+       DEF_FIXED("s0d2",       R8A774E1_CLK_S0D2,  CLK_S0,         2, 1),
+       DEF_FIXED("s0d3",       R8A774E1_CLK_S0D3,  CLK_S0,         3, 1),
+       DEF_FIXED("s0d4",       R8A774E1_CLK_S0D4,  CLK_S0,         4, 1),
+       DEF_FIXED("s0d6",       R8A774E1_CLK_S0D6,  CLK_S0,         6, 1),
+       DEF_FIXED("s0d8",       R8A774E1_CLK_S0D8,  CLK_S0,         8, 1),
+       DEF_FIXED("s0d12",      R8A774E1_CLK_S0D12, CLK_S0,        12, 1),
+       DEF_FIXED("s1d2",       R8A774E1_CLK_S1D2,  CLK_S1,         2, 1),
+       DEF_FIXED("s1d4",       R8A774E1_CLK_S1D4,  CLK_S1,         4, 1),
+       DEF_FIXED("s2d1",       R8A774E1_CLK_S2D1,  CLK_S2,         1, 1),
+       DEF_FIXED("s2d2",       R8A774E1_CLK_S2D2,  CLK_S2,         2, 1),
+       DEF_FIXED("s2d4",       R8A774E1_CLK_S2D4,  CLK_S2,         4, 1),
+       DEF_FIXED("s3d1",       R8A774E1_CLK_S3D1,  CLK_S3,         1, 1),
+       DEF_FIXED("s3d2",       R8A774E1_CLK_S3D2,  CLK_S3,         2, 1),
+       DEF_FIXED("s3d4",       R8A774E1_CLK_S3D4,  CLK_S3,         4, 1),
+
+       DEF_GEN3_SD("sd0",      R8A774E1_CLK_SD0,   CLK_SDSRC,     0x074),
+       DEF_GEN3_SD("sd1",      R8A774E1_CLK_SD1,   CLK_SDSRC,     0x078),
+       DEF_GEN3_SD("sd2",      R8A774E1_CLK_SD2,   CLK_SDSRC,     0x268),
+       DEF_GEN3_SD("sd3",      R8A774E1_CLK_SD3,   CLK_SDSRC,     0x26c),
+
+       DEF_FIXED("cl",         R8A774E1_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
+       DEF_FIXED("cr",         R8A774E1_CLK_CR,    CLK_PLL1_DIV4,  2, 1),
+       DEF_FIXED("cp",         R8A774E1_CLK_CP,    CLK_EXTAL,      2, 1),
+       DEF_FIXED("cpex",       R8A774E1_CLK_CPEX,  CLK_EXTAL,      2, 1),
+
+       DEF_DIV6P1("canfd",     R8A774E1_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
+       DEF_DIV6P1("csi0",      R8A774E1_CLK_CSI0,  CLK_PLL1_DIV4, 0x00c),
+       DEF_DIV6P1("mso",       R8A774E1_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
+       DEF_DIV6P1("hdmi",      R8A774E1_CLK_HDMI,  CLK_PLL1_DIV4, 0x250),
+
+       DEF_GEN3_OSC("osc",     R8A774E1_CLK_OSC,   CLK_EXTAL,     8),
+
+       DEF_BASE("r",           R8A774E1_CLK_R,     CLK_TYPE_GEN3_R, CLK_RINT),
+};
+
+static const struct mssr_mod_clk r8a774e1_mod_clks[] = {
+       DEF_MOD("fdp1-1",                118,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fdp1-0",                119,   R8A774E1_CLK_S0D1),
+       DEF_MOD("tmu4",                  121,   R8A774E1_CLK_S0D6),
+       DEF_MOD("tmu3",                  122,   R8A774E1_CLK_S3D2),
+       DEF_MOD("tmu2",                  123,   R8A774E1_CLK_S3D2),
+       DEF_MOD("tmu1",                  124,   R8A774E1_CLK_S3D2),
+       DEF_MOD("tmu0",                  125,   R8A774E1_CLK_CP),
+       DEF_MOD("vcplf",                 130,   R8A774E1_CLK_S2D1),
+       DEF_MOD("vdpb",                  131,   R8A774E1_CLK_S2D1),
+       DEF_MOD("scif5",                 202,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scif4",                 203,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scif3",                 204,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scif1",                 206,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scif0",                 207,   R8A774E1_CLK_S3D4),
+       DEF_MOD("msiof3",                208,   R8A774E1_CLK_MSO),
+       DEF_MOD("msiof2",                209,   R8A774E1_CLK_MSO),
+       DEF_MOD("msiof1",                210,   R8A774E1_CLK_MSO),
+       DEF_MOD("msiof0",                211,   R8A774E1_CLK_MSO),
+       DEF_MOD("sys-dmac2",             217,   R8A774E1_CLK_S3D1),
+       DEF_MOD("sys-dmac1",             218,   R8A774E1_CLK_S3D1),
+       DEF_MOD("sys-dmac0",             219,   R8A774E1_CLK_S0D3),
+       DEF_MOD("cmt3",                  300,   R8A774E1_CLK_R),
+       DEF_MOD("cmt2",                  301,   R8A774E1_CLK_R),
+       DEF_MOD("cmt1",                  302,   R8A774E1_CLK_R),
+       DEF_MOD("cmt0",                  303,   R8A774E1_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scif2",                 310,   R8A774E1_CLK_S3D4),
+       DEF_MOD("sdif3",                 311,   R8A774E1_CLK_SD3),
+       DEF_MOD("sdif2",                 312,   R8A774E1_CLK_SD2),
+       DEF_MOD("sdif1",                 313,   R8A774E1_CLK_SD1),
+       DEF_MOD("sdif0",                 314,   R8A774E1_CLK_SD0),
+       DEF_MOD("pcie1",                 318,   R8A774E1_CLK_S3D1),
+       DEF_MOD("pcie0",                 319,   R8A774E1_CLK_S3D1),
+       DEF_MOD("usb3-if0",              328,   R8A774E1_CLK_S3D1),
+       DEF_MOD("usb-dmac0",             330,   R8A774E1_CLK_S3D1),
+       DEF_MOD("usb-dmac1",             331,   R8A774E1_CLK_S3D1),
+       DEF_MOD("rwdt",                  402,   R8A774E1_CLK_R),
+       DEF_MOD("intc-ex",               407,   R8A774E1_CLK_CP),
+       DEF_MOD("intc-ap",               408,   R8A774E1_CLK_S0D3),
+       DEF_MOD("audmac1",               501,   R8A774E1_CLK_S1D2),
+       DEF_MOD("audmac0",               502,   R8A774E1_CLK_S1D2),
+       DEF_MOD("hscif4",                516,   R8A774E1_CLK_S3D1),
+       DEF_MOD("hscif3",                517,   R8A774E1_CLK_S3D1),
+       DEF_MOD("hscif2",                518,   R8A774E1_CLK_S3D1),
+       DEF_MOD("hscif1",                519,   R8A774E1_CLK_S3D1),
+       DEF_MOD("hscif0",                520,   R8A774E1_CLK_S3D1),
+       DEF_MOD("thermal",               522,   R8A774E1_CLK_CP),
+       DEF_MOD("pwm",                   523,   R8A774E1_CLK_S0D12),
+       DEF_MOD("fcpvd1",                602,   R8A774E1_CLK_S0D2),
+       DEF_MOD("fcpvd0",                603,   R8A774E1_CLK_S0D2),
+       DEF_MOD("fcpvb1",                606,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpvb0",                607,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpvi1",                610,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpvi0",                611,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpf1",                 614,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpf0",                 615,   R8A774E1_CLK_S0D1),
+       DEF_MOD("fcpcs",                 619,   R8A774E1_CLK_S0D1),
+       DEF_MOD("vspd1",                 622,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vspd0",                 623,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vspbc",                 624,   R8A774E1_CLK_S0D1),
+       DEF_MOD("vspbd",                 626,   R8A774E1_CLK_S0D1),
+       DEF_MOD("vspi1",                 630,   R8A774E1_CLK_S0D1),
+       DEF_MOD("vspi0",                 631,   R8A774E1_CLK_S0D1),
+       DEF_MOD("ehci1",                 702,   R8A774E1_CLK_S3D2),
+       DEF_MOD("ehci0",                 703,   R8A774E1_CLK_S3D2),
+       DEF_MOD("hsusb",                 704,   R8A774E1_CLK_S3D2),
+       DEF_MOD("csi20",                 714,   R8A774E1_CLK_CSI0),
+       DEF_MOD("csi40",                 716,   R8A774E1_CLK_CSI0),
+       DEF_MOD("du3",                   721,   R8A774E1_CLK_S2D1),
+       DEF_MOD("du1",                   723,   R8A774E1_CLK_S2D1),
+       DEF_MOD("du0",                   724,   R8A774E1_CLK_S2D1),
+       DEF_MOD("lvds",                  727,   R8A774E1_CLK_S0D4),
+       DEF_MOD("hdmi0",                 729,   R8A774E1_CLK_HDMI),
+       DEF_MOD("vin7",                  804,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin6",                  805,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin5",                  806,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin4",                  807,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin3",                  808,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin2",                  809,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin1",                  810,   R8A774E1_CLK_S0D2),
+       DEF_MOD("vin0",                  811,   R8A774E1_CLK_S0D2),
+       DEF_MOD("etheravb",              812,   R8A774E1_CLK_S0D6),
+       DEF_MOD("sata0",                 815,   R8A774E1_CLK_S3D2),
+       DEF_MOD("gpio7",                 905,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio6",                 906,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio5",                 907,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio4",                 908,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio3",                 909,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio2",                 910,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio1",                 911,   R8A774E1_CLK_S3D4),
+       DEF_MOD("gpio0",                 912,   R8A774E1_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A774E1_CLK_S3D2),
+       DEF_MOD("can-if1",               915,   R8A774E1_CLK_S3D4),
+       DEF_MOD("can-if0",               916,   R8A774E1_CLK_S3D4),
+       DEF_MOD("rpc-if",                917,   R8A774E1_CLK_RPCD2),
+       DEF_MOD("i2c6",                  918,   R8A774E1_CLK_S0D6),
+       DEF_MOD("i2c5",                  919,   R8A774E1_CLK_S0D6),
+       DEF_MOD("adg",                   922,   R8A774E1_CLK_S0D1),
+       DEF_MOD("i2c-dvfs",              926,   R8A774E1_CLK_CP),
+       DEF_MOD("i2c4",                  927,   R8A774E1_CLK_S0D6),
+       DEF_MOD("i2c3",                  928,   R8A774E1_CLK_S0D6),
+       DEF_MOD("i2c2",                  929,   R8A774E1_CLK_S3D2),
+       DEF_MOD("i2c1",                  930,   R8A774E1_CLK_S3D2),
+       DEF_MOD("i2c0",                  931,   R8A774E1_CLK_S3D2),
+       DEF_MOD("ssi-all",              1005,   R8A774E1_CLK_S3D4),
+       DEF_MOD("ssi9",                 1006,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi8",                 1007,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi7",                 1008,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi6",                 1009,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi5",                 1010,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi4",                 1011,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi3",                 1012,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi2",                 1013,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi1",                 1014,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi0",                 1015,   MOD_CLK_ID(1005)),
+       DEF_MOD("scu-all",              1017,   R8A774E1_CLK_S3D4),
+       DEF_MOD("scu-dvc1",             1018,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-dvc0",             1019,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu1-mix1",        1020,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu0-mix0",        1021,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src9",             1022,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src8",             1023,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src7",             1024,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src6",             1025,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src5",             1026,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src4",             1027,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src3",             1028,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src2",             1029,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src1",             1030,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src0",             1031,   MOD_CLK_ID(1017)),
+};
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ *   MD                EXTAL           PLL0    PLL1    PLL2    PLL3    PLL4    OSC
+ * 14 13 19 17 (MHz)
+ *-------------------------------------------------------------------------
+ * 0  0  0  0  16.66 x 1       x180    x192    x144    x192    x144    /16
+ * 0  0  0  1  16.66 x 1       x180    x192    x144    x128    x144    /16
+ * 0  0  1  0  Prohibited setting
+ * 0  0  1  1  16.66 x 1       x180    x192    x144    x192    x144    /16
+ * 0  1  0  0  20    x 1       x150    x160    x120    x160    x120    /19
+ * 0  1  0  1  20    x 1       x150    x160    x120    x106    x120    /19
+ * 0  1  1  0  Prohibited setting
+ * 0  1  1  1  20    x 1       x150    x160    x120    x160    x120    /19
+ * 1  0  0  0  25    x 1       x120    x128    x96     x128    x96     /24
+ * 1  0  0  1  25    x 1       x120    x128    x96     x84     x96     /24
+ * 1  0  1  0  Prohibited setting
+ * 1  0  1  1  25    x 1       x120    x128    x96     x128    x96     /24
+ * 1  1  0  0  33.33 / 2       x180    x192    x144    x192    x144    /32
+ * 1  1  0  1  33.33 / 2       x180    x192    x144    x128    x144    /32
+ * 1  1  1  0  Prohibited setting
+ * 1  1  1  1  33.33 / 2       x180    x192    x144    x192    x144    /32
+ */
+#define CPG_PLL_CONFIG_INDEX(md)       ((((md) & BIT(14)) >> 11) | \
+                                        (((md) & BIT(13)) >> 11) | \
+                                        (((md) & BIT(19)) >> 18) | \
+                                        (((md) & BIT(17)) >> 17))
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] = {
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div   OSC prediv */
+       { 1,            192,    1,      192,    1,      16,     },
+       { 1,            192,    1,      128,    1,      16,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            192,    1,      192,    1,      16,     },
+       { 1,            160,    1,      160,    1,      19,     },
+       { 1,            160,    1,      106,    1,      19,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            160,    1,      160,    1,      19,     },
+       { 1,            128,    1,      128,    1,      24,     },
+       { 1,            128,    1,      84,     1,      24,     },
+       { 0, /* Prohibited setting */                           },
+       { 1,            128,    1,      128,    1,      24,     },
+       { 2,            192,    1,      192,    1,      32,     },
+       { 2,            192,    1,      128,    1,      32,     },
+       { 0, /* Prohibited setting */                           },
+       { 2,            192,    1,      192,    1,      32,     },
+};
+
+/* RMSTPCR[0-11] is not present on RZ/G2H */
+static const struct mstp_stop_table r8a774e1_mstp_table[] = {
+       { 0x00640800, 0x0, 0x0, 0 },
+       { 0xF3EE9390, 0x0, 0x0, 0 },
+       { 0x340FAFDC, 0x2040, 0x0, 0 },
+       { 0xD80C7CDF, 0x400, 0x0, 0 },
+       { 0x80000184, 0x180, 0x0, 0 },
+       { 0x40BFFF46, 0x0, 0x0, 0 },
+       { 0xE5FBEECF, 0x0, 0x0, 0 },
+       { 0x39FFFF0E, 0x0, 0x0, 0 },
+       { 0x01F19FF4, 0x0, 0x0, 0 },
+       { 0xFFDFFFFF, 0x0, 0x0, 0 },
+       { 0xFFFEFFE0, 0x0, 0x0, 0 },
+       { 0x00000000, 0x0, 0x0, 0 },
+};
+
+static const void *r8a774e1_get_pll_config(const u32 cpg_mode)
+{
+       return &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+}
+
+static const struct cpg_mssr_info r8a774e1_cpg_mssr_info = {
+       .core_clk               = r8a774e1_core_clks,
+       .core_clk_size          = ARRAY_SIZE(r8a774e1_core_clks),
+       .mod_clk                = r8a774e1_mod_clks,
+       .mod_clk_size           = ARRAY_SIZE(r8a774e1_mod_clks),
+       .mstp_table             = r8a774e1_mstp_table,
+       .mstp_table_size        = ARRAY_SIZE(r8a774e1_mstp_table),
+       .reset_node             = "renesas,r8a774e1-rst",
+       .extalr_node            = "extalr",
+       .mod_clk_base           = MOD_CLK_BASE,
+       .clk_extal_id           = CLK_EXTAL,
+       .clk_extalr_id          = CLK_EXTALR,
+       .get_pll_config         = r8a774e1_get_pll_config,
+};
+
+static const struct udevice_id r8a774e1_clk_ids[] = {
+       {
+               .compatible     = "renesas,r8a774e1-cpg-mssr",
+               .data           = (ulong)&r8a774e1_cpg_mssr_info
+       },
+       { }
+};
+
+U_BOOT_DRIVER(clk_r8a774e1) = {
+       .name           = "clk_r8a774e1",
+       .id             = UCLASS_CLK,
+       .of_match       = r8a774e1_clk_ids,
+       .priv_auto_alloc_size = sizeof(struct gen3_clk_priv),
+       .ops            = &gen3_clk_ops,
+       .probe          = gen3_clk_probe,
+       .remove         = gen3_clk_remove,
+};
index de22e49..b13fc0b 100644 (file)
 #define IP2_11_8       FM(AVB_MDC)             F_(0, 0)                F_(0, 0)                F_(0, 0)                F_(0, 0)                F_(0, 0)        F_(0, 0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP2_15_12      FM(BS_N)                FM(PWM0_A)              FM(AVB_MAGIC)           FM(VI4_CLK)             F_(0, 0)                FM(TX3_C)       F_(0, 0)        FM(VI5_CLK_B)   F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP2_19_16      FM(RD_N)                FM(PWM1_A)              FM(AVB_LINK)            FM(VI4_FIELD)           F_(0, 0)                FM(RX3_C)       FM(FSCLKST2_N_A) FM(VI5_DATA0_B) F_(0, 0)       F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2_23_20      FM(RD_WR_N)             FM(SCL7_A)              FM(AVB_AVTP_MATCH_A)    FM(VI4_VSYNC_N)         FM(TX5_B)               FM(SCK3_C)      FM(PWM5_A)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2_27_24      FM(EX_WAIT0)            FM(SDA7_A)              FM(AVB_AVTP_CAPTURE_A)  FM(VI4_HSYNC_N)         FM(RX5_B)               FM(PWM6_A)      F_(0, 0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2_23_20      FM(RD_WR_N)             FM(SCL7_A)              FM(AVB_AVTP_MATCH)      FM(VI4_VSYNC_N)         FM(TX5_B)               FM(SCK3_C)      FM(PWM5_A)      F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2_27_24      FM(EX_WAIT0)            FM(SDA7_A)              FM(AVB_AVTP_CAPTURE)    FM(VI4_HSYNC_N)         FM(RX5_B)               FM(PWM6_A)      F_(0, 0)        F_(0, 0)        F_(0, 0)        F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP2_31_28      FM(A0)                  FM(IRQ0)                FM(PWM2_A)              FM(MSIOF3_SS1_B)        FM(VI5_CLK_A)           FM(DU_CDE)      FM(HRX3_D)      FM(IERX)        FM(QSTB_QHE)    F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP3_3_0                FM(A1)                  FM(IRQ1)                FM(PWM3_A)              FM(DU_DOTCLKIN1)        FM(VI5_DATA0_A)         FM(DU_DISP_CDE) FM(SDA6_B)      FM(IETX)        FM(QCPV_QDE)    F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
 #define IP3_7_4                FM(A2)                  FM(IRQ2)                FM(AVB_AVTP_PPS)        FM(VI4_CLKENB)          FM(VI5_DATA1_A)         FM(DU_DISP)     FM(SCL6_B)      F_(0, 0)        FM(QSTVB_QVE)   F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -433,6 +433,8 @@ FM(IP12_31_28)      IP12_31_28      FM(IP13_31_28)  IP13_31_28      FM(IP14_31_28)  IP14_31_28      FM
 #define MOD_SEL0_1_0      REV4(FM(SEL_SPEED_PULSE_IF_0),       FM(SEL_SPEED_PULSE_IF_1),       FM(SEL_SPEED_PULSE_IF_2),       F_(0, 0))
 
 /* MOD_SEL1 */                 /* 0 */                         /* 1 */                         /* 2 */                         /* 3 */                 /* 4 */                 /* 5 */         /* 6 */         /* 7 */
+#define MOD_SEL1_31            FM(SEL_SIMCARD_0)               FM(SEL_SIMCARD_1)
+#define MOD_SEL1_30            FM(SEL_SSI2_0)                  FM(SEL_SSI2_1)
 #define MOD_SEL1_29            FM(SEL_TIMER_TMU_0)             FM(SEL_TIMER_TMU_1)
 #define MOD_SEL1_28            FM(SEL_USB_20_CH0_0)            FM(SEL_USB_20_CH0_1)
 #define MOD_SEL1_26            FM(SEL_DRIF2_0)                 FM(SEL_DRIF2_1)
@@ -453,7 +455,8 @@ FM(IP12_31_28)      IP12_31_28      FM(IP13_31_28)  IP13_31_28      FM(IP14_31_28)  IP14_31_28      FM
 
 #define PINMUX_MOD_SELS        \
 \
-MOD_SEL0_30_29 \
+                       MOD_SEL1_31 \
+MOD_SEL0_30_29         MOD_SEL1_30 \
                        MOD_SEL1_29 \
 MOD_SEL0_28            MOD_SEL1_28 \
 MOD_SEL0_27_26 \
@@ -619,7 +622,7 @@ static const u16 pinmux_data[] = {
 
        PINMUX_IPSR_GPSR(IP2_23_20,             RD_WR_N),
        PINMUX_IPSR_MSEL(IP2_23_20,             SCL7_A,         SEL_I2C7_0),
-       PINMUX_IPSR_GPSR(IP2_23_20,             AVB_AVTP_MATCH_A),
+       PINMUX_IPSR_GPSR(IP2_23_20,             AVB_AVTP_MATCH),
        PINMUX_IPSR_GPSR(IP2_23_20,             VI4_VSYNC_N),
        PINMUX_IPSR_GPSR(IP2_23_20,             TX5_B),
        PINMUX_IPSR_MSEL(IP2_23_20,             SCK3_C,         SEL_SCIF3_2),
@@ -627,7 +630,7 @@ static const u16 pinmux_data[] = {
 
        PINMUX_IPSR_GPSR(IP2_27_24,             EX_WAIT0),
        PINMUX_IPSR_MSEL(IP2_27_24,             SDA7_A,         SEL_I2C7_0),
-       PINMUX_IPSR_GPSR(IP2_27_24,             AVB_AVTP_CAPTURE_A),
+       PINMUX_IPSR_GPSR(IP2_27_24,             AVB_AVTP_CAPTURE),
        PINMUX_IPSR_GPSR(IP2_27_24,             VI4_HSYNC_N),
        PINMUX_IPSR_MSEL(IP2_27_24,             RX5_B,          SEL_SCIF5_1),
        PINMUX_IPSR_MSEL(IP2_27_24,             PWM6_A,         SEL_PWM6_0),
@@ -1043,7 +1046,7 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP10_27_24,            RIF0_CLK_B,     SEL_DRIF0_1),
        PINMUX_IPSR_MSEL(IP10_27_24,            SCL2_B,         SEL_I2C2_1),
        PINMUX_IPSR_MSEL(IP10_27_24,            TCLK1_A,        SEL_TIMER_TMU_0),
-       PINMUX_IPSR_GPSR(IP10_27_24,            SSI_SCK2_B),
+       PINMUX_IPSR_MSEL(IP10_27_24,            SSI_SCK2_B,     SEL_SSI2_1),
        PINMUX_IPSR_GPSR(IP10_27_24,            TS_SCK0),
 
        PINMUX_IPSR_GPSR(IP10_31_28,            SD0_WP),
@@ -1052,7 +1055,7 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP10_31_28,            RIF0_D0_B,      SEL_DRIF0_1),
        PINMUX_IPSR_MSEL(IP10_31_28,            SDA2_B,         SEL_I2C2_1),
        PINMUX_IPSR_MSEL(IP10_31_28,            TCLK2_A,        SEL_TIMER_TMU_0),
-       PINMUX_IPSR_GPSR(IP10_31_28,            SSI_WS2_B),
+       PINMUX_IPSR_MSEL(IP10_31_28,            SSI_WS2_B,      SEL_SSI2_1),
        PINMUX_IPSR_GPSR(IP10_31_28,            TS_SDAT0),
 
        /* IPSR11 */
@@ -1070,13 +1073,13 @@ static const u16 pinmux_data[] = {
 
        PINMUX_IPSR_MSEL(IP11_11_8,             RX0_A,          SEL_SCIF0_0),
        PINMUX_IPSR_MSEL(IP11_11_8,             HRX1_A,         SEL_HSCIF1_0),
-       PINMUX_IPSR_GPSR(IP11_11_8,             SSI_SCK2_A),
+       PINMUX_IPSR_MSEL(IP11_11_8,             SSI_SCK2_A,     SEL_SSI2_0),
        PINMUX_IPSR_GPSR(IP11_11_8,             RIF1_SYNC),
        PINMUX_IPSR_GPSR(IP11_11_8,             TS_SCK1),
 
        PINMUX_IPSR_MSEL(IP11_15_12,            TX0_A,          SEL_SCIF0_0),
        PINMUX_IPSR_GPSR(IP11_15_12,            HTX1_A),
-       PINMUX_IPSR_GPSR(IP11_15_12,            SSI_WS2_A),
+       PINMUX_IPSR_MSEL(IP11_15_12,            SSI_WS2_A,      SEL_SSI2_0),
        PINMUX_IPSR_GPSR(IP11_15_12,            RIF1_D0),
        PINMUX_IPSR_GPSR(IP11_15_12,            TS_SDAT1),
 
@@ -1181,7 +1184,7 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_MSEL(IP13_19_16,            RIF0_D1_A,      SEL_DRIF0_0),
        PINMUX_IPSR_MSEL(IP13_19_16,            SDA1_B,         SEL_I2C1_1),
        PINMUX_IPSR_MSEL(IP13_19_16,            TCLK2_B,        SEL_TIMER_TMU_1),
-       PINMUX_IPSR_GPSR(IP13_19_16,            SIM0_D_A),
+       PINMUX_IPSR_MSEL(IP13_19_16,            SIM0_D_A,       SEL_SIMCARD_0),
 
        PINMUX_IPSR_GPSR(IP13_23_20,            MLB_DAT),
        PINMUX_IPSR_MSEL(IP13_23_20,            TX0_B,          SEL_SCIF0_1),
@@ -1249,7 +1252,7 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_GPSR(IP15_15_12,            TPU0TO2),
        PINMUX_IPSR_MSEL(IP15_15_12,            SDA1_D,         SEL_I2C1_3),
        PINMUX_IPSR_MSEL(IP15_15_12,            FSO_CFE_1_N_B,  SEL_FSO_1),
-       PINMUX_IPSR_GPSR(IP15_15_12,            SIM0_D_B),
+       PINMUX_IPSR_MSEL(IP15_15_12,            SIM0_D_B,       SEL_SIMCARD_1),
 
        PINMUX_IPSR_GPSR(IP15_19_16,            SSI_SDATA6),
        PINMUX_IPSR_MSEL(IP15_19_16,            HRTS2_N_A,      SEL_HSCIF2_0),
@@ -1534,22 +1537,22 @@ static const unsigned int avb_avtp_pps_mux[] = {
        AVB_AVTP_PPS_MARK,
 };
 
-static const unsigned int avb_avtp_match_a_pins[] = {
-       /* AVB_AVTP_MATCH_A */
+static const unsigned int avb_avtp_match_pins[] = {
+       /* AVB_AVTP_MATCH */
        RCAR_GP_PIN(2, 24),
 };
 
-static const unsigned int avb_avtp_match_a_mux[] = {
-       AVB_AVTP_MATCH_A_MARK,
+static const unsigned int avb_avtp_match_mux[] = {
+       AVB_AVTP_MATCH_MARK,
 };
 
-static const unsigned int avb_avtp_capture_a_pins[] = {
-       /* AVB_AVTP_CAPTURE_A */
+static const unsigned int avb_avtp_capture_pins[] = {
+       /* AVB_AVTP_CAPTURE */
        RCAR_GP_PIN(2, 25),
 };
 
-static const unsigned int avb_avtp_capture_a_mux[] = {
-       AVB_AVTP_CAPTURE_A_MARK,
+static const unsigned int avb_avtp_capture_mux[] = {
+       AVB_AVTP_CAPTURE_MARK,
 };
 
 /* - CAN ------------------------------------------------------------------ */
@@ -3794,8 +3797,8 @@ static const struct {
                SH_PFC_PIN_GROUP(avb_phy_int),
                SH_PFC_PIN_GROUP(avb_mii),
                SH_PFC_PIN_GROUP(avb_avtp_pps),
-               SH_PFC_PIN_GROUP(avb_avtp_match_a),
-               SH_PFC_PIN_GROUP(avb_avtp_capture_a),
+               SH_PFC_PIN_GROUP(avb_avtp_match),
+               SH_PFC_PIN_GROUP(avb_avtp_capture),
                SH_PFC_PIN_GROUP(can0_data),
                SH_PFC_PIN_GROUP(can1_data),
                SH_PFC_PIN_GROUP(can_clk),
@@ -4071,8 +4074,8 @@ static const char * const avb_groups[] = {
        "avb_phy_int",
        "avb_mii",
        "avb_avtp_pps",
-       "avb_avtp_match_a",
-       "avb_avtp_capture_a",
+       "avb_avtp_match",
+       "avb_avtp_capture",
 };
 
 static const char * const can0_groups[] = {
@@ -4967,11 +4970,11 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                MOD_SEL0_1_0 ))
        },
        { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xe6060504, 32,
-                            GROUP(2, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1,
-                                  2, 2, 2, 1, 1, 2, 1, 4),
+                            GROUP(1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1,
+                                  1, 2, 2, 2, 1, 1, 2, 1, 4),
                             GROUP(
-               /* RESERVED 31, 30 */
-               0, 0, 0, 0,
+               MOD_SEL1_31
+               MOD_SEL1_30
                MOD_SEL1_29
                MOD_SEL1_28
                /* RESERVED 27 */
index 3ea59b8..d0ff918 100644 (file)
@@ -448,12 +448,13 @@ static const struct dm_spi_ops rpc_spi_ops = {
 };
 
 static const struct udevice_id rpc_spi_ids[] = {
+       { .compatible = "renesas,rpc-r7s72100" },
        { .compatible = "renesas,rpc-r8a7795" },
        { .compatible = "renesas,rpc-r8a7796" },
        { .compatible = "renesas,rpc-r8a77965" },
        { .compatible = "renesas,rpc-r8a77970" },
        { .compatible = "renesas,rpc-r8a77995" },
-       { .compatible = "renesas,rpc-r7s72100" },
+       { .compatible = "renesas,rcar-gen3-rpc" },
        { }
 };
 
index 34881a1..fedc013 100644 (file)
@@ -72,6 +72,8 @@ source "drivers/usb/cdns3/Kconfig"
 
 source "drivers/usb/dwc3/Kconfig"
 
+source "drivers/usb/mtu3/Kconfig"
+
 source "drivers/usb/musb/Kconfig"
 
 source "drivers/usb/musb-new/Kconfig"
index d4ae186..5e5c3c3 100644 (file)
@@ -46,8 +46,16 @@ static const char *const speed_names[] = {
        [USB_SPEED_HIGH] = "high-speed",
        [USB_SPEED_WIRELESS] = "wireless",
        [USB_SPEED_SUPER] = "super-speed",
+       [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
+const char *usb_speed_string(enum usb_device_speed speed)
+{
+       if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
+               speed = USB_SPEED_UNKNOWN;
+       return speed_names[speed];
+}
+
 enum usb_device_speed usb_get_maximum_speed(ofnode node)
 {
        const char *max_speed;
index 1c0505e..f17009a 100644 (file)
@@ -421,6 +421,9 @@ static void process_ep_out_intr(struct dwc2_udc *dev)
 {
        u32 ep_intr, ep_intr_status;
        u8 ep_num = 0;
+       u32 ep_tsr = 0, xfer_size = 0;
+       u32 epsiz_reg = reg->out_endp[ep_num].doeptsiz;
+       u32 req_size = sizeof(struct usb_ctrlrequest);
 
        ep_intr = readl(&reg->daint);
        debug_cond(DEBUG_OUT_EP != 0,
@@ -441,10 +444,17 @@ static void process_ep_out_intr(struct dwc2_udc *dev)
 
                        if (ep_num == 0) {
                                if (ep_intr_status & TRANSFER_DONE) {
-                                       if (dev->ep0state !=
-                                           WAIT_FOR_OUT_COMPLETE)
+                                       ep_tsr = readl(&epsiz_reg);
+                                       xfer_size = ep_tsr &
+                                                  DOEPT_SIZ_XFER_SIZE_MAX_EP0;
+
+                                       if (xfer_size == req_size &&
+                                           dev->ep0state == WAIT_FOR_SETUP) {
+                                               dwc2_udc_pre_setup();
+                                       } else if (dev->ep0state !=
+                                                  WAIT_FOR_OUT_COMPLETE) {
                                                complete_rx(dev, ep_num);
-                                       else {
+                                       else {
                                                dev->ep0state = WAIT_FOR_SETUP;
                                                dwc2_udc_pre_setup();
                                        }
index 587204c..0cdf47c 100644 (file)
 #define gadget_is_max3420(g)        0
 #endif
 
+#ifdef CONFIG_USB_MTU3_GADGET
+#define gadget_is_mtu3(g)        (!strcmp("mtu3-gadget", (g)->name))
+#else
+#define gadget_is_mtu3(g)        0
+#endif
+
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
  * @gadget: the controller being driven
@@ -224,5 +230,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x24;
        else if (gadget_is_max3420(gadget))
                return 0x25;
+       else if (gadget_is_mtu3(gadget))
+               return 0x26;
        return -ENOENT;
 }
index 0b49614..b002d6f 100644 (file)
@@ -279,10 +279,10 @@ static struct xhci_segment *xhci_segment_alloc(void)
 {
        struct xhci_segment *seg;
 
-       seg = (struct xhci_segment *)malloc(sizeof(struct xhci_segment));
+       seg = malloc(sizeof(struct xhci_segment));
        BUG_ON(!seg);
 
-       seg->trbs = (union xhci_trb *)xhci_malloc(SEGMENT_SIZE);
+       seg->trbs = xhci_malloc(SEGMENT_SIZE);
 
        seg->next = NULL;
 
@@ -309,7 +309,7 @@ struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
        struct xhci_ring *ring;
        struct xhci_segment *prev;
 
-       ring = (struct xhci_ring *)malloc(sizeof(struct xhci_ring));
+       ring = malloc(sizeof(struct xhci_ring));
        BUG_ON(!ring);
 
        if (num_segs == 0)
@@ -425,8 +425,7 @@ static struct xhci_container_ctx
 {
        struct xhci_container_ctx *ctx;
 
-       ctx = (struct xhci_container_ctx *)
-               malloc(sizeof(struct xhci_container_ctx));
+       ctx = malloc(sizeof(struct xhci_container_ctx));
        BUG_ON(!ctx);
 
        BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
@@ -436,7 +435,7 @@ static struct xhci_container_ctx
        if (type == XHCI_CTX_TYPE_INPUT)
                ctx->size += CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
 
-       ctx->bytes = (u8 *)xhci_malloc(ctx->size);
+       ctx->bytes = xhci_malloc(ctx->size);
 
        return ctx;
 }
@@ -458,8 +457,7 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
                return -EEXIST;
        }
 
-       ctrl->devs[slot_id] = (struct xhci_virt_device *)
-                                       malloc(sizeof(struct xhci_virt_device));
+       ctrl->devs[slot_id] = malloc(sizeof(struct xhci_virt_device));
 
        if (!ctrl->devs[slot_id]) {
                puts("Failed to allocate virtual device\n");
@@ -518,8 +516,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
        struct xhci_segment *seg;
 
        /* DCBAA initialization */
-       ctrl->dcbaa = (struct xhci_device_context_array *)
-                       xhci_malloc(sizeof(struct xhci_device_context_array));
+       ctrl->dcbaa = xhci_malloc(sizeof(struct xhci_device_context_array));
        if (ctrl->dcbaa == NULL) {
                puts("unable to allocate DCBA\n");
                return -ENOMEM;
@@ -555,8 +552,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
 
        /* Event ring does not maintain link TRB */
        ctrl->event_ring = xhci_ring_alloc(ERST_NUM_SEGS, false);
-       ctrl->erst.entries = (struct xhci_erst_entry *)
-               xhci_malloc(sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS);
+       ctrl->erst.entries = xhci_malloc(sizeof(struct xhci_erst_entry) *
+                                        ERST_NUM_SEGS);
 
        ctrl->erst.num_entries = ERST_NUM_SEGS;
 
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
new file mode 100644 (file)
index 0000000..a2a5991
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# For MTK USB3.0 IP
+
+config USB_MTU3
+       bool "MediaTek USB3 Dual Role controller"
+       depends on USB_HOST || USB_GADGET
+       depends on ARCH_MEDIATEK
+       help
+         Say Y here if your system runs on MediaTek SoCs with
+         Dual Role SuperSpeed USB controller. You can select usb
+         mode as peripheral role or host role.
+
+         If you don't know what this is, please say N.
+
+if USB_MTU3
+choice
+       bool "MTU3 Mode Selection"
+       default USB_MTU3_GADGET if USB_GADGET
+       default USB_MTU3_HOST if (USB_HOST && !USB_GADGET)
+
+config USB_MTU3_HOST
+       bool "Host only mode"
+       depends on USB_XHCI_HCD
+       help
+         Select this when you want to use MTU3 in host mode only,
+         thereby the gadget feature will be regressed.
+
+config USB_MTU3_GADGET
+       bool "Gadget only mode"
+       depends on USB_GADGET
+       select USB_GADGET_DUALSPEED
+       help
+         Select this when you want to use MTU3 in gadget mode only,
+         thereby the host feature will be regressed.
+
+endchoice
+
+config USB_MTU3_DEBUG
+       bool "Enable Debugging Messages"
+       help
+         Say Y here to enable debugging messages in the MTU3 Driver.
+
+endif
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
new file mode 100644 (file)
index 0000000..234f3a3
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-$(CONFIG_USB_MTU3_DEBUG)       += -DDEBUG
+
+obj-$(CONFIG_USB_MTU3) += mtu3.o
+
+mtu3-y := mtu3_plat.o
+
+obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o
+obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_qmu.o
+obj-$(CONFIG_USB_MTU3_HOST)    += mtu3_host.o
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
new file mode 100644 (file)
index 0000000..8a7ae83
--- /dev/null
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3.h - MediaTek USB3 DRD header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTU3_H__
+#define __MTU3_H__
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <power/regulator.h>
+#include <usb/xhci.h>
+
+struct mtu3;
+struct mtu3_ep;
+struct mtu3_request;
+struct mtu3_host;
+
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+#define MU3D_EP_TXCR0(epnum)   (U3D_TX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR1(epnum)   (U3D_TX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR2(epnum)   (U3D_TX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define MU3D_EP_RXCR0(epnum)   (U3D_RX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR1(epnum)   (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR2(epnum)   (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_RQCSR(epnum)   (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQSAR(epnum)   (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQCPR(epnum)   (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_TQCSR(epnum)   (U3D_TXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQSAR(epnum)   (U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQCPR(epnum)   (U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define SSUSB_U3_CTRL(p)       (U3D_SSUSB_U3_CTRL_0P + ((p) * 0x08))
+#define SSUSB_U2_CTRL(p)       (U3D_SSUSB_U2_CTRL_0P + ((p) * 0x08))
+
+#define MTU3_DRIVER_NAME       "mtu3-gadget"
+#define DMA_ADDR_INVALID       (~(dma_addr_t)0)
+
+#define MTU3_EP_ENABLED                BIT(0)
+#define MTU3_EP_STALL          BIT(1)
+#define MTU3_EP_WEDGE          BIT(2)
+#define MTU3_EP_BUSY           BIT(3)
+
+/* should be set as 1 */
+#define MTU3_U2_IP_SLOT_DEFAULT 1
+#define MTU3_U3_IP_SLOT_DEFAULT (MTU3_U2_IP_SLOT_DEFAULT)
+
+/**
+ * IP TRUNK version
+ * from 0x1003 version, USB3 Gen2 is supported, two changes affect driver:
+ * 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted,
+ *    but not backward compatible
+ * 2. QMU extend buffer length supported
+ */
+#define MTU3_TRUNK_VERS_1003   0x1003
+
+/**
+ * Normally the device works on HS or SS, to simplify fifo management,
+ * devide fifo into some 2*maxp parts, use bitmap to manage it; And
+ * 32 bits size of bitmap is large enough, that means it can manage
+ * up to 32KB/64KB fifo size.
+ * NOTE: MTU3_U2/3IP_EP_FIFO_UNIT should be power of two;
+ *     FIFO size is allocated according to @slot which is 1 by default
+ */
+#define USB_HS_MAXP    512
+#define USB_SS_MAXP    1024
+#define MTU3_U2IP_EP_FIFO_UNIT \
+       ((USB_HS_MAXP) * ((MTU3_U2_IP_SLOT_DEFAULT) + 1))
+#define MTU3_U3IP_EP_FIFO_UNIT \
+       ((USB_SS_MAXP) * ((MTU3_U3_IP_SLOT_DEFAULT) + 1))
+
+#define MTU3_FIFO_BIT_SIZE             32
+#define MTU3_U2_IP_EP0_FIFO_SIZE       64
+
+/**
+ * Maximum size of ep0 response buffer for ch9 requests,
+ * the SET_SEL request uses 6 so far, and GET_STATUS is 2
+ */
+#define EP0_RESPONSE_BUF  6
+
+/* device operated link and speed got from DEVICE_CONF register */
+enum mtu3_speed {
+       MTU3_SPEED_INACTIVE = 0,
+       MTU3_SPEED_FULL = 1,
+       MTU3_SPEED_HIGH = 3,
+       MTU3_SPEED_SUPER = 4,
+       MTU3_SPEED_SUPER_PLUS = 5,
+};
+
+/**
+ * @MU3D_EP0_STATE_SETUP: waits for SETUP or received a SETUP
+ *             without data stage.
+ * @MU3D_EP0_STATE_TX: IN data stage
+ * @MU3D_EP0_STATE_RX: OUT data stage
+ * @MU3D_EP0_STATE_TX_END: the last IN data is transferred, and
+ *             waits for its completion interrupt
+ * @MU3D_EP0_STATE_STALL: ep0 is in stall status, will be auto-cleared
+ *             after receives a SETUP.
+ */
+enum mtu3_g_ep0_state {
+       MU3D_EP0_STATE_SETUP = 1,
+       MU3D_EP0_STATE_TX,
+       MU3D_EP0_STATE_RX,
+       MU3D_EP0_STATE_TX_END,
+       MU3D_EP0_STATE_STALL,
+};
+
+/**
+ * MTU3_DR_FORCE_NONE: automatically switch host and peripheral mode
+ *             by IDPIN signal.
+ * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
+ *             IDPIN signal.
+ * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
+ */
+enum mtu3_dr_force_mode {
+       MTU3_DR_FORCE_NONE = 0,
+       MTU3_DR_FORCE_HOST,
+       MTU3_DR_FORCE_DEVICE,
+};
+
+/**
+ * @mac_base: register base address of MAC, include xHCI and device
+ * @ippc_base: register base address of IP Power and Clock interface (IPPC)
+ * @vusb33_supply: usb3.3V shared by device/host IP
+ * @vbus_supply: vbus 5v of OTG port
+ * @clks: optional clocks, include "sys_ck", "ref_ck", "mcu_ck",
+ *             "dma_ck" and "xhci_ck"
+ * @phys: phys used
+ * @dr_mode: works in which mode:
+ *             host only, device only or dual-role mode
+ */
+struct ssusb_mtk {
+       struct udevice *dev;
+       struct mtu3 *u3d;
+       struct mtu3_host *u3h;
+       void __iomem *mac_base;
+       void __iomem *ippc_base;
+       /* common power & clock */
+       struct udevice *vusb33_supply;
+       struct udevice *vbus_supply;
+       struct clk_bulk clks;
+       struct phy_bulk phys;
+       /* otg */
+       enum usb_dr_mode dr_mode;
+};
+
+/**
+ * @ctrl: xHCI controller, needs to come first in this struct!
+ * @hcd: xHCI's register base address
+ * @u2_ports: number of usb2 host ports
+ * @u3_ports: number of usb3 host ports
+ * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
+ *             disable u3port0, bit1==1 to disable u3port1,... etc
+ */
+struct mtu3_host {
+       struct xhci_ctrl ctrl;
+       struct xhci_hccr *hcd;
+       void __iomem *ippc_base;
+       struct ssusb_mtk *ssusb;
+       struct udevice *dev;
+       u32 u2_ports;
+       u32 u3_ports;
+       u32 u3p_dis_msk;
+};
+
+/**
+ * @base: the base address of fifo
+ * @limit: the bitmap size in bits
+ * @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
+ */
+struct mtu3_fifo_info {
+       u32 base;
+       u32 limit;
+       DECLARE_BITMAP(bitmap, MTU3_FIFO_BIT_SIZE);
+};
+
+/**
+ * General Purpose Descriptor (GPD):
+ *     The format of TX GPD is a little different from RX one.
+ *     And the size of GPD is 16 bytes.
+ *
+ * @flag:
+ *     bit0: Hardware Own (HWO)
+ *     bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported
+ *     bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1
+ *     bit7: Interrupt On Completion (IOC)
+ * @chksum: This is used to validate the contents of this GPD;
+ *     If TXQ_CS_EN / RXQ_CS_EN bit is set, an interrupt is issued
+ *     when checksum validation fails;
+ *     Checksum value is calculated over the 16 bytes of the GPD by default;
+ * @data_buf_len (RX ONLY): This value indicates the length of
+ *     the assigned data buffer
+ * @next_gpd: Physical address of the next GPD
+ * @buffer: Physical address of the data buffer
+ * @buf_len:
+ *     (TX): This value indicates the length of the assigned data buffer
+ *     (RX): The total length of data received
+ * @ext_len: reserved
+ * @ext_flag:
+ *     bit5 (TX ONLY): Zero Length Packet (ZLP),
+ */
+struct qmu_gpd {
+       __u8 flag;
+       __u8 chksum;
+       __le16 data_buf_len;
+       __le32 next_gpd;
+       __le32 buffer;
+       __le16 buf_len;
+       __u8 ext_len;
+       __u8 ext_flag;
+} __packed;
+
+/**
+ * dma: physical base address of GPD segment
+ * start: virtual base address of GPD segment
+ * end: the last GPD element
+ * enqueue: the first empty GPD to use
+ * dequeue: the first completed GPD serviced by ISR
+ * NOTE: the size of GPD ring should be >= 2
+ */
+struct mtu3_gpd_ring {
+       dma_addr_t dma;
+       struct qmu_gpd *start;
+       struct qmu_gpd *end;
+       struct qmu_gpd *enqueue;
+       struct qmu_gpd *dequeue;
+};
+
+/**
+ * @fifo_size: it is (@slot + 1) * @fifo_seg_size
+ * @fifo_seg_size: it is roundup_pow_of_two(@maxp)
+ */
+struct mtu3_ep {
+       struct usb_ep ep;
+       char name[12];
+       struct mtu3 *mtu;
+       u8 epnum;
+       u8 type;
+       u8 is_in;
+       u16 maxp;
+       int slot;
+       u32 fifo_size;
+       u32 fifo_addr;
+       u32 fifo_seg_size;
+       struct mtu3_fifo_info *fifo;
+
+       struct list_head req_list;
+       struct mtu3_gpd_ring gpd_ring;
+       const struct usb_ss_ep_comp_descriptor *comp_desc;
+       const struct usb_endpoint_descriptor *desc;
+
+       int flags;
+};
+
+struct mtu3_request {
+       struct usb_request request;
+       struct list_head list;
+       struct mtu3_ep *mep;
+       struct mtu3 *mtu;
+       struct qmu_gpd *gpd;
+       int epnum;
+};
+
+static inline struct ssusb_mtk *dev_to_ssusb(struct udevice *dev)
+{
+       return dev_get_priv(dev);
+}
+
+/**
+ * struct mtu3 - device driver instance data.
+ * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
+ *             MTU3_U3_IP_SLOT_DEFAULT for U3 IP
+ * @may_wakeup: means device's remote wakeup is enabled
+ * @is_self_powered: is reported in device status and the config descriptor
+ * @delayed_status: true when function drivers ask for delayed status
+ * @gen2cp: compatible with USB3 Gen2 IP
+ * @ep0_req: dummy request used while handling standard USB requests
+ *             for GET_STATUS and SET_SEL
+ * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests
+ */
+struct mtu3 {
+       spinlock_t lock;
+       struct ssusb_mtk *ssusb;
+       struct udevice *dev;
+       void __iomem *mac_base;
+       void __iomem *ippc_base;
+       int irq;
+
+       struct mtu3_fifo_info tx_fifo;
+       struct mtu3_fifo_info rx_fifo;
+
+       struct mtu3_ep *ep_array;
+       struct mtu3_ep *in_eps;
+       struct mtu3_ep *out_eps;
+       struct mtu3_ep *ep0;
+       int num_eps;
+       int slot;
+       int active_ep;
+
+       enum mtu3_g_ep0_state ep0_state;
+       struct usb_gadget g;    /* the gadget */
+       struct usb_gadget_driver *gadget_driver;
+       struct mtu3_request ep0_req;
+       u8 setup_buf[EP0_RESPONSE_BUF];
+       enum usb_device_speed max_speed;
+       enum usb_device_speed speed;
+
+       unsigned is_active:1;
+       unsigned may_wakeup:1;
+       unsigned is_self_powered:1;
+       unsigned test_mode:1;
+       unsigned softconnect:1;
+       unsigned u1_enable:1;
+       unsigned u2_enable:1;
+       unsigned is_u3_ip:1;
+       unsigned delayed_status:1;
+       unsigned gen2cp:1;
+       unsigned force_vbus:1;
+
+       u8 address;
+       u8 test_mode_nr;
+       u32 hw_version;
+};
+
+static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g)
+{
+       return container_of(g, struct mtu3, g);
+}
+
+static inline int is_first_entry(const struct list_head *list,
+                                const struct list_head *head)
+{
+       return list_is_last(head, list);
+}
+
+static inline struct mtu3_request *to_mtu3_request(struct usb_request *req)
+{
+       return req ? container_of(req, struct mtu3_request, request) : NULL;
+}
+
+static inline struct mtu3_ep *to_mtu3_ep(struct usb_ep *ep)
+{
+       return ep ? container_of(ep, struct mtu3_ep, ep) : NULL;
+}
+
+static inline struct mtu3_request *next_request(struct mtu3_ep *mep)
+{
+       if (list_empty(&mep->req_list))
+               return NULL;
+
+       return list_first_entry(&mep->req_list, struct mtu3_request, list);
+}
+
+static inline void mtu3_writel(void __iomem *base, u32 offset, u32 data)
+{
+       writel(data, base + offset);
+}
+
+static inline u32 mtu3_readl(void __iomem *base, u32 offset)
+{
+       return readl(base + offset);
+}
+
+static inline void mtu3_setbits(void __iomem *base, u32 offset, u32 bits)
+{
+       void __iomem *addr = base + offset;
+       u32 tmp = readl(addr);
+
+       writel((tmp | (bits)), addr);
+}
+
+static inline void mtu3_clrbits(void __iomem *base, u32 offset, u32 bits)
+{
+       void __iomem *addr = base + offset;
+       u32 tmp = readl(addr);
+
+       writel((tmp & ~(bits)), addr);
+}
+
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks);
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req);
+void mtu3_req_complete(struct mtu3_ep *mep,
+                      struct usb_request *req, int status);
+
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+                  int interval, int burst, int mult);
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep);
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set);
+void mtu3_ep0_setup(struct mtu3 *mtu);
+void mtu3_start(struct mtu3 *mtu);
+void mtu3_stop(struct mtu3 *mtu);
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed);
+
+int mtu3_gadget_setup(struct mtu3 *mtu);
+void mtu3_gadget_cleanup(struct mtu3 *mtu);
+void mtu3_gadget_reset(struct mtu3 *mtu);
+void mtu3_gadget_suspend(struct mtu3 *mtu);
+void mtu3_gadget_resume(struct mtu3 *mtu);
+void mtu3_gadget_disconnect(struct mtu3 *mtu);
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
+extern const struct usb_ep_ops mtu3_ep0_ops;
+
+#endif
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
new file mode 100644 (file)
index 0000000..28136f8
--- /dev/null
@@ -0,0 +1,838 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_core.c - hardware access layer and gadget init/exit of
+ *                     MediaTek usb3 Dual-Role Controller Driver
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size)
+{
+       struct mtu3_fifo_info *fifo = mep->fifo;
+       struct mtu3 *mtu = mep->mtu;
+       u32 fz_bit;
+
+       mep->fifo_seg_size = mtu->is_u3_ip ? USB_SS_MAXP : USB_HS_MAXP;
+
+       fz_bit = find_first_zero_bit(fifo->bitmap, fifo->limit);
+       if (fz_bit >= fifo->limit)
+               return -EOVERFLOW;
+
+       mep->fifo_size = mep->fifo_seg_size * (mep->slot + 1);
+       mep->fifo_addr = fifo->base + mep->fifo_size * fz_bit;
+       generic_set_bit(fz_bit, fifo->bitmap);
+
+       dev_dbg(mep->mtu->dev, "%s fifo:%#x/%#x, bit: %d\n",
+               __func__, mep->fifo_seg_size, mep->fifo_size, fz_bit);
+
+       return mep->fifo_addr;
+}
+
+static void ep_fifo_free(struct mtu3_ep *mep)
+{
+       struct mtu3_fifo_info *fifo = mep->fifo;
+       u32 addr = mep->fifo_addr;
+       u32 bit;
+
+       if (unlikely(addr < fifo->base))
+               return;
+
+       bit = (addr - fifo->base) / mep->fifo_size;
+       generic_clear_bit(bit, fifo->bitmap);
+       mep->fifo_size = 0;
+       mep->fifo_seg_size = 0;
+
+       dev_dbg(mep->mtu->dev, "%s size:%#x/%#x, bit: %d\n",
+               __func__, mep->fifo_seg_size, mep->fifo_size, bit);
+}
+
+/* enable/disable U3D SS function */
+static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable)
+{
+       /* If usb3_en==0, LTSSM will go to SS.Disable state */
+       if (enable)
+               mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+       else
+               mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+
+       dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable);
+}
+
+/* set/clear U3D HS device soft connect */
+static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable)
+{
+       if (enable) {
+               mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+                            SOFT_CONN | SUSPENDM_ENABLE);
+       } else {
+               mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+                            SOFT_CONN | SUSPENDM_ENABLE);
+       }
+       dev_dbg(mtu->dev, "SOFTCONN = %d\n", !!enable);
+}
+
+/* only port0 of U2/U3 supports device mode */
+static int mtu3_device_enable(struct mtu3 *mtu)
+{
+       void __iomem *ibase = mtu->ippc_base;
+       u32 check_clk = 0;
+
+       mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+
+       if (mtu->is_u3_ip) {
+               check_clk = SSUSB_U3_MAC_RST_B_STS;
+               mtu3_clrbits(ibase, SSUSB_U3_CTRL(0),
+                            (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+                             SSUSB_U3_PORT_HOST_SEL));
+       }
+       mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
+                    (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
+                     SSUSB_U2_PORT_HOST_SEL));
+
+       return ssusb_check_clocks(mtu->ssusb, check_clk);
+}
+
+static void mtu3_device_disable(struct mtu3 *mtu)
+{
+       void __iomem *ibase = mtu->ippc_base;
+
+       if (mtu->is_u3_ip)
+               mtu3_setbits(ibase, SSUSB_U3_CTRL(0),
+                            (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN));
+
+       mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
+                    SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
+
+       mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+}
+
+/* reset U3D's device module. */
+static void mtu3_device_reset(struct mtu3 *mtu)
+{
+       void __iomem *ibase = mtu->ippc_base;
+
+       mtu3_setbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+       udelay(1);
+       mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+}
+
+static void mtu3_intr_status_clear(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+
+       /* Clear EP0 and Tx/Rx EPn interrupts status */
+       mtu3_writel(mbase, U3D_EPISR, ~0x0);
+       /* Clear U2 USB common interrupts status */
+       mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
+       /* Clear U3 LTSSM interrupts status */
+       mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
+       /* Clear speed change interrupt status */
+       mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
+       /* Clear QMU interrupt status */
+       mtu3_writel(mbase, U3D_QISAR0, ~0x0);
+}
+
+/* disable all interrupts */
+static void mtu3_intr_disable(struct mtu3 *mtu)
+{
+       /* Disable level 1 interrupts */
+       mtu3_writel(mtu->mac_base, U3D_LV1IECR, ~0x0);
+       /* Disable endpoint interrupts */
+       mtu3_writel(mtu->mac_base, U3D_EPIECR, ~0x0);
+       mtu3_intr_status_clear(mtu);
+}
+
+/* enable system global interrupt */
+static void mtu3_intr_enable(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 value;
+
+       /*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */
+       value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
+       mtu3_writel(mbase, U3D_LV1IESR, value);
+
+       /* Enable U2 common USB interrupts */
+       value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+       mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value);
+
+       if (mtu->is_u3_ip) {
+               /* Enable U3 LTSSM interrupts */
+               value = HOT_RST_INTR | WARM_RST_INTR |
+                       ENTER_U3_INTR | EXIT_U3_INTR;
+               mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value);
+       }
+
+       /* Enable QMU interrupts. */
+       value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
+                       RXQ_LENERR_INT | RXQ_ZLPERR_INT;
+       mtu3_writel(mbase, U3D_QIESR1, value);
+
+       /* Enable speed change interrupt */
+       mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
+}
+
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
+{
+       void __iomem *mbase = mtu->mac_base;
+
+       if (speed > mtu->max_speed)
+               speed = mtu->max_speed;
+
+       switch (speed) {
+       case USB_SPEED_FULL:
+               /* disable U3 SS function */
+               mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+               /* disable HS function */
+               mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+               break;
+       case USB_SPEED_HIGH:
+               mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+               /* HS/FS detected by HW */
+               mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+               break;
+       case USB_SPEED_SUPER:
+               mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+                            SSUSB_U3_PORT_SSP_SPEED);
+               break;
+       case USB_SPEED_SUPER_PLUS:
+               mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+                            SSUSB_U3_PORT_SSP_SPEED);
+               break;
+       default:
+               dev_err(mtu->dev, "invalid speed: %d\n", speed);
+               return;
+       }
+
+       mtu->speed = speed;
+       dev_dbg(mtu->dev, "set speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+/* reset: u2 - data toggle, u3 - SeqN, flow control status etc */
+static void mtu3_ep_reset(struct mtu3_ep *mep)
+{
+       struct mtu3 *mtu = mep->mtu;
+       u32 rst_bit = EP_RST(mep->is_in, mep->epnum);
+
+       mtu3_setbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+       mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+}
+
+/* set/clear the stall and toggle bits for non-ep0 */
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
+{
+       struct mtu3 *mtu = mep->mtu;
+       void __iomem *mbase = mtu->mac_base;
+       u8 epnum = mep->epnum;
+       u32 csr;
+
+       if (mep->is_in) {       /* TX */
+               csr = mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS;
+               if (set)
+                       csr |= TX_SENDSTALL;
+               else
+                       csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
+               mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr);
+       } else {        /* RX */
+               csr = mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS;
+               if (set)
+                       csr |= RX_SENDSTALL;
+               else
+                       csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
+               mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr);
+       }
+
+       if (!set) {
+               mtu3_ep_reset(mep);
+               mep->flags &= ~MTU3_EP_STALL;
+       } else {
+               mep->flags |= MTU3_EP_STALL;
+       }
+
+       dev_dbg(mtu->dev, "%s: %s\n", mep->name,
+               set ? "SEND STALL" : "CLEAR STALL, with EP RESET");
+}
+
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
+{
+       if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER)
+               mtu3_ss_func_set(mtu, is_on);
+       else
+               mtu3_hs_softconn_set(mtu, is_on);
+
+       dev_info(mtu->dev, "gadget (%s) pullup D%s\n",
+                usb_speed_string(mtu->speed), is_on ? "+" : "-");
+}
+
+void mtu3_start(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+
+       dev_dbg(mtu->dev, "%s devctl 0x%x\n", __func__,
+               mtu3_readl(mbase, U3D_DEVICE_CONTROL));
+
+       /* Initialize the default interrupts */
+       mtu3_intr_enable(mtu);
+       mtu->is_active = 1;
+
+       if (mtu->softconnect)
+               mtu3_dev_on_off(mtu, 1);
+}
+
+void mtu3_stop(struct mtu3 *mtu)
+{
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       mtu3_intr_disable(mtu);
+
+       if (mtu->softconnect)
+               mtu3_dev_on_off(mtu, 0);
+
+       mtu->is_active = 0;
+}
+
+/* for non-ep0 */
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+                  int interval, int burst, int mult)
+{
+       void __iomem *mbase = mtu->mac_base;
+       bool gen2cp = mtu->gen2cp;
+       int epnum = mep->epnum;
+       u32 csr0, csr1, csr2;
+       int fifo_sgsz, fifo_addr;
+       int num_pkts;
+
+       fifo_addr = ep_fifo_alloc(mep, mep->maxp);
+       if (fifo_addr < 0) {
+               dev_err(mtu->dev, "alloc ep fifo failed(%d)\n", mep->maxp);
+               return -ENOMEM;
+       }
+       fifo_sgsz = ilog2(mep->fifo_seg_size);
+       dev_dbg(mtu->dev, "%s fifosz: %x(%x/%x)\n", __func__, fifo_sgsz,
+               mep->fifo_seg_size, mep->fifo_size);
+
+       if (mep->is_in) {
+               csr0 = TX_TXMAXPKTSZ(mep->maxp);
+               csr0 |= TX_DMAREQEN;
+
+               num_pkts = (burst + 1) * (mult + 1) - 1;
+               csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot);
+               csr1 |= TX_MAX_PKT(gen2cp, num_pkts) | TX_MULT(gen2cp, mult);
+
+               csr2 = TX_FIFOADDR(fifo_addr >> 4);
+               csr2 |= TX_FIFOSEGSIZE(fifo_sgsz);
+
+               switch (mep->type) {
+               case USB_ENDPOINT_XFER_BULK:
+                       csr1 |= TX_TYPE(TYPE_BULK);
+                       break;
+               case USB_ENDPOINT_XFER_ISOC:
+                       csr1 |= TX_TYPE(TYPE_ISO);
+                       csr2 |= TX_BINTERVAL(interval);
+                       break;
+               case USB_ENDPOINT_XFER_INT:
+                       csr1 |= TX_TYPE(TYPE_INT);
+                       csr2 |= TX_BINTERVAL(interval);
+                       break;
+               }
+
+               /* Enable QMU Done interrupt */
+               mtu3_setbits(mbase, U3D_QIESR0, QMU_TX_DONE_INT(epnum));
+
+               mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr0);
+               mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), csr1);
+               mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), csr2);
+
+               dev_dbg(mtu->dev, "U3D_TX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+                       epnum, mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)),
+                       mtu3_readl(mbase, MU3D_EP_TXCR1(epnum)),
+                       mtu3_readl(mbase, MU3D_EP_TXCR2(epnum)));
+       } else {
+               csr0 = RX_RXMAXPKTSZ(mep->maxp);
+               csr0 |= RX_DMAREQEN;
+
+               num_pkts = (burst + 1) * (mult + 1) - 1;
+               csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot);
+               csr1 |= RX_MAX_PKT(gen2cp, num_pkts) | RX_MULT(gen2cp, mult);
+
+               csr2 = RX_FIFOADDR(fifo_addr >> 4);
+               csr2 |= RX_FIFOSEGSIZE(fifo_sgsz);
+
+               switch (mep->type) {
+               case USB_ENDPOINT_XFER_BULK:
+                       csr1 |= RX_TYPE(TYPE_BULK);
+                       break;
+               case USB_ENDPOINT_XFER_ISOC:
+                       csr1 |= RX_TYPE(TYPE_ISO);
+                       csr2 |= RX_BINTERVAL(interval);
+                       break;
+               case USB_ENDPOINT_XFER_INT:
+                       csr1 |= RX_TYPE(TYPE_INT);
+                       csr2 |= RX_BINTERVAL(interval);
+                       break;
+               }
+
+               /*Enable QMU Done interrupt */
+               mtu3_setbits(mbase, U3D_QIESR0, QMU_RX_DONE_INT(epnum));
+
+               mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr0);
+               mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), csr1);
+               mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), csr2);
+
+               dev_dbg(mtu->dev, "U3D_RX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+                       epnum, mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)),
+                       mtu3_readl(mbase, MU3D_EP_RXCR1(epnum)),
+                       mtu3_readl(mbase, MU3D_EP_RXCR2(epnum)));
+       }
+
+       dev_dbg(mtu->dev, "csr0:%#x, csr1:%#x, csr2:%#x\n", csr0, csr1, csr2);
+       dev_dbg(mtu->dev, "%s: %s, fifo-addr:%#x, fifo-size:%#x(%#x/%#x)\n",
+               __func__, mep->name, mep->fifo_addr, mep->fifo_size,
+               fifo_sgsz, mep->fifo_seg_size);
+
+       return 0;
+}
+
+/* for non-ep0 */
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep)
+{
+       void __iomem *mbase = mtu->mac_base;
+       int epnum = mep->epnum;
+
+       if (mep->is_in) {
+               mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), 0);
+               mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), 0);
+               mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), 0);
+               mtu3_setbits(mbase, U3D_QIECR0, QMU_TX_DONE_INT(epnum));
+       } else {
+               mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), 0);
+               mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), 0);
+               mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), 0);
+               mtu3_setbits(mbase, U3D_QIECR0, QMU_RX_DONE_INT(epnum));
+       }
+
+       mtu3_ep_reset(mep);
+       ep_fifo_free(mep);
+
+       dev_dbg(mtu->dev, "%s: %s\n", __func__, mep->name);
+}
+
+/*
+ * Two scenarios:
+ * 1. when device IP supports SS, the fifo of EP0, TX EPs, RX EPs
+ *     are separated;
+ * 2. when supports only HS, the fifo is shared for all EPs, and
+ *     the capability registers of @EPNTXFFSZ or @EPNRXFFSZ indicate
+ *     the total fifo size of non-ep0, and ep0's is fixed to 64B,
+ *     so the total fifo size is 64B + @EPNTXFFSZ;
+ *     Due to the first 64B should be reserved for EP0, non-ep0's fifo
+ *     starts from offset 64 and are divided into two equal parts for
+ *     TX or RX EPs for simplification.
+ */
+static void get_ep_fifo_config(struct mtu3 *mtu)
+{
+       struct mtu3_fifo_info *tx_fifo;
+       struct mtu3_fifo_info *rx_fifo;
+       u32 fifosize;
+
+       if (mtu->is_u3_ip) {
+               fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+               tx_fifo = &mtu->tx_fifo;
+               tx_fifo->base = 0;
+               tx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+               bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+               fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNRXFFSZ);
+               rx_fifo = &mtu->rx_fifo;
+               rx_fifo->base = 0;
+               rx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+               bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+               mtu->slot = MTU3_U3_IP_SLOT_DEFAULT;
+       } else {
+               fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+               tx_fifo = &mtu->tx_fifo;
+               tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE;
+               tx_fifo->limit = (fifosize / MTU3_U2IP_EP_FIFO_UNIT) >> 1;
+               bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+               rx_fifo = &mtu->rx_fifo;
+               rx_fifo->base = tx_fifo->base +
+                               tx_fifo->limit * MTU3_U2IP_EP_FIFO_UNIT;
+               rx_fifo->limit = tx_fifo->limit;
+               bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+               mtu->slot = MTU3_U2_IP_SLOT_DEFAULT;
+       }
+
+       dev_dbg(mtu->dev, "%s, TX: base-%d, limit-%d; RX: base-%d, limit-%d\n",
+               __func__, tx_fifo->base, tx_fifo->limit,
+               rx_fifo->base, rx_fifo->limit);
+}
+
+void mtu3_ep0_setup(struct mtu3 *mtu)
+{
+       u32 maxpacket = mtu->g.ep0->maxpacket;
+       u32 csr;
+
+       dev_dbg(mtu->dev, "%s maxpacket: %d\n", __func__, maxpacket);
+
+       csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR);
+       csr &= ~EP0_MAXPKTSZ_MSK;
+       csr |= EP0_MAXPKTSZ(maxpacket);
+       csr &= EP0_W1C_BITS;
+       mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+       /* Enable EP0 interrupt */
+       mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR | SETUPENDISR);
+}
+
+static int mtu3_mem_alloc(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       struct mtu3_ep *ep_array;
+       int in_ep_num, out_ep_num;
+       u32 cap_epinfo;
+       int i;
+
+       cap_epinfo = mtu3_readl(mbase, U3D_CAP_EPINFO);
+       in_ep_num = CAP_TX_EP_NUM(cap_epinfo);
+       out_ep_num = CAP_RX_EP_NUM(cap_epinfo);
+
+       dev_info(mtu->dev, "fifosz/epnum: Tx=%#x/%d, Rx=%#x/%d\n",
+                mtu3_readl(mbase, U3D_CAP_EPNTXFFSZ), in_ep_num,
+                mtu3_readl(mbase, U3D_CAP_EPNRXFFSZ), out_ep_num);
+
+       /* one for ep0, another is reserved */
+       mtu->num_eps = min(in_ep_num, out_ep_num) + 1;
+       ep_array = kcalloc(mtu->num_eps * 2, sizeof(*ep_array), GFP_KERNEL);
+       if (!ep_array)
+               return -ENOMEM;
+
+       mtu->ep_array = ep_array;
+       mtu->in_eps = ep_array;
+       mtu->out_eps = &ep_array[mtu->num_eps];
+       /* ep0 uses in_eps[0], out_eps[0] is reserved */
+       mtu->ep0 = mtu->in_eps;
+       mtu->ep0->mtu = mtu;
+       mtu->ep0->epnum = 0;
+
+       for (i = 1; i < mtu->num_eps; i++) {
+               struct mtu3_ep *mep = mtu->in_eps + i;
+
+               mep->fifo = &mtu->tx_fifo;
+               mep = mtu->out_eps + i;
+               mep->fifo = &mtu->rx_fifo;
+       }
+
+       get_ep_fifo_config(mtu);
+       mtu3_qmu_init(mtu);
+
+       return 0;
+}
+
+static void mtu3_mem_free(struct mtu3 *mtu)
+{
+       mtu3_qmu_exit(mtu);
+       kfree(mtu->ep_array);
+}
+
+static void mtu3_regs_init(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+
+       /* be sure interrupts are disabled before registration of ISR */
+       mtu3_intr_disable(mtu);
+
+       if (mtu->is_u3_ip) {
+               /* disable LGO_U1/U2 by default */
+               mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL,
+                            SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE);
+               /* enable accept LGO_U1/U2 link command from host */
+               mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL,
+                            SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE);
+               /* device responses to u3_exit from host automatically */
+               mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN);
+               /* automatically build U2 link when U3 detect fail */
+               mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH);
+               /* auto clear SOFT_CONN when clear USB3_EN if work as HS */
+               mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN);
+       }
+
+       /* delay about 0.1us from detecting reset to send chirp-K */
+       mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
+       /* U2/U3 detected by HW */
+       mtu3_writel(mbase, U3D_DEVICE_CONF, 0);
+       /* enable automatical HWRW from L1 */
+       mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
+
+       mtu3_set_speed(mtu, mtu->max_speed);
+       ssusb_set_force_mode(mtu->ssusb, MTU3_DR_FORCE_DEVICE);
+
+       if (mtu->force_vbus)
+               mtu3_setbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+       else    /* vbus detected by HW */
+               mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+}
+
+static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       enum usb_device_speed udev_speed;
+       u32 maxpkt = 64;
+       u32 link;
+       u32 speed;
+
+       link = mtu3_readl(mbase, U3D_DEV_LINK_INTR);
+       link &= mtu3_readl(mbase, U3D_DEV_LINK_INTR_ENABLE);
+       mtu3_writel(mbase, U3D_DEV_LINK_INTR, link); /* W1C */
+       dev_dbg(mtu->dev, "=== LINK[%x] ===\n", link);
+
+       if (!(link & SSUSB_DEV_SPEED_CHG_INTR))
+               return IRQ_NONE;
+
+       speed = SSUSB_DEV_SPEED(mtu3_readl(mbase, U3D_DEVICE_CONF));
+
+       switch (speed) {
+       case MTU3_SPEED_FULL:
+               udev_speed = USB_SPEED_FULL;
+               /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+               mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+                           | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+               mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+                            LPM_BESL_STALL | LPM_BESLD_STALL);
+               break;
+       case MTU3_SPEED_HIGH:
+               udev_speed = USB_SPEED_HIGH;
+               /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+               mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+                           | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+               mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+                            LPM_BESL_STALL | LPM_BESLD_STALL);
+               break;
+       case MTU3_SPEED_SUPER:
+               udev_speed = USB_SPEED_SUPER;
+               maxpkt = 512;
+               break;
+       case MTU3_SPEED_SUPER_PLUS:
+               udev_speed = USB_SPEED_SUPER_PLUS;
+               maxpkt = 512;
+               break;
+       default:
+               udev_speed = USB_SPEED_UNKNOWN;
+               break;
+       }
+       dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed));
+
+       mtu->g.speed = udev_speed;
+       mtu->g.ep0->maxpacket = maxpkt;
+       mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+       if (udev_speed == USB_SPEED_UNKNOWN)
+               mtu3_gadget_disconnect(mtu);
+       else
+               mtu3_ep0_setup(mtu);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 ltssm;
+
+       ltssm = mtu3_readl(mbase, U3D_LTSSM_INTR);
+       ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE);
+       mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */
+       dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm);
+
+       if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+               mtu3_gadget_reset(mtu);
+
+       if (ltssm & VBUS_FALL_INTR) {
+               mtu3_ss_func_set(mtu, false);
+               mtu3_gadget_reset(mtu);
+       }
+
+       if (ltssm & VBUS_RISE_INTR)
+               mtu3_ss_func_set(mtu, true);
+
+       if (ltssm & EXIT_U3_INTR)
+               mtu3_gadget_resume(mtu);
+
+       if (ltssm & ENTER_U3_INTR)
+               mtu3_gadget_suspend(mtu);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 u2comm;
+
+       u2comm = mtu3_readl(mbase, U3D_COMMON_USB_INTR);
+       u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE);
+       mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */
+       dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm);
+
+       if (u2comm & SUSPEND_INTR)
+               mtu3_gadget_suspend(mtu);
+
+       if (u2comm & RESUME_INTR)
+               mtu3_gadget_resume(mtu);
+
+       if (u2comm & RESET_INTR)
+               mtu3_gadget_reset(mtu);
+
+       return IRQ_HANDLED;
+}
+
+irqreturn_t mtu3_irq(int irq, void *data)
+{
+       struct mtu3 *mtu = (struct mtu3 *)data;
+       unsigned long flags;
+       u32 level1;
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       /* U3D_LV1ISR is RU */
+       level1 = mtu3_readl(mtu->mac_base, U3D_LV1ISR);
+       level1 &= mtu3_readl(mtu->mac_base, U3D_LV1IER);
+
+       if (level1 & EP_CTRL_INTR)
+               mtu3_link_isr(mtu);
+
+       if (level1 & MAC2_INTR)
+               mtu3_u2_common_isr(mtu);
+
+       if (level1 & MAC3_INTR)
+               mtu3_u3_ltssm_isr(mtu);
+
+       if (level1 & BMU_INTR)
+               mtu3_ep0_isr(mtu);
+
+       if (level1 & QMU_INTR)
+               mtu3_qmu_isr(mtu);
+
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static void mtu3_check_params(struct mtu3 *mtu)
+{
+       /* check the max_speed parameter */
+       switch (mtu->max_speed) {
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
+               break;
+       default:
+               dev_err(mtu->dev, "invalid max_speed: %d\n", mtu->max_speed);
+               /* fall through */
+       case USB_SPEED_UNKNOWN:
+               /* default as SS */
+               mtu->max_speed = USB_SPEED_SUPER;
+               break;
+       }
+
+       if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH))
+               mtu->max_speed = USB_SPEED_HIGH;
+
+       mtu->speed = mtu->max_speed;
+
+       dev_info(mtu->dev, "max_speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+static int mtu3_hw_init(struct mtu3 *mtu)
+{
+       u32 value;
+       int ret;
+
+       value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_TRUNK_VERS);
+       mtu->hw_version = IP_TRUNK_VERS(value);
+       mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003);
+
+       value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
+       mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value);
+
+       dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version,
+                mtu->is_u3_ip ? "U3" : "U2");
+
+       mtu3_check_params(mtu);
+
+       mtu3_device_reset(mtu);
+
+       ret = mtu3_device_enable(mtu);
+       if (ret) {
+               dev_err(mtu->dev, "device enable failed %d\n", ret);
+               return ret;
+       }
+
+       ret = mtu3_mem_alloc(mtu);
+       if (ret)
+               return ret;
+
+       mtu3_regs_init(mtu);
+
+       return 0;
+}
+
+static void mtu3_hw_exit(struct mtu3 *mtu)
+{
+       mtu3_device_disable(mtu);
+       mtu3_mem_free(mtu);
+}
+
+int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+       struct mtu3 *mtu = ssusb->u3d;
+       struct udevice *dev = mtu->dev;
+       int ret = -ENOMEM;
+
+       spin_lock_init(&mtu->lock);
+       mtu->ippc_base = ssusb->ippc_base;
+       mtu->mac_base = ssusb->mac_base;
+       mtu->ssusb = ssusb;
+       mtu->max_speed = usb_get_maximum_speed(dev->node);
+       mtu->force_vbus = dev_read_bool(dev, "mediatek,force-vbus");
+
+       ret = mtu3_hw_init(mtu);
+       if (ret) {
+               dev_err(dev, "mtu3 hw init failed:%d\n", ret);
+               return ret;
+       }
+
+       ret = mtu3_gadget_setup(mtu);
+       if (ret) {
+               dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
+               goto gadget_err;
+       }
+
+       dev_info(dev, "%s() done...\n", __func__);
+
+       return 0;
+
+gadget_err:
+       mtu3_hw_exit(mtu);
+       ssusb->u3d = NULL;
+       dev_err(dev, "%s() fail...\n", __func__);
+
+       return ret;
+}
+
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{
+       struct mtu3 *mtu = ssusb->u3d;
+
+       mtu3_gadget_cleanup(mtu);
+       mtu3_hw_exit(mtu);
+}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
new file mode 100644 (file)
index 0000000..ec0e50c
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_dr.h - dual role switch and host glue layer header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _MTU3_DR_H_
+#define _MTU3_DR_H_
+
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+
+int ssusb_host_init(struct ssusb_mtk *ssusb);
+void ssusb_host_exit(struct ssusb_mtk *ssusb);
+
+#else
+
+static inline int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+       return 0;
+}
+
+static inline void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{}
+
+#endif
+
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+int ssusb_gadget_init(struct ssusb_mtk *ssusb);
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
+irqreturn_t mtu3_irq(int irq, void *data);
+#else
+static inline int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+       return 0;
+}
+
+static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline irqreturn_t mtu3_irq(int irq, void *data)
+{
+       return IRQ_NONE;
+}
+#endif
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+                         enum mtu3_dr_force_mode mode);
+
+#endif         /* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
new file mode 100644 (file)
index 0000000..027b7e6
--- /dev/null
@@ -0,0 +1,686 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget.c - MediaTek usb3 DRD peripheral support
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include "mtu3.h"
+
+void mtu3_req_complete(struct mtu3_ep *mep,
+                      struct usb_request *req, int status)
+__releases(mep->mtu->lock)
+__acquires(mep->mtu->lock)
+{
+       struct mtu3_request *mreq = to_mtu3_request(req);
+       struct mtu3 *mtu = mreq->mtu;
+
+       list_del(&mreq->list);
+       if (req->status == -EINPROGRESS)
+               req->status = status;
+
+       spin_unlock(&mtu->lock);
+
+       /* ep0 makes use of PIO, needn't unmap it */
+       if (mep->epnum)
+               usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
+
+       dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
+               mep->name, req, req->status, req->actual, req->length);
+
+       usb_gadget_giveback_request(&mep->ep, req);
+       spin_lock(&mtu->lock);
+}
+
+static void nuke(struct mtu3_ep *mep, const int status)
+{
+       struct mtu3_request *mreq = NULL;
+
+       if (list_empty(&mep->req_list))
+               return;
+
+       dev_dbg(mep->mtu->dev, "abort %s's req: sts %d\n", mep->name, status);
+
+       /* exclude EP0 */
+       if (mep->epnum)
+               mtu3_qmu_flush(mep);
+
+       while (!list_empty(&mep->req_list)) {
+               mreq = list_first_entry(&mep->req_list,
+                                       struct mtu3_request, list);
+               mtu3_req_complete(mep, &mreq->request, status);
+       }
+}
+
+static int mtu3_ep_enable(struct mtu3_ep *mep)
+{
+       const struct usb_endpoint_descriptor *desc;
+       const struct usb_ss_ep_comp_descriptor *comp_desc;
+       struct mtu3 *mtu = mep->mtu;
+       u32 interval = 0;
+       u32 mult = 0;
+       u32 burst = 0;
+       int max_packet;
+       int ret;
+
+       desc = mep->desc;
+       comp_desc = mep->comp_desc;
+       mep->type = usb_endpoint_type(desc);
+       max_packet = usb_endpoint_maxp(desc);
+       mep->maxp = max_packet & GENMASK(10, 0);
+
+       switch (mtu->g.speed) {
+       case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
+               if (usb_endpoint_xfer_int(desc) ||
+                   usb_endpoint_xfer_isoc(desc)) {
+                       interval = desc->bInterval;
+                       interval = clamp_val(interval, 1, 16) - 1;
+                       if (usb_endpoint_xfer_isoc(desc) && comp_desc)
+                               mult = comp_desc->bmAttributes;
+               }
+               if (comp_desc)
+                       burst = comp_desc->bMaxBurst;
+
+               break;
+       case USB_SPEED_HIGH:
+               if (usb_endpoint_xfer_isoc(desc) ||
+                   usb_endpoint_xfer_int(desc)) {
+                       interval = desc->bInterval;
+                       interval = clamp_val(interval, 1, 16) - 1;
+                       burst = (max_packet & GENMASK(12, 11)) >> 11;
+               }
+               break;
+       default:
+               break; /*others are ignored */
+       }
+
+       dev_dbg(mtu->dev, "%s maxp:%d, interval:%d, burst:%d, mult:%d\n",
+               __func__, mep->maxp, interval, burst, mult);
+
+       mep->ep.maxpacket = mep->maxp;
+       mep->ep.desc = desc;
+       mep->ep.comp_desc = comp_desc;
+       mep->slot = mtu->slot;
+
+       ret = mtu3_config_ep(mtu, mep, interval, burst, mult);
+       if (ret < 0)
+               return ret;
+
+       ret = mtu3_gpd_ring_alloc(mep);
+       if (ret < 0) {
+               mtu3_deconfig_ep(mtu, mep);
+               return ret;
+       }
+
+       mtu3_qmu_start(mep);
+
+       return 0;
+}
+
+static int mtu3_ep_disable(struct mtu3_ep *mep)
+{
+       struct mtu3 *mtu = mep->mtu;
+
+       mtu3_qmu_stop(mep);
+
+       /* abort all pending requests */
+       nuke(mep, -ESHUTDOWN);
+       mtu3_deconfig_ep(mtu, mep);
+       mtu3_gpd_ring_free(mep);
+
+       mep->desc = NULL;
+       mep->ep.desc = NULL;
+       mep->comp_desc = NULL;
+       mep->type = 0;
+       mep->flags = 0;
+
+       return 0;
+}
+
+static int mtu3_gadget_ep_enable(struct usb_ep *ep,
+                                const struct usb_endpoint_descriptor *desc)
+{
+       struct mtu3_ep *mep;
+       struct mtu3 *mtu;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+               pr_debug("%s invalid parameters\n", __func__);
+               return -EINVAL;
+       }
+
+       if (!desc->wMaxPacketSize) {
+               pr_debug("%s missing wMaxPacketSize\n", __func__);
+               return -EINVAL;
+       }
+       mep = to_mtu3_ep(ep);
+       mtu = mep->mtu;
+
+       /* check ep number and direction against endpoint */
+       if (usb_endpoint_num(desc) != mep->epnum)
+               return -EINVAL;
+
+       if (!!usb_endpoint_dir_in(desc) ^ !!mep->is_in)
+               return -EINVAL;
+
+       dev_dbg(mtu->dev, "%s %s\n", __func__, ep->name);
+
+       if (mep->flags & MTU3_EP_ENABLED) {
+               dev_warn(mtu->dev, "%s is already enabled\n", mep->name);
+               return 0;
+       }
+
+       spin_lock_irqsave(&mtu->lock, flags);
+       mep->desc = desc;
+       mep->comp_desc = ep->comp_desc;
+
+       ret = mtu3_ep_enable(mep);
+       if (ret)
+               goto error;
+
+       mep->flags = MTU3_EP_ENABLED;
+       mtu->active_ep++;
+
+error:
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep);
+
+       return ret;
+}
+
+static int mtu3_gadget_ep_disable(struct usb_ep *ep)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+       struct mtu3 *mtu = mep->mtu;
+       unsigned long flags;
+
+       dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name);
+
+       if (!(mep->flags & MTU3_EP_ENABLED)) {
+               dev_warn(mtu->dev, "%s is already disabled\n", mep->name);
+               return 0;
+       }
+
+       spin_lock_irqsave(&mtu->lock, flags);
+       mtu3_ep_disable(mep);
+       mep->flags = 0;
+       mtu->active_ep--;
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       dev_dbg(mtu->dev, "%s active_ep=%d, mtu3 is_active=%d\n",
+               __func__, mtu->active_ep, mtu->is_active);
+
+       return 0;
+}
+
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+       struct mtu3_request *mreq;
+
+       mreq = kzalloc(sizeof(*mreq), gfp_flags);
+       if (!mreq)
+               return NULL;
+
+       mreq->request.dma = DMA_ADDR_INVALID;
+       mreq->epnum = mep->epnum;
+       mreq->mep = mep;
+
+       return &mreq->request;
+}
+
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+       struct mtu3_request *mreq = to_mtu3_request(req);
+
+       kfree(mreq);
+}
+
+static int mtu3_gadget_queue(struct usb_ep *ep,
+                            struct usb_request *req, gfp_t gfp_flags)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+       struct mtu3_request *mreq = to_mtu3_request(req);
+       struct mtu3 *mtu = mep->mtu;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!req->buf)
+               return -ENODATA;
+
+       if (mreq->mep != mep)
+               return -EINVAL;
+
+       dev_dbg(mtu->dev, "%s %s EP%d(%s), req=%p, maxp=%d, len#%d\n",
+               __func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name,
+               mreq, ep->maxpacket, mreq->request.length);
+
+       if (req->length > GPD_BUF_SIZE) {
+               dev_warn(mtu->dev,
+                        "req length > supported MAX:%d requested:%d\n",
+                        GPD_BUF_SIZE, req->length);
+               return -EOPNOTSUPP;
+       }
+
+       /* don't queue if the ep is down */
+       if (!mep->desc) {
+               dev_dbg(mtu->dev, "req=%p queued to %s while it's disabled\n",
+                       req, ep->name);
+               return -ESHUTDOWN;
+       }
+
+       mreq->mtu = mtu;
+       mreq->request.actual = 0;
+       mreq->request.status = -EINPROGRESS;
+
+       ret = usb_gadget_map_request(&mtu->g, req, mep->is_in);
+       if (ret) {
+               dev_err(mtu->dev, "dma mapping failed\n");
+               return ret;
+       }
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       if (mtu3_prepare_transfer(mep)) {
+               ret = -EAGAIN;
+               goto error;
+       }
+
+       list_add_tail(&mreq->list, &mep->req_list);
+       mtu3_insert_gpd(mep, mreq);
+       mtu3_qmu_resume(mep);
+
+error:
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return ret;
+}
+
+static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+       struct mtu3_request *mreq = to_mtu3_request(req);
+       struct mtu3_request *r;
+       struct mtu3 *mtu = mep->mtu;
+       unsigned long flags;
+       int ret = 0;
+
+       if (mreq->mep != mep)
+               return -EINVAL;
+
+       dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       list_for_each_entry(r, &mep->req_list, list) {
+               if (r == mreq)
+                       break;
+       }
+       if (r != mreq) {
+               dev_dbg(mtu->dev, "req=%p not queued to %s\n", req, ep->name);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       mtu3_qmu_flush(mep);  /* REVISIT: set BPS ?? */
+       mtu3_req_complete(mep, req, -ECONNRESET);
+       mtu3_qmu_start(mep);
+
+done:
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return ret;
+}
+
+/*
+ * Set or clear the halt bit of an EP.
+ * A halted EP won't TX/RX any data but will queue requests.
+ */
+static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+       struct mtu3 *mtu = mep->mtu;
+       struct mtu3_request *mreq;
+       unsigned long flags = 0;
+       int ret = 0;
+
+       dev_dbg(mtu->dev, "%s : %s...", __func__, ep->name);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       if (mep->type == USB_ENDPOINT_XFER_ISOC) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       mreq = next_request(mep);
+       if (value) {
+               /*
+                * If there is not request for TX-EP, QMU will not transfer
+                * data to TX-FIFO, so no need check whether TX-FIFO
+                * holds bytes or not here
+                */
+               if (mreq) {
+                       dev_dbg(mtu->dev, "req in progress, cannot halt %s\n",
+                               ep->name);
+                       ret = -EAGAIN;
+                       goto done;
+               }
+       } else {
+               mep->flags &= ~MTU3_EP_WEDGE;
+       }
+
+       dev_dbg(mtu->dev, "%s %s stall\n", ep->name, value ? "set" : "clear");
+
+       mtu3_ep_stall_set(mep, value);
+
+done:
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return ret;
+}
+
+/* Sets the halt feature with the clear requests ignored */
+static int mtu3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+       struct mtu3_ep *mep = to_mtu3_ep(ep);
+
+       mep->flags |= MTU3_EP_WEDGE;
+
+       return usb_ep_set_halt(ep);
+}
+
+static const struct usb_ep_ops mtu3_ep_ops = {
+       .enable = mtu3_gadget_ep_enable,
+       .disable = mtu3_gadget_ep_disable,
+       .alloc_request = mtu3_alloc_request,
+       .free_request = mtu3_free_request,
+       .queue = mtu3_gadget_queue,
+       .dequeue = mtu3_gadget_dequeue,
+       .set_halt = mtu3_gadget_ep_set_halt,
+       .set_wedge = mtu3_gadget_ep_set_wedge,
+};
+
+static int mtu3_gadget_get_frame(struct usb_gadget *gadget)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+       return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM);
+}
+
+static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(gadget);
+       unsigned long flags;
+
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       /* remote wakeup feature is not enabled by host */
+       if (!mtu->may_wakeup)
+               return  -EOPNOTSUPP;
+
+       spin_lock_irqsave(&mtu->lock, flags);
+       if (mtu->g.speed >= USB_SPEED_SUPER) {
+               mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
+       } else {
+               mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+               spin_unlock_irqrestore(&mtu->lock, flags);
+               mdelay(10);
+               spin_lock_irqsave(&mtu->lock, flags);
+               mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+       }
+       spin_unlock_irqrestore(&mtu->lock, flags);
+       return 0;
+}
+
+static int mtu3_gadget_set_self_powered(struct usb_gadget *gadget,
+                                       int is_selfpowered)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+       mtu->is_self_powered = !!is_selfpowered;
+       return 0;
+}
+
+static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(gadget);
+       unsigned long flags;
+
+       dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__,
+               is_on ? "on" : "off", mtu->is_active ? "" : "in");
+
+       /* we'd rather not pullup unless the device is active. */
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       is_on = !!is_on;
+       if (!mtu->is_active) {
+               /* save it for mtu3_start() to process the request */
+               mtu->softconnect = is_on;
+       } else if (is_on != mtu->softconnect) {
+               mtu->softconnect = is_on;
+               mtu3_dev_on_off(mtu, is_on);
+       }
+
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return 0;
+}
+
+static int mtu3_gadget_start(struct usb_gadget *gadget,
+                            struct usb_gadget_driver *driver)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(gadget);
+       unsigned long flags;
+
+       if (mtu->gadget_driver) {
+               dev_err(mtu->dev, "%s is already bound to %s\n",
+                       mtu->g.name, mtu->gadget_driver->function);
+               return -EBUSY;
+       }
+
+       dev_dbg(mtu->dev, "bind driver %s\n", driver->function);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       mtu->softconnect = 0;
+       mtu->gadget_driver = driver;
+       mtu3_start(mtu);
+
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return 0;
+}
+
+static void stop_activity(struct mtu3 *mtu)
+{
+       int i;
+
+       mtu->g.speed = USB_SPEED_UNKNOWN;
+
+       /* deactivate the hardware */
+       if (mtu->softconnect) {
+               mtu->softconnect = 0;
+               mtu3_dev_on_off(mtu, 0);
+       }
+
+       /*
+        * killing any outstanding requests will quiesce the driver;
+        * then report disconnect
+        */
+       nuke(mtu->ep0, -ESHUTDOWN);
+       for (i = 1; i < mtu->num_eps; i++) {
+               nuke(mtu->in_eps + i, -ESHUTDOWN);
+               nuke(mtu->out_eps + i, -ESHUTDOWN);
+       }
+}
+
+static int mtu3_gadget_stop(struct usb_gadget *g)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(g);
+       unsigned long flags;
+
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       stop_activity(mtu);
+       mtu->gadget_driver = NULL;
+       mtu3_stop(mtu);
+
+       spin_unlock_irqrestore(&mtu->lock, flags);
+
+       return 0;
+}
+
+static void
+mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
+{
+       struct mtu3 *mtu = gadget_to_mtu3(g);
+       unsigned long flags;
+
+       dev_dbg(mtu->dev, "%s %d\n", __func__, speed);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+       mtu3_set_speed(mtu, speed);
+       spin_unlock_irqrestore(&mtu->lock, flags);
+}
+
+static const struct usb_gadget_ops mtu3_gadget_ops = {
+       .get_frame = mtu3_gadget_get_frame,
+       .wakeup = mtu3_gadget_wakeup,
+       .set_selfpowered = mtu3_gadget_set_self_powered,
+       .pullup = mtu3_gadget_pullup,
+       .udc_start = mtu3_gadget_start,
+       .udc_stop = mtu3_gadget_stop,
+       .udc_set_speed = mtu3_gadget_set_speed,
+};
+
+static void mtu3_state_reset(struct mtu3 *mtu)
+{
+       mtu->address = 0;
+       mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+       mtu->may_wakeup = 0;
+       mtu->u1_enable = 0;
+       mtu->u2_enable = 0;
+       mtu->delayed_status = false;
+       mtu->test_mode = false;
+}
+
+static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+                      u32 epnum, u32 is_in)
+{
+       mep->epnum = epnum;
+       mep->mtu = mtu;
+       mep->is_in = is_in;
+
+       INIT_LIST_HEAD(&mep->req_list);
+
+       sprintf(mep->name, "ep%d%s", epnum,
+               !epnum ? "" : (is_in ? "in" : "out"));
+
+       mep->ep.name = mep->name;
+       INIT_LIST_HEAD(&mep->ep.ep_list);
+
+       /* initialize maxpacket as SS */
+       if (!epnum) {
+               usb_ep_set_maxpacket_limit(&mep->ep, USB_HS_MAXP);
+               mep->ep.ops = &mtu3_ep0_ops;
+               mtu->g.ep0 = &mep->ep;
+       } else {
+               usb_ep_set_maxpacket_limit(&mep->ep, USB_SS_MAXP);
+               mep->ep.ops = &mtu3_ep_ops;
+               list_add_tail(&mep->ep.ep_list, &mtu->g.ep_list);
+       }
+
+       dev_dbg(mtu->dev, "%s, name=%s, maxp=%d\n", __func__, mep->ep.name,
+               mep->ep.maxpacket);
+}
+
+static void mtu3_gadget_init_eps(struct mtu3 *mtu)
+{
+       u8 epnum;
+
+       /* initialize endpoint list just once */
+       INIT_LIST_HEAD(&mtu->g.ep_list);
+
+       dev_dbg(mtu->dev, "%s num_eps(1 for a pair of tx&rx ep)=%d\n",
+               __func__, mtu->num_eps);
+
+       init_hw_ep(mtu, mtu->ep0, 0, 0);
+       for (epnum = 1; epnum < mtu->num_eps; epnum++) {
+               init_hw_ep(mtu, mtu->in_eps + epnum, epnum, 1);
+               init_hw_ep(mtu, mtu->out_eps + epnum, epnum, 0);
+       }
+}
+
+int mtu3_gadget_setup(struct mtu3 *mtu)
+{
+       mtu->g.ops = &mtu3_gadget_ops;
+       mtu->g.max_speed = mtu->max_speed;
+       mtu->g.speed = USB_SPEED_UNKNOWN;
+       mtu->g.is_dualspeed = 1;
+       mtu->g.name = MTU3_DRIVER_NAME;
+       mtu->is_active = 0;
+       mtu->delayed_status = false;
+
+       mtu3_gadget_init_eps(mtu);
+
+       return usb_add_gadget_udc((struct device *)mtu->dev, &mtu->g);
+}
+
+void mtu3_gadget_cleanup(struct mtu3 *mtu)
+{
+       usb_del_gadget_udc(&mtu->g);
+}
+
+void mtu3_gadget_resume(struct mtu3 *mtu)
+{
+       dev_dbg(mtu->dev, "gadget RESUME\n");
+       if (mtu->gadget_driver && mtu->gadget_driver->resume) {
+               spin_unlock(&mtu->lock);
+               mtu->gadget_driver->resume(&mtu->g);
+               spin_lock(&mtu->lock);
+       }
+}
+
+/* called when SOF packets stop for 3+ msec or enters U3 */
+void mtu3_gadget_suspend(struct mtu3 *mtu)
+{
+       dev_dbg(mtu->dev, "gadget SUSPEND\n");
+       if (mtu->gadget_driver && mtu->gadget_driver->suspend) {
+               spin_unlock(&mtu->lock);
+               mtu->gadget_driver->suspend(&mtu->g);
+               spin_lock(&mtu->lock);
+       }
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void mtu3_gadget_disconnect(struct mtu3 *mtu)
+{
+       dev_dbg(mtu->dev, "gadget DISCONNECT\n");
+       if (mtu->gadget_driver && mtu->gadget_driver->disconnect) {
+               spin_unlock(&mtu->lock);
+               mtu->gadget_driver->disconnect(&mtu->g);
+               spin_lock(&mtu->lock);
+       }
+
+       mtu3_state_reset(mtu);
+       usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED);
+}
+
+void mtu3_gadget_reset(struct mtu3 *mtu)
+{
+       dev_dbg(mtu->dev, "gadget RESET\n");
+
+       /* report disconnect, if we didn't flush EP state */
+       if (mtu->g.speed != USB_SPEED_UNKNOWN)
+               mtu3_gadget_disconnect(mtu);
+       else
+               mtu3_state_reset(mtu);
+}
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
new file mode 100644 (file)
index 0000000..4b0bc5f
--- /dev/null
@@ -0,0 +1,933 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Author:  Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/iopoll.h>
+#include <linux/usb/composite.h>
+
+#include "mtu3.h"
+
+/* ep0 is always mtu3->in_eps[0] */
+#define        next_ep0_request(mtu)   next_request((mtu)->ep0)
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 mtu3_test_packet[53] = {
+       /* implicit SYNC then DATA0 to start */
+
+       /* JKJKJKJK x9 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* JJKKJJKK x8 */
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       /* JJJJKKKK x8 */
+       0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+       /* JJJJJJJKKKKKKK x8 */
+       0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       /* JJJJJJJK x8 */
+       0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+       /* JKKKKKKK x10, JK */
+       0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e,
+       /* implicit CRC16 then EOP to end */
+};
+
+static char *decode_ep0_state(struct mtu3 *mtu)
+{
+       switch (mtu->ep0_state) {
+       case MU3D_EP0_STATE_SETUP:
+               return "SETUP";
+       case MU3D_EP0_STATE_TX:
+               return "IN";
+       case MU3D_EP0_STATE_RX:
+               return "OUT";
+       case MU3D_EP0_STATE_TX_END:
+               return "TX-END";
+       case MU3D_EP0_STATE_STALL:
+               return "STALL";
+       default:
+               return "??";
+       }
+}
+
+static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req)
+{
+       mtu3_req_complete(mtu->ep0, req, 0);
+}
+
+static int
+forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+       int ret;
+
+       if (!mtu->gadget_driver)
+               return -EOPNOTSUPP;
+
+       spin_unlock(&mtu->lock);
+       ret = mtu->gadget_driver->setup(&mtu->g, setup);
+       spin_lock(&mtu->lock);
+
+       dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret);
+       return ret;
+}
+
+static inline void writel_rep(volatile void *addr, const void *buffer,
+                             unsigned int count)
+{
+       if (count) {
+               const u32 *buf = buffer;
+
+               do {
+                       writel(*buf++, addr);
+               } while (--count);
+       }
+}
+
+static inline void readl_rep(const volatile void *addr, void *buffer,
+                            unsigned int count)
+{
+       if (count) {
+               u32 *buf = buffer;
+
+               do {
+                       u32 x = readl(addr);
+                       *buf++ = x;
+               } while (--count);
+       }
+}
+
+static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len)
+{
+       void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+       u16 index = 0;
+
+       dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n",
+               __func__, mep->epnum, len, src);
+
+       if (len >= 4) {
+               writel_rep(fifo, src, len >> 2);
+               index = len & ~0x03;
+       }
+       if (len & 0x02) {
+               writew(*(u16 *)&src[index], fifo);
+               index += 2;
+       }
+       if (len & 0x01)
+               writeb(src[index], fifo);
+}
+
+static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len)
+{
+       void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+       u32 value;
+       u16 index = 0;
+
+       dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n",
+               __func__, mep->epnum, len, dst);
+
+       if (len >= 4) {
+               readl_rep(fifo, dst, len >> 2);
+               index = len & ~0x03;
+       }
+       if (len & 0x3) {
+               value = readl(fifo);
+               memcpy(&dst[index], &value, len & 0x3);
+       }
+}
+
+static void ep0_load_test_packet(struct mtu3 *mtu)
+{
+       /*
+        * because the length of test packet is less than max packet of HS ep0,
+        * write it into fifo directly.
+        */
+       ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet));
+}
+
+/*
+ * A. send STALL for setup transfer without data stage:
+ *             set SENDSTALL and SETUPPKTRDY at the same time;
+ * B. send STALL for other cases:
+ *             set SENDSTALL only.
+ */
+static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
+{
+       struct mtu3 *mtu = mep0->mtu;
+       void __iomem *mbase = mtu->mac_base;
+       u32 csr;
+
+       /* EP0_SENTSTALL is W1C */
+       csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+       if (set)
+               csr |= EP0_SENDSTALL | pktrdy;
+       else
+               csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
+       mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+       mtu->delayed_status = false;
+       mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+       dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n",
+               set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
+}
+
+static void ep0_do_status_stage(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 value;
+
+       value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+       mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
+}
+
+static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
+
+static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
+{}
+
+static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct mtu3_request *mreq;
+       struct mtu3 *mtu;
+       struct usb_set_sel_req sel;
+
+       memcpy(&sel, req->buf, sizeof(sel));
+
+       mreq = to_mtu3_request(req);
+       mtu = mreq->mtu;
+       dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n",
+               sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel);
+}
+
+/* queue data stage to handle 6 byte SET_SEL request */
+static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+       int ret;
+       u16 length = le16_to_cpu(setup->wLength);
+
+       if (unlikely(length != 6)) {
+               dev_err(mtu->dev, "%s wrong wLength:%d\n",
+                       __func__, length);
+               return -EINVAL;
+       }
+
+       mtu->ep0_req.mep = mtu->ep0;
+       mtu->ep0_req.request.length = 6;
+       mtu->ep0_req.request.buf = mtu->setup_buf;
+       mtu->ep0_req.request.complete = ep0_set_sel_complete;
+       ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+
+       return ret < 0 ? ret : 1;
+}
+
+static int
+ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+{
+       struct mtu3_ep *mep = NULL;
+       int handled = 1;
+       u8 result[2] = {0, 0};
+       u8 epnum = 0;
+       int is_in;
+
+       switch (setup->bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_DEVICE:
+               result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
+               result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+
+               if (mtu->g.speed >= USB_SPEED_SUPER) {
+                       result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
+                       result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
+               }
+
+               dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__,
+                       result[0], mtu->u1_enable, mtu->u2_enable);
+
+               break;
+       case USB_RECIP_INTERFACE:
+               break;
+       case USB_RECIP_ENDPOINT:
+               epnum = (u8)le16_to_cpu(setup->wIndex);
+               is_in = epnum & USB_DIR_IN;
+               epnum &= USB_ENDPOINT_NUMBER_MASK;
+
+               if (epnum >= mtu->num_eps) {
+                       handled = -EINVAL;
+                       break;
+               }
+               if (!epnum)
+                       break;
+
+               mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+               if (!mep->desc) {
+                       handled = -EINVAL;
+                       break;
+               }
+               if (mep->flags & MTU3_EP_STALL)
+                       result[0] |= 1 << USB_ENDPOINT_HALT;
+
+               break;
+       default:
+               /* class, vendor, etc ... delegate */
+               handled = 0;
+               break;
+       }
+
+       if (handled > 0) {
+               int ret;
+
+               /* prepare a data stage for GET_STATUS */
+               dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result);
+               memcpy(mtu->setup_buf, result, sizeof(result));
+               mtu->ep0_req.mep = mtu->ep0;
+               mtu->ep0_req.request.length = 2;
+               mtu->ep0_req.request.buf = &mtu->setup_buf;
+               mtu->ep0_req.request.complete = ep0_dummy_complete;
+               ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+               if (ret < 0)
+                       handled = ret;
+       }
+       return handled;
+}
+
+static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+       void __iomem *mbase = mtu->mac_base;
+       int handled = 1;
+       u32 value = 0;
+
+       switch (le16_to_cpu(setup->wIndex) >> 8) {
+       case TEST_J:
+               dev_dbg(mtu->dev, "TEST_J\n");
+               mtu->test_mode_nr = TEST_J_MODE;
+               break;
+       case TEST_K:
+               dev_dbg(mtu->dev, "TEST_K\n");
+               mtu->test_mode_nr = TEST_K_MODE;
+               break;
+       case TEST_SE0_NAK:
+               dev_dbg(mtu->dev, "TEST_SE0_NAK\n");
+               mtu->test_mode_nr = TEST_SE0_NAK_MODE;
+               break;
+       case TEST_PACKET:
+               dev_dbg(mtu->dev, "TEST_PACKET\n");
+               mtu->test_mode_nr = TEST_PACKET_MODE;
+               break;
+       default:
+               handled = -EINVAL;
+               goto out;
+       }
+
+       mtu->test_mode = true;
+
+       /* no TX completion interrupt, and need restart platform after test */
+       if (mtu->test_mode_nr == TEST_PACKET_MODE)
+               ep0_load_test_packet(mtu);
+
+       /* send status before entering test mode. */
+       ep0_do_status_stage(mtu);
+
+       /* wait for ACK status sent by host */
+       readl_poll_timeout(mbase + U3D_EP0CSR, value,
+                          !(value & EP0_DATAEND), 5000);
+
+       mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
+
+       mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+out:
+       return handled;
+}
+
+static int ep0_handle_feature_dev(struct mtu3 *mtu,
+                                 struct usb_ctrlrequest *setup, bool set)
+{
+       void __iomem *mbase = mtu->mac_base;
+       int handled = -EINVAL;
+       u32 lpc;
+
+       switch (le16_to_cpu(setup->wValue)) {
+       case USB_DEVICE_REMOTE_WAKEUP:
+               mtu->may_wakeup = !!set;
+               handled = 1;
+               break;
+       case USB_DEVICE_TEST_MODE:
+               if (!set || (mtu->g.speed != USB_SPEED_HIGH) ||
+                   (le16_to_cpu(setup->wIndex) & 0xff))
+                       break;
+
+               handled = handle_test_mode(mtu, setup);
+               break;
+       case USB_DEVICE_U1_ENABLE:
+               if (mtu->g.speed < USB_SPEED_SUPER ||
+                   mtu->g.state != USB_STATE_CONFIGURED)
+                       break;
+
+               lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+               if (set)
+                       lpc |= SW_U1_REQUEST_ENABLE;
+               else
+                       lpc &= ~SW_U1_REQUEST_ENABLE;
+               mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+               mtu->u1_enable = !!set;
+               handled = 1;
+               break;
+       case USB_DEVICE_U2_ENABLE:
+               if (mtu->g.speed < USB_SPEED_SUPER ||
+                   mtu->g.state != USB_STATE_CONFIGURED)
+                       break;
+
+               lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+               if (set)
+                       lpc |= SW_U2_REQUEST_ENABLE;
+               else
+                       lpc &= ~SW_U2_REQUEST_ENABLE;
+               mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+               mtu->u2_enable = !!set;
+               handled = 1;
+               break;
+       default:
+               handled = -EINVAL;
+               break;
+       }
+       return handled;
+}
+
+static int ep0_handle_feature(struct mtu3 *mtu,
+                             struct usb_ctrlrequest *setup, bool set)
+{
+       struct mtu3_ep *mep;
+       int handled = -EINVAL;
+       int is_in;
+       u16 value;
+       u16 index;
+       u8 epnum;
+
+       value = le16_to_cpu(setup->wValue);
+       index = le16_to_cpu(setup->wIndex);
+
+       switch (setup->bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_DEVICE:
+               handled = ep0_handle_feature_dev(mtu, setup, set);
+               break;
+       case USB_RECIP_INTERFACE:
+               /* superspeed only */
+               if (value == USB_INTRF_FUNC_SUSPEND &&
+                   mtu->g.speed >= USB_SPEED_SUPER) {
+                       /*
+                        * forward the request because function drivers
+                        * should handle it
+                        */
+                       handled = 0;
+               }
+               break;
+       case USB_RECIP_ENDPOINT:
+               epnum = index & USB_ENDPOINT_NUMBER_MASK;
+               if (epnum == 0 || epnum >= mtu->num_eps ||
+                   value != USB_ENDPOINT_HALT)
+                       break;
+
+               is_in = index & USB_DIR_IN;
+               mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+               if (!mep->desc)
+                       break;
+
+               handled = 1;
+               /* ignore request if endpoint is wedged */
+               if (mep->flags & MTU3_EP_WEDGE)
+                       break;
+
+               mtu3_ep_stall_set(mep, set);
+               break;
+       default:
+               /* class, vendor, etc ... delegate */
+               handled = 0;
+               break;
+       }
+       return handled;
+}
+
+/*
+ * handle all control requests can be handled
+ * returns:
+ *     negative errno - error happened
+ *     zero - need delegate SETUP to gadget driver
+ *     positive - already handled
+ */
+static int handle_standard_request(struct mtu3 *mtu,
+                                  struct usb_ctrlrequest *setup)
+{
+       void __iomem *mbase = mtu->mac_base;
+       enum usb_device_state state = mtu->g.state;
+       int handled = -EINVAL;
+       u32 dev_conf;
+       u16 value;
+
+       value = le16_to_cpu(setup->wValue);
+
+       /* the gadget driver handles everything except what we must handle */
+       switch (setup->bRequest) {
+       case USB_REQ_SET_ADDRESS:
+               /* change it after the status stage */
+               mtu->address = (u8)(value & 0x7f);
+               dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address);
+
+               dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF);
+               dev_conf &= ~DEV_ADDR_MSK;
+               dev_conf |= DEV_ADDR(mtu->address);
+               mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf);
+
+               if (mtu->address)
+                       usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS);
+               else
+                       usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT);
+
+               handled = 1;
+               break;
+       case USB_REQ_SET_CONFIGURATION:
+               if (state == USB_STATE_ADDRESS) {
+                       usb_gadget_set_state(&mtu->g,
+                                            USB_STATE_CONFIGURED);
+               } else if (state == USB_STATE_CONFIGURED) {
+                       /*
+                        * USB2 spec sec 9.4.7, if wValue is 0 then dev
+                        * is moved to addressed state
+                        */
+                       if (!value)
+                               usb_gadget_set_state(&mtu->g,
+                                                    USB_STATE_ADDRESS);
+               }
+               handled = 0;
+               break;
+       case USB_REQ_CLEAR_FEATURE:
+               handled = ep0_handle_feature(mtu, setup, 0);
+               break;
+       case USB_REQ_SET_FEATURE:
+               handled = ep0_handle_feature(mtu, setup, 1);
+               break;
+       case USB_REQ_GET_STATUS:
+               handled = ep0_get_status(mtu, setup);
+               break;
+       case USB_REQ_SET_SEL:
+               handled = ep0_set_sel(mtu, setup);
+               break;
+       case USB_REQ_SET_ISOCH_DELAY:
+               handled = 1;
+               break;
+       default:
+               /* delegate SET_CONFIGURATION, etc */
+               handled = 0;
+       }
+
+       return handled;
+}
+
+/* receive an data packet (OUT) */
+static void ep0_rx_state(struct mtu3 *mtu)
+{
+       struct mtu3_request *mreq;
+       struct usb_request *req;
+       void __iomem *mbase = mtu->mac_base;
+       u32 maxp;
+       u32 csr;
+       u16 count = 0;
+
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+       mreq = next_ep0_request(mtu);
+       req = &mreq->request;
+
+       /* read packet and ack; or stall because of gadget driver bug */
+       if (req) {
+               void *buf = req->buf + req->actual;
+               unsigned int len = req->length - req->actual;
+
+               /* read the buffer */
+               count = mtu3_readl(mbase, U3D_RXCOUNT0);
+               if (count > len) {
+                       req->status = -EOVERFLOW;
+                       count = len;
+               }
+               ep0_read_fifo(mtu->ep0, buf, count);
+               req->actual += count;
+               csr |= EP0_RXPKTRDY;
+
+               maxp = mtu->g.ep0->maxpacket;
+               if (count < maxp || req->actual == req->length) {
+                       mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+                       dev_dbg(mtu->dev, "ep0 state: %s\n",
+                               decode_ep0_state(mtu));
+
+                       csr |= EP0_DATAEND;
+               } else {
+                       req = NULL;
+               }
+       } else {
+               csr |= EP0_RXPKTRDY | EP0_SENDSTALL;
+               dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__);
+       }
+
+       mtu3_writel(mbase, U3D_EP0CSR, csr);
+
+       /* give back the request if have received all data */
+       if (req)
+               ep0_req_giveback(mtu, req);
+}
+
+/* transmitting to the host (IN) */
+static void ep0_tx_state(struct mtu3 *mtu)
+{
+       struct mtu3_request *mreq = next_ep0_request(mtu);
+       struct usb_request *req;
+       u32 csr;
+       u8 *src;
+       u32 count;
+       u32 maxp;
+
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       if (!mreq)
+               return;
+
+       maxp = mtu->g.ep0->maxpacket;
+       req = &mreq->request;
+
+       /* load the data */
+       src = (u8 *)req->buf + req->actual;
+       count = min(maxp, req->length - req->actual);
+       if (count)
+               ep0_write_fifo(mtu->ep0, src, count);
+
+       dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n",
+               __func__, req->actual, req->length, count, maxp, req->zero);
+
+       req->actual += count;
+
+       if ((count < maxp) ||
+           ((req->actual == req->length) && !req->zero))
+               mtu->ep0_state = MU3D_EP0_STATE_TX_END;
+
+       /* send it out, triggering a "txpktrdy cleared" irq */
+       csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+       mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY);
+
+       dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__,
+               mtu3_readl(mtu->mac_base, U3D_EP0CSR));
+}
+
+static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+       struct mtu3_request *mreq;
+       u32 count;
+       u32 csr;
+
+       csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+       count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0);
+
+       ep0_read_fifo(mtu->ep0, (u8 *)setup, count);
+
+       dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n",
+               setup->bRequestType, setup->bRequest,
+               le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex),
+               le16_to_cpu(setup->wLength));
+
+       /* clean up any leftover transfers */
+       mreq = next_ep0_request(mtu);
+       if (mreq)
+               ep0_req_giveback(mtu, &mreq->request);
+
+       if (le16_to_cpu(setup->wLength) == 0) {
+               ;       /* no data stage, nothing to do */
+       } else if (setup->bRequestType & USB_DIR_IN) {
+               mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+                           csr | EP0_SETUPPKTRDY | EP0_DPHTX);
+               mtu->ep0_state = MU3D_EP0_STATE_TX;
+       } else {
+               mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+                           (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX));
+               mtu->ep0_state = MU3D_EP0_STATE_RX;
+       }
+}
+
+static int ep0_handle_setup(struct mtu3 *mtu)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+       struct usb_ctrlrequest setup;
+       struct mtu3_request *mreq;
+       int handled = 0;
+
+       ep0_read_setup(mtu, &setup);
+
+       if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+               handled = handle_standard_request(mtu, &setup);
+
+       dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n",
+               handled, decode_ep0_state(mtu));
+
+       if (handled < 0)
+               goto stall;
+       else if (handled > 0)
+               goto finish;
+
+       handled = forward_to_driver(mtu, &setup);
+       if (handled < 0) {
+stall:
+               dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled);
+
+               ep0_stall_set(mtu->ep0, true,
+                             le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY);
+
+               return 0;
+       }
+
+finish:
+       if (mtu->test_mode) {
+               ;       /* nothing to do */
+       } else if (handled == USB_GADGET_DELAYED_STATUS) {
+
+               mreq = next_ep0_request(mtu);
+               if (mreq) {
+                       /* already asked us to continue delayed status */
+                       ep0_do_status_stage(mtu);
+                       ep0_req_giveback(mtu, &mreq->request);
+               } else {
+                       /* do delayed STATUS stage till receive ep0_queue */
+                       mtu->delayed_status = true;
+               }
+       } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
+
+               ep0_do_status_stage(mtu);
+               /* complete zlp request directly */
+               mreq = next_ep0_request(mtu);
+               if (mreq && !mreq->request.length)
+                       ep0_req_giveback(mtu, &mreq->request);
+       }
+
+       return 0;
+}
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       struct mtu3_request *mreq;
+       u32 int_status;
+       irqreturn_t ret = IRQ_NONE;
+       u32 csr;
+       u32 len;
+
+       int_status = mtu3_readl(mbase, U3D_EPISR);
+       int_status &= mtu3_readl(mbase, U3D_EPIER);
+       mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */
+
+       /* only handle ep0's */
+       if (!(int_status & (EP0ISR | SETUPENDISR)))
+               return IRQ_NONE;
+
+       /* abort current SETUP, and process new one */
+       if (int_status & SETUPENDISR)
+               mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+       csr = mtu3_readl(mbase, U3D_EP0CSR);
+
+       dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr);
+
+       /* we sent a stall.. need to clear it now.. */
+       if (csr & EP0_SENTSTALL) {
+               ep0_stall_set(mtu->ep0, false, 0);
+               csr = mtu3_readl(mbase, U3D_EP0CSR);
+               ret = IRQ_HANDLED;
+       }
+       dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+
+       switch (mtu->ep0_state) {
+       case MU3D_EP0_STATE_TX:
+               /* irq on clearing txpktrdy */
+               if ((csr & EP0_FIFOFULL) == 0) {
+                       ep0_tx_state(mtu);
+                       ret = IRQ_HANDLED;
+               }
+               break;
+       case MU3D_EP0_STATE_RX:
+               /* irq on set rxpktrdy */
+               if (csr & EP0_RXPKTRDY) {
+                       ep0_rx_state(mtu);
+                       ret = IRQ_HANDLED;
+               }
+               break;
+       case MU3D_EP0_STATE_TX_END:
+               mtu3_writel(mbase, U3D_EP0CSR,
+                           (csr & EP0_W1C_BITS) | EP0_DATAEND);
+
+               mreq = next_ep0_request(mtu);
+               if (mreq)
+                       ep0_req_giveback(mtu, &mreq->request);
+
+               mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+               ret = IRQ_HANDLED;
+               dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+               break;
+       case MU3D_EP0_STATE_SETUP:
+               if (!(csr & EP0_SETUPPKTRDY))
+                       break;
+
+               len = mtu3_readl(mbase, U3D_RXCOUNT0);
+               if (len != 8) {
+                       dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len);
+                       break;
+               }
+
+               ep0_handle_setup(mtu);
+               ret = IRQ_HANDLED;
+               break;
+       default:
+               /* can't happen */
+               ep0_stall_set(mtu->ep0, true, 0);
+               WARN_ON(1);
+               break;
+       }
+
+       return ret;
+}
+
+static int mtu3_ep0_enable(struct usb_ep *ep,
+                          const struct usb_endpoint_descriptor *desc)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static int mtu3_ep0_disable(struct usb_ep *ep)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+       struct mtu3 *mtu = mep->mtu;
+
+       mreq->mtu = mtu;
+       mreq->request.actual = 0;
+       mreq->request.status = -EINPROGRESS;
+
+       dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,
+               mep->name, decode_ep0_state(mtu), mreq->request.length);
+
+       switch (mtu->ep0_state) {
+       case MU3D_EP0_STATE_SETUP:
+       case MU3D_EP0_STATE_RX: /* control-OUT data */
+       case MU3D_EP0_STATE_TX: /* control-IN data */
+               break;
+       default:
+               dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__,
+                       decode_ep0_state(mtu));
+               return -EINVAL;
+       }
+
+       if (mtu->delayed_status) {
+               mtu->delayed_status = false;
+               ep0_do_status_stage(mtu);
+               /* needn't giveback the request for handling delay STATUS */
+               return 0;
+       }
+
+       if (!list_empty(&mep->req_list))
+               return -EBUSY;
+
+       list_add_tail(&mreq->list, &mep->req_list);
+
+       /* sequence #1, IN ... start writing the data */
+       if (mtu->ep0_state == MU3D_EP0_STATE_TX)
+               ep0_tx_state(mtu);
+
+       return 0;
+}
+
+static int mtu3_ep0_queue(struct usb_ep *ep,
+                         struct usb_request *req, gfp_t gfp)
+{
+       struct mtu3_ep *mep;
+       struct mtu3_request *mreq;
+       struct mtu3 *mtu;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!ep || !req)
+               return -EINVAL;
+
+       mep = to_mtu3_ep(ep);
+       mtu = mep->mtu;
+       mreq = to_mtu3_request(req);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+       ret = ep0_queue(mep, mreq);
+       spin_unlock_irqrestore(&mtu->lock, flags);
+       return ret;
+}
+
+static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       /* we just won't support this */
+       return -EINVAL;
+}
+
+static int mtu3_ep0_halt(struct usb_ep *ep, int value)
+{
+       struct mtu3_ep *mep;
+       struct mtu3 *mtu;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!ep || !value)
+               return -EINVAL;
+
+       mep = to_mtu3_ep(ep);
+       mtu = mep->mtu;
+
+       dev_dbg(mtu->dev, "%s\n", __func__);
+
+       spin_lock_irqsave(&mtu->lock, flags);
+
+       if (!list_empty(&mep->req_list)) {
+               ret = -EBUSY;
+               goto cleanup;
+       }
+
+       switch (mtu->ep0_state) {
+       /*
+        * stalls are usually issued after parsing SETUP packet, either
+        * directly in irq context from setup() or else later.
+        */
+       case MU3D_EP0_STATE_TX:
+       case MU3D_EP0_STATE_TX_END:
+       case MU3D_EP0_STATE_RX:
+       case MU3D_EP0_STATE_SETUP:
+               ep0_stall_set(mtu->ep0, true, 0);
+               break;
+       default:
+               dev_dbg(mtu->dev, "ep0 can't halt in state %s\n",
+                       decode_ep0_state(mtu));
+               ret = -EINVAL;
+       }
+
+cleanup:
+       spin_unlock_irqrestore(&mtu->lock, flags);
+       return ret;
+}
+
+const struct usb_ep_ops mtu3_ep0_ops = {
+       .enable = mtu3_ep0_enable,
+       .disable = mtu3_ep0_disable,
+       .alloc_request = mtu3_alloc_request,
+       .free_request = mtu3_free_request,
+       .queue = mtu3_ep0_queue,
+       .dequeue = mtu3_ep0_dequeue,
+       .set_halt = mtu3_ep0_halt,
+};
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
new file mode 100644 (file)
index 0000000..8001fc2
--- /dev/null
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static void host_ports_num_get(struct mtu3_host *u3h)
+{
+       u32 xhci_cap;
+
+       xhci_cap = mtu3_readl(u3h->ippc_base, U3D_SSUSB_IP_XHCI_CAP);
+       u3h->u2_ports = SSUSB_IP_XHCI_U2_PORT_NUM(xhci_cap);
+       u3h->u3_ports = SSUSB_IP_XHCI_U3_PORT_NUM(xhci_cap);
+
+       dev_dbg(u3h->dev, "host - u2_ports:%d, u3_ports:%d\n",
+               u3h->u2_ports, u3h->u3_ports);
+}
+
+/* only configure ports will be used later */
+static int ssusb_host_enable(struct mtu3_host *u3h)
+{
+       void __iomem *ibase = u3h->ippc_base;
+       int num_u3p = u3h->u3_ports;
+       int num_u2p = u3h->u2_ports;
+       int u3_ports_disabed;
+       u32 check_clk;
+       u32 value;
+       int i;
+
+       /* power on host ip */
+       mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+
+       /* power on and enable u3 ports except skipped ones */
+       u3_ports_disabed = 0;
+       for (i = 0; i < num_u3p; i++) {
+               if ((0x1 << i) & u3h->u3p_dis_msk) {
+                       u3_ports_disabed++;
+                       continue;
+               }
+
+               value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+               value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+               value |= SSUSB_U3_PORT_HOST_SEL;
+               mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+       }
+
+       /* power on and enable all u2 ports */
+       for (i = 0; i < num_u2p; i++) {
+               value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+               value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+               value |= SSUSB_U2_PORT_HOST_SEL;
+               mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+       }
+
+       check_clk = SSUSB_XHCI_RST_B_STS;
+       if (num_u3p > u3_ports_disabed)
+               check_clk = SSUSB_U3_MAC_RST_B_STS;
+
+       return ssusb_check_clocks(u3h->ssusb, check_clk);
+}
+
+static void ssusb_host_disable(struct mtu3_host *u3h)
+{
+       void __iomem *ibase = u3h->ippc_base;
+       int num_u3p = u3h->u3_ports;
+       int num_u2p = u3h->u2_ports;
+       u32 value;
+       int i;
+
+       /* power down and disable u3 ports except skipped ones */
+       for (i = 0; i < num_u3p; i++) {
+               if ((0x1 << i) & u3h->u3p_dis_msk)
+                       continue;
+
+               value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+               value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
+               mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+       }
+
+       /* power down and disable all u2 ports */
+       for (i = 0; i < num_u2p; i++) {
+               value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+               value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
+               mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+       }
+
+       /* power down host ip */
+       mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+}
+
+/*
+ * If host supports multiple ports, the VBUSes(5V) of ports except port0
+ * which supports OTG are better to be enabled by default in DTS.
+ * Because the host driver will keep link with devices attached when system
+ * enters suspend mode, so no need to control VBUSes after initialization.
+ */
+int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+       struct mtu3_host *u3h = ssusb->u3h;
+       struct udevice *dev = u3h->dev;
+       int ret;
+
+       u3h->ssusb = ssusb;
+       u3h->hcd = ssusb->mac_base;
+       u3h->ippc_base = ssusb->ippc_base;
+
+       /* optional property, ignore the error */
+       dev_read_u32(dev, "mediatek,u3p-dis-msk", &u3h->u3p_dis_msk);
+
+       host_ports_num_get(u3h);
+       ret = ssusb_host_enable(u3h);
+       if (ret)
+               return ret;
+
+       ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+
+       ret = regulator_set_enable(ssusb->vbus_supply, true);
+       if (ret < 0 && ret != -ENOSYS) {
+               dev_err(dev, "failed to enable vbus %d!\n", ret);
+               return ret;
+       }
+
+       dev_info(dev, "%s done...\n", __func__);
+
+       return 0;
+}
+
+void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{
+       regulator_set_enable(ssusb->vbus_supply, false);
+       ssusb_host_disable(ssusb->u3h);
+}
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
new file mode 100644 (file)
index 0000000..9c2a7e1
--- /dev/null
@@ -0,0 +1,515 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _SSUSB_HW_REGS_H_
+#define _SSUSB_HW_REGS_H_
+
+/* segment offset of MAC register */
+#define SSUSB_XCHI_BASE                0x0000
+#define SSUSB_DEV_BASE         0x1000
+#define SSUSB_EPCTL_CSR_BASE   0x1800
+#define SSUSB_USB3_MAC_CSR_BASE        0x2400
+#define SSUSB_USB3_SYS_CSR_BASE        0x2400
+#define SSUSB_USB2_CSR_BASE    0x3400
+
+/* IPPC register in Infra */
+#define SSUSB_SIFSLV_IPPC_BASE 0x0000
+
+/* --------------- SSUSB_DEV REGISTER DEFINITION --------------- */
+
+#define U3D_LV1ISR             (SSUSB_DEV_BASE + 0x0000)
+#define U3D_LV1IER             (SSUSB_DEV_BASE + 0x0004)
+#define U3D_LV1IESR            (SSUSB_DEV_BASE + 0x0008)
+#define U3D_LV1IECR            (SSUSB_DEV_BASE + 0x000C)
+
+#define U3D_EPISR              (SSUSB_DEV_BASE + 0x0080)
+#define U3D_EPIER              (SSUSB_DEV_BASE + 0x0084)
+#define U3D_EPIESR             (SSUSB_DEV_BASE + 0x0088)
+#define U3D_EPIECR             (SSUSB_DEV_BASE + 0x008C)
+
+#define U3D_EP0CSR             (SSUSB_DEV_BASE + 0x0100)
+#define U3D_RXCOUNT0           (SSUSB_DEV_BASE + 0x0108)
+#define U3D_RESERVED           (SSUSB_DEV_BASE + 0x010C)
+#define U3D_TX1CSR0            (SSUSB_DEV_BASE + 0x0110)
+#define U3D_TX1CSR1            (SSUSB_DEV_BASE + 0x0114)
+#define U3D_TX1CSR2            (SSUSB_DEV_BASE + 0x0118)
+
+#define U3D_RX1CSR0            (SSUSB_DEV_BASE + 0x0210)
+#define U3D_RX1CSR1            (SSUSB_DEV_BASE + 0x0214)
+#define U3D_RX1CSR2            (SSUSB_DEV_BASE + 0x0218)
+
+#define U3D_FIFO0              (SSUSB_DEV_BASE + 0x0300)
+
+#define U3D_QCR0               (SSUSB_DEV_BASE + 0x0400)
+#define U3D_QCR1               (SSUSB_DEV_BASE + 0x0404)
+#define U3D_QCR2               (SSUSB_DEV_BASE + 0x0408)
+#define U3D_QCR3               (SSUSB_DEV_BASE + 0x040C)
+#define U3D_QFCR               (SSUSB_DEV_BASE + 0x0428)
+
+#define U3D_TXQCSR1            (SSUSB_DEV_BASE + 0x0510)
+#define U3D_TXQSAR1            (SSUSB_DEV_BASE + 0x0514)
+#define U3D_TXQCPR1            (SSUSB_DEV_BASE + 0x0518)
+
+#define U3D_RXQCSR1            (SSUSB_DEV_BASE + 0x0610)
+#define U3D_RXQSAR1            (SSUSB_DEV_BASE + 0x0614)
+#define U3D_RXQCPR1            (SSUSB_DEV_BASE + 0x0618)
+#define U3D_RXQLDPR1           (SSUSB_DEV_BASE + 0x061C)
+
+#define U3D_QISAR0             (SSUSB_DEV_BASE + 0x0700)
+#define U3D_QIER0              (SSUSB_DEV_BASE + 0x0704)
+#define U3D_QIESR0             (SSUSB_DEV_BASE + 0x0708)
+#define U3D_QIECR0             (SSUSB_DEV_BASE + 0x070C)
+#define U3D_QISAR1             (SSUSB_DEV_BASE + 0x0710)
+#define U3D_QIER1              (SSUSB_DEV_BASE + 0x0714)
+#define U3D_QIESR1             (SSUSB_DEV_BASE + 0x0718)
+#define U3D_QIECR1             (SSUSB_DEV_BASE + 0x071C)
+
+#define U3D_TQERRIR0           (SSUSB_DEV_BASE + 0x0780)
+#define U3D_TQERRIER0          (SSUSB_DEV_BASE + 0x0784)
+#define U3D_TQERRIESR0         (SSUSB_DEV_BASE + 0x0788)
+#define U3D_TQERRIECR0         (SSUSB_DEV_BASE + 0x078C)
+#define U3D_RQERRIR0           (SSUSB_DEV_BASE + 0x07C0)
+#define U3D_RQERRIER0          (SSUSB_DEV_BASE + 0x07C4)
+#define U3D_RQERRIESR0         (SSUSB_DEV_BASE + 0x07C8)
+#define U3D_RQERRIECR0         (SSUSB_DEV_BASE + 0x07CC)
+#define U3D_RQERRIR1           (SSUSB_DEV_BASE + 0x07D0)
+#define U3D_RQERRIER1          (SSUSB_DEV_BASE + 0x07D4)
+#define U3D_RQERRIESR1         (SSUSB_DEV_BASE + 0x07D8)
+#define U3D_RQERRIECR1         (SSUSB_DEV_BASE + 0x07DC)
+
+#define U3D_CAP_EP0FFSZ                (SSUSB_DEV_BASE + 0x0C04)
+#define U3D_CAP_EPNTXFFSZ      (SSUSB_DEV_BASE + 0x0C08)
+#define U3D_CAP_EPNRXFFSZ      (SSUSB_DEV_BASE + 0x0C0C)
+#define U3D_CAP_EPINFO         (SSUSB_DEV_BASE + 0x0C10)
+#define U3D_MISC_CTRL          (SSUSB_DEV_BASE + 0x0C84)
+
+/*---------------- SSUSB_DEV FIELD DEFINITION ---------------*/
+
+/* U3D_LV1ISR */
+#define EP_CTRL_INTR           BIT(5)
+#define MAC2_INTR              BIT(4)
+#define DMA_INTR               BIT(3)
+#define MAC3_INTR              BIT(2)
+#define QMU_INTR               BIT(1)
+#define BMU_INTR               BIT(0)
+
+/* U3D_LV1IECR */
+#define LV1IECR_MSK            GENMASK(31, 0)
+
+/* U3D_EPISR */
+#define EPRISR(x)              (BIT(16) << (x))
+#define SETUPENDISR            BIT(16)
+#define EPTISR(x)              (BIT(0) << (x))
+#define EP0ISR                 BIT(0)
+
+/* U3D_EP0CSR */
+#define EP0_SENDSTALL          BIT(25)
+#define EP0_FIFOFULL           BIT(23)
+#define EP0_SENTSTALL          BIT(22)
+#define EP0_DPHTX              BIT(20)
+#define EP0_DATAEND            BIT(19)
+#define EP0_TXPKTRDY           BIT(18)
+#define EP0_SETUPPKTRDY                BIT(17)
+#define EP0_RXPKTRDY           BIT(16)
+#define EP0_MAXPKTSZ_MSK       GENMASK(9, 0)
+#define EP0_MAXPKTSZ(x)                ((x) & EP0_MAXPKTSZ_MSK)
+#define EP0_W1C_BITS   (~(EP0_RXPKTRDY | EP0_SETUPPKTRDY | EP0_SENTSTALL))
+
+/* U3D_TX1CSR0 */
+#define TX_DMAREQEN            BIT(29)
+#define TX_FIFOFULL            BIT(25)
+#define TX_FIFOEMPTY           BIT(24)
+#define TX_SENTSTALL           BIT(22)
+#define TX_SENDSTALL           BIT(21)
+#define TX_TXPKTRDY            BIT(16)
+#define TX_TXMAXPKTSZ_MSK      GENMASK(10, 0)
+#define TX_TXMAXPKTSZ(x)       ((x) & TX_TXMAXPKTSZ_MSK)
+#define TX_W1C_BITS            (~(TX_SENTSTALL))
+
+/* U3D_TX1CSR1 */
+#define TX_MAX_PKT_G2(x)       (((x) & 0xff) << 24)
+#define TX_MULT_G2(x)          (((x) & 0x7) << 21)
+#define TX_MULT_OG(x)          (((x) & 0x3) << 22)
+#define TX_MAX_PKT_OG(x)       (((x) & 0x3f) << 16)
+#define TX_SLOT(x)             (((x) & 0x3f) << 8)
+#define TX_TYPE(x)             (((x) & 0x3) << 4)
+#define TX_SS_BURST(x)         (((x) & 0xf) << 0)
+#define TX_MULT(g2c, x)                \
+({                             \
+       typeof(x) x_ = (x);     \
+       (g2c) ? TX_MULT_G2(x_) : TX_MULT_OG(x_);        \
+})
+#define TX_MAX_PKT(g2c, x)     \
+({                             \
+       typeof(x) x_ = (x);     \
+       (g2c) ? TX_MAX_PKT_G2(x_) : TX_MAX_PKT_OG(x_);  \
+})
+
+/* for TX_TYPE & RX_TYPE */
+#define TYPE_BULK              (0x0)
+#define TYPE_INT               (0x1)
+#define TYPE_ISO               (0x2)
+#define TYPE_MASK              (0x3)
+
+/* U3D_TX1CSR2 */
+#define TX_BINTERVAL(x)                (((x) & 0xff) << 24)
+#define TX_FIFOSEGSIZE(x)      (((x) & 0xf) << 16)
+#define TX_FIFOADDR(x)         (((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR0 */
+#define RX_DMAREQEN            BIT(29)
+#define RX_SENTSTALL           BIT(22)
+#define RX_SENDSTALL           BIT(21)
+#define RX_RXPKTRDY            BIT(16)
+#define RX_RXMAXPKTSZ_MSK      GENMASK(10, 0)
+#define RX_RXMAXPKTSZ(x)       ((x) & RX_RXMAXPKTSZ_MSK)
+#define RX_W1C_BITS            (~(RX_SENTSTALL | RX_RXPKTRDY))
+
+/* U3D_RX1CSR1 */
+#define RX_MAX_PKT_G2(x)       (((x) & 0xff) << 24)
+#define RX_MULT_G2(x)          (((x) & 0x7) << 21)
+#define RX_MULT_OG(x)          (((x) & 0x3) << 22)
+#define RX_MAX_PKT_OG(x)       (((x) & 0x3f) << 16)
+#define RX_SLOT(x)             (((x) & 0x3f) << 8)
+#define RX_TYPE(x)             (((x) & 0x3) << 4)
+#define RX_SS_BURST(x)         (((x) & 0xf) << 0)
+#define RX_MULT(g2c, x)                \
+({                             \
+       typeof(x) x_ = (x);     \
+       (g2c) ? RX_MULT_G2(x_) : RX_MULT_OG(x_);        \
+})
+#define RX_MAX_PKT(g2c, x)     \
+({                             \
+       typeof(x) x_ = (x);     \
+       (g2c) ? RX_MAX_PKT_G2(x_) : RX_MAX_PKT_OG(x_);  \
+})
+
+/* U3D_RX1CSR2 */
+#define RX_BINTERVAL(x)                (((x) & 0xff) << 24)
+#define RX_FIFOSEGSIZE(x)      (((x) & 0xf) << 16)
+#define RX_FIFOADDR(x)         (((x) & 0x1fff) << 0)
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)                (BIT(16) << (x))
+#define QMU_TX_CS_EN(x)                (BIT(0) << (x))
+#define QMU_CS16B_EN           BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)          (BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)          (BIT(16) << (x))
+#define QMU_RX_ZLP(x)          (BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE           BIT(15)
+#define QMU_Q_STOP             BIT(2)
+#define QMU_Q_RESUME           BIT(1)
+#define QMU_Q_START            BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)     (BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)     (BIT(0) << (x))
+
+/* U3D_QISAR1, U3D_QIER1, U3D_QIESR1, U3D_QIECR1 */
+#define RXQ_ZLPERR_INT         BIT(20)
+#define RXQ_LENERR_INT         BIT(18)
+#define RXQ_CSERR_INT          BIT(17)
+#define RXQ_EMPTY_INT          BIT(16)
+#define TXQ_LENERR_INT         BIT(2)
+#define TXQ_CSERR_INT          BIT(1)
+#define TXQ_EMPTY_INT          BIT(0)
+
+/* U3D_TQERRIR0, U3D_TQERRIER0, U3D_TQERRIESR0, U3D_TQERRIECR0 */
+#define QMU_TX_LEN_ERR(x)      (BIT(16) << (x))
+#define QMU_TX_CS_ERR(x)       (BIT(0) << (x))
+
+/* U3D_RQERRIR0, U3D_RQERRIER0, U3D_RQERRIESR0, U3D_RQERRIECR0 */
+#define QMU_RX_LEN_ERR(x)      (BIT(16) << (x))
+#define QMU_RX_CS_ERR(x)       (BIT(0) << (x))
+
+/* U3D_RQERRIR1, U3D_RQERRIER1, U3D_RQERRIESR1, U3D_RQERRIECR1 */
+#define QMU_RX_ZLP_ERR(n)      (BIT(16) << (n))
+
+/* U3D_CAP_EPINFO */
+#define CAP_RX_EP_NUM(x)       (((x) >> 8) & 0x1f)
+#define CAP_TX_EP_NUM(x)       ((x) & 0x1f)
+
+/* U3D_MISC_CTRL */
+#define VBUS_ON                        BIT(1)
+#define VBUS_FRC_EN            BIT(0)
+
+/*---------------- SSUSB_EPCTL_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_DEVICE_CONF                        (SSUSB_EPCTL_CSR_BASE + 0x0000)
+#define U3D_EP_RST                     (SSUSB_EPCTL_CSR_BASE + 0x0004)
+
+#define U3D_DEV_LINK_INTR_ENABLE       (SSUSB_EPCTL_CSR_BASE + 0x0050)
+#define U3D_DEV_LINK_INTR              (SSUSB_EPCTL_CSR_BASE + 0x0054)
+
+/*---------------- SSUSB_EPCTL_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_DEVICE_CONF */
+#define DEV_ADDR_MSK           GENMASK(30, 24)
+#define DEV_ADDR(x)            ((0x7f & (x)) << 24)
+#define HW_USB2_3_SEL          BIT(18)
+#define SW_USB2_3_SEL_EN       BIT(17)
+#define SW_USB2_3_SEL          BIT(16)
+#define SSUSB_DEV_SPEED(x)     ((x) & 0x7)
+
+/* U3D_EP_RST */
+#define EP1_IN_RST             BIT(17)
+#define EP1_OUT_RST            BIT(1)
+#define EP_RST(is_in, epnum)   (((is_in) ? BIT(16) : BIT(0)) << (epnum))
+#define EP0_RST                        BIT(0)
+
+/* U3D_DEV_LINK_INTR_ENABLE */
+/* U3D_DEV_LINK_INTR */
+#define SSUSB_DEV_SPEED_CHG_INTR       BIT(0)
+
+/*---------------- SSUSB_USB3_MAC_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LTSSM_CTRL         (SSUSB_USB3_MAC_CSR_BASE + 0x0010)
+#define U3D_USB3_CONFIG                (SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+
+#define U3D_LINK_STATE_MACHINE (SSUSB_USB3_MAC_CSR_BASE + 0x0134)
+#define U3D_LTSSM_INTR_ENABLE  (SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR         (SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
+#define U3D_U3U2_SWITCH_CTRL   (SSUSB_USB3_MAC_CSR_BASE + 0x0170)
+
+/*---------------- SSUSB_USB3_MAC_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL     BIT(4)
+#define FORCE_RXDETECT_FAIL    BIT(3)
+#define SOFT_U3_EXIT_EN                BIT(2)
+#define COMPLIANCE_EN          BIT(1)
+#define U1_GO_U2_EN            BIT(0)
+
+/* U3D_USB3_CONFIG */
+#define USB3_EN                        BIT(0)
+
+/* U3D_LINK_STATE_MACHINE */
+#define LTSSM_STATE(x) ((x) & 0x1f)
+
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR         BIT(18)
+#define U3_LFPS_TMOUT_INTR     BIT(17)
+#define VBUS_FALL_INTR         BIT(16)
+#define VBUS_RISE_INTR         BIT(15)
+#define RXDET_SUCCESS_INTR     BIT(14)
+#define EXIT_U3_INTR           BIT(13)
+#define EXIT_U2_INTR           BIT(12)
+#define EXIT_U1_INTR           BIT(11)
+#define ENTER_U3_INTR          BIT(10)
+#define ENTER_U2_INTR          BIT(9)
+#define ENTER_U1_INTR          BIT(8)
+#define ENTER_U0_INTR          BIT(7)
+#define RECOVERY_INTR          BIT(6)
+#define WARM_RST_INTR          BIT(5)
+#define HOT_RST_INTR           BIT(4)
+#define LOOPBACK_INTR          BIT(3)
+#define COMPLIANCE_INTR                BIT(2)
+#define SS_DISABLE_INTR                BIT(1)
+#define SS_INACTIVE_INTR       BIT(0)
+
+/* U3D_U3U2_SWITCH_CTRL */
+#define SOFTCON_CLR_AUTO_EN    BIT(0)
+
+/*---------------- SSUSB_USB3_SYS_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LINK_UX_INACT_TIMER        (SSUSB_USB3_SYS_CSR_BASE + 0x020C)
+#define U3D_LINK_POWER_CONTROL (SSUSB_USB3_SYS_CSR_BASE + 0x0210)
+#define U3D_LINK_ERR_COUNT     (SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+
+/*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LINK_UX_INACT_TIMER */
+#define DEV_U2_INACT_TIMEOUT_MSK       GENMASK(23, 16)
+#define DEV_U2_INACT_TIMEOUT_VALUE(x)  (((x) & 0xff) << 16)
+#define U2_INACT_TIMEOUT_MSK           GENMASK(15, 8)
+#define U1_INACT_TIMEOUT_MSK           GENMASK(7, 0)
+#define U1_INACT_TIMEOUT_VALUE(x)      ((x) & 0xff)
+
+/* U3D_LINK_POWER_CONTROL */
+#define SW_U2_ACCEPT_ENABLE    BIT(9)
+#define SW_U1_ACCEPT_ENABLE    BIT(8)
+#define UX_EXIT                        BIT(5)
+#define LGO_U3                 BIT(4)
+#define LGO_U2                 BIT(3)
+#define LGO_U1                 BIT(2)
+#define SW_U2_REQUEST_ENABLE   BIT(1)
+#define SW_U1_REQUEST_ENABLE   BIT(0)
+
+/* U3D_LINK_ERR_COUNT */
+#define CLR_LINK_ERR_CNT       BIT(16)
+#define LINK_ERROR_COUNT       GENMASK(15, 0)
+
+/*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_POWER_MANAGEMENT           (SSUSB_USB2_CSR_BASE + 0x0004)
+#define U3D_DEVICE_CONTROL             (SSUSB_USB2_CSR_BASE + 0x000C)
+#define U3D_USB2_TEST_MODE             (SSUSB_USB2_CSR_BASE + 0x0014)
+#define U3D_COMMON_USB_INTR_ENABLE     (SSUSB_USB2_CSR_BASE + 0x0018)
+#define U3D_COMMON_USB_INTR            (SSUSB_USB2_CSR_BASE + 0x001C)
+#define U3D_LINK_RESET_INFO            (SSUSB_USB2_CSR_BASE + 0x0024)
+#define U3D_USB20_FRAME_NUM            (SSUSB_USB2_CSR_BASE + 0x003C)
+#define U3D_USB20_LPM_PARAMETER                (SSUSB_USB2_CSR_BASE + 0x0044)
+#define U3D_USB20_MISC_CONTROL         (SSUSB_USB2_CSR_BASE + 0x004C)
+#define U3D_USB20_OPSTATE              (SSUSB_USB2_CSR_BASE + 0x0060)
+
+/*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_POWER_MANAGEMENT */
+#define LPM_BESL_STALL         BIT(14)
+#define LPM_BESLD_STALL                BIT(13)
+#define LPM_RWP                        BIT(11)
+#define LPM_HRWE               BIT(10)
+#define LPM_MODE(x)            (((x) & 0x3) << 8)
+#define ISO_UPDATE             BIT(7)
+#define SOFT_CONN              BIT(6)
+#define HS_ENABLE              BIT(5)
+#define RESUME                 BIT(2)
+#define SUSPENDM_ENABLE                BIT(0)
+
+/* U3D_DEVICE_CONTROL */
+#define DC_HOSTREQ             BIT(1)
+#define DC_SESSION             BIT(0)
+
+/* U3D_USB2_TEST_MODE */
+#define U2U3_AUTO_SWITCH       BIT(10)
+#define LPM_FORCE_STALL                BIT(8)
+#define FIFO_ACCESS            BIT(6)
+#define FORCE_FS               BIT(5)
+#define FORCE_HS               BIT(4)
+#define TEST_PACKET_MODE       BIT(3)
+#define TEST_K_MODE            BIT(2)
+#define TEST_J_MODE            BIT(1)
+#define TEST_SE0_NAK_MODE      BIT(0)
+
+/* U3D_COMMON_USB_INTR_ENABLE */
+/* U3D_COMMON_USB_INTR */
+#define LPM_RESUME_INTR                BIT(9)
+#define LPM_INTR               BIT(8)
+#define DISCONN_INTR           BIT(5)
+#define CONN_INTR              BIT(4)
+#define SOF_INTR               BIT(3)
+#define RESET_INTR             BIT(2)
+#define RESUME_INTR            BIT(1)
+#define SUSPEND_INTR           BIT(0)
+
+/* U3D_LINK_RESET_INFO */
+#define WTCHRP_MSK             GENMASK(19, 16)
+
+/* U3D_USB20_LPM_PARAMETER */
+#define LPM_BESLCK_U3(x)       (((x) & 0xf) << 12)
+#define LPM_BESLCK(x)          (((x) & 0xf) << 8)
+#define LPM_BESLDCK(x)         (((x) & 0xf) << 4)
+#define LPM_BESL               GENMASK(3, 0)
+
+/* U3D_USB20_MISC_CONTROL */
+#define LPM_U3_ACK_EN          BIT(0)
+
+/*---------------- SSUSB_SIFSLV_IPPC REGISTER DEFINITION ----------------*/
+
+#define U3D_SSUSB_IP_PW_CTRL0  (SSUSB_SIFSLV_IPPC_BASE + 0x0000)
+#define U3D_SSUSB_IP_PW_CTRL1  (SSUSB_SIFSLV_IPPC_BASE + 0x0004)
+#define U3D_SSUSB_IP_PW_CTRL2  (SSUSB_SIFSLV_IPPC_BASE + 0x0008)
+#define U3D_SSUSB_IP_PW_CTRL3  (SSUSB_SIFSLV_IPPC_BASE + 0x000C)
+#define U3D_SSUSB_IP_PW_STS1   (SSUSB_SIFSLV_IPPC_BASE + 0x0010)
+#define U3D_SSUSB_IP_PW_STS2   (SSUSB_SIFSLV_IPPC_BASE + 0x0014)
+#define U3D_SSUSB_OTG_STS      (SSUSB_SIFSLV_IPPC_BASE + 0x0018)
+#define U3D_SSUSB_OTG_STS_CLR  (SSUSB_SIFSLV_IPPC_BASE + 0x001C)
+#define U3D_SSUSB_IP_XHCI_CAP  (SSUSB_SIFSLV_IPPC_BASE + 0x0024)
+#define U3D_SSUSB_IP_DEV_CAP   (SSUSB_SIFSLV_IPPC_BASE + 0x0028)
+#define U3D_SSUSB_OTG_INT_EN   (SSUSB_SIFSLV_IPPC_BASE + 0x002C)
+#define U3D_SSUSB_U3_CTRL_0P   (SSUSB_SIFSLV_IPPC_BASE + 0x0030)
+#define U3D_SSUSB_U2_CTRL_0P   (SSUSB_SIFSLV_IPPC_BASE + 0x0050)
+#define U3D_SSUSB_REF_CK_CTRL  (SSUSB_SIFSLV_IPPC_BASE + 0x008C)
+#define U3D_SSUSB_DEV_RST_CTRL (SSUSB_SIFSLV_IPPC_BASE + 0x0098)
+#define U3D_SSUSB_HW_ID                (SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
+#define U3D_SSUSB_HW_SUB_ID    (SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_TRUNK_VERS        (U3D_SSUSB_HW_SUB_ID)
+#define U3D_SSUSB_PRB_CTRL0    (SSUSB_SIFSLV_IPPC_BASE + 0x00B0)
+#define U3D_SSUSB_PRB_CTRL1    (SSUSB_SIFSLV_IPPC_BASE + 0x00B4)
+#define U3D_SSUSB_PRB_CTRL2    (SSUSB_SIFSLV_IPPC_BASE + 0x00B8)
+#define U3D_SSUSB_PRB_CTRL3    (SSUSB_SIFSLV_IPPC_BASE + 0x00BC)
+#define U3D_SSUSB_PRB_CTRL4    (SSUSB_SIFSLV_IPPC_BASE + 0x00C0)
+#define U3D_SSUSB_PRB_CTRL5    (SSUSB_SIFSLV_IPPC_BASE + 0x00C4)
+#define U3D_SSUSB_IP_SPARE0    (SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
+
+/*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/
+
+/* U3D_SSUSB_IP_PW_CTRL0 */
+#define SSUSB_IP_SW_RST                        BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL1 */
+#define SSUSB_IP_HOST_PDN              BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL2 */
+#define SSUSB_IP_DEV_PDN               BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL3 */
+#define SSUSB_IP_PCIE_PDN              BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS1 */
+#define SSUSB_IP_SLEEP_STS             BIT(30)
+#define SSUSB_U3_MAC_RST_B_STS         BIT(16)
+#define SSUSB_XHCI_RST_B_STS           BIT(11)
+#define SSUSB_SYS125_RST_B_STS         BIT(10)
+#define SSUSB_REF_RST_B_STS            BIT(8)
+#define SSUSB_SYSPLL_STABLE            BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS2 */
+#define SSUSB_U2_MAC_SYS_RST_B_STS     BIT(0)
+
+/* U3D_SSUSB_OTG_STS */
+#define SSUSB_VBUS_VALID               BIT(9)
+
+/* U3D_SSUSB_OTG_STS_CLR */
+#define SSUSB_VBUS_INTR_CLR            BIT(6)
+
+/* U3D_SSUSB_IP_XHCI_CAP */
+#define SSUSB_IP_XHCI_U2_PORT_NUM(x)   (((x) >> 8) & 0xff)
+#define SSUSB_IP_XHCI_U3_PORT_NUM(x)   ((x) & 0xff)
+
+/* U3D_SSUSB_IP_DEV_CAP */
+#define SSUSB_IP_DEV_U3_PORT_NUM(x)    ((x) & 0xff)
+
+/* U3D_SSUSB_OTG_INT_EN */
+#define SSUSB_VBUS_CHG_INT_A_EN                BIT(7)
+#define SSUSB_VBUS_CHG_INT_B_EN                BIT(6)
+
+/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED        BIT(9)
+#define SSUSB_U3_PORT_DUAL_MODE        BIT(7)
+#define SSUSB_U3_PORT_HOST_SEL         BIT(2)
+#define SSUSB_U3_PORT_PDN              BIT(1)
+#define SSUSB_U3_PORT_DIS              BIT(0)
+
+/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_RG_IDDIG         BIT(12)
+#define SSUSB_U2_PORT_FORCE_IDDIG      BIT(11)
+#define SSUSB_U2_PORT_VBUSVALID        BIT(9)
+#define SSUSB_U2_PORT_OTG_SEL          BIT(7)
+#define SSUSB_U2_PORT_HOST             BIT(2)
+#define SSUSB_U2_PORT_PDN              BIT(1)
+#define SSUSB_U2_PORT_DIS              BIT(0)
+#define SSUSB_U2_PORT_HOST_SEL (SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST)
+
+/* U3D_SSUSB_DEV_RST_CTRL */
+#define SSUSB_DEV_SW_RST               BIT(0)
+
+/* U3D_SSUSB_IP_TRUNK_VERS */
+#define IP_TRUNK_VERS(x)               (((x) >> 16) & 0xffff)
+
+#endif /* _SSUSB_HW_REGS_H_ */
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
new file mode 100644 (file)
index 0000000..3795e69
--- /dev/null
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+                         enum mtu3_dr_force_mode mode)
+{
+       u32 value;
+
+       value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
+       switch (mode) {
+       case MTU3_DR_FORCE_DEVICE:
+               value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
+               break;
+       case MTU3_DR_FORCE_HOST:
+               value |= SSUSB_U2_PORT_FORCE_IDDIG;
+               value &= ~SSUSB_U2_PORT_RG_IDDIG;
+               break;
+       case MTU3_DR_FORCE_NONE:
+               value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
+               break;
+       default:
+               return;
+       }
+       mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
+}
+
+/* u2-port0 should be powered on and enabled; */
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
+{
+       void __iomem *ibase = ssusb->ippc_base;
+       u32 value, check_val;
+       int ret;
+
+       check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
+                       SSUSB_REF_RST_B_STS;
+
+       ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
+                                ((value & check_val) == check_val), 10000);
+       if (ret) {
+               dev_err(ssusb->dev, "clks of sts1 are not stable!\n");
+               return ret;
+       }
+
+       ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value,
+                                (value & SSUSB_U2_MAC_SYS_RST_B_STS), 10000);
+       if (ret) {
+               dev_err(ssusb->dev, "mac2 clock is not stable\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int ssusb_phy_setup(struct ssusb_mtk *ssusb)
+{
+       struct udevice *dev = ssusb->dev;
+       struct phy_bulk *phys = &ssusb->phys;
+       int ret;
+
+       ret = generic_phy_get_bulk(dev, phys);
+       if (ret)
+               return ret;
+
+       ret = generic_phy_init_bulk(phys);
+       if (ret)
+               return ret;
+
+       ret = generic_phy_power_on_bulk(phys);
+       if (ret)
+               generic_phy_exit_bulk(phys);
+
+       return ret;
+}
+
+void ssusb_phy_shutdown(struct ssusb_mtk *ssusb)
+{
+       generic_phy_power_off_bulk(&ssusb->phys);
+       generic_phy_exit_bulk(&ssusb->phys);
+}
+
+static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
+{
+       int ret = 0;
+
+       ret = regulator_set_enable(ssusb->vusb33_supply, true);
+       if (ret < 0 && ret != -ENOSYS) {
+               dev_err(ssusb->dev, "failed to enable vusb33\n");
+               goto vusb33_err;
+       }
+
+       ret = clk_enable_bulk(&ssusb->clks);
+       if (ret)
+               goto clks_err;
+
+       ret = ssusb_phy_setup(ssusb);
+       if (ret) {
+               dev_err(ssusb->dev, "failed to setup phy\n");
+               goto phy_err;
+       }
+
+       return 0;
+
+phy_err:
+       clk_disable_bulk(&ssusb->clks);
+clks_err:
+       regulator_set_enable(ssusb->vusb33_supply, false);
+vusb33_err:
+       return ret;
+}
+
+static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
+{
+       clk_disable_bulk(&ssusb->clks);
+       regulator_set_enable(ssusb->vusb33_supply, false);
+       ssusb_phy_shutdown(ssusb);
+}
+
+static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
+{
+       /* reset whole ip (xhci & u3d) */
+       mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+       udelay(1);
+       mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+}
+
+static int get_ssusb_rscs(struct udevice *dev, struct ssusb_mtk *ssusb)
+{
+       struct udevice *child;
+       int ret;
+
+       ret = device_get_supply_regulator(dev, "vusb33-supply",
+                                         &ssusb->vusb33_supply);
+       if (ret)        /* optional, ignore error */
+               dev_warn(dev, "can't get optional vusb33 %d\n", ret);
+
+       ret = device_get_supply_regulator(dev, "vbus-supply",
+                                         &ssusb->vbus_supply);
+       if (ret)        /* optional, ignore error */
+               dev_warn(dev, "can't get optional vbus regulator %d!\n", ret);
+
+       ret = clk_get_bulk(dev, &ssusb->clks);
+       if (ret) {
+               dev_err(dev, "failed to get clocks %d!\n", ret);
+               return ret;
+       }
+
+       ssusb->ippc_base = devfdt_remap_addr_name(dev, "ippc");
+       if (!ssusb->ippc_base) {
+               dev_err(dev, "error mapping memory for ippc\n");
+               return -ENODEV;
+       }
+
+       ret = device_find_first_child(dev, &child);
+       if (ret || !child) {
+               dev_err(dev, "failed to get child %d!\n", ret);
+               return ret;
+       }
+
+       ssusb->mac_base = devfdt_remap_addr_name(child, "mac");
+       if (!ssusb->mac_base) {
+               dev_err(dev, "error mapping memory for mac\n");
+               return -ENODEV;
+       }
+
+       ssusb->dr_mode = usb_get_dr_mode(child->node);
+
+       if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN ||
+               ssusb->dr_mode == USB_DR_MODE_OTG)
+               ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+       if (IS_ENABLED(CONFIG_USB_MTU3_GADGET))
+               ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+       else if (IS_ENABLED(CONFIG_USB_MTU3_HOST))
+               ssusb->dr_mode = USB_DR_MODE_HOST;
+
+       dev_info(dev, "dr_mode: %d, ippc: 0x%p, mac: 0x%p\n",
+                ssusb->dr_mode, ssusb->ippc_base, ssusb->mac_base);
+
+       return 0;
+}
+
+static int mtu3_probe(struct udevice *dev)
+{
+       struct ssusb_mtk *ssusb = dev_get_priv(dev);
+       int ret = -ENOMEM;
+
+       ssusb->dev = dev;
+
+       ret = get_ssusb_rscs(dev, ssusb);
+       if (ret)
+               return ret;
+
+       ret = ssusb_rscs_init(ssusb);
+       if (ret)
+               return ret;
+
+       ssusb_ip_sw_reset(ssusb);
+
+       return 0;
+}
+
+static int mtu3_remove(struct udevice *dev)
+{
+       struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
+
+       ssusb_rscs_exit(ssusb);
+       return 0;
+}
+
+static const struct udevice_id ssusb_of_match[] = {
+       {.compatible = "mediatek,ssusb",},
+       {},
+};
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+       struct mtu3 *mtu = dev_get_priv(dev);
+
+       mtu3_irq(0, mtu);
+
+       return 0;
+}
+
+static int mtu3_gadget_probe(struct udevice *dev)
+{
+       struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+       struct mtu3 *mtu = dev_get_priv(dev);
+
+       mtu->dev = dev;
+       ssusb->u3d = mtu;
+       return ssusb_gadget_init(ssusb);
+}
+
+static int mtu3_gadget_remove(struct udevice *dev)
+{
+       struct mtu3 *mtu = dev_get_priv(dev);
+
+       ssusb_gadget_exit(mtu->ssusb);
+       return 0;
+}
+
+U_BOOT_DRIVER(mtu3_peripheral) = {
+       .name = "mtu3-peripheral",
+       .id = UCLASS_USB_GADGET_GENERIC,
+       .of_match = ssusb_of_match,
+       .probe = mtu3_gadget_probe,
+       .remove = mtu3_gadget_remove,
+       .priv_auto_alloc_size = sizeof(struct mtu3),
+};
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+       (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+static int mtu3_host_probe(struct udevice *dev)
+{
+       struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+       struct mtu3_host *u3h = dev_get_priv(dev);
+       struct xhci_hcor *hcor;
+       int rc;
+
+       u3h->dev = dev;
+       ssusb->u3h = u3h;
+       rc = ssusb_host_init(ssusb);
+       if (rc)
+               return rc;
+
+       u3h->ctrl.quirks = XHCI_MTK_HOST;
+       hcor = (struct xhci_hcor *)((uintptr_t)u3h->hcd +
+                       HC_LENGTH(xhci_readl(&u3h->hcd->cr_capbase)));
+
+       return xhci_register(dev, u3h->hcd, hcor);
+}
+
+static int mtu3_host_remove(struct udevice *dev)
+{
+       struct mtu3_host *u3h = dev_get_priv(dev);
+
+       xhci_deregister(dev);
+       ssusb_host_exit(u3h->ssusb);
+       return 0;
+}
+
+U_BOOT_DRIVER(mtu3_host) = {
+       .name = "mtu3-host",
+       .id = UCLASS_USB,
+       .of_match = ssusb_of_match,
+       .probe = mtu3_host_probe,
+       .remove = mtu3_host_remove,
+       .priv_auto_alloc_size = sizeof(struct mtu3_host),
+       .ops = &xhci_usb_ops,
+       .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
+
+static int mtu3_glue_bind(struct udevice *parent)
+{
+       struct udevice *dev;
+       enum usb_dr_mode dr_mode;
+       const char *driver;
+       const char *name;
+       ofnode node;
+       int ret;
+
+       node = ofnode_by_compatible(parent->node, "mediatek,ssusb");
+       if (!ofnode_valid(node))
+               return -ENODEV;
+
+       name = ofnode_get_name(node);
+       dr_mode = usb_get_dr_mode(node);
+
+       switch (dr_mode) {
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               dev_dbg(parent, "%s: dr_mode: peripheral\n", __func__);
+               driver = "mtu3-peripheral";
+               break;
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+       (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+       case USB_DR_MODE_HOST:
+               dev_dbg(parent, "%s: dr_mode: host\n", __func__);
+               driver = "mtu3-host";
+               break;
+#endif
+       default:
+               dev_err(parent, "%s: unsupported dr_mode %d\n",
+                       __func__, dr_mode);
+               return -ENODEV;
+       };
+
+       dev_dbg(parent, "%s: node name: %s, driver %s, dr_mode %d\n",
+               __func__, name, driver, dr_mode);
+
+       ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
+       if (ret)
+               dev_err(parent, "%s: not able to bind usb device mode\n",
+                       __func__);
+
+       return ret;
+}
+
+static const struct udevice_id mtu3_of_match[] = {
+       {.compatible = "mediatek,mtu3",},
+       {},
+};
+
+U_BOOT_DRIVER(mtu3) = {
+       .name = "mtu3",
+       .id = UCLASS_NOP,
+       .of_match = mtu3_of_match,
+       .bind = mtu3_glue_bind,
+       .probe = mtu3_probe,
+       .remove = mtu3_remove,
+       .priv_auto_alloc_size = sizeof(struct ssusb_mtk),
+};
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
new file mode 100644 (file)
index 0000000..801c2bc
--- /dev/null
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_qmu.c - Queue Management Unit driver for device controller
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+/*
+ * Queue Management Unit (QMU) is designed to unload SW effort
+ * to serve DMA interrupts.
+ * By preparing General Purpose Descriptor (GPD) and Buffer Descriptor (BD),
+ * SW links data buffers and triggers QMU to send / receive data to
+ * host / from device at a time.
+ * And now only GPD is supported.
+ *
+ * For more detailed information, please refer to QMU Programming Guide
+ */
+
+#include <asm/cache.h>
+#include <cpu_func.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "mtu3.h"
+
+#define QMU_CHECKSUM_LEN       16
+
+#define GPD_FLAGS_HWO  BIT(0)
+#define GPD_FLAGS_BDP  BIT(1)
+#define GPD_FLAGS_BPS  BIT(2)
+#define GPD_FLAGS_IOC  BIT(7)
+
+#define GPD_EXT_FLAG_ZLP       BIT(5)
+
+#define DCACHELINE_SIZE                CONFIG_SYS_CACHELINE_SIZE
+
+void mtu3_flush_cache(uintptr_t addr, u32 len)
+{
+       WARN_ON(!(void *)addr || len == 0);
+
+       flush_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+                          ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+void mtu3_inval_cache(uintptr_t addr, u32 len)
+{
+       WARN_ON(!(void *)addr || len == 0);
+
+       invalidate_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+                               ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
+                                      dma_addr_t dma_addr)
+{
+       dma_addr_t dma_base = ring->dma;
+       struct qmu_gpd *gpd_head = ring->start;
+       u32 offset = (dma_addr - dma_base) / sizeof(*gpd_head);
+
+       if (offset >= MAX_GPD_NUM)
+               return NULL;
+
+       return gpd_head + offset;
+}
+
+static dma_addr_t gpd_virt_to_dma(struct mtu3_gpd_ring *ring,
+                                 struct qmu_gpd *gpd)
+{
+       dma_addr_t dma_base = ring->dma;
+       struct qmu_gpd *gpd_head = ring->start;
+       u32 offset;
+
+       offset = gpd - gpd_head;
+       if (offset >= MAX_GPD_NUM)
+               return 0;
+
+       return dma_base + (offset * sizeof(*gpd));
+}
+
+static void gpd_ring_init(struct mtu3_gpd_ring *ring, struct qmu_gpd *gpd)
+{
+       ring->start = gpd;
+       ring->enqueue = gpd;
+       ring->dequeue = gpd;
+       ring->end = gpd + MAX_GPD_NUM - 1;
+}
+
+static void reset_gpd_list(struct mtu3_ep *mep)
+{
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       struct qmu_gpd *gpd = ring->start;
+
+       if (gpd) {
+               gpd->flag &= ~GPD_FLAGS_HWO;
+               gpd_ring_init(ring, gpd);
+               mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+       }
+}
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep)
+{
+       struct qmu_gpd *gpd;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+       /* software own all gpds as default */
+       gpd = memalign(DCACHELINE_SIZE, QMU_GPD_RING_SIZE);
+       if (!gpd)
+               return -ENOMEM;
+
+       memset(gpd, 0, QMU_GPD_RING_SIZE);
+       ring->dma = (dma_addr_t)gpd;
+       gpd_ring_init(ring, gpd);
+
+       return 0;
+}
+
+void mtu3_gpd_ring_free(struct mtu3_ep *mep)
+{
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+       kfree(ring->start);
+       memset(ring, 0, sizeof(*ring));
+}
+
+void mtu3_qmu_resume(struct mtu3_ep *mep)
+{
+       struct mtu3 *mtu = mep->mtu;
+       void __iomem *mbase = mtu->mac_base;
+       int epnum = mep->epnum;
+       u32 offset;
+
+       offset = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+       mtu3_writel(mbase, offset, QMU_Q_RESUME);
+       if (!(mtu3_readl(mbase, offset) & QMU_Q_ACTIVE))
+               mtu3_writel(mbase, offset, QMU_Q_RESUME);
+}
+
+static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
+{
+       if (ring->enqueue < ring->end)
+               ring->enqueue++;
+       else
+               ring->enqueue = ring->start;
+
+       return ring->enqueue;
+}
+
+static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
+{
+       if (ring->dequeue < ring->end)
+               ring->dequeue++;
+       else
+               ring->dequeue = ring->start;
+
+       return ring->dequeue;
+}
+
+/* check if a ring is emtpy */
+static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+{
+       struct qmu_gpd *enq = ring->enqueue;
+       struct qmu_gpd *next;
+
+       if (ring->enqueue < ring->end)
+               next = enq + 1;
+       else
+               next = ring->start;
+
+       /* one gpd is reserved to simplify gpd preparation */
+       return next == ring->dequeue;
+}
+
+int mtu3_prepare_transfer(struct mtu3_ep *mep)
+{
+       return gpd_ring_empty(&mep->gpd_ring);
+}
+
+static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+       struct qmu_gpd *enq;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       struct qmu_gpd *gpd = ring->enqueue;
+       struct usb_request *req = &mreq->request;
+
+       /* set all fields to zero as default value */
+       memset(gpd, 0, sizeof(*gpd));
+
+       gpd->buffer = cpu_to_le32((u32)req->dma);
+       gpd->buf_len = cpu_to_le16(req->length);
+
+       /* get the next GPD */
+       enq = advance_enq_gpd(ring);
+       dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n",
+               mep->epnum, gpd, enq);
+
+       enq->flag &= ~GPD_FLAGS_HWO;
+       gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+
+       if (req->zero)
+               gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+
+       gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+       mreq->gpd = gpd;
+
+       if (req->length)
+               mtu3_flush_cache((uintptr_t)req->buf, req->length);
+
+       mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+       return 0;
+}
+
+static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+       struct qmu_gpd *enq;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       struct qmu_gpd *gpd = ring->enqueue;
+       struct usb_request *req = &mreq->request;
+
+       /* set all fields to zero as default value */
+       memset(gpd, 0, sizeof(*gpd));
+
+       gpd->buffer = cpu_to_le32((u32)req->dma);
+       gpd->data_buf_len = cpu_to_le16(req->length);
+
+       /* get the next GPD */
+       enq = advance_enq_gpd(ring);
+       dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n",
+               mep->epnum, gpd, enq);
+
+       enq->flag &= ~GPD_FLAGS_HWO;
+       gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+       gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+       mreq->gpd = gpd;
+
+       mtu3_inval_cache((uintptr_t)req->buf, req->length);
+       mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+       return 0;
+}
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+       if (mep->is_in)
+               mtu3_prepare_tx_gpd(mep, mreq);
+       else
+               mtu3_prepare_rx_gpd(mep, mreq);
+}
+
+int mtu3_qmu_start(struct mtu3_ep *mep)
+{
+       struct mtu3 *mtu = mep->mtu;
+       void __iomem *mbase = mtu->mac_base;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       u8 epnum = mep->epnum;
+
+       if (mep->is_in) {
+               /* set QMU start address */
+               mtu3_writel(mbase, USB_QMU_TQSAR(epnum), ring->dma);
+               mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
+               /* send zero length packet according to ZLP flag in GPD */
+               mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
+               mtu3_writel(mbase, U3D_TQERRIESR0,
+                           QMU_TX_LEN_ERR(epnum) | QMU_TX_CS_ERR(epnum));
+
+               if (mtu3_readl(mbase, USB_QMU_TQCSR(epnum)) & QMU_Q_ACTIVE) {
+                       dev_warn(mtu->dev, "Tx %d Active Now!\n", epnum);
+                       return 0;
+               }
+               mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
+
+       } else {
+               mtu3_writel(mbase, USB_QMU_RQSAR(epnum), ring->dma);
+               mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
+               /* don't expect ZLP */
+               mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum));
+               /* move to next GPD when receive ZLP */
+               mtu3_setbits(mbase, U3D_QCR3, QMU_RX_COZ(epnum));
+               mtu3_writel(mbase, U3D_RQERRIESR0,
+                           QMU_RX_LEN_ERR(epnum) | QMU_RX_CS_ERR(epnum));
+               mtu3_writel(mbase, U3D_RQERRIESR1, QMU_RX_ZLP_ERR(epnum));
+
+               if (mtu3_readl(mbase, USB_QMU_RQCSR(epnum)) & QMU_Q_ACTIVE) {
+                       dev_warn(mtu->dev, "Rx %d Active Now!\n", epnum);
+                       return 0;
+               }
+               mtu3_writel(mbase, USB_QMU_RQCSR(epnum), QMU_Q_START);
+       }
+
+       return 0;
+}
+
+/* may called in atomic context */
+void mtu3_qmu_stop(struct mtu3_ep *mep)
+{
+       struct mtu3 *mtu = mep->mtu;
+       void __iomem *mbase = mtu->mac_base;
+       int epnum = mep->epnum;
+       u32 value = 0;
+       u32 qcsr;
+       int ret;
+
+       qcsr = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+       if (!(mtu3_readl(mbase, qcsr) & QMU_Q_ACTIVE)) {
+               dev_dbg(mtu->dev, "%s's qmu is inactive now!\n", mep->name);
+               return;
+       }
+       mtu3_writel(mbase, qcsr, QMU_Q_STOP);
+
+       ret = readl_poll_timeout(mbase + qcsr, value,
+                                !(value & QMU_Q_ACTIVE), 1000);
+       if (ret) {
+               dev_err(mtu->dev, "stop %s's qmu failed\n", mep->name);
+               return;
+       }
+
+       dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
+}
+
+void mtu3_qmu_flush(struct mtu3_ep *mep)
+{
+       dev_dbg(mep->mtu->dev, "%s flush QMU %s\n", __func__,
+               ((mep->is_in) ? "TX" : "RX"));
+
+       /*Stop QMU */
+       mtu3_qmu_stop(mep);
+       reset_gpd_list(mep);
+}
+
+/*
+ * NOTE: request list maybe is already empty as following case:
+ * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
+ * queue_tx --> process_tasklet(meanwhile, the second one is transferred,
+ * tasklet process both of them)-->qmu_interrupt for second one.
+ * To avoid upper case, put qmu_done_tx in ISR directly to process it.
+ */
+static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
+{
+       struct mtu3_ep *mep = mtu->in_eps + epnum;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       void __iomem *mbase = mtu->mac_base;
+       struct qmu_gpd *gpd = ring->dequeue;
+       struct qmu_gpd *gpd_current = NULL;
+       struct usb_request *req = NULL;
+       struct mtu3_request *mreq;
+       dma_addr_t cur_gpd_dma;
+
+       /*transfer phy address got from QMU register to virtual address */
+       cur_gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
+       gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+       mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+       dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+               __func__, epnum, gpd, gpd_current, ring->enqueue);
+
+       while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+               mreq = next_request(mep);
+
+               if (!mreq || mreq->gpd != gpd) {
+                       dev_err(mtu->dev, "no correct TX req is found\n");
+                       break;
+               }
+
+               req = &mreq->request;
+               req->actual = le16_to_cpu(gpd->buf_len);
+               mtu3_req_complete(mep, req, 0);
+
+               gpd = advance_deq_gpd(ring);
+               mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+       }
+
+       dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+               __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
+{
+       struct mtu3_ep *mep = mtu->out_eps + epnum;
+       struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+       void __iomem *mbase = mtu->mac_base;
+       struct qmu_gpd *gpd = ring->dequeue;
+       struct qmu_gpd *gpd_current = NULL;
+       struct usb_request *req = NULL;
+       struct mtu3_request *mreq;
+       dma_addr_t cur_gpd_dma;
+
+       cur_gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
+       gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+       mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+       dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+               __func__, epnum, gpd, gpd_current, ring->enqueue);
+
+       while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+               mreq = next_request(mep);
+
+               if (!mreq || mreq->gpd != gpd) {
+                       dev_err(mtu->dev, "no correct RX req is found\n");
+                       break;
+               }
+               req = &mreq->request;
+
+               req->actual = le16_to_cpu(gpd->buf_len);
+               mtu3_req_complete(mep, req, 0);
+
+               gpd = advance_deq_gpd(ring);
+               mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+       }
+
+       dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+               __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_isr(struct mtu3 *mtu, u32 done_status)
+{
+       int i;
+
+       for (i = 1; i < mtu->num_eps; i++) {
+               if (done_status & QMU_RX_DONE_INT(i))
+                       qmu_done_rx(mtu, i);
+               if (done_status & QMU_TX_DONE_INT(i))
+                       qmu_done_tx(mtu, i);
+       }
+}
+
+static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 errval;
+       int i;
+
+       if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
+               errval = mtu3_readl(mbase, U3D_RQERRIR0);
+               for (i = 1; i < mtu->num_eps; i++) {
+                       if (errval & QMU_RX_CS_ERR(i))
+                               dev_err(mtu->dev, "Rx %d CS error!\n", i);
+
+                       if (errval & QMU_RX_LEN_ERR(i))
+                               dev_err(mtu->dev, "RX %d Length error\n", i);
+               }
+               mtu3_writel(mbase, U3D_RQERRIR0, errval);
+       }
+
+       if (qmu_status & RXQ_ZLPERR_INT) {
+               errval = mtu3_readl(mbase, U3D_RQERRIR1);
+               for (i = 1; i < mtu->num_eps; i++) {
+                       if (errval & QMU_RX_ZLP_ERR(i))
+                               dev_dbg(mtu->dev, "RX EP%d Recv ZLP\n", i);
+               }
+               mtu3_writel(mbase, U3D_RQERRIR1, errval);
+       }
+
+       if ((qmu_status & TXQ_CSERR_INT) || (qmu_status & TXQ_LENERR_INT)) {
+               errval = mtu3_readl(mbase, U3D_TQERRIR0);
+               for (i = 1; i < mtu->num_eps; i++) {
+                       if (errval & QMU_TX_CS_ERR(i))
+                               dev_err(mtu->dev, "Tx %d checksum error!\n", i);
+
+                       if (errval & QMU_TX_LEN_ERR(i))
+                               dev_err(mtu->dev, "Tx %d zlp error!\n", i);
+               }
+               mtu3_writel(mbase, U3D_TQERRIR0, errval);
+       }
+}
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu)
+{
+       void __iomem *mbase = mtu->mac_base;
+       u32 qmu_status;
+       u32 qmu_done_status;
+
+       /* U3D_QISAR1 is read update */
+       qmu_status = mtu3_readl(mbase, U3D_QISAR1);
+       qmu_status &= mtu3_readl(mbase, U3D_QIER1);
+
+       qmu_done_status = mtu3_readl(mbase, U3D_QISAR0);
+       qmu_done_status &= mtu3_readl(mbase, U3D_QIER0);
+       mtu3_writel(mbase, U3D_QISAR0, qmu_done_status); /* W1C */
+       dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n",
+               (qmu_done_status & 0xFFFF), qmu_done_status >> 16,
+               qmu_status);
+
+       if (qmu_done_status)
+               qmu_done_isr(mtu, qmu_done_status);
+
+       if (qmu_status)
+               qmu_exception_isr(mtu, qmu_status);
+
+       return IRQ_HANDLED;
+}
+
+void mtu3_qmu_init(struct mtu3 *mtu)
+{
+       compiletime_assert(QMU_GPD_SIZE == 16, "QMU_GPD size SHOULD be 16B");
+}
+
+void mtu3_qmu_exit(struct mtu3 *mtu)
+{
+}
diff --git a/drivers/usb/mtu3/mtu3_qmu.h b/drivers/usb/mtu3/mtu3_qmu.h
new file mode 100644 (file)
index 0000000..ba8a3aa
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_qmu.h - Queue Management Unit driver header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTK_QMU_H__
+#define __MTK_QMU_H__
+
+#define MAX_GPD_NUM            16
+#define QMU_GPD_SIZE           (sizeof(struct qmu_gpd))
+#define QMU_GPD_RING_SIZE      (MAX_GPD_NUM * QMU_GPD_SIZE)
+
+#define GPD_BUF_SIZE           65532
+
+void mtu3_flush_cache(uintptr_t addr, u32 len);
+void mtu3_inval_cache(uintptr_t addr, u32 len);
+
+void mtu3_qmu_stop(struct mtu3_ep *mep);
+int mtu3_qmu_start(struct mtu3_ep *mep);
+void mtu3_qmu_resume(struct mtu3_ep *mep);
+void mtu3_qmu_flush(struct mtu3_ep *mep);
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq);
+int mtu3_prepare_transfer(struct mtu3_ep *mep);
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep);
+void mtu3_gpd_ring_free(struct mtu3_ep *mep);
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu);
+void mtu3_qmu_init(struct mtu3 *mtu);
+void mtu3_qmu_exit(struct mtu3 *mtu);
+
+#endif
index 236bab3..d55a920 100644 (file)
@@ -340,7 +340,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
         * Also, DRVVBUS pulses for SRP (but not at 5V) ...
         */
        if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
-               pr_info("CAUTION: musb: Babble Interrupt Occured\n");
+               pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
 
        if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
                int drvvbus = dsps_readl(reg_base, wrp->status);
diff --git a/include/dt-bindings/clock/r8a774c0-cpg-mssr.h b/include/dt-bindings/clock/r8a774c0-cpg-mssr.h
new file mode 100644 (file)
index 0000000..9db5c76
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+#ifndef __DT_BINDINGS_CLOCK_R8A774C0_CPG_MSSR_H__
+#define __DT_BINDINGS_CLOCK_R8A774C0_CPG_MSSR_H__
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/* r8a774c0 CPG Core Clocks */
+#define R8A774C0_CLK_Z2                        0
+#define R8A774C0_CLK_ZG                        1
+#define R8A774C0_CLK_ZTR               2
+#define R8A774C0_CLK_ZT                        3
+#define R8A774C0_CLK_ZX                        4
+#define R8A774C0_CLK_S0D1              5
+#define R8A774C0_CLK_S0D3              6
+#define R8A774C0_CLK_S0D6              7
+#define R8A774C0_CLK_S0D12             8
+#define R8A774C0_CLK_S0D24             9
+#define R8A774C0_CLK_S1D1              10
+#define R8A774C0_CLK_S1D2              11
+#define R8A774C0_CLK_S1D4              12
+#define R8A774C0_CLK_S2D1              13
+#define R8A774C0_CLK_S2D2              14
+#define R8A774C0_CLK_S2D4              15
+#define R8A774C0_CLK_S3D1              16
+#define R8A774C0_CLK_S3D2              17
+#define R8A774C0_CLK_S3D4              18
+#define R8A774C0_CLK_S0D6C             19
+#define R8A774C0_CLK_S3D1C             20
+#define R8A774C0_CLK_S3D2C             21
+#define R8A774C0_CLK_S3D4C             22
+#define R8A774C0_CLK_LB                        23
+#define R8A774C0_CLK_CL                        24
+#define R8A774C0_CLK_ZB3               25
+#define R8A774C0_CLK_ZB3D2             26
+#define R8A774C0_CLK_CR                        27
+#define R8A774C0_CLK_CRD2              28
+#define R8A774C0_CLK_SD0H              29
+#define R8A774C0_CLK_SD0               30
+#define R8A774C0_CLK_SD1H              31
+#define R8A774C0_CLK_SD1               32
+#define R8A774C0_CLK_SD3H              33
+#define R8A774C0_CLK_SD3               34
+#define R8A774C0_CLK_RPC               35
+#define R8A774C0_CLK_RPCD2             36
+#define R8A774C0_CLK_ZA2               37
+#define R8A774C0_CLK_ZA8               38
+#define R8A774C0_CLK_Z2D               39
+#define R8A774C0_CLK_MSO               40
+#define R8A774C0_CLK_R                 41
+#define R8A774C0_CLK_OSC               42
+#define R8A774C0_CLK_LV0               43
+#define R8A774C0_CLK_LV1               44
+#define R8A774C0_CLK_CSI0              45
+#define R8A774C0_CLK_CP                        46
+#define R8A774C0_CLK_CPEX              47
+#define R8A774C0_CLK_CANFD             48
+
+#endif /* __DT_BINDINGS_CLOCK_R8A774C0_CPG_MSSR_H__ */
diff --git a/include/dt-bindings/power/r8a774c0-sysc.h b/include/dt-bindings/power/r8a774c0-sysc.h
new file mode 100644 (file)
index 0000000..dd0cd65
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+#ifndef __DT_BINDINGS_POWER_R8A774C0_SYSC_H__
+#define __DT_BINDINGS_POWER_R8A774C0_SYSC_H__
+
+/*
+ * These power domain indices match the numbers of the interrupt bits
+ * representing the power areas in the various Interrupt Registers
+ * (e.g. SYSCISR, Interrupt Status Register)
+ */
+
+#define R8A774C0_PD_CA53_CPU0          5
+#define R8A774C0_PD_CA53_CPU1          6
+#define R8A774C0_PD_A3VC               14
+#define R8A774C0_PD_3DG_A              17
+#define R8A774C0_PD_3DG_B              18
+#define R8A774C0_PD_CA53_SCU           21
+#define R8A774C0_PD_A2VC1              26
+
+/* Always-on power area */
+#define R8A774C0_PD_ALWAYS_ON          32
+
+#endif /* __DT_BINDINGS_POWER_R8A774C0_SYSC_H__ */
index 989a5fc..a8fa5d7 100644 (file)
@@ -956,10 +956,9 @@ enum usb_device_speed {
        USB_SPEED_HIGH,                         /* usb 2.0 */
        USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
        USB_SPEED_SUPER,                        /* usb 3.0 */
+       USB_SPEED_SUPER_PLUS,                   /* usb 3.1 */
 };
 
-#ifdef __KERNEL__
-
 /**
  * usb_speed_string() - Returns human readable-name of the speed.
  * @speed: The speed to return human-readable name for.  If it's not
@@ -968,8 +967,6 @@ enum usb_device_speed {
  */
 extern const char *usb_speed_string(enum usb_device_speed speed);
 
-#endif
-
 enum usb_device_state {
        /* NOTATTACHED isn't in the USB spec, and this state acts
         * the same as ATTACHED ... but it's clearer this way.
index 778acf7..aff6674 100644 (file)
@@ -44,6 +44,9 @@ struct udevice;
 
 #define PKTALIGN       ARCH_DMA_MINALIGN
 
+/* Number of packets processed together */
+#define ETH_PACKETS_BATCH_RECV 32
+
 /* ARP hardware address length */
 #define ARP_HLEN 6
 /*
index 22f0123..69276b2 100644 (file)
@@ -24,9 +24,12 @@ static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
 static const efi_guid_t efi_pxe_base_code_protocol_guid =
                                        EFI_PXE_BASE_CODE_PROTOCOL_GUID;
 static struct efi_pxe_packet *dhcp_ack;
-static bool new_rx_packet;
 static void *new_tx_packet;
 static void *transmit_buffer;
+static uchar **receive_buffer;
+static size_t *receive_lengths;
+static int rx_packet_idx;
+static int rx_packet_num;
 
 /*
  * The notification function of this event is called in every timer cycle
@@ -115,6 +118,8 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
        } else {
                /* Disable hardware and put it into the reset state */
                eth_halt();
+               /* Clear cache of packets */
+               rx_packet_num = 0;
                this->mode->state = EFI_NETWORK_STOPPED;
        }
 out:
@@ -160,6 +165,8 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
        net_init();
        /* Disable hardware and put it into the reset state */
        eth_halt();
+       /* Clear cache of packets */
+       rx_packet_num = 0;
        /* Set current device according to environment variables */
        eth_set_current();
        /* Get hardware ready for send and receive operations */
@@ -602,16 +609,16 @@ static efi_status_t EFIAPI efi_net_receive
                break;
        }
 
-       if (!new_rx_packet) {
+       if (!rx_packet_num) {
                ret = EFI_NOT_READY;
                goto out;
        }
        /* Fill export parameters */
-       eth_hdr = (struct ethernet_hdr *)net_rx_packet;
+       eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
        protlen = ntohs(eth_hdr->et_protlen);
        if (protlen == 0x8100) {
                hdr_size += 4;
-               protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
+               protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
        }
        if (header_size)
                *header_size = hdr_size;
@@ -621,17 +628,22 @@ static efi_status_t EFIAPI efi_net_receive
                memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
        if (protocol)
                *protocol = protlen;
-       if (*buffer_size < net_rx_packet_len) {
+       if (*buffer_size < receive_lengths[rx_packet_idx]) {
                /* Packet doesn't fit, try again with bigger buffer */
-               *buffer_size = net_rx_packet_len;
+               *buffer_size = receive_lengths[rx_packet_idx];
                ret = EFI_BUFFER_TOO_SMALL;
                goto out;
        }
        /* Copy packet */
-       memcpy(buffer, net_rx_packet, net_rx_packet_len);
-       *buffer_size = net_rx_packet_len;
-       new_rx_packet = 0;
-       this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+       memcpy(buffer, receive_buffer[rx_packet_idx],
+              receive_lengths[rx_packet_idx]);
+       *buffer_size = receive_lengths[rx_packet_idx];
+       rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
+       rx_packet_num--;
+       if (rx_packet_num)
+               wait_for_packet->is_signaled = true;
+       else
+               this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
 out:
        return EFI_EXIT(ret);
 }
@@ -664,7 +676,26 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
  */
 static void efi_net_push(void *pkt, int len)
 {
-       new_rx_packet = true;
+       int rx_packet_next;
+
+       /* Check that we at least received an Ethernet header */
+       if (len < sizeof(struct ethernet_hdr))
+               return;
+
+       /* Check that the buffer won't overflow */
+       if (len > PKTSIZE_ALIGN)
+               return;
+
+       /* Can't store more than pre-alloced buffer */
+       if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
+               return;
+
+       rx_packet_next = (rx_packet_idx + rx_packet_num) %
+           ETH_PACKETS_BATCH_RECV;
+       memcpy(receive_buffer[rx_packet_next], pkt, len);
+       receive_lengths[rx_packet_next] = len;
+
+       rx_packet_num++;
 }
 
 /**
@@ -689,20 +720,14 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event,
        if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
                goto out;
 
-       if (!new_rx_packet) {
+       if (!rx_packet_num) {
                push_packet = efi_net_push;
                eth_rx();
                push_packet = NULL;
-               if (new_rx_packet) {
-                       /* Check that we at least received an Ethernet header */
-                       if (net_rx_packet_len >=
-                           sizeof(struct ethernet_hdr)) {
-                               this->int_status |=
-                                       EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
-                               wait_for_packet->is_signaled = true;
-                       } else {
-                               new_rx_packet = 0;
-                       }
+               if (rx_packet_num) {
+                       this->int_status |=
+                               EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+                       wait_for_packet->is_signaled = true;
                }
        }
 out:
@@ -830,6 +855,7 @@ efi_status_t efi_net_register(void)
 {
        struct efi_net_obj *netobj = NULL;
        efi_status_t r;
+       int i;
 
        if (!eth_get_dev()) {
                /* No network device active, don't expose any */
@@ -847,6 +873,21 @@ efi_status_t efi_net_register(void)
                goto out_of_resources;
        transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
 
+       /* Allocate a number of receive buffers */
+       receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
+                               sizeof(*receive_buffer));
+       if (!receive_buffer)
+               goto out_of_resources;
+       for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
+               receive_buffer[i] = malloc(PKTSIZE_ALIGN);
+               if (!receive_buffer[i])
+                       goto out_of_resources;
+       }
+       receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
+                                sizeof(*receive_lengths));
+       if (!receive_lengths)
+               goto out_of_resources;
+
        /* Hook net up to the device list */
        efi_add_handle(&netobj->header);
 
@@ -941,7 +982,12 @@ failure_to_add_protocol:
        return r;
 out_of_resources:
        free(netobj);
-       /* free(transmit_buffer) not needed yet */
+       free(transmit_buffer);
+       if (receive_buffer)
+               for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
+                       free(receive_buffer[i]);
+       free(receive_buffer);
+       free(receive_lengths);
        printf("ERROR: Out of memory\n");
        return EFI_OUT_OF_RESOURCES;
 }
index 4424d59..e14695c 100644 (file)
@@ -383,7 +383,7 @@ int eth_rx(void)
 
        /* Process up to 32 packets at one time */
        flags = ETH_RECV_CHECK_DEVICE;
-       for (i = 0; i < 32; i++) {
+       for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
                ret = eth_get_ops(current)->recv(current, flags, &packet);
                flags = 0;
                if (ret > 0)