1 From 28758a9da77954ed323f86123ef448c6a563c037 Mon Sep 17 00:00:00 2001
2 From: Florian Fainelli <florian@openwrt.org>
3 Date: Mon, 28 Jan 2013 20:06:22 +0100
4 Subject: [PATCH 04/11] MIPS: BCM63XX: add OHCI/EHCI configuration bits to
7 This patch updates the common USB code touching the USB private
8 registers with the specific bits to properly enable OHCI and EHCI
9 controllers on BCM63xx SoCs. As a result we now need to protect access
10 to Read Modify Write sequences using a spinlock because we cannot
11 guarantee that any of the exposed helper will not be called
14 Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
15 Signed-off-by: Florian Fainelli <florian@openwrt.org>
17 arch/mips/bcm63xx/usb-common.c | 97 ++++++++++++++++++++
18 .../include/asm/mach-bcm63xx/bcm63xx_usb_priv.h | 2 +
19 2 files changed, 99 insertions(+)
21 --- a/arch/mips/bcm63xx/usb-common.c
22 +++ b/arch/mips/bcm63xx/usb-common.c
24 * License. See the file "COPYING" in the main directory of this archive
27 + * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
28 * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
29 * Copyright (C) 2012 Broadcom Corporation
32 +#include <linux/spinlock.h>
33 #include <linux/export.h>
35 #include <bcm63xx_cpu.h>
37 #include <bcm63xx_io.h>
38 #include <bcm63xx_usb_priv.h>
40 +static DEFINE_SPINLOCK(usb_priv_reg_lock);
42 void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device)
45 + unsigned long flags;
47 + spin_lock_irqsave(&usb_priv_reg_lock, flags);
49 val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
51 @@ -36,12 +43,17 @@ void bcm63xx_usb_priv_select_phy_mode(u3
53 val &= ~USBH_PRIV_SWAP_USBD_MASK;
54 bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
56 + spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
58 EXPORT_SYMBOL(bcm63xx_usb_priv_select_phy_mode);
60 void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on)
63 + unsigned long flags;
65 + spin_lock_irqsave(&usb_priv_reg_lock, flags);
67 val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
69 @@ -49,5 +61,90 @@ void bcm63xx_usb_priv_select_pullup(u32
71 val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
72 bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
74 + spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
76 EXPORT_SYMBOL(bcm63xx_usb_priv_select_pullup);
78 +/* The following array represents the meaning of the DESC/DATA
79 + * endian swapping with respect to the CPU configured endianness
81 + * DATA ENDN mmio descriptor
87 + * Since BCM63XX SoCs are configured to be in big-endian mode
88 + * we want configuration at line 3.
90 +void bcm63xx_usb_priv_ohci_cfg_set(void)
93 + unsigned long flags;
95 + spin_lock_irqsave(&usb_priv_reg_lock, flags);
97 + if (BCMCPU_IS_6348())
98 + bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
99 + else if (BCMCPU_IS_6358()) {
100 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
101 + reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
102 + reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
103 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
105 + * The magic value comes for the original vendor BSP
106 + * and is needed for USB to work. Datasheet does not
107 + * help, so the magic value is used as-is.
109 + bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
110 + USBH_PRIV_TEST_6358_REG);
112 + } else if (BCMCPU_IS_6328() || BCMCPU_IS_6368()) {
113 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
114 + reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
115 + reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
116 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
118 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
119 + reg |= USBH_PRIV_SETUP_IOC_MASK;
120 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
123 + spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
126 +void bcm63xx_usb_priv_ehci_cfg_set(void)
129 + unsigned long flags;
131 + spin_lock_irqsave(&usb_priv_reg_lock, flags);
133 + if (BCMCPU_IS_6358()) {
134 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6358_REG);
135 + reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
136 + reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
137 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6358_REG);
140 + * The magic value comes for the original vendor BSP
141 + * and is needed for USB to work. Datasheet does not
142 + * help, so the magic value is used as-is.
144 + bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020,
145 + USBH_PRIV_TEST_6358_REG);
147 + } else if (BCMCPU_IS_6328() || BCMCPU_IS_6368()) {
148 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
149 + reg &= ~USBH_PRIV_SWAP_EHCI_ENDN_MASK;
150 + reg |= USBH_PRIV_SWAP_EHCI_DATA_MASK;
151 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_6368_REG);
153 + reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SETUP_6368_REG);
154 + reg |= USBH_PRIV_SETUP_IOC_MASK;
155 + bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SETUP_6368_REG);
158 + spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
160 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
161 +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_usb_priv.h
164 void bcm63xx_usb_priv_select_phy_mode(u32 portmask, bool is_device);
165 void bcm63xx_usb_priv_select_pullup(u32 portmask, bool is_on);
166 +void bcm63xx_usb_priv_ohci_cfg_set(void);
167 +void bcm63xx_usb_priv_ehci_cfg_set(void);
169 #endif /* BCM63XX_USB_PRIV_H_ */