aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-29 14:13:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-29 14:13:10 -0400
commitb77d643ced576bdd1e918aebda869de74696cde9 (patch)
treebb5d708f4bbb48461923a28e63a8cf8bdd477dd7 /drivers/usb/host
parentb4020c1b198c0f0c0b0ff0cfdd824a26b93edd6f (diff)
parent64575f918f3279d8487cf670dbefa956ce16a526 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus: (46 commits) ftrace/MIPS: Enable C Version of recordmcount ftrace/MIPS: Add module support for C version of recordmcount ftrace/MIPS: Add MIPS64 support for C version of recordmcount MIPS: Make TASK_SIZE reflect proper size for both 32 and 64 bit processes. MIPS: Allow UserLocal on MIPS_R1 processors MIPS: Honor L2 bypass bit MIPS: Add BMIPS CP0 register definitions MIPS: Add BMIPS processor types to Kconfig MIPS: Decouple BMIPS CPU support from bcm47xx/bcm63xx SoC code MIPS: Add support for hardware performance events (mipsxx) MIPS: Perf-events: Add callchain support MIPS: add support for hardware performance events (skeleton) MIPS: add support for software performance events MIPS: define local_xchg from xchg_local to atomic_long_xchg MIPS: AR7: Add support for Titan (TNETV10xx) SoC variant MIPS: AR7: Initialize GPIO earlier MIPS: Add platform device and Kconfig for Octeon USB EHCI / OHCI USB: Add EHCI and OHCH glue for OCTEON II SOCs. MIPS: Octeon: Add register definitions for EHCI / OHCI USB glue logic. MIPS: Octeon: Apply CN63XXP1 errata workarounds. ...
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig30
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-octeon.c207
-rw-r--r--drivers/usb/host/octeon2-common.c185
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-octeon.c214
7 files changed, 645 insertions, 2 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index bf2e7d234533..2391c396ca32 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -93,8 +93,9 @@ config USB_EHCI_TT_NEWSCHED
93 93
94config USB_EHCI_BIG_ENDIAN_MMIO 94config USB_EHCI_BIG_ENDIAN_MMIO
95 bool 95 bool
96 depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \ 96 depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
97 XPS_USB_HCD_XILINX || PPC_MPC512x) 97 ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
98 PPC_MPC512x || CPU_CAVIUM_OCTEON)
98 default y 99 default y
99 100
100config USB_EHCI_BIG_ENDIAN_DESC 101config USB_EHCI_BIG_ENDIAN_DESC
@@ -434,3 +435,28 @@ config USB_IMX21_HCD
434 To compile this driver as a module, choose M here: the 435 To compile this driver as a module, choose M here: the
435 module will be called "imx21-hcd". 436 module will be called "imx21-hcd".
436 437
438config USB_OCTEON_EHCI
439 bool "Octeon on-chip EHCI support"
440 depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON
441 default n
442 select USB_EHCI_BIG_ENDIAN_MMIO
443 help
444 Enable support for the Octeon II SOC's on-chip EHCI
445 controller. It is needed for high-speed (480Mbit/sec)
446 USB 2.0 device support. All CN6XXX based chips with USB are
447 supported.
448
449config USB_OCTEON_OHCI
450 bool "Octeon on-chip OHCI support"
451 depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON
452 default USB_OCTEON_EHCI
453 select USB_OHCI_BIG_ENDIAN_MMIO
454 select USB_OHCI_LITTLE_ENDIAN
455 help
456 Enable support for the Octeon II SOC's on-chip OHCI
457 controller. It is needed for low-speed USB 1.0 device
458 support. All CN6XXX based chips with USB are supported.
459
460config USB_OCTEON2_COMMON
461 bool
462 default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 91c5a1bd1026..624a362f2fee 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
34obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o 34obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
35obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o 35obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
36obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o 36obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
37obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 2adae8e39bba..502a7e6fef42 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1211,6 +1211,11 @@ MODULE_LICENSE ("GPL");
1211#define PLATFORM_DRIVER ehci_atmel_driver 1211#define PLATFORM_DRIVER ehci_atmel_driver
1212#endif 1212#endif
1213 1213
1214#ifdef CONFIG_USB_OCTEON_EHCI
1215#include "ehci-octeon.c"
1216#define PLATFORM_DRIVER ehci_octeon_driver
1217#endif
1218
1214#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1219#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
1215 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1220 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
1216 !defined(XILINX_OF_PLATFORM_DRIVER) 1221 !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
new file mode 100644
index 000000000000..a31a031178a8
--- /dev/null
+++ b/drivers/usb/host/ehci-octeon.c
@@ -0,0 +1,207 @@
1/*
2 * EHCI HCD glue for Cavium Octeon II SOCs.
3 *
4 * Loosely based on ehci-au1xxx.c
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 *
10 * Copyright (C) 2010 Cavium Networks
11 *
12 */
13
14#include <linux/platform_device.h>
15
16#include <asm/octeon/octeon.h>
17#include <asm/octeon/cvmx-uctlx-defs.h>
18
19#define OCTEON_EHCI_HCD_NAME "octeon-ehci"
20
21/* Common clock init code. */
22void octeon2_usb_clocks_start(void);
23void octeon2_usb_clocks_stop(void);
24
25static void ehci_octeon_start(void)
26{
27 union cvmx_uctlx_ehci_ctl ehci_ctl;
28
29 octeon2_usb_clocks_start();
30
31 ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
32 /* Use 64-bit addressing. */
33 ehci_ctl.s.ehci_64b_addr_en = 1;
34 ehci_ctl.s.l2c_addr_msb = 0;
35 ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
36 ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
37 cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64);
38}
39
40static void ehci_octeon_stop(void)
41{
42 octeon2_usb_clocks_stop();
43}
44
45static const struct hc_driver ehci_octeon_hc_driver = {
46 .description = hcd_name,
47 .product_desc = "Octeon EHCI",
48 .hcd_priv_size = sizeof(struct ehci_hcd),
49
50 /*
51 * generic hardware linkage
52 */
53 .irq = ehci_irq,
54 .flags = HCD_MEMORY | HCD_USB2,
55
56 /*
57 * basic lifecycle operations
58 */
59 .reset = ehci_init,
60 .start = ehci_run,
61 .stop = ehci_stop,
62 .shutdown = ehci_shutdown,
63
64 /*
65 * managing i/o requests and associated device resources
66 */
67 .urb_enqueue = ehci_urb_enqueue,
68 .urb_dequeue = ehci_urb_dequeue,
69 .endpoint_disable = ehci_endpoint_disable,
70 .endpoint_reset = ehci_endpoint_reset,
71
72 /*
73 * scheduling support
74 */
75 .get_frame_number = ehci_get_frame,
76
77 /*
78 * root hub support
79 */
80 .hub_status_data = ehci_hub_status_data,
81 .hub_control = ehci_hub_control,
82 .bus_suspend = ehci_bus_suspend,
83 .bus_resume = ehci_bus_resume,
84 .relinquish_port = ehci_relinquish_port,
85 .port_handed_over = ehci_port_handed_over,
86
87 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
88};
89
90static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64);
91
92static int ehci_octeon_drv_probe(struct platform_device *pdev)
93{
94 struct usb_hcd *hcd;
95 struct ehci_hcd *ehci;
96 struct resource *res_mem;
97 int irq;
98 int ret;
99
100 if (usb_disabled())
101 return -ENODEV;
102
103 irq = platform_get_irq(pdev, 0);
104 if (irq < 0) {
105 dev_err(&pdev->dev, "No irq assigned\n");
106 return -ENODEV;
107 }
108
109 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
110 if (res_mem == NULL) {
111 dev_err(&pdev->dev, "No register space assigned\n");
112 return -ENODEV;
113 }
114
115 /*
116 * We can DMA from anywhere. But the descriptors must be in
117 * the lower 4GB.
118 */
119 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
120 pdev->dev.dma_mask = &ehci_octeon_dma_mask;
121
122 hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon");
123 if (!hcd)
124 return -ENOMEM;
125
126 hcd->rsrc_start = res_mem->start;
127 hcd->rsrc_len = res_mem->end - res_mem->start + 1;
128
129 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
130 OCTEON_EHCI_HCD_NAME)) {
131 dev_err(&pdev->dev, "request_mem_region failed\n");
132 ret = -EBUSY;
133 goto err1;
134 }
135
136 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
137 if (!hcd->regs) {
138 dev_err(&pdev->dev, "ioremap failed\n");
139 ret = -ENOMEM;
140 goto err2;
141 }
142
143 ehci_octeon_start();
144
145 ehci = hcd_to_ehci(hcd);
146
147 /* Octeon EHCI matches CPU endianness. */
148#ifdef __BIG_ENDIAN
149 ehci->big_endian_mmio = 1;
150#endif
151
152 ehci->caps = hcd->regs;
153 ehci->regs = hcd->regs +
154 HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
155 /* cache this readonly data; minimize chip reads */
156 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
157
158 ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
159 if (ret) {
160 dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
161 goto err3;
162 }
163
164 platform_set_drvdata(pdev, hcd);
165
166 /* root ports should always stay powered */
167 ehci_port_power(ehci, 1);
168
169 return 0;
170err3:
171 ehci_octeon_stop();
172
173 iounmap(hcd->regs);
174err2:
175 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
176err1:
177 usb_put_hcd(hcd);
178 return ret;
179}
180
181static int ehci_octeon_drv_remove(struct platform_device *pdev)
182{
183 struct usb_hcd *hcd = platform_get_drvdata(pdev);
184
185 usb_remove_hcd(hcd);
186
187 ehci_octeon_stop();
188 iounmap(hcd->regs);
189 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
190 usb_put_hcd(hcd);
191
192 platform_set_drvdata(pdev, NULL);
193
194 return 0;
195}
196
197static struct platform_driver ehci_octeon_driver = {
198 .probe = ehci_octeon_drv_probe,
199 .remove = ehci_octeon_drv_remove,
200 .shutdown = usb_hcd_platform_shutdown,
201 .driver = {
202 .name = OCTEON_EHCI_HCD_NAME,
203 .owner = THIS_MODULE,
204 }
205};
206
207MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME);
diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c
new file mode 100644
index 000000000000..72d672cfcf39
--- /dev/null
+++ b/drivers/usb/host/octeon2-common.c
@@ -0,0 +1,185 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2010 Cavium Networks
7 */
8
9#include <linux/module.h>
10#include <linux/delay.h>
11
12#include <asm/atomic.h>
13
14#include <asm/octeon/octeon.h>
15#include <asm/octeon/cvmx-uctlx-defs.h>
16
17static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0);
18
19void octeon2_usb_clocks_start(void)
20{
21 u64 div;
22 union cvmx_uctlx_if_ena if_ena;
23 union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
24 union cvmx_uctlx_uphy_ctl_status uphy_ctl_status;
25 union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
26 int i;
27 unsigned long io_clk_64_to_ns;
28
29 if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1)
30 return;
31
32 io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
33
34 /*
35 * Step 1: Wait for voltages stable. That surely happened
36 * before starting the kernel.
37 *
38 * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1
39 */
40 if_ena.u64 = 0;
41 if_ena.s.en = 1;
42 cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
43
44 /* Step 3: Configure the reference clock, PHY, and HCLK */
45 clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
46 /* 3a */
47 clk_rst_ctl.s.p_por = 1;
48 clk_rst_ctl.s.hrst = 0;
49 clk_rst_ctl.s.p_prst = 0;
50 clk_rst_ctl.s.h_clkdiv_rst = 0;
51 clk_rst_ctl.s.o_clkdiv_rst = 0;
52 clk_rst_ctl.s.h_clkdiv_en = 0;
53 clk_rst_ctl.s.o_clkdiv_en = 0;
54 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
55
56 /* 3b */
57 /* 12MHz crystal. */
58 clk_rst_ctl.s.p_refclk_sel = 0;
59 clk_rst_ctl.s.p_refclk_div = 0;
60 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
61
62 /* 3c */
63 div = octeon_get_io_clock_rate() / 130000000ull;
64
65 switch (div) {
66 case 0:
67 div = 1;
68 break;
69 case 1:
70 case 2:
71 case 3:
72 case 4:
73 break;
74 case 5:
75 div = 4;
76 break;
77 case 6:
78 case 7:
79 div = 6;
80 break;
81 case 8:
82 case 9:
83 case 10:
84 case 11:
85 div = 8;
86 break;
87 default:
88 div = 12;
89 break;
90 }
91 clk_rst_ctl.s.h_div = div;
92 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
93 /* Read it back, */
94 clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
95 clk_rst_ctl.s.h_clkdiv_en = 1;
96 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
97 /* 3d */
98 clk_rst_ctl.s.h_clkdiv_rst = 1;
99 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
100
101 /* 3e: delay 64 io clocks */
102 ndelay(io_clk_64_to_ns);
103
104 /*
105 * Step 4: Program the power-on reset field in the UCTL
106 * clock-reset-control register.
107 */
108 clk_rst_ctl.s.p_por = 0;
109 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
110
111 /* Step 5: Wait 1 ms for the PHY clock to start. */
112 mdelay(1);
113
114 /*
115 * Step 6: Program the reset input from automatic test
116 * equipment field in the UPHY CSR
117 */
118 uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0));
119 uphy_ctl_status.s.ate_reset = 1;
120 cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
121
122 /* Step 7: Wait for at least 10ns. */
123 ndelay(10);
124
125 /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */
126 uphy_ctl_status.s.ate_reset = 0;
127 cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
128
129 /*
130 * Step 9: Wait for at least 20ns for UPHY to output PHY clock
131 * signals and OHCI_CLK48
132 */
133 ndelay(20);
134
135 /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */
136 /* 10a */
137 clk_rst_ctl.s.o_clkdiv_rst = 1;
138 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
139
140 /* 10b */
141 clk_rst_ctl.s.o_clkdiv_en = 1;
142 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
143
144 /* 10c */
145 ndelay(io_clk_64_to_ns);
146
147 /*
148 * Step 11: Program the PHY reset field:
149 * UCTL0_CLK_RST_CTL[P_PRST] = 1
150 */
151 clk_rst_ctl.s.p_prst = 1;
152 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
153
154 /* Step 12: Wait 1 uS. */
155 udelay(1);
156
157 /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */
158 clk_rst_ctl.s.hrst = 1;
159 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
160
161 /* Now we can set some other registers. */
162
163 for (i = 0; i <= 1; i++) {
164 port_ctl_status.u64 =
165 cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
166 /* Set txvreftune to 15 to obtain complient 'eye' diagram. */
167 port_ctl_status.s.txvreftune = 15;
168 cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
169 port_ctl_status.u64);
170 }
171}
172EXPORT_SYMBOL(octeon2_usb_clocks_start);
173
174void octeon2_usb_clocks_stop(void)
175{
176 union cvmx_uctlx_if_ena if_ena;
177
178 if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0)
179 return;
180
181 if_ena.u64 = 0;
182 if_ena.s.en = 0;
183 cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
184}
185EXPORT_SYMBOL(octeon2_usb_clocks_stop);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f3713f43f3fe..5179acb7aa2f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1106,6 +1106,11 @@ MODULE_LICENSE ("GPL");
1106#define PLATFORM_DRIVER ohci_hcd_jz4740_driver 1106#define PLATFORM_DRIVER ohci_hcd_jz4740_driver
1107#endif 1107#endif
1108 1108
1109#ifdef CONFIG_USB_OCTEON_OHCI
1110#include "ohci-octeon.c"
1111#define PLATFORM_DRIVER ohci_octeon_driver
1112#endif
1113
1109#if !defined(PCI_DRIVER) && \ 1114#if !defined(PCI_DRIVER) && \
1110 !defined(PLATFORM_DRIVER) && \ 1115 !defined(PLATFORM_DRIVER) && \
1111 !defined(OMAP1_PLATFORM_DRIVER) && \ 1116 !defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c
new file mode 100644
index 000000000000..e4ddfaf8870f
--- /dev/null
+++ b/drivers/usb/host/ohci-octeon.c
@@ -0,0 +1,214 @@
1/*
2 * EHCI HCD glue for Cavium Octeon II SOCs.
3 *
4 * Loosely based on ehci-au1xxx.c
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 *
10 * Copyright (C) 2010 Cavium Networks
11 *
12 */
13
14#include <linux/platform_device.h>
15
16#include <asm/octeon/octeon.h>
17#include <asm/octeon/cvmx-uctlx-defs.h>
18
19#define OCTEON_OHCI_HCD_NAME "octeon-ohci"
20
21/* Common clock init code. */
22void octeon2_usb_clocks_start(void);
23void octeon2_usb_clocks_stop(void);
24
25static void ohci_octeon_hw_start(void)
26{
27 union cvmx_uctlx_ohci_ctl ohci_ctl;
28
29 octeon2_usb_clocks_start();
30
31 ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
32 ohci_ctl.s.l2c_addr_msb = 0;
33 ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
34 ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
35 cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64);
36
37}
38
39static void ohci_octeon_hw_stop(void)
40{
41 /* Undo ohci_octeon_start() */
42 octeon2_usb_clocks_stop();
43}
44
45static int __devinit ohci_octeon_start(struct usb_hcd *hcd)
46{
47 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
48 int ret;
49
50 ret = ohci_init(ohci);
51
52 if (ret < 0)
53 return ret;
54
55 ret = ohci_run(ohci);
56
57 if (ret < 0) {
58 ohci_err(ohci, "can't start %s", hcd->self.bus_name);
59 ohci_stop(hcd);
60 return ret;
61 }
62
63 return 0;
64}
65
66static const struct hc_driver ohci_octeon_hc_driver = {
67 .description = hcd_name,
68 .product_desc = "Octeon OHCI",
69 .hcd_priv_size = sizeof(struct ohci_hcd),
70
71 /*
72 * generic hardware linkage
73 */
74 .irq = ohci_irq,
75 .flags = HCD_USB11 | HCD_MEMORY,
76
77 /*
78 * basic lifecycle operations
79 */
80 .start = ohci_octeon_start,
81 .stop = ohci_stop,
82 .shutdown = ohci_shutdown,
83
84 /*
85 * managing i/o requests and associated device resources
86 */
87 .urb_enqueue = ohci_urb_enqueue,
88 .urb_dequeue = ohci_urb_dequeue,
89 .endpoint_disable = ohci_endpoint_disable,
90
91 /*
92 * scheduling support
93 */
94 .get_frame_number = ohci_get_frame,
95
96 /*
97 * root hub support
98 */
99 .hub_status_data = ohci_hub_status_data,
100 .hub_control = ohci_hub_control,
101
102 .start_port_reset = ohci_start_port_reset,
103};
104
105static int ohci_octeon_drv_probe(struct platform_device *pdev)
106{
107 struct usb_hcd *hcd;
108 struct ohci_hcd *ohci;
109 void *reg_base;
110 struct resource *res_mem;
111 int irq;
112 int ret;
113
114 if (usb_disabled())
115 return -ENODEV;
116
117 irq = platform_get_irq(pdev, 0);
118 if (irq < 0) {
119 dev_err(&pdev->dev, "No irq assigned\n");
120 return -ENODEV;
121 }
122
123 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
124 if (res_mem == NULL) {
125 dev_err(&pdev->dev, "No register space assigned\n");
126 return -ENODEV;
127 }
128
129 /* Ohci is a 32-bit device. */
130 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
131 pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
132
133 hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon");
134 if (!hcd)
135 return -ENOMEM;
136
137 hcd->rsrc_start = res_mem->start;
138 hcd->rsrc_len = res_mem->end - res_mem->start + 1;
139
140 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
141 OCTEON_OHCI_HCD_NAME)) {
142 dev_err(&pdev->dev, "request_mem_region failed\n");
143 ret = -EBUSY;
144 goto err1;
145 }
146
147 reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len);
148 if (!reg_base) {
149 dev_err(&pdev->dev, "ioremap failed\n");
150 ret = -ENOMEM;
151 goto err2;
152 }
153
154 ohci_octeon_hw_start();
155
156 hcd->regs = reg_base;
157
158 ohci = hcd_to_ohci(hcd);
159
160 /* Octeon OHCI matches CPU endianness. */
161#ifdef __BIG_ENDIAN
162 ohci->flags |= OHCI_QUIRK_BE_MMIO;
163#endif
164
165 ohci_hcd_init(ohci);
166
167 ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
168 if (ret) {
169 dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
170 goto err3;
171 }
172
173 platform_set_drvdata(pdev, hcd);
174
175 return 0;
176
177err3:
178 ohci_octeon_hw_stop();
179
180 iounmap(hcd->regs);
181err2:
182 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
183err1:
184 usb_put_hcd(hcd);
185 return ret;
186}
187
188static int ohci_octeon_drv_remove(struct platform_device *pdev)
189{
190 struct usb_hcd *hcd = platform_get_drvdata(pdev);
191
192 usb_remove_hcd(hcd);
193
194 ohci_octeon_hw_stop();
195 iounmap(hcd->regs);
196 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
197 usb_put_hcd(hcd);
198
199 platform_set_drvdata(pdev, NULL);
200
201 return 0;
202}
203
204static struct platform_driver ohci_octeon_driver = {
205 .probe = ohci_octeon_drv_probe,
206 .remove = ohci_octeon_drv_remove,
207 .shutdown = usb_hcd_platform_shutdown,
208 .driver = {
209 .name = OCTEON_OHCI_HCD_NAME,
210 .owner = THIS_MODULE,
211 }
212};
213
214MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME);