From 7f902c962b3314665cbccf013e3bac599d514581 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Sat, 21 Apr 2012 12:30:48 +0000
Subject: [PATCH] ramips: rt305x: add OHCI/EHCI registration code for RT3352

SVN-Revision: 31402
---
 .../include/asm/mach-ralink/rt305x_regs.h     |  34 +++++
 .../files/arch/mips/ralink/rt305x/devices.c   | 132 +++++++++++++++++-
 2 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/rt305x_regs.h b/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/rt305x_regs.h
index e121582055..db037a583a 100644
--- a/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/rt305x_regs.h
+++ b/target/linux/ramips/files/arch/mips/include/asm/mach-ralink/rt305x_regs.h
@@ -46,6 +46,11 @@
 #define RT305X_FLASH1_SIZE	(16 * 1024 * 1024)
 #define RT305X_FLASH0_SIZE	(8 * 1024 * 1024)
 
+#define RT3352_EHCI_BASE	0x101c0000
+#define RT3352_EHCI_SIZE	0x1000
+#define RT3352_OHCI_BASE	0x101c1000
+#define RT3352_OHCI_SIZE	0x1000
+
 /* SYSC registers */
 #define SYSC_REG_CHIP_NAME0	0x000	/* Chip Name 0 */
 #define SYSC_REG_CHIP_NAME1	0x004	/* Chip Name 1 */
@@ -57,6 +62,11 @@
 #define SYSC_REG_IA_ADDRESS	0x310	/* Illegal Access Address */
 #define SYSC_REG_IA_TYPE	0x314	/* Illegal Access Type */
 
+#define RT3352_SYSC_REG_SYSCFG1		0x014
+#define RT3352_SYSC_REG_CLKCFG1		0x030
+#define RT3352_SYSC_REG_RSTCTRL		0x034
+#define RT3352_SYSC_REG_USB_PS		0x05c
+
 #define RT3052_CHIP_NAME0	0x30335452
 #define RT3052_CHIP_NAME1	0x20203235
 
@@ -85,6 +95,11 @@
 #define RT3352_SYSCFG0_CPUCLK_LOW	0x0
 #define RT3352_SYSCFG0_CPUCLK_HIGH	0x1
 
+#define RT3352_SYSCFG1_USB0_HOST_MODE	BIT(10)
+
+#define RT3352_CLKCFG1_UPHY0_CLK_EN	BIT(18)
+#define RT3352_CLKCFG1_UPHY1_CLK_EN	BIT(20)
+
 #define RT305X_GPIO_MODE_I2C		BIT(0)
 #define RT305X_GPIO_MODE_SPI		BIT(1)
 #define RT305X_GPIO_MODE_UART0_SHIFT	2
@@ -121,6 +136,25 @@
 #define RT305X_RESET_OTG	BIT(22)
 #define RT305X_RESET_ESW	BIT(23)
 
+#define RT3352_RSTCTRL_SYS	BIT(0)
+#define RT3352_RSTCTRL_TIMER	BIT(8)
+#define RT3352_RSTCTRL_INTC	BIT(9)
+#define RT3352_RSTCTRL_MEMC	BIT(10)
+#define RT3352_RSTCTRL_PCM	BIT(11)
+#define RT3352_RSTCTRL_UART0	BIT(12)
+#define RT3352_RSTCTRL_PIO	BIT(13)
+#define RT3352_RSTCTRL_DMA	BIT(14)
+#define RT3352_RSTCTRL_I2C	BIT(16)
+#define RT3352_RSTCTRL_I2S	BIT(17)
+#define RT3352_RSTCTRL_SPI	BIT(18)
+#define RT3352_RSTCTRL_UART1	BIT(19)
+#define RT3352_RSTCTRL_WNIC	BIT(20)
+#define RT3352_RSTCTRL_FE	BIT(21)
+#define RT3352_RSTCTRL_UHST	BIT(22)
+#define RT3352_RSTCTRL_ESW	BIT(23)
+#define RT3352_RSTCTRL_EPHY	BIT(24)
+#define RT3352_RSTCTRL_UDEV	BIT(25)
+
 #define RT305X_INTC_INT_SYSCTL	BIT(0)
 #define RT305X_INTC_INT_TIMER0	BIT(1)
 #define RT305X_INTC_INT_TIMER1	BIT(2)
diff --git a/target/linux/ramips/files/arch/mips/ralink/rt305x/devices.c b/target/linux/ramips/files/arch/mips/ralink/rt305x/devices.c
index 60e5711797..bebab8171a 100644
--- a/target/linux/ramips/files/arch/mips/ralink/rt305x/devices.c
+++ b/target/linux/ramips/files/arch/mips/ralink/rt305x/devices.c
@@ -16,6 +16,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/rt2x00_platform.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/addrspace.h>
 
@@ -25,6 +27,8 @@
 
 #include <ramips_eth_platform.h>
 #include <rt305x_esw_platform.h>
+#include <rt3883_ehci_platform.h>
+#include <rt3883_ohci_platform.h>
 
 static struct resource rt305x_flash0_resources[] = {
 	{
@@ -257,7 +261,7 @@ void __init rt305x_register_spi(struct spi_board_info *info, int n)
 	platform_device_register(&rt305x_spi_device);
 }
 
-static struct resource rt305x_usb_resources[] = {
+static struct resource rt305x_dwc_otg_resources[] = {
 	{
 		.start	= RT305X_OTG_BASE,
 		.end	= RT305X_OTG_BASE + 0x3FFFF,
@@ -269,16 +273,134 @@ static struct resource rt305x_usb_resources[] = {
 	},
 };
 
-static struct platform_device rt305x_usb_device = {
+static struct platform_device rt305x_dwc_otg_device = {
 	.name			= "dwc_otg",
-	.resource		= rt305x_usb_resources,
-	.num_resources	= ARRAY_SIZE(rt305x_usb_resources),
+	.resource		= rt305x_dwc_otg_resources,
+	.num_resources	= ARRAY_SIZE(rt305x_dwc_otg_resources),
 	.dev = {
 		.platform_data = NULL,
 	}
 };
 
+static atomic_t rt3352_usb_use_count = ATOMIC_INIT(0);
+
+static void rt3352_usb_host_start(void)
+{
+	u32 t;
+
+	if (atomic_inc_return(&rt3352_usb_use_count) != 1)
+		return;
+
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_USB_PS);
+
+	/* enable clock for port0's and port1's phys */
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_CLKCFG1);
+	t = t | RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN;
+	rt305x_sysc_wr(t, RT3352_SYSC_REG_CLKCFG1);
+	mdelay(500);
+
+	/* pull USBHOST and USBDEV out from reset */
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_RSTCTRL);
+	t &= ~(RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV);
+	rt305x_sysc_wr(t, RT3352_SYSC_REG_RSTCTRL);
+	mdelay(500);
+
+	/* enable host mode */
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_SYSCFG1);
+	t |= RT3352_SYSCFG1_USB0_HOST_MODE;
+	rt305x_sysc_wr(t, RT3352_SYSC_REG_SYSCFG1);
+
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_USB_PS);
+}
+
+static void rt3352_usb_host_stop(void)
+{
+	u32 t;
+
+	if (atomic_dec_return(&rt3352_usb_use_count) != 0)
+		return;
+
+	/* put USBHOST and USBDEV into reset */
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_RSTCTRL);
+	t |= RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV;
+	rt305x_sysc_wr(t, RT3352_SYSC_REG_RSTCTRL);
+	udelay(10000);
+
+	/* disable clock for port0's and port1's phys*/
+	t = rt305x_sysc_rr(RT3352_SYSC_REG_CLKCFG1);
+	t &= ~(RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN);
+	rt305x_sysc_wr(t, RT3352_SYSC_REG_CLKCFG1);
+	udelay(10000);
+}
+
+static struct rt3883_ehci_platform_data rt3352_ehci_data = {
+	.start_hw	= rt3352_usb_host_start,
+	.stop_hw	= rt3352_usb_host_stop,
+};
+
+static struct resource rt3352_ehci_resources[] = {
+	{
+		.start	= RT3352_EHCI_BASE,
+		.end	= RT3352_EHCI_BASE + RT3352_EHCI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= RT305X_INTC_IRQ_OTG,
+		.end	= RT305X_INTC_IRQ_OTG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 rt3352_ehci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device rt3352_ehci_device = {
+	.name		= "rt3352-ehci",
+	.id		= -1,
+	.resource	= rt3352_ehci_resources,
+	.num_resources	= ARRAY_SIZE(rt3352_ehci_resources),
+	.dev            = {
+		.dma_mask		= &rt3352_ehci_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &rt3352_ehci_data,
+	},
+};
+
+static struct resource rt3352_ohci_resources[] = {
+	{
+		.start	= RT3352_OHCI_BASE,
+		.end	= RT3352_OHCI_BASE + RT3352_OHCI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= RT305X_INTC_IRQ_OTG,
+		.end	= RT305X_INTC_IRQ_OTG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct rt3883_ohci_platform_data rt3352_ohci_data = {
+	.start_hw	= rt3352_usb_host_start,
+	.stop_hw	= rt3352_usb_host_stop,
+};
+
+static u64 rt3352_ohci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device rt3352_ohci_device = {
+	.name		= "rt3352-ohci",
+	.id		= -1,
+	.resource	= rt3352_ohci_resources,
+	.num_resources	= ARRAY_SIZE(rt3352_ohci_resources),
+	.dev            = {
+		.dma_mask		= &rt3352_ohci_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &rt3352_ohci_data,
+	},
+};
+
 void __init rt305x_register_usb(void)
 {
-	platform_device_register(&rt305x_usb_device);
+	if (soc_is_rt305x() || soc_is_rt3350()) {
+		platform_device_register(&rt305x_dwc_otg_device);
+	} else if (soc_is_rt3352()) {
+		platform_device_register(&rt3352_ehci_device);
+		platform_device_register(&rt3352_ohci_device);
+	} else {
+		BUG();
+	}
 }
-- 
2.30.2