summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/sunxi/Kconfig89
-rw-r--r--drivers/clk/sunxi/Makefile19
-rw-r--r--drivers/clk/sunxi/clk_a10.c68
-rw-r--r--drivers/clk/sunxi/clk_a10s.c61
-rw-r--r--drivers/clk/sunxi/clk_a23.c75
-rw-r--r--drivers/clk/sunxi/clk_a31.c82
-rw-r--r--drivers/clk/sunxi/clk_a64.c78
-rw-r--r--drivers/clk/sunxi/clk_a80.c57
-rw-r--r--drivers/clk/sunxi/clk_a83t.c75
-rw-r--r--drivers/clk/sunxi/clk_h3.c89
-rw-r--r--drivers/clk/sunxi/clk_h6.c53
-rw-r--r--drivers/clk/sunxi/clk_r40.c88
-rw-r--r--drivers/clk/sunxi/clk_sunxi.c74
-rw-r--r--drivers/clk/sunxi/clk_v3s.c59
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c77
-rw-r--r--drivers/reset/Kconfig8
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-sunxi.c124
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-sunxi.c204
-rw-r--r--drivers/usb/host/ohci-sunxi.c233
-rw-r--r--drivers/usb/musb-new/sunxi.c79
25 files changed, 1200 insertions, 499 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index eadf7f8250..51c931b906 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -104,6 +104,7 @@ source "drivers/clk/imx/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/owl/Kconfig"
source "drivers/clk/renesas/Kconfig"
+source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/uniphier/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 9acbb1a650..6a4ff9143b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
obj-$(CONFIG_CLK_OWL) += owl/
obj-$(CONFIG_CLK_RENESAS) += renesas/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
new file mode 100644
index 0000000000..5ff101b993
--- /dev/null
+++ b/drivers/clk/sunxi/Kconfig
@@ -0,0 +1,89 @@
+config CLK_SUNXI
+ bool "Clock support for Allwinner SoCs"
+ depends on CLK && ARCH_SUNXI
+ select DM_RESET
+ default y
+ help
+ This enables support for common clock driver API on Allwinner
+ SoCs.
+
+if CLK_SUNXI
+
+config CLK_SUN4I_A10
+ bool "Clock driver for Allwinner A10/A20"
+ default MACH_SUN4I || MACH_SUN7I
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A10/A20 SoC.
+
+config CLK_SUN5I_A10S
+ bool "Clock driver for Allwinner A10s/A13"
+ default MACH_SUN5I
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A10s/A13 SoC.
+
+config CLK_SUN6I_A31
+ bool "Clock driver for Allwinner A31/A31s"
+ default MACH_SUN6I
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A31/A31s SoC.
+
+config CLK_SUN8I_A23
+ bool "Clock driver for Allwinner A23/A33"
+ default MACH_SUN8I_A23 || MACH_SUN8I_A33
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A23/A33 SoC.
+
+config CLK_SUN8I_A83T
+ bool "Clock driver for Allwinner A83T"
+ default MACH_SUN8I_A83T
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A83T SoC.
+
+config CLK_SUN8I_R40
+ bool "Clock driver for Allwinner R40"
+ default MACH_SUN8I_R40
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner R40 SoC.
+
+config CLK_SUN8I_V3S
+ bool "Clock driver for Allwinner V3S"
+ default MACH_SUN8I_V3S
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner V3S SoC.
+
+config CLK_SUN9I_A80
+ bool "Clock driver for Allwinner A80"
+ default MACH_SUN9I
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A80 SoC.
+
+config CLK_SUN8I_H3
+ bool "Clock driver for Allwinner H3/H5"
+ default MACH_SUNXI_H3_H5
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner H3/H5 SoC.
+
+config CLK_SUN50I_H6
+ bool "Clock driver for Allwinner H6"
+ default MACH_SUN50I_H6
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner H6 SoC.
+
+config CLK_SUN50I_A64
+ bool "Clock driver for Allwinner A64"
+ default MACH_SUN50I
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A64 SoC.
+
+endif # CLK_SUNXI
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
new file mode 100644
index 0000000000..36fb2aeb56
--- /dev/null
+++ b/drivers/clk/sunxi/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2018 Amarula Solutions.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o
+
+obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
+obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
+obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
+obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o
+obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o
+obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
+obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o
+obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o
+obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o
+obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o
+obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o
diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c
new file mode 100644
index 0000000000..b00f51af8b
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a10.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun4i-a10-ccu.h>
+#include <dt-bindings/reset/sun4i-a10-ccu.h>
+
+static struct ccu_clk_gate a10_gates[] = {
+ [CLK_AHB_OTG] = GATE(0x060, BIT(0)),
+ [CLK_AHB_EHCI0] = GATE(0x060, BIT(1)),
+ [CLK_AHB_OHCI0] = GATE(0x060, BIT(2)),
+ [CLK_AHB_EHCI1] = GATE(0x060, BIT(3)),
+ [CLK_AHB_OHCI1] = GATE(0x060, BIT(4)),
+
+ [CLK_APB1_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_APB1_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_APB1_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_APB1_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_APB1_UART4] = GATE(0x06c, BIT(20)),
+ [CLK_APB1_UART5] = GATE(0x06c, BIT(21)),
+ [CLK_APB1_UART6] = GATE(0x06c, BIT(22)),
+ [CLK_APB1_UART7] = GATE(0x06c, BIT(23)),
+
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(6)),
+ [CLK_USB_OHCI1] = GATE(0x0cc, BIT(7)),
+ [CLK_USB_PHY] = GATE(0x0cc, BIT(8)),
+};
+
+static struct ccu_reset a10_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_PHY2] = RESET(0x0cc, BIT(2)),
+};
+
+static const struct ccu_desc a10_ccu_desc = {
+ .gates = a10_gates,
+ .resets = a10_resets,
+};
+
+static int a10_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a10_resets));
+}
+
+static const struct udevice_id a10_ccu_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-ccu",
+ .data = (ulong)&a10_ccu_desc },
+ { .compatible = "allwinner,sun7i-a20-ccu",
+ .data = (ulong)&a10_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun4i_a10) = {
+ .name = "sun4i_a10_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a10_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a10_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c
new file mode 100644
index 0000000000..aa904ce067
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a10s.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun5i-ccu.h>
+#include <dt-bindings/reset/sun5i-ccu.h>
+
+static struct ccu_clk_gate a10s_gates[] = {
+ [CLK_AHB_OTG] = GATE(0x060, BIT(0)),
+ [CLK_AHB_EHCI] = GATE(0x060, BIT(1)),
+ [CLK_AHB_OHCI] = GATE(0x060, BIT(2)),
+
+ [CLK_APB1_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_APB1_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_APB1_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_APB1_UART3] = GATE(0x06c, BIT(19)),
+
+ [CLK_USB_OHCI] = GATE(0x0cc, BIT(6)),
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+};
+
+static struct ccu_reset a10s_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+};
+
+static const struct ccu_desc a10s_ccu_desc = {
+ .gates = a10s_gates,
+ .resets = a10s_resets,
+};
+
+static int a10s_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a10s_resets));
+}
+
+static const struct udevice_id a10s_ccu_ids[] = {
+ { .compatible = "allwinner,sun5i-a10s-ccu",
+ .data = (ulong)&a10s_ccu_desc },
+ { .compatible = "allwinner,sun5i-a13-ccu",
+ .data = (ulong)&a10s_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun5i_a10s) = {
+ .name = "sun5i_a10s_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a10s_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a10s_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c
new file mode 100644
index 0000000000..854259bf81
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a23.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions B.V.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun8i-a23-a33-ccu.h>
+#include <dt-bindings/reset/sun8i-a23-a33-ccu.h>
+
+static struct ccu_clk_gate a23_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(24)),
+ [CLK_BUS_EHCI] = GATE(0x060, BIT(26)),
+ [CLK_BUS_OHCI] = GATE(0x060, BIT(29)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_HSIC_12M] = GATE(0x0cc, BIT(11)),
+ [CLK_USB_OHCI] = GATE(0x0cc, BIT(16)),
+};
+
+static struct ccu_reset a23_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_HSIC] = RESET(0x0cc, BIT(2)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(24)),
+ [RST_BUS_EHCI] = RESET(0x2c0, BIT(26)),
+ [RST_BUS_OHCI] = RESET(0x2c0, BIT(29)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x2d8, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x2d8, BIT(20)),
+};
+
+static const struct ccu_desc a23_ccu_desc = {
+ .gates = a23_gates,
+ .resets = a23_resets,
+};
+
+static int a23_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a23_resets));
+}
+
+static const struct udevice_id a23_clk_ids[] = {
+ { .compatible = "allwinner,sun8i-a23-ccu",
+ .data = (ulong)&a23_ccu_desc },
+ { .compatible = "allwinner,sun8i-a33-ccu",
+ .data = (ulong)&a23_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun8i_a23) = {
+ .name = "sun8i_a23_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a23_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a23_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c
new file mode 100644
index 0000000000..a38d76cb7c
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a31.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions B.V.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun6i-a31-ccu.h>
+#include <dt-bindings/reset/sun6i-a31-ccu.h>
+
+static struct ccu_clk_gate a31_gates[] = {
+ [CLK_AHB1_OTG] = GATE(0x060, BIT(24)),
+ [CLK_AHB1_EHCI0] = GATE(0x060, BIT(26)),
+ [CLK_AHB1_EHCI1] = GATE(0x060, BIT(27)),
+ [CLK_AHB1_OHCI0] = GATE(0x060, BIT(29)),
+ [CLK_AHB1_OHCI1] = GATE(0x060, BIT(30)),
+ [CLK_AHB1_OHCI2] = GATE(0x060, BIT(31)),
+
+ [CLK_APB2_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_APB2_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_APB2_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_APB2_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_APB2_UART4] = GATE(0x06c, BIT(20)),
+ [CLK_APB2_UART5] = GATE(0x06c, BIT(21)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)),
+ [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)),
+ [CLK_USB_OHCI2] = GATE(0x0cc, BIT(18)),
+};
+
+static struct ccu_reset a31_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_PHY2] = RESET(0x0cc, BIT(2)),
+
+ [RST_AHB1_OTG] = RESET(0x2c0, BIT(24)),
+ [RST_AHB1_EHCI0] = RESET(0x2c0, BIT(26)),
+ [RST_AHB1_EHCI1] = RESET(0x2c0, BIT(27)),
+ [RST_AHB1_OHCI0] = RESET(0x2c0, BIT(29)),
+ [RST_AHB1_OHCI1] = RESET(0x2c0, BIT(30)),
+ [RST_AHB1_OHCI2] = RESET(0x2c0, BIT(31)),
+
+ [RST_APB2_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_APB2_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_APB2_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_APB2_UART3] = RESET(0x2d8, BIT(19)),
+ [RST_APB2_UART4] = RESET(0x2d8, BIT(20)),
+ [RST_APB2_UART5] = RESET(0x2d8, BIT(21)),
+};
+
+static const struct ccu_desc a31_ccu_desc = {
+ .gates = a31_gates,
+ .resets = a31_resets,
+};
+
+static int a31_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a31_resets));
+}
+
+static const struct udevice_id a31_clk_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-ccu",
+ .data = (ulong)&a31_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun6i_a31) = {
+ .name = "sun6i_a31_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a31_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a31_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c
new file mode 100644
index 0000000000..a2ba6eefc5
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a64.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun50i-a64-ccu.h>
+#include <dt-bindings/reset/sun50i-a64-ccu.h>
+
+static const struct ccu_clk_gate a64_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(23)),
+ [CLK_BUS_EHCI0] = GATE(0x060, BIT(24)),
+ [CLK_BUS_EHCI1] = GATE(0x060, BIT(25)),
+ [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)),
+ [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_HSIC_12M] = GATE(0x0cc, BIT(11)),
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)),
+ [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)),
+};
+
+static const struct ccu_reset a64_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_HSIC] = RESET(0x0cc, BIT(2)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(23)),
+ [RST_BUS_EHCI0] = RESET(0x2c0, BIT(24)),
+ [RST_BUS_EHCI1] = RESET(0x2c0, BIT(25)),
+ [RST_BUS_OHCI0] = RESET(0x2c0, BIT(28)),
+ [RST_BUS_OHCI1] = RESET(0x2c0, BIT(29)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x2d8, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x2d8, BIT(20)),
+};
+
+static const struct ccu_desc a64_ccu_desc = {
+ .gates = a64_gates,
+ .resets = a64_resets,
+};
+
+static int a64_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a64_resets));
+}
+
+static const struct udevice_id a64_ccu_ids[] = {
+ { .compatible = "allwinner,sun50i-a64-ccu",
+ .data = (ulong)&a64_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun50i_a64) = {
+ .name = "sun50i_a64_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a64_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a64_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c
new file mode 100644
index 0000000000..d6dd6a1fa1
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a80.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun9i-a80-ccu.h>
+#include <dt-bindings/reset/sun9i-a80-ccu.h>
+
+static const struct ccu_clk_gate a80_gates[] = {
+ [CLK_BUS_UART0] = GATE(0x594, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x594, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x594, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x594, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x594, BIT(20)),
+ [CLK_BUS_UART5] = GATE(0x594, BIT(21)),
+};
+
+static const struct ccu_reset a80_resets[] = {
+ [RST_BUS_UART0] = RESET(0x5b4, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x5b4, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x5b4, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x5b4, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x5b4, BIT(20)),
+ [RST_BUS_UART5] = RESET(0x5b4, BIT(21)),
+};
+
+static const struct ccu_desc a80_ccu_desc = {
+ .gates = a80_gates,
+ .resets = a80_resets,
+};
+
+static int a80_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a80_resets));
+}
+
+static const struct udevice_id a80_ccu_ids[] = {
+ { .compatible = "allwinner,sun9i-a80-ccu",
+ .data = (ulong)&a80_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun9i_a80) = {
+ .name = "sun9i_a80_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a80_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a80_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c
new file mode 100644
index 0000000000..1ef6ac5b25
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a83t.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun8i-a83t-ccu.h>
+#include <dt-bindings/reset/sun8i-a83t-ccu.h>
+
+static struct ccu_clk_gate a83t_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(24)),
+ [CLK_BUS_EHCI0] = GATE(0x060, BIT(26)),
+ [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)),
+ [CLK_BUS_OHCI0] = GATE(0x060, BIT(29)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_HSIC_12M] = GATE(0x0cc, BIT(11)),
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)),
+};
+
+static struct ccu_reset a83t_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_HSIC] = RESET(0x0cc, BIT(2)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(24)),
+ [RST_BUS_EHCI0] = RESET(0x2c0, BIT(26)),
+ [RST_BUS_EHCI1] = RESET(0x2c0, BIT(27)),
+ [RST_BUS_OHCI0] = RESET(0x2c0, BIT(29)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x2d8, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x2d8, BIT(20)),
+};
+
+static const struct ccu_desc a83t_ccu_desc = {
+ .gates = a83t_gates,
+ .resets = a83t_resets,
+};
+
+static int a83t_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(a83t_resets));
+}
+
+static const struct udevice_id a83t_clk_ids[] = {
+ { .compatible = "allwinner,sun8i-a83t-ccu",
+ .data = (ulong)&a83t_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun8i_a83t) = {
+ .name = "sun8i_a83t_ccu",
+ .id = UCLASS_CLK,
+ .of_match = a83t_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = a83t_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c
new file mode 100644
index 0000000000..f82949b3b6
--- /dev/null
+++ b/drivers/clk/sunxi/clk_h3.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun8i-h3-ccu.h>
+#include <dt-bindings/reset/sun8i-h3-ccu.h>
+
+static struct ccu_clk_gate h3_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(23)),
+ [CLK_BUS_EHCI0] = GATE(0x060, BIT(24)),
+ [CLK_BUS_EHCI1] = GATE(0x060, BIT(25)),
+ [CLK_BUS_EHCI2] = GATE(0x060, BIT(26)),
+ [CLK_BUS_EHCI3] = GATE(0x060, BIT(27)),
+ [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)),
+ [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)),
+ [CLK_BUS_OHCI2] = GATE(0x060, BIT(30)),
+ [CLK_BUS_OHCI3] = GATE(0x060, BIT(31)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_PHY3] = GATE(0x0cc, BIT(11)),
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)),
+ [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)),
+ [CLK_USB_OHCI2] = GATE(0x0cc, BIT(18)),
+ [CLK_USB_OHCI3] = GATE(0x0cc, BIT(19)),
+};
+
+static struct ccu_reset h3_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_PHY2] = RESET(0x0cc, BIT(2)),
+ [RST_USB_PHY3] = RESET(0x0cc, BIT(3)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(23)),
+ [RST_BUS_EHCI0] = RESET(0x2c0, BIT(24)),
+ [RST_BUS_EHCI1] = RESET(0x2c0, BIT(25)),
+ [RST_BUS_EHCI2] = RESET(0x2c0, BIT(26)),
+ [RST_BUS_EHCI3] = RESET(0x2c0, BIT(27)),
+ [RST_BUS_OHCI0] = RESET(0x2c0, BIT(28)),
+ [RST_BUS_OHCI1] = RESET(0x2c0, BIT(29)),
+ [RST_BUS_OHCI2] = RESET(0x2c0, BIT(30)),
+ [RST_BUS_OHCI3] = RESET(0x2c0, BIT(31)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x2d8, BIT(19)),
+};
+
+static const struct ccu_desc h3_ccu_desc = {
+ .gates = h3_gates,
+ .resets = h3_resets,
+};
+
+static int h3_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(h3_resets));
+}
+
+static const struct udevice_id h3_ccu_ids[] = {
+ { .compatible = "allwinner,sun8i-h3-ccu",
+ .data = (ulong)&h3_ccu_desc },
+ { .compatible = "allwinner,sun50i-h5-ccu",
+ .data = (ulong)&h3_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun8i_h3) = {
+ .name = "sun8i_h3_ccu",
+ .id = UCLASS_CLK,
+ .of_match = h3_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = h3_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c
new file mode 100644
index 0000000000..0da3a40e3d
--- /dev/null
+++ b/drivers/clk/sunxi/clk_h6.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun50i-h6-ccu.h>
+#include <dt-bindings/reset/sun50i-h6-ccu.h>
+
+static struct ccu_clk_gate h6_gates[] = {
+ [CLK_BUS_UART0] = GATE(0x90c, BIT(0)),
+ [CLK_BUS_UART1] = GATE(0x90c, BIT(1)),
+ [CLK_BUS_UART2] = GATE(0x90c, BIT(2)),
+ [CLK_BUS_UART3] = GATE(0x90c, BIT(3)),
+};
+
+static struct ccu_reset h6_resets[] = {
+ [RST_BUS_UART0] = RESET(0x90c, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x90c, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x90c, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x90c, BIT(19)),
+};
+
+static const struct ccu_desc h6_ccu_desc = {
+ .gates = h6_gates,
+ .resets = h6_resets,
+};
+
+static int h6_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(h6_resets));
+}
+
+static const struct udevice_id h6_ccu_ids[] = {
+ { .compatible = "allwinner,sun50i-h6-ccu",
+ .data = (ulong)&h6_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun50i_h6) = {
+ .name = "sun50i_h6_ccu",
+ .id = UCLASS_CLK,
+ .of_match = h6_ccu_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = h6_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c
new file mode 100644
index 0000000000..fd7aae97ea
--- /dev/null
+++ b/drivers/clk/sunxi/clk_r40.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun8i-r40-ccu.h>
+#include <dt-bindings/reset/sun8i-r40-ccu.h>
+
+static struct ccu_clk_gate r40_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(25)),
+ [CLK_BUS_EHCI0] = GATE(0x060, BIT(26)),
+ [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)),
+ [CLK_BUS_EHCI2] = GATE(0x060, BIT(28)),
+ [CLK_BUS_OHCI0] = GATE(0x060, BIT(29)),
+ [CLK_BUS_OHCI1] = GATE(0x060, BIT(30)),
+ [CLK_BUS_OHCI2] = GATE(0x060, BIT(31)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+ [CLK_BUS_UART5] = GATE(0x06c, BIT(21)),
+ [CLK_BUS_UART6] = GATE(0x06c, BIT(22)),
+ [CLK_BUS_UART7] = GATE(0x06c, BIT(23)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+ [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)),
+ [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)),
+ [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)),
+ [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)),
+ [CLK_USB_OHCI2] = GATE(0x0cc, BIT(18)),
+};
+
+static struct ccu_reset r40_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+ [RST_USB_PHY1] = RESET(0x0cc, BIT(1)),
+ [RST_USB_PHY2] = RESET(0x0cc, BIT(2)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(25)),
+ [RST_BUS_EHCI0] = RESET(0x2c0, BIT(26)),
+ [RST_BUS_EHCI1] = RESET(0x2c0, BIT(27)),
+ [RST_BUS_EHCI2] = RESET(0x2c0, BIT(28)),
+ [RST_BUS_OHCI0] = RESET(0x2c0, BIT(29)),
+ [RST_BUS_OHCI1] = RESET(0x2c0, BIT(30)),
+ [RST_BUS_OHCI2] = RESET(0x2c0, BIT(31)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x2d8, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x2d8, BIT(20)),
+ [RST_BUS_UART5] = RESET(0x2d8, BIT(21)),
+ [RST_BUS_UART6] = RESET(0x2d8, BIT(22)),
+ [RST_BUS_UART7] = RESET(0x2d8, BIT(23)),
+};
+
+static const struct ccu_desc r40_ccu_desc = {
+ .gates = r40_gates,
+ .resets = r40_resets,
+};
+
+static int r40_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(r40_resets));
+}
+
+static const struct udevice_id r40_clk_ids[] = {
+ { .compatible = "allwinner,sun8i-r40-ccu",
+ .data = (ulong)&r40_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun8i_r40) = {
+ .name = "sun8i_r40_ccu",
+ .id = UCLASS_CLK,
+ .of_match = r40_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = r40_clk_bind,
+};
diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
new file mode 100644
index 0000000000..62ce2994e4
--- /dev/null
+++ b/drivers/clk/sunxi/clk_sunxi.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/ccu.h>
+#include <linux/log2.h>
+
+static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv,
+ unsigned long id)
+{
+ return &priv->desc->gates[id];
+}
+
+static int sunxi_set_gate(struct clk *clk, bool on)
+{
+ struct ccu_priv *priv = dev_get_priv(clk->dev);
+ const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id);
+ u32 reg;
+
+ if (!(gate->flags & CCU_CLK_F_IS_VALID)) {
+ printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__,
+ clk->id, gate->off, ilog2(gate->bit));
+
+ reg = readl(priv->base + gate->off);
+ if (on)
+ reg |= gate->bit;
+ else
+ reg &= ~gate->bit;
+
+ writel(reg, priv->base + gate->off);
+
+ return 0;
+}
+
+static int sunxi_clk_enable(struct clk *clk)
+{
+ return sunxi_set_gate(clk, true);
+}
+
+static int sunxi_clk_disable(struct clk *clk)
+{
+ return sunxi_set_gate(clk, false);
+}
+
+struct clk_ops sunxi_clk_ops = {
+ .enable = sunxi_clk_enable,
+ .disable = sunxi_clk_disable,
+};
+
+int sunxi_clk_probe(struct udevice *dev)
+{
+ struct ccu_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
+ if (!priv->desc)
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c
new file mode 100644
index 0000000000..25ad87500e
--- /dev/null
+++ b/drivers/clk/sunxi/clk_v3s.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun8i-v3s-ccu.h>
+#include <dt-bindings/reset/sun8i-v3s-ccu.h>
+
+static struct ccu_clk_gate v3s_gates[] = {
+ [CLK_BUS_OTG] = GATE(0x060, BIT(24)),
+
+ [CLK_BUS_UART0] = GATE(0x06c, BIT(16)),
+ [CLK_BUS_UART1] = GATE(0x06c, BIT(17)),
+ [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
+
+ [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)),
+};
+
+static struct ccu_reset v3s_resets[] = {
+ [RST_USB_PHY0] = RESET(0x0cc, BIT(0)),
+
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(24)),
+
+ [RST_BUS_UART0] = RESET(0x2d8, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x2d8, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
+};
+
+static const struct ccu_desc v3s_ccu_desc = {
+ .gates = v3s_gates,
+ .resets = v3s_resets,
+};
+
+static int v3s_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(v3s_resets));
+}
+
+static const struct udevice_id v3s_clk_ids[] = {
+ { .compatible = "allwinner,sun8i-v3s-ccu",
+ .data = (ulong)&v3s_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun8i_v3s) = {
+ .name = "sun8i_v3s_ccu",
+ .id = UCLASS_CLK,
+ .of_match = v3s_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = v3s_clk_bind,
+};
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index a7d7e3f044..f206fa3f5d 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -11,10 +11,12 @@
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
#include <dm/device.h>
#include <generic-phy.h>
#include <phy-sun4i-usb.h>
+#include <reset.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
@@ -80,6 +82,7 @@ struct sun4i_usb_phy_cfg {
enum sun4i_usb_phy_type type;
u32 disc_thresh;
u8 phyctl_offset;
+ bool dedicated_clocks;
bool enable_pmu_unk1;
bool phy0_dual_route;
};
@@ -88,30 +91,21 @@ struct sun4i_usb_phy_info {
const char *gpio_vbus;
const char *gpio_vbus_det;
const char *gpio_id_det;
- int rst_mask;
} phy_info[] = {
{
.gpio_vbus = CONFIG_USB0_VBUS_PIN,
.gpio_vbus_det = CONFIG_USB0_VBUS_DET,
.gpio_id_det = CONFIG_USB0_ID_DET,
- .rst_mask = (CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK),
},
{
.gpio_vbus = CONFIG_USB1_VBUS_PIN,
.gpio_vbus_det = NULL,
.gpio_id_det = NULL,
- .rst_mask = (CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK),
},
{
.gpio_vbus = CONFIG_USB2_VBUS_PIN,
.gpio_vbus_det = NULL,
.gpio_id_det = NULL,
-#ifdef CONFIG_MACH_SUN8I_A83T
- .rst_mask = (CCM_USB_CTRL_HSIC_RST | CCM_USB_CTRL_HSIC_CLK |
- CCM_USB_CTRL_12M_CLK),
-#else
- .rst_mask = (CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK),
-#endif
},
{
.gpio_vbus = CONFIG_USB3_VBUS_PIN,
@@ -126,13 +120,13 @@ struct sun4i_usb_phy_plat {
int gpio_vbus;
int gpio_vbus_det;
int gpio_id_det;
- int rst_mask;
+ struct clk clocks;
+ struct reset_ctl resets;
int id;
};
struct sun4i_usb_phy_data {
void __iomem *base;
- struct sunxi_ccm_reg *ccm;
const struct sun4i_usb_phy_cfg *cfg;
struct sun4i_usb_phy_plat *usb_phy;
};
@@ -266,8 +260,19 @@ static int sun4i_usb_phy_init(struct phy *phy)
struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
u32 val;
+ int ret;
- setbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask);
+ ret = clk_enable(&usb_phy->clocks);
+ if (ret) {
+ dev_err(dev, "failed to enable usb_%ldphy clock\n", phy->id);
+ return ret;
+ }
+
+ ret = reset_deassert(&usb_phy->resets);
+ if (ret) {
+ dev_err(dev, "failed to deassert usb_%ldreset reset\n", phy->id);
+ return ret;
+ }
if (data->cfg->type == sun8i_a83t_phy) {
if (phy->id == 0) {
@@ -308,6 +313,7 @@ static int sun4i_usb_phy_exit(struct phy *phy)
{
struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ int ret;
if (phy->id == 0) {
if (data->cfg->type == sun8i_a83t_phy) {
@@ -320,7 +326,17 @@ static int sun4i_usb_phy_exit(struct phy *phy)
sun4i_usb_phy_passby(phy, false);
- clrbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask);
+ ret = clk_disable(&usb_phy->clocks);
+ if (ret) {
+ dev_err(dev, "failed to disable usb_%ldphy clock\n", phy->id);
+ return ret;
+ }
+
+ ret = reset_assert(&usb_phy->resets);
+ if (ret) {
+ dev_err(dev, "failed to assert usb_%ldreset reset\n", phy->id);
+ return ret;
+ }
return 0;
}
@@ -407,10 +423,6 @@ static int sun4i_usb_phy_probe(struct udevice *dev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
- data->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- if (IS_ERR(data->ccm))
- return PTR_ERR(data->ccm);
-
data->usb_phy = plat;
for (i = 0; i < data->cfg->num_phys; i++) {
struct sun4i_usb_phy_plat *phy = &plat[i];
@@ -448,6 +460,24 @@ static int sun4i_usb_phy_probe(struct udevice *dev)
sunxi_gpio_set_pull(phy->gpio_id_det, SUNXI_GPIO_PULL_UP);
}
+ if (data->cfg->dedicated_clocks)
+ snprintf(name, sizeof(name), "usb%d_phy", i);
+ else
+ strlcpy(name, "usb_phy", sizeof(name));
+
+ ret = clk_get_by_name(dev, name, &phy->clocks);
+ if (ret) {
+ dev_err(dev, "failed to get usb%d_phy clock phandle\n", i);
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "usb%d_reset", i);
+ ret = reset_get_by_name(dev, name, &phy->resets);
+ if (ret) {
+ dev_err(dev, "failed to get usb%d_reset reset phandle\n", i);
+ return ret;
+ }
+
if (i || data->cfg->phy0_dual_route) {
snprintf(name, sizeof(name), "pmu%d", i);
phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
@@ -456,9 +486,6 @@ static int sun4i_usb_phy_probe(struct udevice *dev)
}
phy->id = i;
- phy->rst_mask = info->rst_mask;
- if ((data->cfg->type == sun8i_h3_phy) && (phy->id == 3))
- phy->rst_mask = (BIT(3) | BIT(11));
};
debug("Allwinner Sun4I USB PHY driver loaded\n");
@@ -470,6 +497,7 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
.type = sun4i_a10_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
.enable_pmu_unk1 = false,
};
@@ -478,6 +506,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
.type = sun4i_a10_phy,
.disc_thresh = 2,
.phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
.enable_pmu_unk1 = false,
};
@@ -486,6 +515,7 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
.type = sun6i_a31_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = false,
};
@@ -494,6 +524,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
.type = sun4i_a10_phy,
.disc_thresh = 2,
.phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
.enable_pmu_unk1 = false,
};
@@ -502,6 +533,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
.type = sun4i_a10_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = false,
};
@@ -510,6 +542,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
.type = sun8i_a33_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = false,
};
@@ -517,6 +550,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
.num_phys = 3,
.type = sun8i_a83t_phy,
.phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
};
static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
@@ -524,6 +558,7 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
.type = sun8i_h3_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = true,
.phy0_dual_route = true,
};
@@ -533,6 +568,7 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
.type = sun8i_v3s_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = true,
.phy0_dual_route = true,
};
@@ -542,6 +578,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
.type = sun50i_a64_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
.enable_pmu_unk1 = true,
.phy0_dual_route = true,
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 3a6d61f440..a81e767696 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -113,4 +113,12 @@ config RESET_MEDIATEK
help
Support for reset controller on MediaTek SoCs.
+config RESET_SUNXI
+ bool "RESET support for Allwinner SoCs"
+ depends on DM_RESET && ARCH_SUNXI
+ default y
+ help
+ This enables support for common reset driver for
+ Allwinner SoCs.
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 8a4dcab8f6..4fad7d4129 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o
+obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c
new file mode 100644
index 0000000000..364dc52fb7
--- /dev/null
+++ b/drivers/reset/reset-sunxi.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <asm/io.h>
+#include <dm/lists.h>
+#include <linux/log2.h>
+#include <asm/arch/ccu.h>
+
+struct sunxi_reset_priv {
+ void *base;
+ ulong count;
+ const struct ccu_desc *desc;
+};
+
+static const struct ccu_reset *priv_to_reset(struct sunxi_reset_priv *priv,
+ unsigned long id)
+{
+ return &priv->desc->resets[id];
+}
+
+static int sunxi_reset_request(struct reset_ctl *reset_ctl)
+{
+ struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+ debug("%s: (RST#%ld)\n", __func__, reset_ctl->id);
+
+ if (reset_ctl->id >= priv->count)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sunxi_reset_free(struct reset_ctl *reset_ctl)
+{
+ debug("%s: (RST#%ld)\n", __func__, reset_ctl->id);
+
+ return 0;
+}
+
+static int sunxi_set_reset(struct reset_ctl *reset_ctl, bool on)
+{
+ struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ const struct ccu_reset *reset = priv_to_reset(priv, reset_ctl->id);
+ u32 reg;
+
+ if (!(reset->flags & CCU_RST_F_IS_VALID)) {
+ printf("%s: (RST#%ld) unhandled\n", __func__, reset_ctl->id);
+ return 0;
+ }
+
+ debug("%s: (RST#%ld) off#0x%x, BIT(%d)\n", __func__,
+ reset_ctl->id, reset->off, ilog2(reset->bit));
+
+ reg = readl(priv->base + reset->off);
+ if (on)
+ reg |= reset->bit;
+ else
+ reg &= ~reset->bit;
+
+ writel(reg, priv->base + reset->off);
+
+ return 0;
+}
+
+static int sunxi_reset_assert(struct reset_ctl *reset_ctl)
+{
+ return sunxi_set_reset(reset_ctl, false);
+}
+
+static int sunxi_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ return sunxi_set_reset(reset_ctl, true);
+}
+
+struct reset_ops sunxi_reset_ops = {
+ .request = sunxi_reset_request,
+ .free = sunxi_reset_free,
+ .rst_assert = sunxi_reset_assert,
+ .rst_deassert = sunxi_reset_deassert,
+};
+
+static int sunxi_reset_probe(struct udevice *dev)
+{
+ struct sunxi_reset_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+int sunxi_reset_bind(struct udevice *dev, ulong count)
+{
+ struct udevice *rst_dev;
+ struct sunxi_reset_priv *priv;
+ int ret;
+
+ ret = device_bind_driver_to_node(dev, "sunxi_reset", "reset",
+ dev_ofnode(dev), &rst_dev);
+ if (ret) {
+ debug("failed to bind sunxi_reset driver (ret=%d)\n", ret);
+ return ret;
+ }
+ priv = malloc(sizeof(struct sunxi_reset_priv));
+ priv->count = count;
+ priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
+ rst_dev->priv = priv;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(sunxi_reset) = {
+ .name = "sunxi_reset",
+ .id = UCLASS_RESET,
+ .ops = &sunxi_reset_ops,
+ .probe = sunxi_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct sunxi_reset_priv),
+};
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a213c918bc..60f37f40fd 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -190,6 +190,7 @@ config USB_EHCI_GENERIC
bool "Support for generic EHCI USB controller"
depends on OF_CONTROL
depends on DM_USB
+ default ARCH_SUNXI
default n
---help---
Enables support for generic EHCI controller.
@@ -220,6 +221,7 @@ config USB_OHCI_GENERIC
bool "Support for generic OHCI USB controller"
depends on OF_CONTROL
depends on DM_USB
+ default ARCH_SUNXI
select USB_HOST
---help---
Enables support for generic OHCI controller.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 948683a52b..6aa574f6f7 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_USB_OHCI_DA8XX) += ohci-da8xx.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o
obj-$(CONFIG_USB_OHCI_EP93XX) += ohci-ep93xx.o
-obj-$(CONFIG_USB_OHCI_SUNXI) += ohci-sunxi.o
obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o
obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o
@@ -37,7 +36,6 @@ obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
-obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
deleted file mode 100644
index 7a79931a97..0000000000
--- a/drivers/usb/host/ehci-sunxi.c
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Sunxi ehci glue
- *
- * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
- * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
- *
- * Based on code from
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- */
-
-#include <common.h>
-#include <asm/arch/clock.h>
-#include <asm/io.h>
-#include <dm.h>
-#include "ehci.h"
-#include <generic-phy.h>
-
-#ifdef CONFIG_SUNXI_GEN_SUN4I
-#define BASE_DIST 0x8000
-#define AHB_CLK_DIST 2
-#else
-#define BASE_DIST 0x1000
-#define AHB_CLK_DIST 1
-#endif
-
-#define SUN6I_AHB_RESET0_CFG_OFFSET 0x2c0
-#define SUN9I_AHB_RESET0_CFG_OFFSET 0x5a0
-
-struct ehci_sunxi_cfg {
- bool has_reset;
- u32 extra_ahb_gate_mask;
- u32 reset0_cfg_offset;
-};
-
-struct ehci_sunxi_priv {
- struct ehci_ctrl ehci;
- struct sunxi_ccm_reg *ccm;
- u32 *reset0_cfg;
- int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
- struct phy phy;
- const struct ehci_sunxi_cfg *cfg;
-};
-
-static int ehci_usb_probe(struct udevice *dev)
-{
- struct usb_platdata *plat = dev_get_platdata(dev);
- struct ehci_sunxi_priv *priv = dev_get_priv(dev);
- struct ehci_hccr *hccr = (struct ehci_hccr *)devfdt_get_addr(dev);
- struct ehci_hcor *hcor;
- int extra_ahb_gate_mask = 0;
- u8 reg_mask = 0;
- int phys, ret;
-
- priv->cfg = (const struct ehci_sunxi_cfg *)dev_get_driver_data(dev);
- priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- if (IS_ERR(priv->ccm))
- return PTR_ERR(priv->ccm);
-
- priv->reset0_cfg = (void *)priv->ccm +
- priv->cfg->reset0_cfg_offset;
-
- phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
- if (phys < 0) {
- phys = 0;
- goto no_phy;
- }
-
- ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
- if (ret) {
- pr_err("failed to get %s usb PHY\n", dev->name);
- return ret;
- }
-
- ret = generic_phy_init(&priv->phy);
- if (ret) {
- pr_err("failed to init %s USB PHY\n", dev->name);
- return ret;
- }
-
- ret = generic_phy_power_on(&priv->phy);
- if (ret) {
- pr_err("failed to power on %s USB PHY\n", dev->name);
- return ret;
- }
-
-no_phy:
- /*
- * This should go away once we've moved to the driver model for
- * clocks resp. phys.
- */
- reg_mask = ((uintptr_t)hccr - SUNXI_USB1_BASE) / BASE_DIST;
- priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
- extra_ahb_gate_mask = priv->cfg->extra_ahb_gate_mask;
- priv->ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
- extra_ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
-
- setbits_le32(&priv->ccm->ahb_gate0,
- priv->ahb_gate_mask | extra_ahb_gate_mask);
- if (priv->cfg->has_reset)
- setbits_le32(priv->reset0_cfg,
- priv->ahb_gate_mask | extra_ahb_gate_mask);
-
- hcor = (struct ehci_hcor *)((uintptr_t)hccr +
- HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
- return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type);
-}
-
-static int ehci_usb_remove(struct udevice *dev)
-{
- struct ehci_sunxi_priv *priv = dev_get_priv(dev);
- int ret;
-
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret) {
- pr_err("failed to exit %s USB PHY\n", dev->name);
- return ret;
- }
- }
-
- ret = ehci_deregister(dev);
- if (ret)
- return ret;
-
- if (priv->cfg->has_reset)
- clrbits_le32(priv->reset0_cfg, priv->ahb_gate_mask);
- clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
-
- return 0;
-}
-
-static const struct ehci_sunxi_cfg sun4i_a10_cfg = {
- .has_reset = false,
-};
-
-static const struct ehci_sunxi_cfg sun6i_a31_cfg = {
- .has_reset = true,
- .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct ehci_sunxi_cfg sun8i_h3_cfg = {
- .has_reset = true,
- .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0,
- .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct ehci_sunxi_cfg sun9i_a80_cfg = {
- .has_reset = true,
- .reset0_cfg_offset = SUN9I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct udevice_id ehci_usb_ids[] = {
- {
- .compatible = "allwinner,sun4i-a10-ehci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun5i-a13-ehci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun6i-a31-ehci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun7i-a20-ehci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun8i-a23-ehci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun8i-a83t-ehci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun8i-h3-ehci",
- .data = (ulong)&sun8i_h3_cfg,
- },
- {
- .compatible = "allwinner,sun9i-a80-ehci",
- .data = (ulong)&sun9i_a80_cfg,
- },
- {
- .compatible = "allwinner,sun50i-a64-ehci",
- .data = (ulong)&sun8i_h3_cfg,
- },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(ehci_sunxi) = {
- .name = "ehci_sunxi",
- .id = UCLASS_USB,
- .of_match = ehci_usb_ids,
- .probe = ehci_usb_probe,
- .remove = ehci_usb_remove,
- .ops = &ehci_usb_ops,
- .platdata_auto_alloc_size = sizeof(struct usb_platdata),
- .priv_auto_alloc_size = sizeof(struct ehci_sunxi_priv),
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
-};
diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c
deleted file mode 100644
index bb3c2475df..0000000000
--- a/drivers/usb/host/ohci-sunxi.c
+++ /dev/null
@@ -1,233 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Sunxi ohci glue
- *
- * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
- *
- * Based on code from
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- */
-
-#include <common.h>
-#include <asm/arch/clock.h>
-#include <asm/io.h>
-#include <dm.h>
-#include <usb.h>
-#include "ohci.h"
-#include <generic-phy.h>
-
-#ifdef CONFIG_SUNXI_GEN_SUN4I
-#define BASE_DIST 0x8000
-#define AHB_CLK_DIST 2
-#else
-#define BASE_DIST 0x1000
-#define AHB_CLK_DIST 1
-#endif
-
-#define SUN6I_AHB_RESET0_CFG_OFFSET 0x2c0
-#define SUN9I_AHB_RESET0_CFG_OFFSET 0x5a0
-
-struct ohci_sunxi_cfg {
- bool has_reset;
- u32 extra_ahb_gate_mask;
- u32 extra_usb_gate_mask;
- u32 reset0_cfg_offset;
-};
-
-struct ohci_sunxi_priv {
- ohci_t ohci;
- struct sunxi_ccm_reg *ccm;
- u32 *reset0_cfg;
- int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
- int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
- struct phy phy;
- const struct ohci_sunxi_cfg *cfg;
-};
-
-static fdt_addr_t last_ohci_addr = 0;
-
-static int ohci_usb_probe(struct udevice *dev)
-{
- struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
- struct ohci_sunxi_priv *priv = dev_get_priv(dev);
- struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
- int extra_ahb_gate_mask = 0;
- u8 reg_mask = 0;
- int phys, ret;
-
- if ((fdt_addr_t)regs > last_ohci_addr)
- last_ohci_addr = (fdt_addr_t)regs;
-
- priv->cfg = (const struct ohci_sunxi_cfg *)dev_get_driver_data(dev);
- priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- if (IS_ERR(priv->ccm))
- return PTR_ERR(priv->ccm);
-
- priv->reset0_cfg = (void *)priv->ccm +
- priv->cfg->reset0_cfg_offset;
-
- phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
- if (phys < 0) {
- phys = 0;
- goto no_phy;
- }
-
- ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
- if (ret) {
- pr_err("failed to get %s usb PHY\n", dev->name);
- return ret;
- }
-
- ret = generic_phy_init(&priv->phy);
- if (ret) {
- pr_err("failed to init %s USB PHY\n", dev->name);
- return ret;
- }
-
- ret = generic_phy_power_on(&priv->phy);
- if (ret) {
- pr_err("failed to power on %s USB PHY\n", dev->name);
- return ret;
- }
-
-no_phy:
- bus_priv->companion = true;
-
- /*
- * This should go away once we've moved to the driver model for
- * clocks resp. phys.
- */
- reg_mask = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
- priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
- extra_ahb_gate_mask = priv->cfg->extra_ahb_gate_mask;
- priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
- priv->ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
- extra_ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
- priv->usb_gate_mask <<= reg_mask;
-
- setbits_le32(&priv->ccm->ahb_gate0,
- priv->ahb_gate_mask | extra_ahb_gate_mask);
- setbits_le32(&priv->ccm->usb_clk_cfg,
- priv->usb_gate_mask | priv->cfg->extra_usb_gate_mask);
- if (priv->cfg->has_reset)
- setbits_le32(priv->reset0_cfg,
- priv->ahb_gate_mask | extra_ahb_gate_mask);
-
- return ohci_register(dev, regs);
-}
-
-static int ohci_usb_remove(struct udevice *dev)
-{
- struct ohci_sunxi_priv *priv = dev_get_priv(dev);
- fdt_addr_t base_addr = devfdt_get_addr(dev);
- int ret;
-
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret) {
- pr_err("failed to exit %s USB PHY\n", dev->name);
- return ret;
- }
- }
-
- ret = ohci_deregister(dev);
- if (ret)
- return ret;
-
- if (priv->cfg->has_reset)
- clrbits_le32(priv->reset0_cfg, priv->ahb_gate_mask);
- /*
- * On the A64 CLK_USB_OHCI0 is the parent of CLK_USB_OHCI1, so
- * we have to wait with bringing down any clock until the last
- * OHCI controller is removed.
- */
- if (!priv->cfg->extra_usb_gate_mask || base_addr == last_ohci_addr) {
- u32 usb_gate_mask = priv->usb_gate_mask;
-
- usb_gate_mask |= priv->cfg->extra_usb_gate_mask;
- clrbits_le32(&priv->ccm->usb_clk_cfg, usb_gate_mask);
- }
-
- clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
-
- return 0;
-}
-
-static const struct ohci_sunxi_cfg sun4i_a10_cfg = {
- .has_reset = false,
-};
-
-static const struct ohci_sunxi_cfg sun6i_a31_cfg = {
- .has_reset = true,
- .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct ohci_sunxi_cfg sun8i_h3_cfg = {
- .has_reset = true,
- .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
- .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct ohci_sunxi_cfg sun9i_a80_cfg = {
- .has_reset = true,
- .reset0_cfg_offset = SUN9I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct ohci_sunxi_cfg sun50i_a64_cfg = {
- .has_reset = true,
- .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
- .extra_usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK,
- .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
-};
-
-static const struct udevice_id ohci_usb_ids[] = {
- {
- .compatible = "allwinner,sun4i-a10-ohci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun5i-a13-ohci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun6i-a31-ohci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun7i-a20-ohci",
- .data = (ulong)&sun4i_a10_cfg,
- },
- {
- .compatible = "allwinner,sun8i-a23-ohci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun8i-a83t-ohci",
- .data = (ulong)&sun6i_a31_cfg,
- },
- {
- .compatible = "allwinner,sun8i-h3-ohci",
- .data = (ulong)&sun8i_h3_cfg,
- },
- {
- .compatible = "allwinner,sun9i-a80-ohci",
- .data = (ulong)&sun9i_a80_cfg,
- },
- {
- .compatible = "allwinner,sun50i-a64-ohci",
- .data = (ulong)&sun50i_a64_cfg,
- },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(usb_ohci) = {
- .name = "ohci_sunxi",
- .id = UCLASS_USB,
- .of_match = ohci_usb_ids,
- .probe = ohci_usb_probe,
- .remove = ohci_usb_remove,
- .ops = &ohci_usb_ops,
- .platdata_auto_alloc_size = sizeof(struct usb_platdata),
- .priv_auto_alloc_size = sizeof(struct ohci_sunxi_priv),
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
-};
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index f542a181fa..45eecfeee6 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -16,9 +16,11 @@
* This file is part of the Inventra Controller Driver for Linux.
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
#include <generic-phy.h>
#include <phy-sun4i-usb.h>
+#include <reset.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
@@ -80,16 +82,12 @@
struct sunxi_musb_config {
struct musb_hdrc_config *config;
- bool has_reset;
- u8 rst_bit;
- u8 clkgate_bit;
- u32 off_reset0;
};
struct sunxi_glue {
struct musb_host_data mdata;
- struct sunxi_ccm_reg *ccm;
- u32 *reg_reset0;
+ struct clk clk;
+ struct reset_ctl rst;
struct sunxi_musb_config *cfg;
struct device dev;
struct phy phy;
@@ -296,24 +294,27 @@ static int sunxi_musb_init(struct musb *musb)
pr_debug("%s():\n", __func__);
- ret = generic_phy_init(&glue->phy);
+ ret = clk_enable(&glue->clk);
if (ret) {
- pr_err("failed to init USB PHY\n");
+ dev_err(dev, "failed to enable clock\n");
return ret;
}
- musb->isr = sunxi_musb_interrupt;
-
- setbits_le32(&glue->ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_USB0));
- if (glue->cfg->clkgate_bit)
- setbits_le32(&glue->ccm->ahb_gate0,
- BIT(glue->cfg->clkgate_bit));
+ if (reset_valid(&glue->rst)) {
+ ret = reset_deassert(&glue->rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset\n");
+ goto err_clk;
+ }
+ }
- if (glue->cfg->has_reset)
- setbits_le32(glue->reg_reset0, BIT(AHB_GATE_OFFSET_USB0));
+ ret = generic_phy_init(&glue->phy);
+ if (ret) {
+ dev_err(dev, "failed to init USB PHY\n");
+ goto err_rst;
+ }
- if (glue->cfg->rst_bit)
- setbits_le32(glue->reg_reset0, BIT(glue->cfg->rst_bit));
+ musb->isr = sunxi_musb_interrupt;
USBC_ConfigFIFO_Base();
USBC_EnableDpDmPullUp(musb->mregs);
@@ -329,6 +330,13 @@ static int sunxi_musb_init(struct musb *musb)
USBC_ForceVbusValidToHigh(musb->mregs);
return 0;
+
+err_rst:
+ if (reset_valid(&glue->rst))
+ reset_assert(&glue->rst);
+err_clk:
+ clk_disable(&glue->clk);
+ return ret;
}
static int sunxi_musb_exit(struct musb *musb)
@@ -344,16 +352,9 @@ static int sunxi_musb_exit(struct musb *musb)
}
}
- if (glue->cfg->has_reset)
- clrbits_le32(glue->reg_reset0, BIT(AHB_GATE_OFFSET_USB0));
-
- if (glue->cfg->rst_bit)
- clrbits_le32(glue->reg_reset0, BIT(glue->cfg->rst_bit));
-
- clrbits_le32(&glue->ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_USB0));
- if (glue->cfg->clkgate_bit)
- clrbits_le32(&glue->ccm->ahb_gate0,
- BIT(glue->cfg->clkgate_bit));
+ if (reset_valid(&glue->rst))
+ reset_assert(&glue->rst);
+ clk_disable(&glue->clk);
return 0;
}
@@ -450,11 +451,17 @@ static int musb_usb_probe(struct udevice *dev)
if (!glue->cfg)
return -EINVAL;
- glue->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- if (IS_ERR(glue->ccm))
- return PTR_ERR(glue->ccm);
+ ret = clk_get_by_index(dev, 0, &glue->clk);
+ if (ret) {
+ dev_err(dev, "failed to get clock\n");
+ return ret;
+ }
- glue->reg_reset0 = (void *)glue->ccm + glue->cfg->off_reset0;
+ ret = reset_get_by_index(dev, 0, &glue->rst);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get reset\n");
+ return ret;
+ }
ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
if (ret) {
@@ -462,7 +469,6 @@ static int musb_usb_probe(struct udevice *dev)
return ret;
}
-
memset(&pdata, 0, sizeof(pdata));
pdata.power = 250;
pdata.platform_ops = &sunxi_musb_ops;
@@ -505,21 +511,14 @@ static int musb_usb_remove(struct udevice *dev)
static const struct sunxi_musb_config sun4i_a10_cfg = {
.config = &musb_config,
- .has_reset = false,
};
static const struct sunxi_musb_config sun6i_a31_cfg = {
.config = &musb_config,
- .has_reset = true,
- .off_reset0 = OFF_SUN6I_AHB_RESET0,
};
static const struct sunxi_musb_config sun8i_h3_cfg = {
.config = &musb_config_h3,
- .has_reset = true,
- .rst_bit = 23,
- .clkgate_bit = 23,
- .off_reset0 = OFF_SUN6I_AHB_RESET0,
};
static const struct udevice_id sunxi_musb_ids[] = {