diff options
Diffstat (limited to 'drivers/usb/host/octeon2-common.c')
-rw-r--r-- | drivers/usb/host/octeon2-common.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c index 72d672cfcf39..d9df423f3d12 100644 --- a/drivers/usb/host/octeon2-common.c +++ b/drivers/usb/host/octeon2-common.c | |||
@@ -3,18 +3,19 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2010 Cavium Networks | 6 | * Copyright (C) 2010, 2011 Cavium Networks |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/mutex.h> | ||
10 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
11 | 12 | ||
12 | #include <asm/atomic.h> | ||
13 | |||
14 | #include <asm/octeon/octeon.h> | 13 | #include <asm/octeon/octeon.h> |
15 | #include <asm/octeon/cvmx-uctlx-defs.h> | 14 | #include <asm/octeon/cvmx-uctlx-defs.h> |
16 | 15 | ||
17 | static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0); | 16 | static DEFINE_MUTEX(octeon2_usb_clocks_mutex); |
17 | |||
18 | static int octeon2_usb_clock_start_cnt; | ||
18 | 19 | ||
19 | void octeon2_usb_clocks_start(void) | 20 | void octeon2_usb_clocks_start(void) |
20 | { | 21 | { |
@@ -26,8 +27,12 @@ void octeon2_usb_clocks_start(void) | |||
26 | int i; | 27 | int i; |
27 | unsigned long io_clk_64_to_ns; | 28 | unsigned long io_clk_64_to_ns; |
28 | 29 | ||
29 | if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1) | 30 | |
30 | return; | 31 | mutex_lock(&octeon2_usb_clocks_mutex); |
32 | |||
33 | octeon2_usb_clock_start_cnt++; | ||
34 | if (octeon2_usb_clock_start_cnt != 1) | ||
35 | goto exit; | ||
31 | 36 | ||
32 | io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); | 37 | io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); |
33 | 38 | ||
@@ -43,6 +48,13 @@ void octeon2_usb_clocks_start(void) | |||
43 | 48 | ||
44 | /* Step 3: Configure the reference clock, PHY, and HCLK */ | 49 | /* Step 3: Configure the reference clock, PHY, and HCLK */ |
45 | clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); | 50 | clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); |
51 | |||
52 | /* | ||
53 | * If the UCTL looks like it has already been started, skip | ||
54 | * the initialization, otherwise bus errors are obtained. | ||
55 | */ | ||
56 | if (clk_rst_ctl.s.hrst) | ||
57 | goto end_clock; | ||
46 | /* 3a */ | 58 | /* 3a */ |
47 | clk_rst_ctl.s.p_por = 1; | 59 | clk_rst_ctl.s.p_por = 1; |
48 | clk_rst_ctl.s.hrst = 0; | 60 | clk_rst_ctl.s.hrst = 0; |
@@ -158,28 +170,31 @@ void octeon2_usb_clocks_start(void) | |||
158 | clk_rst_ctl.s.hrst = 1; | 170 | clk_rst_ctl.s.hrst = 1; |
159 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); | 171 | cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); |
160 | 172 | ||
173 | end_clock: | ||
161 | /* Now we can set some other registers. */ | 174 | /* Now we can set some other registers. */ |
162 | 175 | ||
163 | for (i = 0; i <= 1; i++) { | 176 | for (i = 0; i <= 1; i++) { |
164 | port_ctl_status.u64 = | 177 | port_ctl_status.u64 = |
165 | cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); | 178 | cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); |
166 | /* Set txvreftune to 15 to obtain complient 'eye' diagram. */ | 179 | /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ |
167 | port_ctl_status.s.txvreftune = 15; | 180 | port_ctl_status.s.txvreftune = 15; |
181 | port_ctl_status.s.txrisetune = 1; | ||
182 | port_ctl_status.s.txpreemphasistune = 1; | ||
168 | cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), | 183 | cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), |
169 | port_ctl_status.u64); | 184 | port_ctl_status.u64); |
170 | } | 185 | } |
186 | |||
187 | /* Set uSOF cycle period to 60,000 bits. */ | ||
188 | cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); | ||
189 | exit: | ||
190 | mutex_unlock(&octeon2_usb_clocks_mutex); | ||
171 | } | 191 | } |
172 | EXPORT_SYMBOL(octeon2_usb_clocks_start); | 192 | EXPORT_SYMBOL(octeon2_usb_clocks_start); |
173 | 193 | ||
174 | void octeon2_usb_clocks_stop(void) | 194 | void octeon2_usb_clocks_stop(void) |
175 | { | 195 | { |
176 | union cvmx_uctlx_if_ena if_ena; | 196 | mutex_lock(&octeon2_usb_clocks_mutex); |
177 | 197 | octeon2_usb_clock_start_cnt--; | |
178 | if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0) | 198 | mutex_unlock(&octeon2_usb_clocks_mutex); |
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 | } | 199 | } |
185 | EXPORT_SYMBOL(octeon2_usb_clocks_stop); | 200 | EXPORT_SYMBOL(octeon2_usb_clocks_stop); |