aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/octeon2-common.c
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-10-08 17:47:52 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-10-29 14:08:44 -0400
commit1643accdaad4625c2877f7ceefa39c1cb3e90117 (patch)
treee3dcc5b371c89591e1d90f80bd82727b8e0fd245 /drivers/usb/host/octeon2-common.c
parent4169b86324fbefdf137a0bd69154d0e874f2bec2 (diff)
USB: Add EHCI and OHCH glue for OCTEON II SOCs.
The OCTEON II SOC has USB EHCI and OHCI controllers connected directly to the internal I/O bus. This patch adds the necessary 'glue' logic to allow ehci-hcd and ohci-hcd drivers to work on OCTEON II. The OCTEON normally runs big-endian, and the ehci/ohci internal registers have host endianness, so we need to select USB_EHCI_BIG_ENDIAN_MMIO. The ehci and ohci blocks share a common clocking and PHY infrastructure. Initialization of the host controller and PHY clocks is common between the two and is factored out into the octeon2-common.c file. Setting of USB_ARCH_HAS_OHCI and USB_ARCH_HAS_EHCI is done in arch/mips/Kconfig in a following patch. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-usb@vger.kernel.org To: dbrownell@users.sourceforge.net Patchwork: http://patchwork.linux-mips.org/patch/1675/ Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/usb/host/octeon2-common.c')
-rw-r--r--drivers/usb/host/octeon2-common.c185
1 files changed, 185 insertions, 0 deletions
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);