diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2009-10-12 08:08:46 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-27 16:48:03 -0400 |
commit | 451de97adb4d0f101f3befc881a548adb47c467a (patch) | |
tree | 6d40eb04db29f66983a6dd98e8bfff7eb654935b /drivers/net/wireless/wl12xx/wl1271_spi.c | |
parent | 37079a831d8194e138c03663b7cab281ab1dc181 (diff) |
wl1271: Update memory mapping for firmware revision 6.1.0.0.241
Update the memory regions and memory mapping to support firmware revision
6.1.0.0.241.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_spi.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_spi.c | 178 |
1 files changed, 64 insertions, 114 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 504991acb052..367f2d3319ac 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -30,17 +30,29 @@ | |||
30 | #include "wl12xx_80211.h" | 30 | #include "wl12xx_80211.h" |
31 | #include "wl1271_spi.h" | 31 | #include "wl1271_spi.h" |
32 | 32 | ||
33 | static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) | 33 | static int wl1271_translate_addr(struct wl1271 *wl, int addr) |
34 | { | 34 | { |
35 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | 35 | /* |
36 | } | 36 | * To translate, first check to which window of addresses the |
37 | 37 | * particular address belongs. Then subtract the starting address | |
38 | static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) | 38 | * of that window from the address. Then, add offset of the |
39 | { | 39 | * translated region. |
40 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | 40 | * |
41 | * The translated regions occur next to each other in physical device | ||
42 | * memory, so just add the sizes of the preceeding address regions to | ||
43 | * get the offset to the new region. | ||
44 | * | ||
45 | * Currently, only the two first regions are addressed, and the | ||
46 | * assumption is that all addresses will fall into either of those | ||
47 | * two. | ||
48 | */ | ||
49 | if ((addr >= wl->part.reg.start) && | ||
50 | (addr < wl->part.reg.start + wl->part.reg.size)) | ||
51 | return addr - wl->part.reg.start + wl->part.mem.size; | ||
52 | else | ||
53 | return addr - wl->part.mem.start; | ||
41 | } | 54 | } |
42 | 55 | ||
43 | |||
44 | void wl1271_spi_reset(struct wl1271 *wl) | 56 | void wl1271_spi_reset(struct wl1271 *wl) |
45 | { | 57 | { |
46 | u8 *cmd; | 58 | u8 *cmd; |
@@ -123,123 +135,61 @@ void wl1271_spi_init(struct wl1271 *wl) | |||
123 | 135 | ||
124 | /* Set the SPI partitions to access the chip addresses | 136 | /* Set the SPI partitions to access the chip addresses |
125 | * | 137 | * |
126 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | 138 | * To simplify driver code, a fixed (virtual) memory map is defined for |
127 | * registers partition), which are mapped to two different areas of the | 139 | * register and memory addresses. Because in the chipset, in different stages |
128 | * PHYSICAL (hardware) memory. This function also makes other checks to | 140 | * of operation, those addresses will move around, an address translation |
129 | * ensure that the partitions are not overlapping. In the diagram below, the | 141 | * mechanism is required. |
130 | * memory partition comes before the register partition, but the opposite is | ||
131 | * also supported. | ||
132 | * | 142 | * |
133 | * PHYSICAL address | 143 | * There are four partitions (three memory and one register partition), |
144 | * which are mapped to two different areas of the hardware memory. | ||
145 | * | ||
146 | * Virtual address | ||
134 | * space | 147 | * space |
135 | * | 148 | * |
136 | * | | | 149 | * | | |
137 | * ...+----+--> mem_start | 150 | * ...+----+--> mem.start |
138 | * VIRTUAL address ... | | | 151 | * Physical address ... | | |
139 | * space ... | | [PART_0] | 152 | * space ... | | [PART_0] |
140 | * ... | | | 153 | * ... | | |
141 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | 154 | * 00000000 <--+----+... ...+----+--> mem.start + mem.size |
142 | * | | ... | | | 155 | * | | ... | | |
143 | * |MEM | ... | | | 156 | * |MEM | ... | | |
144 | * | | ... | | | 157 | * | | ... | | |
145 | * part_size <--+----+... | | {unused area) | 158 | * mem.size <--+----+... | | {unused area) |
146 | * | | ... | | | 159 | * | | ... | | |
147 | * |REG | ... | | | 160 | * |REG | ... | | |
148 | * part_size | | ... | | | 161 | * mem.size | | ... | | |
149 | * + <--+----+... ...+----+--> reg_start | 162 | * + <--+----+... ...+----+--> reg.start |
150 | * reg_size ... | | | 163 | * reg.size | | ... | | |
151 | * ... | | [PART_1] | 164 | * |MEM2| ... | | [PART_1] |
152 | * ... | | | 165 | * | | ... | | |
153 | * ...+----+--> reg_start + reg_size | 166 | * ...+----+--> reg.start + reg.size |
154 | * | | | 167 | * | | |
155 | * | 168 | * |
156 | */ | 169 | */ |
157 | int wl1271_set_partition(struct wl1271 *wl, | 170 | int wl1271_set_partition(struct wl1271 *wl, |
158 | u32 mem_start, u32 mem_size, | 171 | struct wl1271_partition_set *p) |
159 | u32 reg_start, u32 reg_size) | ||
160 | { | 172 | { |
161 | struct wl1271_partition *partition; | 173 | /* copy partition info */ |
162 | struct spi_transfer t; | 174 | memcpy(&wl->part, p, sizeof(*p)); |
163 | struct spi_message m; | ||
164 | size_t len, cmd_len; | ||
165 | u32 *cmd; | ||
166 | int addr; | ||
167 | |||
168 | cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); | ||
169 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
170 | if (!cmd) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | spi_message_init(&m); | ||
174 | memset(&t, 0, sizeof(t)); | ||
175 | |||
176 | partition = (struct wl1271_partition *) (cmd + 1); | ||
177 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
178 | len = 2 * sizeof(struct wl1271_partition); | ||
179 | |||
180 | *cmd |= WSPI_CMD_WRITE; | ||
181 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
182 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
183 | 175 | ||
184 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | 176 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", |
185 | mem_start, mem_size); | 177 | p->mem.start, p->mem.size); |
186 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | 178 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", |
187 | reg_start, reg_size); | 179 | p->reg.start, p->reg.size); |
188 | 180 | wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", | |
189 | /* Make sure that the two partitions together don't exceed the | 181 | p->mem2.start, p->mem2.size); |
190 | * address range */ | 182 | wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", |
191 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | 183 | p->mem3.start, p->mem3.size); |
192 | wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | 184 | |
193 | " address range. Truncating partition[0]."); | 185 | /* write partition info to the chipset */ |
194 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | 186 | wl1271_write32(wl, HW_PART0_START_ADDR, p->mem.start); |
195 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | 187 | wl1271_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); |
196 | mem_start, mem_size); | 188 | wl1271_write32(wl, HW_PART1_START_ADDR, p->reg.start); |
197 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | 189 | wl1271_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); |
198 | reg_start, reg_size); | 190 | wl1271_write32(wl, HW_PART2_START_ADDR, p->mem2.start); |
199 | } | 191 | wl1271_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); |
200 | 192 | wl1271_write32(wl, HW_PART3_START_ADDR, p->mem3.start); | |
201 | if ((mem_start < reg_start) && | ||
202 | ((mem_start + mem_size) > reg_start)) { | ||
203 | /* Guarantee that the memory partition doesn't overlap the | ||
204 | * registers partition */ | ||
205 | wl1271_debug(DEBUG_SPI, "End of partition[0] is " | ||
206 | "overlapping partition[1]. Adjusted."); | ||
207 | mem_size = reg_start - mem_start; | ||
208 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
209 | mem_start, mem_size); | ||
210 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
211 | reg_start, reg_size); | ||
212 | } else if ((reg_start < mem_start) && | ||
213 | ((reg_start + reg_size) > mem_start)) { | ||
214 | /* Guarantee that the register partition doesn't overlap the | ||
215 | * memory partition */ | ||
216 | wl1271_debug(DEBUG_SPI, "End of partition[1] is" | ||
217 | " overlapping partition[0]. Adjusted."); | ||
218 | reg_size = mem_start - reg_start; | ||
219 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } | ||
224 | |||
225 | partition[0].start = mem_start; | ||
226 | partition[0].size = mem_size; | ||
227 | partition[1].start = reg_start; | ||
228 | partition[1].size = reg_size; | ||
229 | |||
230 | wl->physical_mem_addr = mem_start; | ||
231 | wl->physical_reg_addr = reg_start; | ||
232 | |||
233 | wl->virtual_mem_addr = 0; | ||
234 | wl->virtual_reg_addr = mem_size; | ||
235 | |||
236 | t.tx_buf = cmd; | ||
237 | t.len = cmd_len; | ||
238 | spi_message_add_tail(&t, &m); | ||
239 | |||
240 | spi_sync(wl->spi, &m); | ||
241 | |||
242 | kfree(cmd); | ||
243 | 193 | ||
244 | return 0; | 194 | return 0; |
245 | } | 195 | } |
@@ -391,7 +341,7 @@ void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, | |||
391 | { | 341 | { |
392 | int physical; | 342 | int physical; |
393 | 343 | ||
394 | physical = wl1271_translate_mem_addr(wl, addr); | 344 | physical = wl1271_translate_addr(wl, addr); |
395 | 345 | ||
396 | wl1271_spi_read(wl, physical, buf, len, false); | 346 | wl1271_spi_read(wl, physical, buf, len, false); |
397 | } | 347 | } |
@@ -401,7 +351,7 @@ void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, | |||
401 | { | 351 | { |
402 | int physical; | 352 | int physical; |
403 | 353 | ||
404 | physical = wl1271_translate_mem_addr(wl, addr); | 354 | physical = wl1271_translate_addr(wl, addr); |
405 | 355 | ||
406 | wl1271_spi_write(wl, physical, buf, len, false); | 356 | wl1271_spi_write(wl, physical, buf, len, false); |
407 | } | 357 | } |
@@ -411,7 +361,7 @@ void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, | |||
411 | { | 361 | { |
412 | int physical; | 362 | int physical; |
413 | 363 | ||
414 | physical = wl1271_translate_reg_addr(wl, addr); | 364 | physical = wl1271_translate_addr(wl, addr); |
415 | 365 | ||
416 | wl1271_spi_read(wl, physical, buf, len, fixed); | 366 | wl1271_spi_read(wl, physical, buf, len, fixed); |
417 | } | 367 | } |
@@ -421,27 +371,27 @@ void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, | |||
421 | { | 371 | { |
422 | int physical; | 372 | int physical; |
423 | 373 | ||
424 | physical = wl1271_translate_reg_addr(wl, addr); | 374 | physical = wl1271_translate_addr(wl, addr); |
425 | 375 | ||
426 | wl1271_spi_write(wl, physical, buf, len, fixed); | 376 | wl1271_spi_write(wl, physical, buf, len, fixed); |
427 | } | 377 | } |
428 | 378 | ||
429 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr) | 379 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr) |
430 | { | 380 | { |
431 | return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); | 381 | return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); |
432 | } | 382 | } |
433 | 383 | ||
434 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) | 384 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) |
435 | { | 385 | { |
436 | wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); | 386 | wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); |
437 | } | 387 | } |
438 | 388 | ||
439 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr) | 389 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr) |
440 | { | 390 | { |
441 | return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); | 391 | return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); |
442 | } | 392 | } |
443 | 393 | ||
444 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) | 394 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) |
445 | { | 395 | { |
446 | wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); | 396 | wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); |
447 | } | 397 | } |