Commit | Line | Data |
---|---|---|
2f01a1f5 | 1 | /* |
80301cdc | 2 | * This file is part of wl1251 |
2f01a1f5 KV |
3 | * |
4 | * Copyright (C) 2008 Nokia Corporation | |
5 | * | |
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License | |
10 | * version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
20 | * 02110-1301 USA | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <linux/gpio.h> | |
25 | ||
26 | #include "reg.h" | |
ef2f8d45 KV |
27 | #include "wl1251_boot.h" |
28 | #include "wl1251_spi.h" | |
29 | #include "wl1251_event.h" | |
2f01a1f5 | 30 | |
80301cdc | 31 | static void wl1251_boot_enable_interrupts(struct wl1251 *wl) |
2f01a1f5 KV |
32 | { |
33 | enable_irq(wl->irq); | |
34 | } | |
35 | ||
80301cdc | 36 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) |
2f01a1f5 | 37 | { |
80301cdc KV |
38 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); |
39 | wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | |
2f01a1f5 KV |
40 | } |
41 | ||
80301cdc | 42 | int wl1251_boot_soft_reset(struct wl1251 *wl) |
2f01a1f5 KV |
43 | { |
44 | unsigned long timeout; | |
45 | u32 boot_data; | |
46 | ||
47 | /* perform soft reset */ | |
80301cdc | 48 | wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); |
2f01a1f5 KV |
49 | |
50 | /* SOFT_RESET is self clearing */ | |
51 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | |
52 | while (1) { | |
80301cdc KV |
53 | boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); |
54 | wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | |
2f01a1f5 KV |
55 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) |
56 | break; | |
57 | ||
58 | if (time_after(jiffies, timeout)) { | |
59 | /* 1.2 check pWhalBus->uSelfClearTime if the | |
60 | * timeout was reached */ | |
80301cdc | 61 | wl1251_error("soft reset timeout"); |
2f01a1f5 KV |
62 | return -1; |
63 | } | |
64 | ||
65 | udelay(SOFT_RESET_STALL_TIME); | |
66 | } | |
67 | ||
68 | /* disable Rx/Tx */ | |
80301cdc | 69 | wl1251_reg_write32(wl, ENABLE, 0x0); |
2f01a1f5 KV |
70 | |
71 | /* disable auto calibration on start*/ | |
80301cdc | 72 | wl1251_reg_write32(wl, SPARE_A2, 0xffff); |
2f01a1f5 KV |
73 | |
74 | return 0; | |
75 | } | |
76 | ||
80301cdc | 77 | int wl1251_boot_init_seq(struct wl1251 *wl) |
2f01a1f5 KV |
78 | { |
79 | u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; | |
80 | ||
81 | /* | |
82 | * col #1: INTEGER_DIVIDER | |
83 | * col #2: FRACTIONAL_DIVIDER | |
84 | * col #3: ATTN_BB | |
85 | * col #4: ALPHA_BB | |
86 | * col #5: STOP_TIME_BB | |
87 | * col #6: BB_PLL_LOOP_FILTER | |
88 | */ | |
89 | static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { | |
90 | ||
91 | { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ | |
92 | { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ | |
93 | { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ | |
94 | { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ | |
95 | { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ | |
96 | }; | |
97 | ||
98 | /* read NVS params */ | |
80301cdc KV |
99 | scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); |
100 | wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); | |
2f01a1f5 KV |
101 | |
102 | /* read ELP_CMD */ | |
80301cdc KV |
103 | elp_cmd = wl1251_reg_read32(wl, ELP_CMD); |
104 | wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); | |
2f01a1f5 KV |
105 | |
106 | /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ | |
107 | ref_freq = scr_pad6 & 0x000000FF; | |
80301cdc | 108 | wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); |
2f01a1f5 | 109 | |
80301cdc | 110 | wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); |
2f01a1f5 KV |
111 | |
112 | /* | |
113 | * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) | |
114 | */ | |
80301cdc | 115 | wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); |
2f01a1f5 KV |
116 | |
117 | /* | |
118 | * set the clock detect feature to work in the restart wu procedure | |
119 | * (ELP_CFG_MODE[14]) and Select the clock source type | |
120 | * (ELP_CFG_MODE[13:12]) | |
121 | */ | |
122 | tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; | |
80301cdc | 123 | wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); |
2f01a1f5 KV |
124 | |
125 | /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ | |
126 | elp_cmd |= 0x00000040; | |
80301cdc | 127 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd); |
2f01a1f5 KV |
128 | |
129 | /* PG 1.2: Set the BB PLL stable time to be 1000usec | |
130 | * (PLL_STABLE_TIME) */ | |
80301cdc | 131 | wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); |
2f01a1f5 KV |
132 | |
133 | /* PG 1.2: read clock request time */ | |
80301cdc | 134 | init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); |
2f01a1f5 KV |
135 | |
136 | /* | |
137 | * PG 1.2: set the clock request time to be ref_clk_settling_time - | |
138 | * 1ms = 4ms | |
139 | */ | |
140 | if (init_data > 0x21) | |
141 | tmp = init_data - 0x21; | |
142 | else | |
143 | tmp = 0; | |
80301cdc | 144 | wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); |
2f01a1f5 KV |
145 | |
146 | /* set BB PLL configurations in RF AFE */ | |
80301cdc | 147 | wl1251_reg_write32(wl, 0x003058cc, 0x4B5); |
2f01a1f5 KV |
148 | |
149 | /* set RF_AFE_REG_5 */ | |
80301cdc | 150 | wl1251_reg_write32(wl, 0x003058d4, 0x50); |
2f01a1f5 KV |
151 | |
152 | /* set RF_AFE_CTRL_REG_2 */ | |
80301cdc | 153 | wl1251_reg_write32(wl, 0x00305948, 0x11c001); |
2f01a1f5 KV |
154 | |
155 | /* | |
156 | * change RF PLL and BB PLL divider for VCO clock and adjust VCO | |
157 | * bais current(RF_AFE_REG_13) | |
158 | */ | |
80301cdc | 159 | wl1251_reg_write32(wl, 0x003058f4, 0x1e); |
2f01a1f5 KV |
160 | |
161 | /* set BB PLL configurations */ | |
162 | tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; | |
80301cdc | 163 | wl1251_reg_write32(wl, 0x00305840, tmp); |
2f01a1f5 KV |
164 | |
165 | /* set fractional divider according to Appendix C-BB PLL | |
166 | * Calculations | |
167 | */ | |
168 | tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; | |
80301cdc | 169 | wl1251_reg_write32(wl, 0x00305844, tmp); |
2f01a1f5 KV |
170 | |
171 | /* set the initial data for the sigma delta */ | |
80301cdc | 172 | wl1251_reg_write32(wl, 0x00305848, 0x3039); |
2f01a1f5 KV |
173 | |
174 | /* | |
175 | * set the accumulator attenuation value, calibration loop1 | |
176 | * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and | |
177 | * the VCO gain | |
178 | */ | |
179 | tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | | |
180 | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; | |
80301cdc | 181 | wl1251_reg_write32(wl, 0x00305854, tmp); |
2f01a1f5 KV |
182 | |
183 | /* | |
184 | * set the calibration stop time after holdoff time expires and set | |
185 | * settling time HOLD_OFF_TIME_BB | |
186 | */ | |
187 | tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; | |
80301cdc | 188 | wl1251_reg_write32(wl, 0x00305858, tmp); |
2f01a1f5 KV |
189 | |
190 | /* | |
191 | * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL | |
192 | * constant leakage current to linearize PFD to 0uA - | |
193 | * BB_ILOOPF[7:3] | |
194 | */ | |
195 | tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; | |
80301cdc | 196 | wl1251_reg_write32(wl, 0x003058f8, tmp); |
2f01a1f5 KV |
197 | |
198 | /* | |
199 | * set regulator output voltage for n divider to | |
200 | * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], | |
201 | * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB | |
202 | * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] | |
203 | */ | |
80301cdc | 204 | wl1251_reg_write32(wl, 0x003058f0, 0x29); |
2f01a1f5 KV |
205 | |
206 | /* enable restart wakeup sequence (ELP_CMD[0]) */ | |
80301cdc | 207 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); |
2f01a1f5 KV |
208 | |
209 | /* restart sequence completed */ | |
210 | udelay(2000); | |
211 | ||
212 | return 0; | |
213 | } | |
214 | ||
80301cdc | 215 | int wl1251_boot_run_firmware(struct wl1251 *wl) |
2f01a1f5 KV |
216 | { |
217 | int loop, ret; | |
218 | u32 chip_id, interrupt; | |
219 | ||
220 | wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | |
221 | ||
80301cdc | 222 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); |
2f01a1f5 | 223 | |
80301cdc | 224 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); |
2f01a1f5 KV |
225 | |
226 | if (chip_id != wl->chip.id) { | |
80301cdc | 227 | wl1251_error("chip id doesn't match after firmware boot"); |
2f01a1f5 KV |
228 | return -EIO; |
229 | } | |
230 | ||
231 | /* wait for init to complete */ | |
232 | loop = 0; | |
233 | while (loop++ < INIT_LOOP) { | |
234 | udelay(INIT_LOOP_DELAY); | |
80301cdc | 235 | interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
2f01a1f5 KV |
236 | |
237 | if (interrupt == 0xffffffff) { | |
80301cdc | 238 | wl1251_error("error reading hardware complete " |
2f01a1f5 KV |
239 | "init indication"); |
240 | return -EIO; | |
241 | } | |
242 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | |
243 | else if (interrupt & wl->chip.intr_init_complete) { | |
80301cdc | 244 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, |
2f01a1f5 KV |
245 | wl->chip.intr_init_complete); |
246 | break; | |
247 | } | |
248 | } | |
249 | ||
250 | if (loop >= INIT_LOOP) { | |
80301cdc | 251 | wl1251_error("timeout waiting for the hardware to " |
2f01a1f5 KV |
252 | "complete initialization"); |
253 | return -EIO; | |
254 | } | |
255 | ||
256 | /* get hardware config command mail box */ | |
80301cdc | 257 | wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); |
2f01a1f5 KV |
258 | |
259 | /* get hardware config event mail box */ | |
80301cdc | 260 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); |
2f01a1f5 KV |
261 | |
262 | /* set the working partition to its "running" mode offset */ | |
80301cdc | 263 | wl1251_set_partition(wl, |
2f01a1f5 KV |
264 | wl->chip.p_table[PART_WORK].mem.start, |
265 | wl->chip.p_table[PART_WORK].mem.size, | |
266 | wl->chip.p_table[PART_WORK].reg.start, | |
267 | wl->chip.p_table[PART_WORK].reg.size); | |
268 | ||
80301cdc | 269 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", |
2f01a1f5 KV |
270 | wl->cmd_box_addr, wl->event_box_addr); |
271 | ||
0d1c3839 LC |
272 | wl->chip.op_fw_version(wl); |
273 | ||
2f01a1f5 KV |
274 | /* |
275 | * in case of full asynchronous mode the firmware event must be | |
276 | * ready to receive event from the command mailbox | |
277 | */ | |
278 | ||
279 | /* enable gpio interrupts */ | |
80301cdc | 280 | wl1251_boot_enable_interrupts(wl); |
2f01a1f5 KV |
281 | |
282 | wl->chip.op_target_enable_interrupts(wl); | |
283 | ||
284 | /* unmask all mbox events */ | |
285 | wl->event_mask = 0xffffffff; | |
286 | ||
80301cdc | 287 | ret = wl1251_event_unmask(wl); |
2f01a1f5 | 288 | if (ret < 0) { |
80301cdc | 289 | wl1251_error("EVENT mask setting failed"); |
2f01a1f5 KV |
290 | return ret; |
291 | } | |
292 | ||
80301cdc | 293 | wl1251_event_mbox_config(wl); |
2f01a1f5 KV |
294 | |
295 | /* firmware startup completed */ | |
296 | return 0; | |
297 | } |