diff options
Diffstat (limited to 'recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch')
-rw-r--r-- | recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch | 210 |
1 files changed, 0 insertions, 210 deletions
diff --git a/recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch b/recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch deleted file mode 100644 index 8d65b5f0..00000000 --- a/recipes-kernel/linux/linux-3.0/usb/0001-Fix-sprz319-erratum-2.1.patch +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | From cf5db5477d8d43f02f4511f3835ab4bec0dcc27c Mon Sep 17 00:00:00 2001 | ||
2 | From: Richard Watts <rrw@kynesim.co.uk> | ||
3 | Date: Mon, 20 Feb 2012 17:58:26 +0000 | ||
4 | Subject: [PATCH] Fix sprz319 erratum 2.1 | ||
5 | |||
6 | There is an erratum in DM3730 which results in the | ||
7 | EHCI USB PLL (DPLL5) not updating sufficiently frequently; this | ||
8 | leads to USB PHY clock drift and once the clock has drifted far | ||
9 | enough, the PHY's ULPI interface stops responding and USB | ||
10 | drops out. This is manifested on a Beagle xM by having the attached | ||
11 | SMSC9514 report 'Cannot enable port 2. Maybe the USB cable is bad?' | ||
12 | or similar. | ||
13 | |||
14 | The fix is to carefully adjust your DPLL5 settings so as to | ||
15 | keep the PHY clock as close as possible to 120MHz over the long | ||
16 | term; TI SPRZ319e gives a table of such settings and this patch | ||
17 | applies that table to systems with a 13MHz or a 26MHz clock, | ||
18 | thus fixing the issue (inasfar as it can be fixed) on Beagle xM | ||
19 | and Overo Firestorm. | ||
20 | |||
21 | Signed-off-by: Richard Watts <rrw@kynesim.co.uk> | ||
22 | --- | ||
23 | arch/arm/mach-omap2/clkt_clksel.c | 15 ++++++++ | ||
24 | arch/arm/mach-omap2/clock.h | 7 ++++ | ||
25 | arch/arm/mach-omap2/clock3xxx.c | 65 +++++++++++++++++++++++++++++---- | ||
26 | arch/arm/mach-omap2/clock3xxx.h | 1 + | ||
27 | arch/arm/mach-omap2/clock3xxx_data.c | 2 +- | ||
28 | arch/arm/mach-omap2/dpll3xxx.c | 2 +- | ||
29 | 6 files changed, 82 insertions(+), 10 deletions(-) | ||
30 | |||
31 | diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c | ||
32 | index e25364d..e378fe7 100644 | ||
33 | --- a/arch/arm/mach-omap2/clkt_clksel.c | ||
34 | +++ b/arch/arm/mach-omap2/clkt_clksel.c | ||
35 | @@ -460,6 +460,21 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | +int omap2_clksel_force_divisor(struct clk *clk, int new_div) | ||
40 | +{ | ||
41 | + u32 field_val; | ||
42 | + | ||
43 | + field_val = _divisor_to_clksel(clk, new_div); | ||
44 | + if (field_val == ~0) | ||
45 | + return -EINVAL; | ||
46 | + | ||
47 | + _write_clksel_reg(clk, field_val); | ||
48 | + | ||
49 | + clk->rate = clk->parent->rate / new_div; | ||
50 | + | ||
51 | + return 0; | ||
52 | +} | ||
53 | + | ||
54 | /* | ||
55 | * Clksel parent setting function - not passed in struct clk function | ||
56 | * pointer - instead, the OMAP clock code currently assumes that any | ||
57 | diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h | ||
58 | index 8bad1c6..ac3d367 100644 | ||
59 | --- a/arch/arm/mach-omap2/clock.h | ||
60 | +++ b/arch/arm/mach-omap2/clock.h | ||
61 | @@ -61,6 +61,12 @@ void omap3_dpll_allow_idle(struct clk *clk); | ||
62 | void omap3_dpll_deny_idle(struct clk *clk); | ||
63 | u32 omap3_dpll_autoidle_read(struct clk *clk); | ||
64 | int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate); | ||
65 | +#if CONFIG_ARCH_OMAP3 | ||
66 | +int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel); | ||
67 | +/* If you are using this function and not on OMAP3, you are | ||
68 | + * Doing It Wrong(tm), so there is no stub. | ||
69 | + */ | ||
70 | +#endif | ||
71 | int omap3_noncore_dpll_enable(struct clk *clk); | ||
72 | void omap3_noncore_dpll_disable(struct clk *clk); | ||
73 | int omap4_dpllmx_gatectrl_read(struct clk *clk); | ||
74 | @@ -84,6 +90,7 @@ unsigned long omap2_clksel_recalc(struct clk *clk); | ||
75 | long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); | ||
76 | int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); | ||
77 | int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); | ||
78 | +int omap2_clksel_force_divisor(struct clk *clk, int new_div); | ||
79 | |||
80 | /* clkt_iclk.c public functions */ | ||
81 | extern void omap2_clkt_iclk_allow_idle(struct clk *clk); | ||
82 | diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c | ||
83 | index 952c3e0..d5be086 100644 | ||
84 | --- a/arch/arm/mach-omap2/clock3xxx.c | ||
85 | +++ b/arch/arm/mach-omap2/clock3xxx.c | ||
86 | @@ -40,6 +40,60 @@ | ||
87 | /* needed by omap3_core_dpll_m2_set_rate() */ | ||
88 | struct clk *sdrc_ick_p, *arm_fck_p; | ||
89 | |||
90 | +struct dpll_settings { | ||
91 | + int rate, m, n, f; | ||
92 | +}; | ||
93 | + | ||
94 | + | ||
95 | +static int omap3_dpll5_apply_erratum21(struct clk *clk, struct clk *dpll5_m2) | ||
96 | +{ | ||
97 | + struct clk *sys_clk; | ||
98 | + int i, rv; | ||
99 | + static const struct dpll_settings precomputed[] = { | ||
100 | + /* From DM3730 errata (sprz319e), table 36 | ||
101 | + * +1 is because the values in the table are register values; | ||
102 | + * dpll_program() will subtract one from what we give it, | ||
103 | + * so ... | ||
104 | + */ | ||
105 | + { 13000000, 443+1, 5+1, 8 }, | ||
106 | + { 26000000, 443+1, 11+1, 8 } | ||
107 | + }; | ||
108 | + | ||
109 | + sys_clk = clk_get(NULL, "sys_ck"); | ||
110 | + | ||
111 | + for (i = 0 ; i < (sizeof(precomputed)/sizeof(struct dpll_settings)) ; | ||
112 | + ++i) { | ||
113 | + const struct dpll_settings *d = &precomputed[i]; | ||
114 | + if (sys_clk->rate == d->rate) { | ||
115 | + rv = omap3_noncore_dpll_program(clk, d->m , d->n, 0); | ||
116 | + if (rv) | ||
117 | + return 1; | ||
118 | + rv = omap2_clksel_force_divisor(dpll5_m2 , d->f); | ||
119 | + return 1; | ||
120 | + } | ||
121 | + } | ||
122 | + return 0; | ||
123 | +} | ||
124 | + | ||
125 | +int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate) | ||
126 | +{ | ||
127 | + struct clk *dpll5_m2; | ||
128 | + int rv; | ||
129 | + dpll5_m2 = clk_get(NULL, "dpll5_m2_ck"); | ||
130 | + | ||
131 | + if (cpu_is_omap3630() && rate == DPLL5_FREQ_FOR_USBHOST && | ||
132 | + omap3_dpll5_apply_erratum21(clk, dpll5_m2)) { | ||
133 | + return 1; | ||
134 | + } | ||
135 | + rv = omap3_noncore_dpll_set_rate(clk, rate); | ||
136 | + if (rv) | ||
137 | + goto out; | ||
138 | + rv = clk_set_rate(dpll5_m2, rate); | ||
139 | + | ||
140 | +out: | ||
141 | + return rv; | ||
142 | +} | ||
143 | + | ||
144 | int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) | ||
145 | { | ||
146 | /* | ||
147 | @@ -59,19 +113,14 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) | ||
148 | void __init omap3_clk_lock_dpll5(void) | ||
149 | { | ||
150 | struct clk *dpll5_clk; | ||
151 | - struct clk *dpll5_m2_clk; | ||
152 | |||
153 | dpll5_clk = clk_get(NULL, "dpll5_ck"); | ||
154 | clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); | ||
155 | - clk_enable(dpll5_clk); | ||
156 | |||
157 | - /* Program dpll5_m2_clk divider for no division */ | ||
158 | - dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); | ||
159 | - clk_enable(dpll5_m2_clk); | ||
160 | - clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); | ||
161 | + /* dpll5_m2_ck is now (grottily!) handled by dpll5_clk's set routine, | ||
162 | + * to cope with an erratum on DM3730 | ||
163 | + */ | ||
164 | |||
165 | - clk_disable(dpll5_m2_clk); | ||
166 | - clk_disable(dpll5_clk); | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h | ||
171 | index 8bbeeaf..0ede513 100644 | ||
172 | --- a/arch/arm/mach-omap2/clock3xxx.h | ||
173 | +++ b/arch/arm/mach-omap2/clock3xxx.h | ||
174 | @@ -10,6 +10,7 @@ | ||
175 | |||
176 | int omap3xxx_clk_init(void); | ||
177 | int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate); | ||
178 | +int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate); | ||
179 | int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate); | ||
180 | void omap3_clk_lock_dpll5(void); | ||
181 | |||
182 | diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c | ||
183 | index ffd55b1..dcd7bdc 100644 | ||
184 | --- a/arch/arm/mach-omap2/clock3xxx_data.c | ||
185 | +++ b/arch/arm/mach-omap2/clock3xxx_data.c | ||
186 | @@ -942,7 +942,7 @@ static struct clk dpll5_ck = { | ||
187 | .parent = &sys_ck, | ||
188 | .dpll_data = &dpll5_dd, | ||
189 | .round_rate = &omap2_dpll_round_rate, | ||
190 | - .set_rate = &omap3_noncore_dpll_set_rate, | ||
191 | + .set_rate = &omap3_dpll5_set_rate, | ||
192 | .clkdm_name = "dpll5_clkdm", | ||
193 | .recalc = &omap3_dpll_recalc, | ||
194 | }; | ||
195 | diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c | ||
196 | index f77022b..1909cd0 100644 | ||
197 | --- a/arch/arm/mach-omap2/dpll3xxx.c | ||
198 | +++ b/arch/arm/mach-omap2/dpll3xxx.c | ||
199 | @@ -291,7 +291,7 @@ static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n) | ||
200 | * Program the DPLL with the supplied M, N values, and wait for the DPLL to | ||
201 | * lock.. Returns -EINVAL upon error, or 0 upon success. | ||
202 | */ | ||
203 | -static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | ||
204 | +int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | ||
205 | { | ||
206 | struct dpll_data *dd = clk->dpll_data; | ||
207 | u8 dco, sd_div; | ||
208 | -- | ||
209 | 1.7.2.5 | ||
210 | |||