170 lines
5.4 KiB
Diff
170 lines
5.4 KiB
Diff
From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
|
|
From: Florian Fainelli <florian@openwrt.org>
|
|
Date: Mon, 28 Jan 2013 20:06:22 +0100
|
|
Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
|
|
common USB code
|
|
|
|
This patch updates the common USB code touching the USB private
|
|
registers with the specific bits to properly enable OHCI and EHCI
|
|
controllers on BCM63xx SoCs. As a result we now need to protect access
|
|
to Read Modify Write sequences using a spinlock because we cannot
|
|
guarantee that any of the exposed helper will not be called
|
|
concurrently.
|
|
|
|
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
|
|
Signed-off-by: Florian Fainelli <florian@openwrt.org>
|
|
---
|
|
arch/mips/bcm63xx/usb-common.c | 97 ++++++++++++++++++++
|
|
.../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h | 2 +
|
|
2 files changed, 99 insertions(+)
|
|
|
|
--- a/arch/mips/bcm63xx/usb-common.c
|
|
+++ b/arch/mips/bcm63xx/usb-common.c
|
|
@@ -5,10 +5,12 @@
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
|
* Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
|
|
* Copyright (C) 2012 Broadcom Corporation
|
|
*
|
|
*/
|
|
+#include <linux/spinlock.h>
|
|
#include <linux/export.h>
|
|
|
|
#include <bcm63xx_cpu.h>
|
|
@@ -16,9 +18,14 @@
|
|
#include <bcm63xx_io.h>
|
|
#include <bcm63xx_usb_priv.h>
|
|
|
|
+static DEFINE_SPINLOCK(usb_priv_reg_lock);
|
|
+
|
|
void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
|
|
{
|
|
u32 val;
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&usb_priv_reg_lock, flags);
|
|
|
|
val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
|
|
if (is_device) {
|
|
@@ -36,12 +43,17 @@ void bcm63xx_usb_priv_select_phy_mode(u3
|
|
else
|
|
val &= ~USBH_PRIV_SWAP_USBD_MASK;
|
|
bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
|
|
+
|
|
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
|
|
|
|
void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
|
|
{
|
|
u32 val;
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&usb_priv_reg_lock, flags);
|
|
|
|
val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
|
|
if (is_on)
|
|
@@ -49,5 +61,90 @@ void bcm63xx_usb_priv_select_pullup(u32
|
|
else
|
|
val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
|
|
bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
|
|
+
|
|
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
|
|
+
|
|
+/* The following array represents the meaning of the DESC/DATA
|
|
+ * endian swapping with respect to the CPU configured endianness
|
|
+ *
|
|
+ * DATA ENDN mmio descriptor
|
|
+ * 0 0 BE invalid
|
|
+ * 0 1 BE LE
|
|
+ * 1 0 BE BE
|
|
+ * 1 1 BE invalid
|
|
+ *
|
|
+ * Since BCM63XX SoCs are configured to be in big-endian mode
|
|
+ * we want configuration at line 3.
|
|
+ */
|
|
+void bcm63xx_usb_priv_ohci_cfg_set(void)
|
|
+{
|
|
+ u32 reg;
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&usb_priv_reg_lock, flags);
|
|
+
|
|
+ if (BCMCPU_IS_6348())
|
|
+ bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
|
|
+ else if (BCMCPU_IS_6358()) {
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
|
|
+ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
|
|
+ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
|
|
+ /*
|
|
+ * The magic value comes for the original vendor BSP
|
|
+ * and is needed for USB to work. Datasheet does not
|
|
+ * help, so the magic value is used as-is.
|
|
+ */
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
|
|
+ USBH_PRIV_TEST_6358_REG);
|
|
+
|
|
+ } else if (BCMCPU_IS_6328() || BCMCPU_IS_6368()) {
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
|
|
+ reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
|
|
+ reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
|
|
+
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
|
|
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
|
|
+ }
|
|
+
|
|
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
|
|
+}
|
|
+
|
|
+void bcm63xx_usb_priv_ehci_cfg_set(void)
|
|
+{
|
|
+ u32 reg;
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&usb_priv_reg_lock, flags);
|
|
+
|
|
+ if (BCMCPU_IS_6358()) {
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
|
|
+ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
|
|
+ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
|
|
+
|
|
+ /*
|
|
+ * The magic value comes for the original vendor BSP
|
|
+ * and is needed for USB to work. Datasheet does not
|
|
+ * help, so the magic value is used as-is.
|
|
+ */
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
|
|
+ USBH_PRIV_TEST_6358_REG);
|
|
+
|
|
+ } else if (BCMCPU_IS_6328() || BCMCPU_IS_6368()) {
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
|
|
+ reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
|
|
+ reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
|
|
+
|
|
+ reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
|
|
+ reg |= USBH_PRIV_SETUP_IOC_MASK;
|
|
+ bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
|
|
+ }
|
|
+
|
|
+ spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
|
|
+}
|
|
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
|
|
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
|
|
@@ -5,5 +5,7 @@
|
|
|
|
void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
|
|
void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
|
|
+void bcm63xx_usb_priv_ohci_cfg_set(void);
|
|
+void bcm63xx_usb_priv_ehci_cfg_set(void);
|
|
|
|
#endif /* BCM63XX_USB_PRIV_H_ */
|