From 809f36c6f4a0568178c909ff1096ca83eae33f7d Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 1 Nov 2011 20:03:30 +0100 Subject: MIPS: Alchemy: Au1300 SoC support Add basic support for the Au1300 variant(s): - New GPIO/Interrupt controller - DBDMA ids - USB setup - MMC support - enable various PSC drivers - detection code. Signed-off-by: Manuel Lauss To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2866/ Signed-off-by: Ralf Baechle --- drivers/usb/host/alchemy-common.c | 277 ++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-au1xxx.c | 13 +- 2 files changed, 286 insertions(+), 4 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/alchemy-common.c b/drivers/usb/host/alchemy-common.c index b4192c9..936af83 100644 --- a/drivers/usb/host/alchemy-common.c +++ b/drivers/usb/host/alchemy-common.c @@ -52,9 +52,263 @@ USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ USBCFG_OME) +/* Au1300 USB config registers */ +#define USB_DWC_CTRL1 0x00 +#define USB_DWC_CTRL2 0x04 +#define USB_VBUS_TIMER 0x10 +#define USB_SBUS_CTRL 0x14 +#define USB_MSR_ERR 0x18 +#define USB_DWC_CTRL3 0x1C +#define USB_DWC_CTRL4 0x20 +#define USB_OTG_STATUS 0x28 +#define USB_DWC_CTRL5 0x2C +#define USB_DWC_CTRL6 0x30 +#define USB_DWC_CTRL7 0x34 +#define USB_PHY_STATUS 0xC0 +#define USB_INT_STATUS 0xC4 +#define USB_INT_ENABLE 0xC8 + +#define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ +#define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ +#define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ + +#define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ +#define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ +#define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ + +#define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) +#define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) +#define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) +#define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) + +#define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ + +#define USB_INTEN_FORCE 0x20 +#define USB_INTEN_PHY 0x10 +#define USB_INTEN_UDC 0x08 +#define USB_INTEN_EHCI 0x04 +#define USB_INTEN_OHCI1 0x02 +#define USB_INTEN_OHCI0 0x01 static DEFINE_SPINLOCK(alchemy_usb_lock); +static inline void __au1300_usb_phyctl(void __iomem *base, int enable) +{ + unsigned long r, s; + + r = __raw_readl(base + USB_DWC_CTRL2); + s = __raw_readl(base + USB_DWC_CTRL3); + + s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | + USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; + + if (enable) { + /* simply enable all PHYs */ + r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS; + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } else if (!s) { + /* no USB block active, do disable all PHYs */ + r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS); + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } +} + +static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) +{ + unsigned long r; + + if (enable) { + __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ + r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); /* power up the PHYs */ + + r = __raw_readl(base + USB_INT_ENABLE); + r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + /* reset the OHCI start clock bit */ + __raw_writel(0, base + USB_DWC_CTRL7); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN); + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_ehci_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_udc_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_otg_control(void __iomem *base, int enable) +{ + unsigned long r; + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } else { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline int au1300_usb_control(int block, int enable) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + int ret = 0; + + switch (block) { + case ALCHEMY_USB_OHCI0: + __au1300_ohci_control(base, enable, 0); + break; + case ALCHEMY_USB_OHCI1: + __au1300_ohci_control(base, enable, 1); + break; + case ALCHEMY_USB_EHCI0: + __au1300_ehci_control(base, enable); + break; + case ALCHEMY_USB_UDC0: + __au1300_udc_control(base, enable); + break; + case ALCHEMY_USB_OTG0: + __au1300_otg_control(base, enable); + break; + default: + ret = -ENODEV; + } + return ret; +} + +static inline void au1300_usb_init(void) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + + /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 + * here at all: Port 2 routing (EHCI or UDC) must be set either + * by boot firmware or platform init code; I can't autodetect + * a sane setting. + */ + __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ + wmb(); + __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ + wmb(); + __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ + wmb(); + __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ + wmb(); + /* set coherent access bit */ + __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); + wmb(); +} static inline void __au1200_ohci_control(void __iomem *base, int enable) { @@ -233,6 +487,9 @@ int alchemy_usb_control(int block, int enable) case ALCHEMY_CPU_AU1200: ret = au1200_usb_control(block, enable); break; + case ALCHEMY_CPU_AU1300: + ret = au1300_usb_control(block, enable); + break; default: ret = -ENODEV; } @@ -281,6 +538,20 @@ static void au1200_usb_pm(int susp) } } +static void au1300_usb_pm(int susp) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + /* remember Port2 routing */ + if (susp) { + alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); + } else { + au1300_usb_init(); + __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); + wmb(); + } +} + static void alchemy_usb_pm(int susp) { switch (alchemy_get_cputype()) { @@ -295,6 +566,9 @@ static void alchemy_usb_pm(int susp) case ALCHEMY_CPU_AU1200: au1200_usb_pm(susp); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_pm(susp); + break; } } @@ -328,6 +602,9 @@ static int __init alchemy_usb_init(void) case ALCHEMY_CPU_AU1200: au1200_usb_init(); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_init(); + break; } register_syscore_ops(&alchemy_usb_pm_ops); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 9b66df8..95d1a71 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -89,7 +89,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) { - int ret; + int ret, unit; struct usb_hcd *hcd; if (usb_disabled()) @@ -120,7 +120,9 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) goto err2; } - if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) { + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; + if (alchemy_usb_control(unit, 1)) { printk(KERN_INFO "%s: controller init failed!\n", pdev->name); ret = -ENODEV; goto err3; @@ -135,7 +137,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) return ret; } - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); err3: iounmap(hcd->regs); err2: @@ -148,9 +150,12 @@ err1: static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + int unit; + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); -- cgit v1.1 From 9d6b204f93cfeb7ec5e6ec499aca43d2c1d6da3f Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 20 Jun 2011 21:26:09 +0200 Subject: USB: ehci-ath79: Add device_id entry for the AR933X SoCs Also make the USB_EHCI_ATH79 selectable for the AR933X SoCs. Signed-off-by: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: Kathy Giori Cc: "Luis R. Rodriguez" Cc: Greg Kroah-Hartman Cc: Alan Stern Cc: linux-usb@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2529/ Signed-off-by: Ralf Baechle --- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/ehci-ath79.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 060e0e2..8b094b4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -210,7 +210,7 @@ config USB_CNS3XXX_EHCI config USB_EHCI_ATH79 bool "EHCI support for AR7XXX/AR9XXX SoCs" - depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X) + depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) select USB_EHCI_ROOT_HUB_TT default y ---help--- diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index afb6743..f1424f9 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -33,6 +33,10 @@ static const struct platform_device_id ehci_ath79_id_table[] = { .driver_data = EHCI_ATH79_IP_V2, }, { + .name = "ar933x-ehci", + .driver_data = EHCI_ATH79_IP_V2, + }, + { /* terminating entry */ }, }; -- cgit v1.1