diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/cavium-octeon/octeon-platform.c | 274 | ||||
-rw-r--r-- | arch/mips/configs/cavium_octeon_defconfig | 3 |
2 files changed, 275 insertions, 2 deletions
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 6df0f4d8f197..b67ddf0f8bcd 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c | |||
@@ -7,22 +7,27 @@ | |||
7 | * Copyright (C) 2008 Wind River Systems | 7 | * Copyright (C) 2008 Wind River Systems |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/delay.h> | ||
10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
11 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
12 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
13 | #include <linux/usb.h> | 14 | #include <linux/usb.h> |
14 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/mutex.h> | ||
16 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
17 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
18 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
19 | #include <linux/of_fdt.h> | 21 | #include <linux/of_fdt.h> |
20 | #include <linux/libfdt.h> | 22 | #include <linux/libfdt.h> |
23 | #include <linux/usb/ehci_pdriver.h> | ||
24 | #include <linux/usb/ohci_pdriver.h> | ||
21 | 25 | ||
22 | #include <asm/octeon/octeon.h> | 26 | #include <asm/octeon/octeon.h> |
23 | #include <asm/octeon/cvmx-rnm-defs.h> | 27 | #include <asm/octeon/cvmx-rnm-defs.h> |
24 | #include <asm/octeon/cvmx-helper.h> | 28 | #include <asm/octeon/cvmx-helper.h> |
25 | #include <asm/octeon/cvmx-helper-board.h> | 29 | #include <asm/octeon/cvmx-helper-board.h> |
30 | #include <asm/octeon/cvmx-uctlx-defs.h> | ||
26 | 31 | ||
27 | /* Octeon Random Number Generator. */ | 32 | /* Octeon Random Number Generator. */ |
28 | static int __init octeon_rng_device_init(void) | 33 | static int __init octeon_rng_device_init(void) |
@@ -68,6 +73,229 @@ device_initcall(octeon_rng_device_init); | |||
68 | 73 | ||
69 | #ifdef CONFIG_USB | 74 | #ifdef CONFIG_USB |
70 | 75 | ||
76 | static DEFINE_MUTEX(octeon2_usb_clocks_mutex); | ||
77 | |||
78 | static int octeon2_usb_clock_start_cnt; | ||
79 | |||
80 | static void octeon2_usb_clocks_start(void) | ||
81 | { | ||
82 | u64 div; | ||
83 | union cvmx_uctlx_if_ena if_ena; | ||
84 | union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; | ||
85 | union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; | ||
86 | union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; | ||
87 | int i; | ||
88 | unsigned long io_clk_64_to_ns; | ||
89 | |||
90 | |||
91 | mutex_lock(&octeon2_usb_clocks_mutex); | ||
92 | |||
93 | octeon2_usb_clock_start_cnt++; | ||
94 | if (octeon2_usb_clock_start_cnt != 1) | ||
95 | goto exit; | ||
96 | |||
97 | io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); | ||
98 | |||
99 | /* | ||
100 | * Step 1: Wait for voltages stable. That surely happened | ||
101 | * before starting the kernel. | ||
102 | * | ||
103 | * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 | ||
104 | */ | ||
105 | if_ena.u64 = 0; | ||
106 | if_ena.s.en = 1; | ||
107 | cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); | ||
108 | |||
109 | /* Step 3: Configure the reference clock, PHY, and HCLK */ | ||
110 | clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); | ||
111 | |||
112 | /* | ||
113 | * If the UCTL looks like it has already been started, skip | ||
114 | * the initialization, otherwise bus errors are obtained. | ||
115 | */ | ||
116 | if (clk_rst_ctl.s.hrst) | ||
117 | goto end_clock; | ||
118 | /* 3a */ | ||
119 | clk_rst_ctl.s.p_por = 1; | ||
120 | clk_rst_ctl.s.hrst = 0; | ||
121 | clk_rst_ctl.s.p_prst = 0; | ||
122 | clk_rst_ctl.s.h_clkdiv_rst = 0; | ||
123 | clk_rst_ctl.s.o_clkdiv_rst = 0; | ||
124 | clk_rst_ctl.s.h_clkdiv_en = 0; | ||
125 | clk_rst_ctl.s.o_clkdiv_en = 0; | ||
126 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
127 | |||
128 | /* 3b */ | ||
129 | /* 12MHz crystal. */ | ||
130 | clk_rst_ctl.s.p_refclk_sel = 0; | ||
131 | clk_rst_ctl.s.p_refclk_div = 0; | ||
132 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
133 | |||
134 | /* 3c */ | ||
135 | div = octeon_get_io_clock_rate() / 130000000ull; | ||
136 | |||
137 | switch (div) { | ||
138 | case 0: | ||
139 | div = 1; | ||
140 | break; | ||
141 | case 1: | ||
142 | case 2: | ||
143 | case 3: | ||
144 | case 4: | ||
145 | break; | ||
146 | case 5: | ||
147 | div = 4; | ||
148 | break; | ||
149 | case 6: | ||
150 | case 7: | ||
151 | div = 6; | ||
152 | break; | ||
153 | case 8: | ||
154 | case 9: | ||
155 | case 10: | ||
156 | case 11: | ||
157 | div = 8; | ||
158 | break; | ||
159 | default: | ||
160 | div = 12; | ||
161 | break; | ||
162 | } | ||
163 | clk_rst_ctl.s.h_div = div; | ||
164 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
165 | /* Read it back, */ | ||
166 | clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); | ||
167 | clk_rst_ctl.s.h_clkdiv_en = 1; | ||
168 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
169 | /* 3d */ | ||
170 | clk_rst_ctl.s.h_clkdiv_rst = 1; | ||
171 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
172 | |||
173 | /* 3e: delay 64 io clocks */ | ||
174 | ndelay(io_clk_64_to_ns); | ||
175 | |||
176 | /* | ||
177 | * Step 4: Program the power-on reset field in the UCTL | ||
178 | * clock-reset-control register. | ||
179 | */ | ||
180 | clk_rst_ctl.s.p_por = 0; | ||
181 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
182 | |||
183 | /* Step 5: Wait 1 ms for the PHY clock to start. */ | ||
184 | mdelay(1); | ||
185 | |||
186 | /* | ||
187 | * Step 6: Program the reset input from automatic test | ||
188 | * equipment field in the UPHY CSR | ||
189 | */ | ||
190 | uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); | ||
191 | uphy_ctl_status.s.ate_reset = 1; | ||
192 | cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); | ||
193 | |||
194 | /* Step 7: Wait for at least 10ns. */ | ||
195 | ndelay(10); | ||
196 | |||
197 | /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ | ||
198 | uphy_ctl_status.s.ate_reset = 0; | ||
199 | cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); | ||
200 | |||
201 | /* | ||
202 | * Step 9: Wait for at least 20ns for UPHY to output PHY clock | ||
203 | * signals and OHCI_CLK48 | ||
204 | */ | ||
205 | ndelay(20); | ||
206 | |||
207 | /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ | ||
208 | /* 10a */ | ||
209 | clk_rst_ctl.s.o_clkdiv_rst = 1; | ||
210 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
211 | |||
212 | /* 10b */ | ||
213 | clk_rst_ctl.s.o_clkdiv_en = 1; | ||
214 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
215 | |||
216 | /* 10c */ | ||
217 | ndelay(io_clk_64_to_ns); | ||
218 | |||
219 | /* | ||
220 | * Step 11: Program the PHY reset field: | ||
221 | * UCTL0_CLK_RST_CTL[P_PRST] = 1 | ||
222 | */ | ||
223 | clk_rst_ctl.s.p_prst = 1; | ||
224 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
225 | |||
226 | /* Step 12: Wait 1 uS. */ | ||
227 | udelay(1); | ||
228 | |||
229 | /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ | ||
230 | clk_rst_ctl.s.hrst = 1; | ||
231 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | ||
232 | |||
233 | end_clock: | ||
234 | /* Now we can set some other registers. */ | ||
235 | |||
236 | for (i = 0; i <= 1; i++) { | ||
237 | port_ctl_status.u64 = | ||
238 | cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); | ||
239 | /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ | ||
240 | port_ctl_status.s.txvreftune = 15; | ||
241 | port_ctl_status.s.txrisetune = 1; | ||
242 | port_ctl_status.s.txpreemphasistune = 1; | ||
243 | cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), | ||
244 | port_ctl_status.u64); | ||
245 | } | ||
246 | |||
247 | /* Set uSOF cycle period to 60,000 bits. */ | ||
248 | cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); | ||
249 | exit: | ||
250 | mutex_unlock(&octeon2_usb_clocks_mutex); | ||
251 | } | ||
252 | |||
253 | static void octeon2_usb_clocks_stop(void) | ||
254 | { | ||
255 | mutex_lock(&octeon2_usb_clocks_mutex); | ||
256 | octeon2_usb_clock_start_cnt--; | ||
257 | mutex_unlock(&octeon2_usb_clocks_mutex); | ||
258 | } | ||
259 | |||
260 | static int octeon_ehci_power_on(struct platform_device *pdev) | ||
261 | { | ||
262 | octeon2_usb_clocks_start(); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static void octeon_ehci_power_off(struct platform_device *pdev) | ||
267 | { | ||
268 | octeon2_usb_clocks_stop(); | ||
269 | } | ||
270 | |||
271 | static struct usb_ehci_pdata octeon_ehci_pdata = { | ||
272 | /* Octeon EHCI matches CPU endianness. */ | ||
273 | #ifdef __BIG_ENDIAN | ||
274 | .big_endian_mmio = 1, | ||
275 | #endif | ||
276 | .power_on = octeon_ehci_power_on, | ||
277 | .power_off = octeon_ehci_power_off, | ||
278 | }; | ||
279 | |||
280 | static void __init octeon_ehci_hw_start(void) | ||
281 | { | ||
282 | union cvmx_uctlx_ehci_ctl ehci_ctl; | ||
283 | |||
284 | octeon2_usb_clocks_start(); | ||
285 | |||
286 | ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); | ||
287 | /* Use 64-bit addressing. */ | ||
288 | ehci_ctl.s.ehci_64b_addr_en = 1; | ||
289 | ehci_ctl.s.l2c_addr_msb = 0; | ||
290 | ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ | ||
291 | ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ | ||
292 | cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); | ||
293 | |||
294 | octeon2_usb_clocks_stop(); | ||
295 | } | ||
296 | |||
297 | static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64); | ||
298 | |||
71 | static int __init octeon_ehci_device_init(void) | 299 | static int __init octeon_ehci_device_init(void) |
72 | { | 300 | { |
73 | struct platform_device *pd; | 301 | struct platform_device *pd; |
@@ -88,7 +316,7 @@ static int __init octeon_ehci_device_init(void) | |||
88 | if (octeon_is_simulation() || usb_disabled()) | 316 | if (octeon_is_simulation() || usb_disabled()) |
89 | return 0; /* No USB in the simulator. */ | 317 | return 0; /* No USB in the simulator. */ |
90 | 318 | ||
91 | pd = platform_device_alloc("octeon-ehci", 0); | 319 | pd = platform_device_alloc("ehci-platform", 0); |
92 | if (!pd) { | 320 | if (!pd) { |
93 | ret = -ENOMEM; | 321 | ret = -ENOMEM; |
94 | goto out; | 322 | goto out; |
@@ -105,6 +333,10 @@ static int __init octeon_ehci_device_init(void) | |||
105 | if (ret) | 333 | if (ret) |
106 | goto fail; | 334 | goto fail; |
107 | 335 | ||
336 | pd->dev.dma_mask = &octeon_ehci_dma_mask; | ||
337 | pd->dev.platform_data = &octeon_ehci_pdata; | ||
338 | octeon_ehci_hw_start(); | ||
339 | |||
108 | ret = platform_device_add(pd); | 340 | ret = platform_device_add(pd); |
109 | if (ret) | 341 | if (ret) |
110 | goto fail; | 342 | goto fail; |
@@ -117,6 +349,41 @@ out: | |||
117 | } | 349 | } |
118 | device_initcall(octeon_ehci_device_init); | 350 | device_initcall(octeon_ehci_device_init); |
119 | 351 | ||
352 | static int octeon_ohci_power_on(struct platform_device *pdev) | ||
353 | { | ||
354 | octeon2_usb_clocks_start(); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static void octeon_ohci_power_off(struct platform_device *pdev) | ||
359 | { | ||
360 | octeon2_usb_clocks_stop(); | ||
361 | } | ||
362 | |||
363 | static struct usb_ohci_pdata octeon_ohci_pdata = { | ||
364 | /* Octeon OHCI matches CPU endianness. */ | ||
365 | #ifdef __BIG_ENDIAN | ||
366 | .big_endian_mmio = 1, | ||
367 | #endif | ||
368 | .power_on = octeon_ohci_power_on, | ||
369 | .power_off = octeon_ohci_power_off, | ||
370 | }; | ||
371 | |||
372 | static void __init octeon_ohci_hw_start(void) | ||
373 | { | ||
374 | union cvmx_uctlx_ohci_ctl ohci_ctl; | ||
375 | |||
376 | octeon2_usb_clocks_start(); | ||
377 | |||
378 | ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); | ||
379 | ohci_ctl.s.l2c_addr_msb = 0; | ||
380 | ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ | ||
381 | ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ | ||
382 | cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); | ||
383 | |||
384 | octeon2_usb_clocks_stop(); | ||
385 | } | ||
386 | |||
120 | static int __init octeon_ohci_device_init(void) | 387 | static int __init octeon_ohci_device_init(void) |
121 | { | 388 | { |
122 | struct platform_device *pd; | 389 | struct platform_device *pd; |
@@ -137,7 +404,7 @@ static int __init octeon_ohci_device_init(void) | |||
137 | if (octeon_is_simulation() || usb_disabled()) | 404 | if (octeon_is_simulation() || usb_disabled()) |
138 | return 0; /* No USB in the simulator. */ | 405 | return 0; /* No USB in the simulator. */ |
139 | 406 | ||
140 | pd = platform_device_alloc("octeon-ohci", 0); | 407 | pd = platform_device_alloc("ohci-platform", 0); |
141 | if (!pd) { | 408 | if (!pd) { |
142 | ret = -ENOMEM; | 409 | ret = -ENOMEM; |
143 | goto out; | 410 | goto out; |
@@ -154,6 +421,9 @@ static int __init octeon_ohci_device_init(void) | |||
154 | if (ret) | 421 | if (ret) |
155 | goto fail; | 422 | goto fail; |
156 | 423 | ||
424 | pd->dev.platform_data = &octeon_ohci_pdata; | ||
425 | octeon_ohci_hw_start(); | ||
426 | |||
157 | ret = platform_device_add(pd); | 427 | ret = platform_device_add(pd); |
158 | if (ret) | 428 | if (ret) |
159 | goto fail; | 429 | goto fail; |
diff --git a/arch/mips/configs/cavium_octeon_defconfig b/arch/mips/configs/cavium_octeon_defconfig index b2476a1c4aaa..e57058d4ec22 100644 --- a/arch/mips/configs/cavium_octeon_defconfig +++ b/arch/mips/configs/cavium_octeon_defconfig | |||
@@ -120,6 +120,9 @@ CONFIG_SPI_OCTEON=y | |||
120 | # CONFIG_HWMON is not set | 120 | # CONFIG_HWMON is not set |
121 | CONFIG_WATCHDOG=y | 121 | CONFIG_WATCHDOG=y |
122 | # CONFIG_USB_SUPPORT is not set | 122 | # CONFIG_USB_SUPPORT is not set |
123 | CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y | ||
124 | CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y | ||
125 | CONFIG_USB_OHCI_LITTLE_ENDIAN=y | ||
123 | CONFIG_RTC_CLASS=y | 126 | CONFIG_RTC_CLASS=y |
124 | CONFIG_RTC_DRV_DS1307=y | 127 | CONFIG_RTC_DRV_DS1307=y |
125 | CONFIG_STAGING=y | 128 | CONFIG_STAGING=y |