target/linux/brcm47xx/files-2.6.32/drivers/mtd/maps/bcm47xx-flash.c |
| 1 | /* |
| 2 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 3 | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
| 4 | * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
| 5 | * |
| 6 | * original functions for finding root filesystem from Mike Baker |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License as published by the |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| 16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 | * |
| 24 | * You should have received a copy of the GNU General Public License along |
| 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 27 | * |
| 28 | * Copyright 2001-2003, Broadcom Corporation |
| 29 | * All Rights Reserved. |
| 30 | * |
| 31 | * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
| 32 | * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
| 33 | * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
| 34 | * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
| 35 | * |
| 36 | * Flash mapping for BCM947XX boards |
| 37 | */ |
| 38 | |
| 39 | #include <linux/init.h> |
| 40 | #include <linux/module.h> |
| 41 | #include <linux/types.h> |
| 42 | #include <linux/kernel.h> |
| 43 | #include <linux/sched.h> |
| 44 | #include <linux/wait.h> |
| 45 | #include <linux/mtd/mtd.h> |
| 46 | #include <linux/mtd/map.h> |
| 47 | #ifdef CONFIG_MTD_PARTITIONS |
| 48 | #include <linux/mtd/partitions.h> |
| 49 | #endif |
| 50 | #include <linux/crc32.h> |
| 51 | #ifdef CONFIG_SSB |
| 52 | #include <linux/ssb/ssb.h> |
| 53 | #endif |
| 54 | #include <asm/io.h> |
| 55 | |
| 56 | |
| 57 | #define TRX_MAGIC 0x30524448 /* "HDR0" */ |
| 58 | #define TRX_VERSION 1 |
| 59 | #define TRX_MAX_LEN 0x3A0000 |
| 60 | #define TRX_NO_HEADER 1 /* Do not write TRX header */ |
| 61 | #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
| 62 | #define TRX_MAX_OFFSET 3 |
| 63 | |
| 64 | struct trx_header { |
| 65 | u32 magic; /* "HDR0" */ |
| 66 | u32 len; /* Length of file including header */ |
| 67 | u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
| 68 | u32 flag_version; /* 0:15 flags, 16:31 version */ |
| 69 | u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
| 70 | }; |
| 71 | |
| 72 | #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
| 73 | #define NVRAM_SPACE 0x8000 |
| 74 | #define WINDOW_ADDR 0x1fc00000 |
| 75 | #define WINDOW_SIZE 0x400000 |
| 76 | #define BUSWIDTH 2 |
| 77 | |
| 78 | #ifdef CONFIG_SSB |
| 79 | extern struct ssb_bus ssb_bcm47xx; |
| 80 | #endif |
| 81 | static struct mtd_info *bcm47xx_mtd; |
| 82 | |
| 83 | static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
| 84 | { |
| 85 | if (len==1) { |
| 86 | memcpy_fromio(to, map->virt + from, len); |
| 87 | } else { |
| 88 | int i; |
| 89 | u16 *dest = (u16 *) to; |
| 90 | u16 *src = (u16 *) (map->virt + from); |
| 91 | for (i = 0; i < (len / 2); i++) { |
| 92 | dest[i] = src[i]; |
| 93 | } |
| 94 | if (len & 1) |
| 95 | *((u8 *)dest+len-1) = src[i] & 0xff; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | static struct map_info bcm47xx_map = { |
| 100 | name: "Physically mapped flash", |
| 101 | size: WINDOW_SIZE, |
| 102 | bankwidth: BUSWIDTH, |
| 103 | phys: WINDOW_ADDR, |
| 104 | }; |
| 105 | |
| 106 | #ifdef CONFIG_MTD_PARTITIONS |
| 107 | |
| 108 | static struct mtd_partition bcm47xx_parts[] = { |
| 109 | { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
| 110 | { name: "linux", offset: 0, size: 0, }, |
| 111 | { name: "rootfs", offset: 0, size: 0, }, |
| 112 | { name: "nvram", offset: 0, size: 0, }, |
| 113 | { name: NULL, }, |
| 114 | }; |
| 115 | |
| 116 | static int __init |
| 117 | find_cfe_size(struct mtd_info *mtd, size_t size) |
| 118 | { |
| 119 | struct trx_header *trx; |
| 120 | unsigned char buf[512]; |
| 121 | int off; |
| 122 | size_t len; |
| 123 | int blocksize; |
| 124 | |
| 125 | trx = (struct trx_header *) buf; |
| 126 | |
| 127 | blocksize = mtd->erasesize; |
| 128 | if (blocksize < 0x10000) |
| 129 | blocksize = 0x10000; |
| 130 | |
| 131 | for (off = (128*1024); off < size; off += blocksize) { |
| 132 | memset(buf, 0xe5, sizeof(buf)); |
| 133 | |
| 134 | /* |
| 135 | * Read into buffer |
| 136 | */ |
| 137 | if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
| 138 | len != sizeof(buf)) |
| 139 | continue; |
| 140 | |
| 141 | /* found a TRX header */ |
| 142 | if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
| 143 | goto found; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | printk(KERN_NOTICE |
| 148 | "%s: Couldn't find bootloader size\n", |
| 149 | mtd->name); |
| 150 | return -1; |
| 151 | |
| 152 | found: |
| 153 | printk(KERN_NOTICE "bootloader size: %d\n", off); |
| 154 | return off; |
| 155 | |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Copied from mtdblock.c |
| 160 | * |
| 161 | * Cache stuff... |
| 162 | * |
| 163 | * Since typical flash erasable sectors are much larger than what Linux's |
| 164 | * buffer cache can handle, we must implement read-modify-write on flash |
| 165 | * sectors for each block write requests. To avoid over-erasing flash sectors |
| 166 | * and to speed things up, we locally cache a whole flash sector while it is |
| 167 | * being written to until a different sector is required. |
| 168 | */ |
| 169 | |
| 170 | static void erase_callback(struct erase_info *done) |
| 171 | { |
| 172 | wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
| 173 | wake_up(wait_q); |
| 174 | } |
| 175 | |
| 176 | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
| 177 | int len, const char *buf) |
| 178 | { |
| 179 | struct erase_info erase; |
| 180 | DECLARE_WAITQUEUE(wait, current); |
| 181 | wait_queue_head_t wait_q; |
| 182 | size_t retlen; |
| 183 | int ret; |
| 184 | |
| 185 | /* |
| 186 | * First, let's erase the flash block. |
| 187 | */ |
| 188 | |
| 189 | init_waitqueue_head(&wait_q); |
| 190 | erase.mtd = mtd; |
| 191 | erase.callback = erase_callback; |
| 192 | erase.addr = pos; |
| 193 | erase.len = len; |
| 194 | erase.priv = (u_long)&wait_q; |
| 195 | |
| 196 | set_current_state(TASK_INTERRUPTIBLE); |
| 197 | add_wait_queue(&wait_q, &wait); |
| 198 | |
| 199 | ret = mtd->erase(mtd, &erase); |
| 200 | if (ret) { |
| 201 | set_current_state(TASK_RUNNING); |
| 202 | remove_wait_queue(&wait_q, &wait); |
| 203 | printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
| 204 | "on \"%s\" failed\n", |
| 205 | pos, len, mtd->name); |
| 206 | return ret; |
| 207 | } |
| 208 | |
| 209 | schedule(); /* Wait for erase to finish. */ |
| 210 | remove_wait_queue(&wait_q, &wait); |
| 211 | |
| 212 | /* |
| 213 | * Next, writhe data to flash. |
| 214 | */ |
| 215 | |
| 216 | ret = mtd->write (mtd, pos, len, &retlen, buf); |
| 217 | if (ret) |
| 218 | return ret; |
| 219 | if (retlen != len) |
| 220 | return -EIO; |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | |
| 225 | static int __init |
| 226 | find_dual_image_off (struct mtd_info *mtd, size_t size) |
| 227 | { |
| 228 | struct trx_header trx; |
| 229 | int off, blocksize; |
| 230 | size_t len; |
| 231 | |
| 232 | blocksize = mtd->erasesize; |
| 233 | if (blocksize < 0x10000) |
| 234 | blocksize = 0x10000; |
| 235 | |
| 236 | for (off = (128*1024); off < size; off += blocksize) { |
| 237 | memset(&trx, 0xe5, sizeof(trx)); |
| 238 | /* |
| 239 | * Read into buffer |
| 240 | */ |
| 241 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 242 | len != sizeof(trx)) |
| 243 | continue; |
| 244 | /* found last TRX header */ |
| 245 | if (le32_to_cpu(trx.magic) == TRX_MAGIC){ |
| 246 | if (le32_to_cpu(trx.flag_version >> 16)==2){ |
| 247 | printk("dual image TRX header found\n"); |
| 248 | return size/2; |
| 249 | } else { |
| 250 | return 0; |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | return 0; |
| 255 | } |
| 256 | |
| 257 | |
| 258 | static int __init |
| 259 | find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
| 260 | { |
| 261 | struct trx_header trx, *trx2; |
| 262 | unsigned char buf[512], *block; |
| 263 | int off, blocksize; |
| 264 | u32 i, crc = ~0; |
| 265 | size_t len; |
| 266 | |
| 267 | blocksize = mtd->erasesize; |
| 268 | if (blocksize < 0x10000) |
| 269 | blocksize = 0x10000; |
| 270 | |
| 271 | for (off = (128*1024); off < size; off += blocksize) { |
| 272 | memset(&trx, 0xe5, sizeof(trx)); |
| 273 | |
| 274 | /* |
| 275 | * Read into buffer |
| 276 | */ |
| 277 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 278 | len != sizeof(trx)) |
| 279 | continue; |
| 280 | |
| 281 | /* found a TRX header */ |
| 282 | if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
| 283 | part->offset = le32_to_cpu(trx.offsets[2]) ? : |
| 284 | le32_to_cpu(trx.offsets[1]); |
| 285 | part->size = le32_to_cpu(trx.len); |
| 286 | |
| 287 | part->size -= part->offset; |
| 288 | part->offset += off; |
| 289 | |
| 290 | goto found; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | printk(KERN_NOTICE |
| 295 | "%s: Couldn't find root filesystem\n", |
| 296 | mtd->name); |
| 297 | return -1; |
| 298 | |
| 299 | found: |
| 300 | if (part->size == 0) |
| 301 | return 0; |
| 302 | |
| 303 | if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 304 | return 0; |
| 305 | |
| 306 | /* Move the fs outside of the trx */ |
| 307 | part->size = 0; |
| 308 | |
| 309 | if (trx.len != part->offset + part->size - off) { |
| 310 | /* Update the trx offsets and length */ |
| 311 | trx.len = part->offset + part->size - off; |
| 312 | |
| 313 | /* Update the trx crc32 */ |
| 314 | for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
| 315 | if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 316 | return 0; |
| 317 | crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
| 318 | } |
| 319 | trx.crc32 = crc; |
| 320 | |
| 321 | /* read first eraseblock from the trx */ |
| 322 | block = kmalloc(mtd->erasesize, GFP_KERNEL); |
| 323 | trx2 = (struct trx_header *) block; |
| 324 | if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
| 325 | printk("Error accessing the first trx eraseblock\n"); |
| 326 | return 0; |
| 327 | } |
| 328 | |
| 329 | printk("Updating TRX offsets and length:\n"); |
| 330 | printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
| 331 | printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
| 332 | |
| 333 | /* Write updated trx header to the flash */ |
| 334 | memcpy(block, &trx, sizeof(trx)); |
| 335 | if (mtd->unlock) |
| 336 | mtd->unlock(mtd, off, mtd->erasesize); |
| 337 | erase_write(mtd, off, mtd->erasesize, block); |
| 338 | if (mtd->sync) |
| 339 | mtd->sync(mtd); |
| 340 | kfree(block); |
| 341 | printk("Done\n"); |
| 342 | } |
| 343 | |
| 344 | return part->size; |
| 345 | } |
| 346 | |
| 347 | struct mtd_partition * __init |
| 348 | init_mtd_partitions(struct mtd_info *mtd, size_t size) |
| 349 | { |
| 350 | int cfe_size; |
| 351 | int dual_image_offset = 0; |
| 352 | |
| 353 | if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
| 354 | return NULL; |
| 355 | |
| 356 | /* boot loader */ |
| 357 | bcm47xx_parts[0].offset = 0; |
| 358 | bcm47xx_parts[0].size = cfe_size; |
| 359 | |
| 360 | /* nvram */ |
| 361 | if (cfe_size != 384 * 1024) { |
| 362 | bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 363 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 364 | } else { |
| 365 | /* nvram (old 128kb config partition on netgear wgt634u) */ |
| 366 | bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
| 367 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 368 | } |
| 369 | |
| 370 | /* dual image offset*/ |
| 371 | printk("Looking for dual image\n"); |
| 372 | dual_image_offset=find_dual_image_off(mtd,size); |
| 373 | /* linux (kernel and rootfs) */ |
| 374 | if (cfe_size != 384 * 1024) { |
| 375 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
| 376 | bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
| 377 | bcm47xx_parts[1].offset; |
| 378 | } else { |
| 379 | /* do not count the elf loader, which is on one block */ |
| 380 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size + |
| 381 | bcm47xx_parts[3].size + mtd->erasesize; |
| 382 | bcm47xx_parts[1].size = size - |
| 383 | bcm47xx_parts[0].size - |
| 384 | (2*bcm47xx_parts[3].size) - |
| 385 | mtd->erasesize; |
| 386 | } |
| 387 | |
| 388 | /* find and size rootfs */ |
| 389 | find_root(mtd,size,&bcm47xx_parts[2]); |
| 390 | bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
| 391 | |
| 392 | return bcm47xx_parts; |
| 393 | } |
| 394 | #endif |
| 395 | |
| 396 | int __init init_bcm47xx_map(void) |
| 397 | { |
| 398 | #ifdef CONFIG_SSB |
| 399 | struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
| 400 | #endif |
| 401 | size_t size; |
| 402 | int ret = 0; |
| 403 | #ifdef CONFIG_MTD_PARTITIONS |
| 404 | struct mtd_partition *parts; |
| 405 | int i; |
| 406 | #endif |
| 407 | |
| 408 | #ifdef CONFIG_SSB |
| 409 | u32 window = mcore->flash_window; |
| 410 | u32 window_size = mcore->flash_window_size; |
| 411 | |
| 412 | printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
| 413 | bcm47xx_map.phys = window; |
| 414 | bcm47xx_map.size = window_size; |
| 415 | bcm47xx_map.bankwidth = mcore->flash_buswidth; |
| 416 | bcm47xx_map.virt = ioremap_nocache(window, window_size); |
| 417 | #else |
| 418 | printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
| 419 | bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
| 420 | #endif |
| 421 | |
| 422 | if (!bcm47xx_map.virt) { |
| 423 | printk("Failed to ioremap\n"); |
| 424 | return -EIO; |
| 425 | } |
| 426 | |
| 427 | simple_map_init(&bcm47xx_map); |
| 428 | |
| 429 | if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
| 430 | printk("Failed to do_map_probe\n"); |
| 431 | iounmap((void *)bcm47xx_map.virt); |
| 432 | return -ENXIO; |
| 433 | } |
| 434 | |
| 435 | /* override copy_from routine */ |
| 436 | bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
| 437 | |
| 438 | bcm47xx_mtd->owner = THIS_MODULE; |
| 439 | |
| 440 | size = bcm47xx_mtd->size; |
| 441 | |
| 442 | printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
| 443 | |
| 444 | #ifdef CONFIG_MTD_PARTITIONS |
| 445 | parts = init_mtd_partitions(bcm47xx_mtd, size); |
| 446 | for (i = 0; parts[i].name; i++); |
| 447 | ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
| 448 | if (ret) { |
| 449 | printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
| 450 | goto fail; |
| 451 | } |
| 452 | #endif |
| 453 | return 0; |
| 454 | |
| 455 | fail: |
| 456 | if (bcm47xx_mtd) |
| 457 | map_destroy(bcm47xx_mtd); |
| 458 | if (bcm47xx_map.virt) |
| 459 | iounmap((void *)bcm47xx_map.virt); |
| 460 | bcm47xx_map.virt = 0; |
| 461 | return ret; |
| 462 | } |
| 463 | |
| 464 | void __exit cleanup_bcm47xx_map(void) |
| 465 | { |
| 466 | #ifdef CONFIG_MTD_PARTITIONS |
| 467 | del_mtd_partitions(bcm47xx_mtd); |
| 468 | #endif |
| 469 | map_destroy(bcm47xx_mtd); |
| 470 | iounmap((void *)bcm47xx_map.virt); |
| 471 | } |
| 472 | |
| 473 | module_init(init_bcm47xx_map); |
| 474 | module_exit(cleanup_bcm47xx_map); |
target/linux/brcm47xx/files-2.6.34/drivers/mtd/maps/bcm47xx-flash.c |
| 1 | /* |
| 2 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 3 | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
| 4 | * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
| 5 | * |
| 6 | * original functions for finding root filesystem from Mike Baker |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License as published by the |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| 16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 | * |
| 24 | * You should have received a copy of the GNU General Public License along |
| 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 27 | * |
| 28 | * Copyright 2001-2003, Broadcom Corporation |
| 29 | * All Rights Reserved. |
| 30 | * |
| 31 | * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
| 32 | * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
| 33 | * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
| 34 | * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
| 35 | * |
| 36 | * Flash mapping for BCM947XX boards |
| 37 | */ |
| 38 | |
| 39 | #include <linux/init.h> |
| 40 | #include <linux/module.h> |
| 41 | #include <linux/types.h> |
| 42 | #include <linux/kernel.h> |
| 43 | #include <linux/sched.h> |
| 44 | #include <linux/wait.h> |
| 45 | #include <linux/mtd/mtd.h> |
| 46 | #include <linux/mtd/map.h> |
| 47 | #ifdef CONFIG_MTD_PARTITIONS |
| 48 | #include <linux/mtd/partitions.h> |
| 49 | #endif |
| 50 | #include <linux/crc32.h> |
| 51 | #ifdef CONFIG_SSB |
| 52 | #include <linux/ssb/ssb.h> |
| 53 | #endif |
| 54 | #include <asm/io.h> |
| 55 | |
| 56 | |
| 57 | #define TRX_MAGIC 0x30524448 /* "HDR0" */ |
| 58 | #define TRX_VERSION 1 |
| 59 | #define TRX_MAX_LEN 0x3A0000 |
| 60 | #define TRX_NO_HEADER 1 /* Do not write TRX header */ |
| 61 | #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
| 62 | #define TRX_MAX_OFFSET 3 |
| 63 | |
| 64 | struct trx_header { |
| 65 | u32 magic; /* "HDR0" */ |
| 66 | u32 len; /* Length of file including header */ |
| 67 | u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
| 68 | u32 flag_version; /* 0:15 flags, 16:31 version */ |
| 69 | u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
| 70 | }; |
| 71 | |
| 72 | #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
| 73 | #define NVRAM_SPACE 0x8000 |
| 74 | #define WINDOW_ADDR 0x1fc00000 |
| 75 | #define WINDOW_SIZE 0x400000 |
| 76 | #define BUSWIDTH 2 |
| 77 | |
| 78 | #ifdef CONFIG_SSB |
| 79 | extern struct ssb_bus ssb_bcm47xx; |
| 80 | #endif |
| 81 | static struct mtd_info *bcm47xx_mtd; |
| 82 | |
| 83 | static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
| 84 | { |
| 85 | if (len==1) { |
| 86 | memcpy_fromio(to, map->virt + from, len); |
| 87 | } else { |
| 88 | int i; |
| 89 | u16 *dest = (u16 *) to; |
| 90 | u16 *src = (u16 *) (map->virt + from); |
| 91 | for (i = 0; i < (len / 2); i++) { |
| 92 | dest[i] = src[i]; |
| 93 | } |
| 94 | if (len & 1) |
| 95 | *((u8 *)dest+len-1) = src[i] & 0xff; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | static struct map_info bcm47xx_map = { |
| 100 | name: "Physically mapped flash", |
| 101 | size: WINDOW_SIZE, |
| 102 | bankwidth: BUSWIDTH, |
| 103 | phys: WINDOW_ADDR, |
| 104 | }; |
| 105 | |
| 106 | #ifdef CONFIG_MTD_PARTITIONS |
| 107 | |
| 108 | static struct mtd_partition bcm47xx_parts[] = { |
| 109 | { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
| 110 | { name: "linux", offset: 0, size: 0, }, |
| 111 | { name: "rootfs", offset: 0, size: 0, }, |
| 112 | { name: "nvram", offset: 0, size: 0, }, |
| 113 | { name: NULL, }, |
| 114 | }; |
| 115 | |
| 116 | static int __init |
| 117 | find_cfe_size(struct mtd_info *mtd, size_t size) |
| 118 | { |
| 119 | struct trx_header *trx; |
| 120 | unsigned char buf[512]; |
| 121 | int off; |
| 122 | size_t len; |
| 123 | int blocksize; |
| 124 | |
| 125 | trx = (struct trx_header *) buf; |
| 126 | |
| 127 | blocksize = mtd->erasesize; |
| 128 | if (blocksize < 0x10000) |
| 129 | blocksize = 0x10000; |
| 130 | |
| 131 | for (off = (128*1024); off < size; off += blocksize) { |
| 132 | memset(buf, 0xe5, sizeof(buf)); |
| 133 | |
| 134 | /* |
| 135 | * Read into buffer |
| 136 | */ |
| 137 | if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
| 138 | len != sizeof(buf)) |
| 139 | continue; |
| 140 | |
| 141 | /* found a TRX header */ |
| 142 | if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
| 143 | goto found; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | printk(KERN_NOTICE |
| 148 | "%s: Couldn't find bootloader size\n", |
| 149 | mtd->name); |
| 150 | return -1; |
| 151 | |
| 152 | found: |
| 153 | printk(KERN_NOTICE "bootloader size: %d\n", off); |
| 154 | return off; |
| 155 | |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Copied from mtdblock.c |
| 160 | * |
| 161 | * Cache stuff... |
| 162 | * |
| 163 | * Since typical flash erasable sectors are much larger than what Linux's |
| 164 | * buffer cache can handle, we must implement read-modify-write on flash |
| 165 | * sectors for each block write requests. To avoid over-erasing flash sectors |
| 166 | * and to speed things up, we locally cache a whole flash sector while it is |
| 167 | * being written to until a different sector is required. |
| 168 | */ |
| 169 | |
| 170 | static void erase_callback(struct erase_info *done) |
| 171 | { |
| 172 | wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
| 173 | wake_up(wait_q); |
| 174 | } |
| 175 | |
| 176 | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
| 177 | int len, const char *buf) |
| 178 | { |
| 179 | struct erase_info erase; |
| 180 | DECLARE_WAITQUEUE(wait, current); |
| 181 | wait_queue_head_t wait_q; |
| 182 | size_t retlen; |
| 183 | int ret; |
| 184 | |
| 185 | /* |
| 186 | * First, let's erase the flash block. |
| 187 | */ |
| 188 | |
| 189 | init_waitqueue_head(&wait_q); |
| 190 | erase.mtd = mtd; |
| 191 | erase.callback = erase_callback; |
| 192 | erase.addr = pos; |
| 193 | erase.len = len; |
| 194 | erase.priv = (u_long)&wait_q; |
| 195 | |
| 196 | set_current_state(TASK_INTERRUPTIBLE); |
| 197 | add_wait_queue(&wait_q, &wait); |
| 198 | |
| 199 | ret = mtd->erase(mtd, &erase); |
| 200 | if (ret) { |
| 201 | set_current_state(TASK_RUNNING); |
| 202 | remove_wait_queue(&wait_q, &wait); |
| 203 | printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
| 204 | "on \"%s\" failed\n", |
| 205 | pos, len, mtd->name); |
| 206 | return ret; |
| 207 | } |
| 208 | |
| 209 | schedule(); /* Wait for erase to finish. */ |
| 210 | remove_wait_queue(&wait_q, &wait); |
| 211 | |
| 212 | /* |
| 213 | * Next, writhe data to flash. |
| 214 | */ |
| 215 | |
| 216 | ret = mtd->write (mtd, pos, len, &retlen, buf); |
| 217 | if (ret) |
| 218 | return ret; |
| 219 | if (retlen != len) |
| 220 | return -EIO; |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | |
| 225 | static int __init |
| 226 | find_dual_image_off (struct mtd_info *mtd, size_t size) |
| 227 | { |
| 228 | struct trx_header trx; |
| 229 | int off, blocksize; |
| 230 | size_t len; |
| 231 | |
| 232 | blocksize = mtd->erasesize; |
| 233 | if (blocksize < 0x10000) |
| 234 | blocksize = 0x10000; |
| 235 | |
| 236 | for (off = (128*1024); off < size; off += blocksize) { |
| 237 | memset(&trx, 0xe5, sizeof(trx)); |
| 238 | /* |
| 239 | * Read into buffer |
| 240 | */ |
| 241 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 242 | len != sizeof(trx)) |
| 243 | continue; |
| 244 | /* found last TRX header */ |
| 245 | if (le32_to_cpu(trx.magic) == TRX_MAGIC){ |
| 246 | if (le32_to_cpu(trx.flag_version >> 16)==2){ |
| 247 | printk("dual image TRX header found\n"); |
| 248 | return size/2; |
| 249 | } else { |
| 250 | return 0; |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | return 0; |
| 255 | } |
| 256 | |
| 257 | |
| 258 | static int __init |
| 259 | find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
| 260 | { |
| 261 | struct trx_header trx, *trx2; |
| 262 | unsigned char buf[512], *block; |
| 263 | int off, blocksize; |
| 264 | u32 i, crc = ~0; |
| 265 | size_t len; |
| 266 | |
| 267 | blocksize = mtd->erasesize; |
| 268 | if (blocksize < 0x10000) |
| 269 | blocksize = 0x10000; |
| 270 | |
| 271 | for (off = (128*1024); off < size; off += blocksize) { |
| 272 | memset(&trx, 0xe5, sizeof(trx)); |
| 273 | |
| 274 | /* |
| 275 | * Read into buffer |
| 276 | */ |
| 277 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 278 | len != sizeof(trx)) |
| 279 | continue; |
| 280 | |
| 281 | /* found a TRX header */ |
| 282 | if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
| 283 | part->offset = le32_to_cpu(trx.offsets[2]) ? : |
| 284 | le32_to_cpu(trx.offsets[1]); |
| 285 | part->size = le32_to_cpu(trx.len); |
| 286 | |
| 287 | part->size -= part->offset; |
| 288 | part->offset += off; |
| 289 | |
| 290 | goto found; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | printk(KERN_NOTICE |
| 295 | "%s: Couldn't find root filesystem\n", |
| 296 | mtd->name); |
| 297 | return -1; |
| 298 | |
| 299 | found: |
| 300 | if (part->size == 0) |
| 301 | return 0; |
| 302 | |
| 303 | if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 304 | return 0; |
| 305 | |
| 306 | /* Move the fs outside of the trx */ |
| 307 | part->size = 0; |
| 308 | |
| 309 | if (trx.len != part->offset + part->size - off) { |
| 310 | /* Update the trx offsets and length */ |
| 311 | trx.len = part->offset + part->size - off; |
| 312 | |
| 313 | /* Update the trx crc32 */ |
| 314 | for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
| 315 | if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 316 | return 0; |
| 317 | crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
| 318 | } |
| 319 | trx.crc32 = crc; |
| 320 | |
| 321 | /* read first eraseblock from the trx */ |
| 322 | block = kmalloc(mtd->erasesize, GFP_KERNEL); |
| 323 | trx2 = (struct trx_header *) block; |
| 324 | if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
| 325 | printk("Error accessing the first trx eraseblock\n"); |
| 326 | return 0; |
| 327 | } |
| 328 | |
| 329 | printk("Updating TRX offsets and length:\n"); |
| 330 | printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
| 331 | printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
| 332 | |
| 333 | /* Write updated trx header to the flash */ |
| 334 | memcpy(block, &trx, sizeof(trx)); |
| 335 | if (mtd->unlock) |
| 336 | mtd->unlock(mtd, off, mtd->erasesize); |
| 337 | erase_write(mtd, off, mtd->erasesize, block); |
| 338 | if (mtd->sync) |
| 339 | mtd->sync(mtd); |
| 340 | kfree(block); |
| 341 | printk("Done\n"); |
| 342 | } |
| 343 | |
| 344 | return part->size; |
| 345 | } |
| 346 | |
| 347 | struct mtd_partition * __init |
| 348 | init_mtd_partitions(struct mtd_info *mtd, size_t size) |
| 349 | { |
| 350 | int cfe_size; |
| 351 | int dual_image_offset = 0; |
| 352 | |
| 353 | if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
| 354 | return NULL; |
| 355 | |
| 356 | /* boot loader */ |
| 357 | bcm47xx_parts[0].offset = 0; |
| 358 | bcm47xx_parts[0].size = cfe_size; |
| 359 | |
| 360 | /* nvram */ |
| 361 | if (cfe_size != 384 * 1024) { |
| 362 | bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 363 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 364 | } else { |
| 365 | /* nvram (old 128kb config partition on netgear wgt634u) */ |
| 366 | bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
| 367 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 368 | } |
| 369 | |
| 370 | /* dual image offset*/ |
| 371 | printk("Looking for dual image\n"); |
| 372 | dual_image_offset=find_dual_image_off(mtd,size); |
| 373 | /* linux (kernel and rootfs) */ |
| 374 | if (cfe_size != 384 * 1024) { |
| 375 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
| 376 | bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
| 377 | bcm47xx_parts[1].offset; |
| 378 | } else { |
| 379 | /* do not count the elf loader, which is on one block */ |
| 380 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size + |
| 381 | bcm47xx_parts[3].size + mtd->erasesize; |
| 382 | bcm47xx_parts[1].size = size - |
| 383 | bcm47xx_parts[0].size - |
| 384 | (2*bcm47xx_parts[3].size) - |
| 385 | mtd->erasesize; |
| 386 | } |
| 387 | |
| 388 | /* find and size rootfs */ |
| 389 | find_root(mtd,size,&bcm47xx_parts[2]); |
| 390 | bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
| 391 | |
| 392 | return bcm47xx_parts; |
| 393 | } |
| 394 | #endif |
| 395 | |
| 396 | int __init init_bcm47xx_map(void) |
| 397 | { |
| 398 | #ifdef CONFIG_SSB |
| 399 | struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
| 400 | #endif |
| 401 | size_t size; |
| 402 | int ret = 0; |
| 403 | #ifdef CONFIG_MTD_PARTITIONS |
| 404 | struct mtd_partition *parts; |
| 405 | int i; |
| 406 | #endif |
| 407 | |
| 408 | #ifdef CONFIG_SSB |
| 409 | u32 window = mcore->flash_window; |
| 410 | u32 window_size = mcore->flash_window_size; |
| 411 | |
| 412 | printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
| 413 | bcm47xx_map.phys = window; |
| 414 | bcm47xx_map.size = window_size; |
| 415 | bcm47xx_map.bankwidth = mcore->flash_buswidth; |
| 416 | bcm47xx_map.virt = ioremap_nocache(window, window_size); |
| 417 | #else |
| 418 | printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
| 419 | bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
| 420 | #endif |
| 421 | |
| 422 | if (!bcm47xx_map.virt) { |
| 423 | printk("Failed to ioremap\n"); |
| 424 | return -EIO; |
| 425 | } |
| 426 | |
| 427 | simple_map_init(&bcm47xx_map); |
| 428 | |
| 429 | if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
| 430 | printk("Failed to do_map_probe\n"); |
| 431 | iounmap((void *)bcm47xx_map.virt); |
| 432 | return -ENXIO; |
| 433 | } |
| 434 | |
| 435 | /* override copy_from routine */ |
| 436 | bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
| 437 | |
| 438 | bcm47xx_mtd->owner = THIS_MODULE; |
| 439 | |
| 440 | size = bcm47xx_mtd->size; |
| 441 | |
| 442 | printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
| 443 | |
| 444 | #ifdef CONFIG_MTD_PARTITIONS |
| 445 | parts = init_mtd_partitions(bcm47xx_mtd, size); |
| 446 | for (i = 0; parts[i].name; i++); |
| 447 | ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
| 448 | if (ret) { |
| 449 | printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
| 450 | goto fail; |
| 451 | } |
| 452 | #endif |
| 453 | return 0; |
| 454 | |
| 455 | fail: |
| 456 | if (bcm47xx_mtd) |
| 457 | map_destroy(bcm47xx_mtd); |
| 458 | if (bcm47xx_map.virt) |
| 459 | iounmap((void *)bcm47xx_map.virt); |
| 460 | bcm47xx_map.virt = 0; |
| 461 | return ret; |
| 462 | } |
| 463 | |
| 464 | void __exit cleanup_bcm47xx_map(void) |
| 465 | { |
| 466 | #ifdef CONFIG_MTD_PARTITIONS |
| 467 | del_mtd_partitions(bcm47xx_mtd); |
| 468 | #endif |
| 469 | map_destroy(bcm47xx_mtd); |
| 470 | iounmap((void *)bcm47xx_map.virt); |
| 471 | } |
| 472 | |
| 473 | module_init(init_bcm47xx_map); |
| 474 | module_exit(cleanup_bcm47xx_map); |
target/linux/brcm47xx/files-2.6.35/drivers/mtd/maps/bcm47xx-flash.c |
| 1 | /* |
| 2 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 3 | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
| 4 | * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
| 5 | * |
| 6 | * original functions for finding root filesystem from Mike Baker |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License as published by the |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| 16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 | * |
| 24 | * You should have received a copy of the GNU General Public License along |
| 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 27 | * |
| 28 | * Copyright 2001-2003, Broadcom Corporation |
| 29 | * All Rights Reserved. |
| 30 | * |
| 31 | * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
| 32 | * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
| 33 | * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
| 34 | * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
| 35 | * |
| 36 | * Flash mapping for BCM947XX boards |
| 37 | */ |
| 38 | |
| 39 | #include <linux/init.h> |
| 40 | #include <linux/module.h> |
| 41 | #include <linux/types.h> |
| 42 | #include <linux/kernel.h> |
| 43 | #include <linux/sched.h> |
| 44 | #include <linux/wait.h> |
| 45 | #include <linux/mtd/mtd.h> |
| 46 | #include <linux/mtd/map.h> |
| 47 | #ifdef CONFIG_MTD_PARTITIONS |
| 48 | #include <linux/mtd/partitions.h> |
| 49 | #endif |
| 50 | #include <linux/crc32.h> |
| 51 | #ifdef CONFIG_SSB |
| 52 | #include <linux/ssb/ssb.h> |
| 53 | #endif |
| 54 | #include <asm/io.h> |
| 55 | |
| 56 | |
| 57 | #define TRX_MAGIC 0x30524448 /* "HDR0" */ |
| 58 | #define TRX_VERSION 1 |
| 59 | #define TRX_MAX_LEN 0x3A0000 |
| 60 | #define TRX_NO_HEADER 1 /* Do not write TRX header */ |
| 61 | #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
| 62 | #define TRX_MAX_OFFSET 3 |
| 63 | |
| 64 | struct trx_header { |
| 65 | u32 magic; /* "HDR0" */ |
| 66 | u32 len; /* Length of file including header */ |
| 67 | u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
| 68 | u32 flag_version; /* 0:15 flags, 16:31 version */ |
| 69 | u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
| 70 | }; |
| 71 | |
| 72 | #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
| 73 | #define NVRAM_SPACE 0x8000 |
| 74 | #define WINDOW_ADDR 0x1fc00000 |
| 75 | #define WINDOW_SIZE 0x400000 |
| 76 | #define BUSWIDTH 2 |
| 77 | |
| 78 | #ifdef CONFIG_SSB |
| 79 | extern struct ssb_bus ssb_bcm47xx; |
| 80 | #endif |
| 81 | static struct mtd_info *bcm47xx_mtd; |
| 82 | |
| 83 | static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
| 84 | { |
| 85 | if (len==1) { |
| 86 | memcpy_fromio(to, map->virt + from, len); |
| 87 | } else { |
| 88 | int i; |
| 89 | u16 *dest = (u16 *) to; |
| 90 | u16 *src = (u16 *) (map->virt + from); |
| 91 | for (i = 0; i < (len / 2); i++) { |
| 92 | dest[i] = src[i]; |
| 93 | } |
| 94 | if (len & 1) |
| 95 | *((u8 *)dest+len-1) = src[i] & 0xff; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | static struct map_info bcm47xx_map = { |
| 100 | name: "Physically mapped flash", |
| 101 | size: WINDOW_SIZE, |
| 102 | bankwidth: BUSWIDTH, |
| 103 | phys: WINDOW_ADDR, |
| 104 | }; |
| 105 | |
| 106 | #ifdef CONFIG_MTD_PARTITIONS |
| 107 | |
| 108 | static struct mtd_partition bcm47xx_parts[] = { |
| 109 | { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
| 110 | { name: "linux", offset: 0, size: 0, }, |
| 111 | { name: "rootfs", offset: 0, size: 0, }, |
| 112 | { name: "nvram", offset: 0, size: 0, }, |
| 113 | { name: NULL, }, |
| 114 | }; |
| 115 | |
| 116 | static int __init |
| 117 | find_cfe_size(struct mtd_info *mtd, size_t size) |
| 118 | { |
| 119 | struct trx_header *trx; |
| 120 | unsigned char buf[512]; |
| 121 | int off; |
| 122 | size_t len; |
| 123 | int blocksize; |
| 124 | |
| 125 | trx = (struct trx_header *) buf; |
| 126 | |
| 127 | blocksize = mtd->erasesize; |
| 128 | if (blocksize < 0x10000) |
| 129 | blocksize = 0x10000; |
| 130 | |
| 131 | for (off = (128*1024); off < size; off += blocksize) { |
| 132 | memset(buf, 0xe5, sizeof(buf)); |
| 133 | |
| 134 | /* |
| 135 | * Read into buffer |
| 136 | */ |
| 137 | if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
| 138 | len != sizeof(buf)) |
| 139 | continue; |
| 140 | |
| 141 | /* found a TRX header */ |
| 142 | if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
| 143 | goto found; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | printk(KERN_NOTICE |
| 148 | "%s: Couldn't find bootloader size\n", |
| 149 | mtd->name); |
| 150 | return -1; |
| 151 | |
| 152 | found: |
| 153 | printk(KERN_NOTICE "bootloader size: %d\n", off); |
| 154 | return off; |
| 155 | |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Copied from mtdblock.c |
| 160 | * |
| 161 | * Cache stuff... |
| 162 | * |
| 163 | * Since typical flash erasable sectors are much larger than what Linux's |
| 164 | * buffer cache can handle, we must implement read-modify-write on flash |
| 165 | * sectors for each block write requests. To avoid over-erasing flash sectors |
| 166 | * and to speed things up, we locally cache a whole flash sector while it is |
| 167 | * being written to until a different sector is required. |
| 168 | */ |
| 169 | |
| 170 | static void erase_callback(struct erase_info *done) |
| 171 | { |
| 172 | wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
| 173 | wake_up(wait_q); |
| 174 | } |
| 175 | |
| 176 | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
| 177 | int len, const char *buf) |
| 178 | { |
| 179 | struct erase_info erase; |
| 180 | DECLARE_WAITQUEUE(wait, current); |
| 181 | wait_queue_head_t wait_q; |
| 182 | size_t retlen; |
| 183 | int ret; |
| 184 | |
| 185 | /* |
| 186 | * First, let's erase the flash block. |
| 187 | */ |
| 188 | |
| 189 | init_waitqueue_head(&wait_q); |
| 190 | erase.mtd = mtd; |
| 191 | erase.callback = erase_callback; |
| 192 | erase.addr = pos; |
| 193 | erase.len = len; |
| 194 | erase.priv = (u_long)&wait_q; |
| 195 | |
| 196 | set_current_state(TASK_INTERRUPTIBLE); |
| 197 | add_wait_queue(&wait_q, &wait); |
| 198 | |
| 199 | ret = mtd->erase(mtd, &erase); |
| 200 | if (ret) { |
| 201 | set_current_state(TASK_RUNNING); |
| 202 | remove_wait_queue(&wait_q, &wait); |
| 203 | printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
| 204 | "on \"%s\" failed\n", |
| 205 | pos, len, mtd->name); |
| 206 | return ret; |
| 207 | } |
| 208 | |
| 209 | schedule(); /* Wait for erase to finish. */ |
| 210 | remove_wait_queue(&wait_q, &wait); |
| 211 | |
| 212 | /* |
| 213 | * Next, writhe data to flash. |
| 214 | */ |
| 215 | |
| 216 | ret = mtd->write (mtd, pos, len, &retlen, buf); |
| 217 | if (ret) |
| 218 | return ret; |
| 219 | if (retlen != len) |
| 220 | return -EIO; |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | |
| 225 | static int __init |
| 226 | find_dual_image_off (struct mtd_info *mtd, size_t size) |
| 227 | { |
| 228 | struct trx_header trx; |
| 229 | int off, blocksize; |
| 230 | size_t len; |
| 231 | |
| 232 | blocksize = mtd->erasesize; |
| 233 | if (blocksize < 0x10000) |
| 234 | blocksize = 0x10000; |
| 235 | |
| 236 | for (off = (128*1024); off < size; off += blocksize) { |
| 237 | memset(&trx, 0xe5, sizeof(trx)); |
| 238 | /* |
| 239 | * Read into buffer |
| 240 | */ |
| 241 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 242 | len != sizeof(trx)) |
| 243 | continue; |
| 244 | /* found last TRX header */ |
| 245 | if (le32_to_cpu(trx.magic) == TRX_MAGIC){ |
| 246 | if (le32_to_cpu(trx.flag_version >> 16)==2){ |
| 247 | printk("dual image TRX header found\n"); |
| 248 | return size/2; |
| 249 | } else { |
| 250 | return 0; |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | return 0; |
| 255 | } |
| 256 | |
| 257 | |
| 258 | static int __init |
| 259 | find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
| 260 | { |
| 261 | struct trx_header trx, *trx2; |
| 262 | unsigned char buf[512], *block; |
| 263 | int off, blocksize; |
| 264 | u32 i, crc = ~0; |
| 265 | size_t len; |
| 266 | |
| 267 | blocksize = mtd->erasesize; |
| 268 | if (blocksize < 0x10000) |
| 269 | blocksize = 0x10000; |
| 270 | |
| 271 | for (off = (128*1024); off < size; off += blocksize) { |
| 272 | memset(&trx, 0xe5, sizeof(trx)); |
| 273 | |
| 274 | /* |
| 275 | * Read into buffer |
| 276 | */ |
| 277 | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
| 278 | len != sizeof(trx)) |
| 279 | continue; |
| 280 | |
| 281 | /* found a TRX header */ |
| 282 | if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
| 283 | part->offset = le32_to_cpu(trx.offsets[2]) ? : |
| 284 | le32_to_cpu(trx.offsets[1]); |
| 285 | part->size = le32_to_cpu(trx.len); |
| 286 | |
| 287 | part->size -= part->offset; |
| 288 | part->offset += off; |
| 289 | |
| 290 | goto found; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | printk(KERN_NOTICE |
| 295 | "%s: Couldn't find root filesystem\n", |
| 296 | mtd->name); |
| 297 | return -1; |
| 298 | |
| 299 | found: |
| 300 | if (part->size == 0) |
| 301 | return 0; |
| 302 | |
| 303 | if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 304 | return 0; |
| 305 | |
| 306 | /* Move the fs outside of the trx */ |
| 307 | part->size = 0; |
| 308 | |
| 309 | if (trx.len != part->offset + part->size - off) { |
| 310 | /* Update the trx offsets and length */ |
| 311 | trx.len = part->offset + part->size - off; |
| 312 | |
| 313 | /* Update the trx crc32 */ |
| 314 | for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
| 315 | if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
| 316 | return 0; |
| 317 | crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
| 318 | } |
| 319 | trx.crc32 = crc; |
| 320 | |
| 321 | /* read first eraseblock from the trx */ |
| 322 | block = kmalloc(mtd->erasesize, GFP_KERNEL); |
| 323 | trx2 = (struct trx_header *) block; |
| 324 | if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
| 325 | printk("Error accessing the first trx eraseblock\n"); |
| 326 | return 0; |
| 327 | } |
| 328 | |
| 329 | printk("Updating TRX offsets and length:\n"); |
| 330 | printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
| 331 | printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
| 332 | |
| 333 | /* Write updated trx header to the flash */ |
| 334 | memcpy(block, &trx, sizeof(trx)); |
| 335 | if (mtd->unlock) |
| 336 | mtd->unlock(mtd, off, mtd->erasesize); |
| 337 | erase_write(mtd, off, mtd->erasesize, block); |
| 338 | if (mtd->sync) |
| 339 | mtd->sync(mtd); |
| 340 | kfree(block); |
| 341 | printk("Done\n"); |
| 342 | } |
| 343 | |
| 344 | return part->size; |
| 345 | } |
| 346 | |
| 347 | struct mtd_partition * __init |
| 348 | init_mtd_partitions(struct mtd_info *mtd, size_t size) |
| 349 | { |
| 350 | int cfe_size; |
| 351 | int dual_image_offset = 0; |
| 352 | |
| 353 | if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
| 354 | return NULL; |
| 355 | |
| 356 | /* boot loader */ |
| 357 | bcm47xx_parts[0].offset = 0; |
| 358 | bcm47xx_parts[0].size = cfe_size; |
| 359 | |
| 360 | /* nvram */ |
| 361 | if (cfe_size != 384 * 1024) { |
| 362 | bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 363 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 364 | } else { |
| 365 | /* nvram (old 128kb config partition on netgear wgt634u) */ |
| 366 | bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
| 367 | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
| 368 | } |
| 369 | |
| 370 | /* dual image offset*/ |
| 371 | printk("Looking for dual image\n"); |
| 372 | dual_image_offset=find_dual_image_off(mtd,size); |
| 373 | /* linux (kernel and rootfs) */ |
| 374 | if (cfe_size != 384 * 1024) { |
| 375 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
| 376 | bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
| 377 | bcm47xx_parts[1].offset; |
| 378 | } else { |
| 379 | /* do not count the elf loader, which is on one block */ |
| 380 | bcm47xx_parts[1].offset = bcm47xx_parts[0].size + |
| 381 | bcm47xx_parts[3].size + mtd->erasesize; |
| 382 | bcm47xx_parts[1].size = size - |
| 383 | bcm47xx_parts[0].size - |
| 384 | (2*bcm47xx_parts[3].size) - |
| 385 | mtd->erasesize; |
| 386 | } |
| 387 | |
| 388 | /* find and size rootfs */ |
| 389 | find_root(mtd,size,&bcm47xx_parts[2]); |
| 390 | bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
| 391 | |
| 392 | return bcm47xx_parts; |
| 393 | } |
| 394 | #endif |
| 395 | |
| 396 | int __init init_bcm47xx_map(void) |
| 397 | { |
| 398 | #ifdef CONFIG_SSB |
| 399 | struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
| 400 | #endif |
| 401 | size_t size; |
| 402 | int ret = 0; |
| 403 | #ifdef CONFIG_MTD_PARTITIONS |
| 404 | struct mtd_partition *parts; |
| 405 | int i; |
| 406 | #endif |
| 407 | |
| 408 | #ifdef CONFIG_SSB |
| 409 | u32 window = mcore->flash_window; |
| 410 | u32 window_size = mcore->flash_window_size; |
| 411 | |
| 412 | printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
| 413 | bcm47xx_map.phys = window; |
| 414 | bcm47xx_map.size = window_size; |
| 415 | bcm47xx_map.bankwidth = mcore->flash_buswidth; |
| 416 | bcm47xx_map.virt = ioremap_nocache(window, window_size); |
| 417 | #else |
| 418 | printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
| 419 | bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
| 420 | #endif |
| 421 | |
| 422 | if (!bcm47xx_map.virt) { |
| 423 | printk("Failed to ioremap\n"); |
| 424 | return -EIO; |
| 425 | } |
| 426 | |
| 427 | simple_map_init(&bcm47xx_map); |
| 428 | |
| 429 | if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
| 430 | printk("Failed to do_map_probe\n"); |
| 431 | iounmap((void *)bcm47xx_map.virt); |
| 432 | return -ENXIO; |
| 433 | } |
| 434 | |
| 435 | /* override copy_from routine */ |
| 436 | bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
| 437 | |
| 438 | bcm47xx_mtd->owner = THIS_MODULE; |
| 439 | |
| 440 | size = bcm47xx_mtd->size; |
| 441 | |
| 442 | printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
| 443 | |
| 444 | #ifdef CONFIG_MTD_PARTITIONS |
| 445 | parts = init_mtd_partitions(bcm47xx_mtd, size); |
| 446 | for (i = 0; parts[i].name; i++); |
| 447 | ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
| 448 | if (ret) { |
| 449 | printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
| 450 | goto fail; |
| 451 | } |
| 452 | #endif |
| 453 | return 0; |
| 454 | |
| 455 | fail: |
| 456 | if (bcm47xx_mtd) |
| 457 | map_destroy(bcm47xx_mtd); |
| 458 | if (bcm47xx_map.virt) |
| 459 | iounmap((void *)bcm47xx_map.virt); |
| 460 | bcm47xx_map.virt = 0; |
| 461 | return ret; |
| 462 | } |
| 463 | |
| 464 | void __exit cleanup_bcm47xx_map(void) |
| 465 | { |
| 466 | #ifdef CONFIG_MTD_PARTITIONS |
| 467 | del_mtd_partitions(bcm47xx_mtd); |
| 468 | #endif |
| 469 | map_destroy(bcm47xx_mtd); |
| 470 | iounmap((void *)bcm47xx_map.virt); |
| 471 | } |
| 472 | |
| 473 | module_init(init_bcm47xx_map); |
| 474 | module_exit(cleanup_bcm47xx_map); |
target/linux/brcm47xx/files/drivers/mtd/maps/bcm47xx-flash.c |
1 | | /* |
2 | | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
3 | | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
4 | | * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
5 | | * |
6 | | * original functions for finding root filesystem from Mike Baker |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU General Public License as published by the |
10 | | * Free Software Foundation; either version 2 of the License, or (at your |
11 | | * option) any later version. |
12 | | * |
13 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
14 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
15 | | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
16 | | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
17 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
18 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
19 | | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
20 | | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
22 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | | * |
24 | | * You should have received a copy of the GNU General Public License along |
25 | | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | | * |
28 | | * Copyright 2001-2003, Broadcom Corporation |
29 | | * All Rights Reserved. |
30 | | * |
31 | | * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
32 | | * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
33 | | * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
34 | | * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
35 | | * |
36 | | * Flash mapping for BCM947XX boards |
37 | | */ |
38 | | |
39 | | #include <linux/init.h> |
40 | | #include <linux/module.h> |
41 | | #include <linux/types.h> |
42 | | #include <linux/kernel.h> |
43 | | #include <linux/sched.h> |
44 | | #include <linux/wait.h> |
45 | | #include <linux/mtd/mtd.h> |
46 | | #include <linux/mtd/map.h> |
47 | | #ifdef CONFIG_MTD_PARTITIONS |
48 | | #include <linux/mtd/partitions.h> |
49 | | #endif |
50 | | #include <linux/crc32.h> |
51 | | #ifdef CONFIG_SSB |
52 | | #include <linux/ssb/ssb.h> |
53 | | #endif |
54 | | #include <asm/io.h> |
55 | | |
56 | | |
57 | | #define TRX_MAGIC 0x30524448 /* "HDR0" */ |
58 | | #define TRX_VERSION 1 |
59 | | #define TRX_MAX_LEN 0x3A0000 |
60 | | #define TRX_NO_HEADER 1 /* Do not write TRX header */ |
61 | | #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
62 | | #define TRX_MAX_OFFSET 3 |
63 | | |
64 | | struct trx_header { |
65 | | u32 magic; /* "HDR0" */ |
66 | | u32 len; /* Length of file including header */ |
67 | | u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
68 | | u32 flag_version; /* 0:15 flags, 16:31 version */ |
69 | | u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
70 | | }; |
71 | | |
72 | | #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
73 | | #define NVRAM_SPACE 0x8000 |
74 | | #define WINDOW_ADDR 0x1fc00000 |
75 | | #define WINDOW_SIZE 0x400000 |
76 | | #define BUSWIDTH 2 |
77 | | |
78 | | #ifdef CONFIG_SSB |
79 | | extern struct ssb_bus ssb_bcm47xx; |
80 | | #endif |
81 | | static struct mtd_info *bcm47xx_mtd; |
82 | | |
83 | | static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
84 | | { |
85 | | if (len==1) { |
86 | | memcpy_fromio(to, map->virt + from, len); |
87 | | } else { |
88 | | int i; |
89 | | u16 *dest = (u16 *) to; |
90 | | u16 *src = (u16 *) (map->virt + from); |
91 | | for (i = 0; i < (len / 2); i++) { |
92 | | dest[i] = src[i]; |
93 | | } |
94 | | if (len & 1) |
95 | | *((u8 *)dest+len-1) = src[i] & 0xff; |
96 | | } |
97 | | } |
98 | | |
99 | | static struct map_info bcm47xx_map = { |
100 | | name: "Physically mapped flash", |
101 | | size: WINDOW_SIZE, |
102 | | bankwidth: BUSWIDTH, |
103 | | phys: WINDOW_ADDR, |
104 | | }; |
105 | | |
106 | | #ifdef CONFIG_MTD_PARTITIONS |
107 | | |
108 | | static struct mtd_partition bcm47xx_parts[] = { |
109 | | { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
110 | | { name: "linux", offset: 0, size: 0, }, |
111 | | { name: "rootfs", offset: 0, size: 0, }, |
112 | | { name: "nvram", offset: 0, size: 0, }, |
113 | | { name: NULL, }, |
114 | | }; |
115 | | |
116 | | static int __init |
117 | | find_cfe_size(struct mtd_info *mtd, size_t size) |
118 | | { |
119 | | struct trx_header *trx; |
120 | | unsigned char buf[512]; |
121 | | int off; |
122 | | size_t len; |
123 | | int blocksize; |
124 | | |
125 | | trx = (struct trx_header *) buf; |
126 | | |
127 | | blocksize = mtd->erasesize; |
128 | | if (blocksize < 0x10000) |
129 | | blocksize = 0x10000; |
130 | | |
131 | | for (off = (128*1024); off < size; off += blocksize) { |
132 | | memset(buf, 0xe5, sizeof(buf)); |
133 | | |
134 | | /* |
135 | | * Read into buffer |
136 | | */ |
137 | | if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
138 | | len != sizeof(buf)) |
139 | | continue; |
140 | | |
141 | | /* found a TRX header */ |
142 | | if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
143 | | goto found; |
144 | | } |
145 | | } |
146 | | |
147 | | printk(KERN_NOTICE |
148 | | "%s: Couldn't find bootloader size\n", |
149 | | mtd->name); |
150 | | return -1; |
151 | | |
152 | | found: |
153 | | printk(KERN_NOTICE "bootloader size: %d\n", off); |
154 | | return off; |
155 | | |
156 | | } |
157 | | |
158 | | /* |
159 | | * Copied from mtdblock.c |
160 | | * |
161 | | * Cache stuff... |
162 | | * |
163 | | * Since typical flash erasable sectors are much larger than what Linux's |
164 | | * buffer cache can handle, we must implement read-modify-write on flash |
165 | | * sectors for each block write requests. To avoid over-erasing flash sectors |
166 | | * and to speed things up, we locally cache a whole flash sector while it is |
167 | | * being written to until a different sector is required. |
168 | | */ |
169 | | |
170 | | static void erase_callback(struct erase_info *done) |
171 | | { |
172 | | wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
173 | | wake_up(wait_q); |
174 | | } |
175 | | |
176 | | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
177 | | int len, const char *buf) |
178 | | { |
179 | | struct erase_info erase; |
180 | | DECLARE_WAITQUEUE(wait, current); |
181 | | wait_queue_head_t wait_q; |
182 | | size_t retlen; |
183 | | int ret; |
184 | | |
185 | | /* |
186 | | * First, let's erase the flash block. |
187 | | */ |
188 | | |
189 | | init_waitqueue_head(&wait_q); |
190 | | erase.mtd = mtd; |
191 | | erase.callback = erase_callback; |
192 | | erase.addr = pos; |
193 | | erase.len = len; |
194 | | erase.priv = (u_long)&wait_q; |
195 | | |
196 | | set_current_state(TASK_INTERRUPTIBLE); |
197 | | add_wait_queue(&wait_q, &wait); |
198 | | |
199 | | ret = mtd->erase(mtd, &erase); |
200 | | if (ret) { |
201 | | set_current_state(TASK_RUNNING); |
202 | | remove_wait_queue(&wait_q, &wait); |
203 | | printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
204 | | "on \"%s\" failed\n", |
205 | | pos, len, mtd->name); |
206 | | return ret; |
207 | | } |
208 | | |
209 | | schedule(); /* Wait for erase to finish. */ |
210 | | remove_wait_queue(&wait_q, &wait); |
211 | | |
212 | | /* |
213 | | * Next, writhe data to flash. |
214 | | */ |
215 | | |
216 | | ret = mtd->write (mtd, pos, len, &retlen, buf); |
217 | | if (ret) |
218 | | return ret; |
219 | | if (retlen != len) |
220 | | return -EIO; |
221 | | return 0; |
222 | | } |
223 | | |
224 | | |
225 | | static int __init |
226 | | find_dual_image_off (struct mtd_info *mtd, size_t size) |
227 | | { |
228 | | struct trx_header trx; |
229 | | int off, blocksize; |
230 | | size_t len; |
231 | | |
232 | | blocksize = mtd->erasesize; |
233 | | if (blocksize < 0x10000) |
234 | | blocksize = 0x10000; |
235 | | |
236 | | for (off = (128*1024); off < size; off += blocksize) { |
237 | | memset(&trx, 0xe5, sizeof(trx)); |
238 | | /* |
239 | | * Read into buffer |
240 | | */ |
241 | | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
242 | | len != sizeof(trx)) |
243 | | continue; |
244 | | /* found last TRX header */ |
245 | | if (le32_to_cpu(trx.magic) == TRX_MAGIC){ |
246 | | if (le32_to_cpu(trx.flag_version >> 16)==2){ |
247 | | printk("dual image TRX header found\n"); |
248 | | return size/2; |
249 | | } else { |
250 | | return 0; |
251 | | } |
252 | | } |
253 | | } |
254 | | return 0; |
255 | | } |
256 | | |
257 | | |
258 | | static int __init |
259 | | find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
260 | | { |
261 | | struct trx_header trx, *trx2; |
262 | | unsigned char buf[512], *block; |
263 | | int off, blocksize; |
264 | | u32 i, crc = ~0; |
265 | | size_t len; |
266 | | |
267 | | blocksize = mtd->erasesize; |
268 | | if (blocksize < 0x10000) |
269 | | blocksize = 0x10000; |
270 | | |
271 | | for (off = (128*1024); off < size; off += blocksize) { |
272 | | memset(&trx, 0xe5, sizeof(trx)); |
273 | | |
274 | | /* |
275 | | * Read into buffer |
276 | | */ |
277 | | if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
278 | | len != sizeof(trx)) |
279 | | continue; |
280 | | |
281 | | /* found a TRX header */ |
282 | | if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
283 | | part->offset = le32_to_cpu(trx.offsets[2]) ? : |
284 | | le32_to_cpu(trx.offsets[1]); |
285 | | part->size = le32_to_cpu(trx.len); |
286 | | |
287 | | part->size -= part->offset; |
288 | | part->offset += off; |
289 | | |
290 | | goto found; |
291 | | } |
292 | | } |
293 | | |
294 | | printk(KERN_NOTICE |
295 | | "%s: Couldn't find root filesystem\n", |
296 | | mtd->name); |
297 | | return -1; |
298 | | |
299 | | found: |
300 | | if (part->size == 0) |
301 | | return 0; |
302 | | |
303 | | if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
304 | | return 0; |
305 | | |
306 | | /* Move the fs outside of the trx */ |
307 | | part->size = 0; |
308 | | |
309 | | if (trx.len != part->offset + part->size - off) { |
310 | | /* Update the trx offsets and length */ |
311 | | trx.len = part->offset + part->size - off; |
312 | | |
313 | | /* Update the trx crc32 */ |
314 | | for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
315 | | if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
316 | | return 0; |
317 | | crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
318 | | } |
319 | | trx.crc32 = crc; |
320 | | |
321 | | /* read first eraseblock from the trx */ |
322 | | block = kmalloc(mtd->erasesize, GFP_KERNEL); |
323 | | trx2 = (struct trx_header *) block; |
324 | | if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
325 | | printk("Error accessing the first trx eraseblock\n"); |
326 | | return 0; |
327 | | } |
328 | | |
329 | | printk("Updating TRX offsets and length:\n"); |
330 | | printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
331 | | printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
332 | | |
333 | | /* Write updated trx header to the flash */ |
334 | | memcpy(block, &trx, sizeof(trx)); |
335 | | if (mtd->unlock) |
336 | | mtd->unlock(mtd, off, mtd->erasesize); |
337 | | erase_write(mtd, off, mtd->erasesize, block); |
338 | | if (mtd->sync) |
339 | | mtd->sync(mtd); |
340 | | kfree(block); |
341 | | printk("Done\n"); |
342 | | } |
343 | | |
344 | | return part->size; |
345 | | } |
346 | | |
347 | | struct mtd_partition * __init |
348 | | init_mtd_partitions(struct mtd_info *mtd, size_t size) |
349 | | { |
350 | | int cfe_size; |
351 | | int dual_image_offset = 0; |
352 | | |
353 | | if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
354 | | return NULL; |
355 | | |
356 | | /* boot loader */ |
357 | | bcm47xx_parts[0].offset = 0; |
358 | | bcm47xx_parts[0].size = cfe_size; |
359 | | |
360 | | /* nvram */ |
361 | | if (cfe_size != 384 * 1024) { |
362 | | bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
363 | | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
364 | | } else { |
365 | | /* nvram (old 128kb config partition on netgear wgt634u) */ |
366 | | bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
367 | | bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
368 | | } |
369 | | |
370 | | /* dual image offset*/ |
371 | | printk("Looking for dual image\n"); |
372 | | dual_image_offset=find_dual_image_off(mtd,size); |
373 | | /* linux (kernel and rootfs) */ |
374 | | if (cfe_size != 384 * 1024) { |
375 | | bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
376 | | bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
377 | | bcm47xx_parts[1].offset; |
378 | | } else { |
379 | | /* do not count the elf loader, which is on one block */ |
380 | | bcm47xx_parts[1].offset = bcm47xx_parts[0].size + |
381 | | bcm47xx_parts[3].size + mtd->erasesize; |
382 | | bcm47xx_parts[1].size = size - |
383 | | bcm47xx_parts[0].size - |
384 | | (2*bcm47xx_parts[3].size) - |
385 | | mtd->erasesize; |
386 | | } |
387 | | |
388 | | /* find and size rootfs */ |
389 | | find_root(mtd,size,&bcm47xx_parts[2]); |
390 | | bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
391 | | |
392 | | return bcm47xx_parts; |
393 | | } |
394 | | #endif |
395 | | |
396 | | int __init init_bcm47xx_map(void) |
397 | | { |
398 | | #ifdef CONFIG_SSB |
399 | | struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
400 | | #endif |
401 | | size_t size; |
402 | | int ret = 0; |
403 | | #ifdef CONFIG_MTD_PARTITIONS |
404 | | struct mtd_partition *parts; |
405 | | int i; |
406 | | #endif |
407 | | |
408 | | #ifdef CONFIG_SSB |
409 | | u32 window = mcore->flash_window; |
410 | | u32 window_size = mcore->flash_window_size; |
411 | | |
412 | | printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
413 | | bcm47xx_map.phys = window; |
414 | | bcm47xx_map.size = window_size; |
415 | | bcm47xx_map.bankwidth = mcore->flash_buswidth; |
416 | | bcm47xx_map.virt = ioremap_nocache(window, window_size); |
417 | | #else |
418 | | printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
419 | | bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
420 | | #endif |
421 | | |
422 | | if (!bcm47xx_map.virt) { |
423 | | printk("Failed to ioremap\n"); |
424 | | return -EIO; |
425 | | } |
426 | | |
427 | | simple_map_init(&bcm47xx_map); |
428 | | |
429 | | if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
430 | | printk("Failed to do_map_probe\n"); |
431 | | iounmap((void *)bcm47xx_map.virt); |
432 | | return -ENXIO; |
433 | | } |
434 | | |
435 | | /* override copy_from routine */ |
436 | | bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
437 | | |
438 | | bcm47xx_mtd->owner = THIS_MODULE; |
439 | | |
440 | | size = bcm47xx_mtd->size; |
441 | | |
442 | | printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
443 | | |
444 | | #ifdef CONFIG_MTD_PARTITIONS |
445 | | parts = init_mtd_partitions(bcm47xx_mtd, size); |
446 | | for (i = 0; parts[i].name; i++); |
447 | | ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
448 | | if (ret) { |
449 | | printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
450 | | goto fail; |
451 | | } |
452 | | #endif |
453 | | return 0; |
454 | | |
455 | | fail: |
456 | | if (bcm47xx_mtd) |
457 | | map_destroy(bcm47xx_mtd); |
458 | | if (bcm47xx_map.virt) |
459 | | iounmap((void *)bcm47xx_map.virt); |
460 | | bcm47xx_map.virt = 0; |
461 | | return ret; |
462 | | } |
463 | | |
464 | | void __exit cleanup_bcm47xx_map(void) |
465 | | { |
466 | | #ifdef CONFIG_MTD_PARTITIONS |
467 | | del_mtd_partitions(bcm47xx_mtd); |
468 | | #endif |
469 | | map_destroy(bcm47xx_mtd); |
470 | | iounmap((void *)bcm47xx_map.virt); |
471 | | } |
472 | | |
473 | | module_init(init_bcm47xx_map); |
474 | | module_exit(cleanup_bcm47xx_map); |
target/linux/brcm47xx/patches-2.6.34/001-backport.patch |
| 1 | commit 121915c4ee0812a14bc8d752bc210d0238d755c1 |
| 2 | Author: Waldemar Brodkorb <mips@waldemar-brodkorb.de> |
| 3 | Date: Tue Jun 8 19:06:01 2010 +0200 |
| 4 | |
| 5 | MIPS: BCM47xx: Add NVRAM support devices |
| 6 | |
| 7 | When trying to netboot a Linksys WRT54GS WLAN router, the bootup fails, |
| 8 | because of following error message: |
| 9 | |
| 10 | ... |
| 11 | [ 0.424000] b44: b44.c:v2.0 |
| 12 | [ 0.424000] b44: Invalid MAC address found in EEPROM |
| 13 | [ 0.432000] b44 ssb0:1: Problem fetching invariants of chip,aborting |
| 14 | [ 0.436000] b44: probe of ssb0:1 failed with error -22 |
| 15 | ... |
| 16 | |
| 17 | The router uses a CFE bootloader, but most of the needed environment |
| 18 | variables for network card initialization, are not available from CFE |
| 19 | via printenv and even though not via cfe_getenv(). |
| 20 | The required environment variables are saved in a special partition |
| 21 | in flash memory. The attached patch implement nvram_getenv and enables |
| 22 | bootup via NFS root on my router. |
| 23 | |
| 24 | Most of the patch is extracted from the OpenWrt subversion repository and |
| 25 | stripped down and cleaned up to just fix this issue. |
| 26 | |
| 27 | [Ralf: sorted out header file inclusions. Lots of unneded headers and such |
| 28 | that should have been included.] |
| 29 | |
| 30 | Signed-off-by: Waldemar Brodkorb <wbx@openadk.org> |
| 31 | Reviewed-by: Phil Sutter <phil@nwl.cc> |
| 32 | To: linux-mips@linux-mips.org |
| 33 | Cc: Hauke Mehrtens <hauke@hauke-m.de> |
| 34 | Patchwork: http://patchwork.linux-mips.org/patch/1359/ |
| 35 | Signed-off-by: Ralf Baechle <ralf@linux-mips.org> |
| 36 | |
| 37 | --- a/arch/mips/bcm47xx/Makefile |
| 38 | @@ -3,4 +3,4 @@ |
| 39 | # under Linux. |
| 40 | # |
| 41 | |
| 42 | -obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o |
| 43 | +obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o |
| 44 | --- /dev/null |
| 45 | @@ -0,0 +1,94 @@ |
| 46 | +/* |
| 47 | + * BCM947xx nvram variable access |
| 48 | + * |
| 49 | + * Copyright (C) 2005 Broadcom Corporation |
| 50 | + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 51 | + * |
| 52 | + * This program is free software; you can redistribute it and/or modify it |
| 53 | + * under the terms of the GNU General Public License as published by the |
| 54 | + * Free Software Foundation; either version 2 of the License, or (at your |
| 55 | + * option) any later version. |
| 56 | + */ |
| 57 | + |
| 58 | +#include <linux/init.h> |
| 59 | +#include <linux/types.h> |
| 60 | +#include <linux/module.h> |
| 61 | +#include <linux/ssb/ssb.h> |
| 62 | +#include <linux/kernel.h> |
| 63 | +#include <linux/string.h> |
| 64 | +#include <asm/addrspace.h> |
| 65 | +#include <asm/mach-bcm47xx/nvram.h> |
| 66 | +#include <asm/mach-bcm47xx/bcm47xx.h> |
| 67 | + |
| 68 | +static char nvram_buf[NVRAM_SPACE]; |
| 69 | + |
| 70 | +/* Probe for NVRAM header */ |
| 71 | +static void __init early_nvram_init(void) |
| 72 | +{ |
| 73 | + struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
| 74 | + struct nvram_header *header; |
| 75 | + int i; |
| 76 | + u32 base, lim, off; |
| 77 | + u32 *src, *dst; |
| 78 | + |
| 79 | + base = mcore->flash_window; |
| 80 | + lim = mcore->flash_window_size; |
| 81 | + |
| 82 | + off = FLASH_MIN; |
| 83 | + while (off <= lim) { |
| 84 | + /* Windowed flash access */ |
| 85 | + header = (struct nvram_header *) |
| 86 | + KSEG1ADDR(base + off - NVRAM_SPACE); |
| 87 | + if (header->magic == NVRAM_HEADER) |
| 88 | + goto found; |
| 89 | + off <<= 1; |
| 90 | + } |
| 91 | + |
| 92 | + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ |
| 93 | + header = (struct nvram_header *) KSEG1ADDR(base + 4096); |
| 94 | + if (header->magic == NVRAM_HEADER) |
| 95 | + goto found; |
| 96 | + |
| 97 | + header = (struct nvram_header *) KSEG1ADDR(base + 1024); |
| 98 | + if (header->magic == NVRAM_HEADER) |
| 99 | + goto found; |
| 100 | + |
| 101 | + return; |
| 102 | + |
| 103 | +found: |
| 104 | + src = (u32 *) header; |
| 105 | + dst = (u32 *) nvram_buf; |
| 106 | + for (i = 0; i < sizeof(struct nvram_header); i += 4) |
| 107 | + *dst++ = *src++; |
| 108 | + for (; i < header->len && i < NVRAM_SPACE; i += 4) |
| 109 | + *dst++ = le32_to_cpu(*src++); |
| 110 | +} |
| 111 | + |
| 112 | +int nvram_getenv(char *name, char *val, size_t val_len) |
| 113 | +{ |
| 114 | + char *var, *value, *end, *eq; |
| 115 | + |
| 116 | + if (!name) |
| 117 | + return 1; |
| 118 | + |
| 119 | + if (!nvram_buf[0]) |
| 120 | + early_nvram_init(); |
| 121 | + |
| 122 | + /* Look for name=value and return value */ |
| 123 | + var = &nvram_buf[sizeof(struct nvram_header)]; |
| 124 | + end = nvram_buf + sizeof(nvram_buf) - 2; |
| 125 | + end[0] = end[1] = '\0'; |
| 126 | + for (; *var; var = value + strlen(value) + 1) { |
| 127 | + eq = strchr(var, '='); |
| 128 | + if (!eq) |
| 129 | + break; |
| 130 | + value = eq + 1; |
| 131 | + if ((eq - var) == strlen(name) && |
| 132 | + strncmp(var, name, (eq - var)) == 0) { |
| 133 | + snprintf(val, val_len, "%s", value); |
| 134 | + return 0; |
| 135 | + } |
| 136 | + } |
| 137 | + return 1; |
| 138 | +} |
| 139 | +EXPORT_SYMBOL(nvram_getenv); |
| 140 | --- a/arch/mips/bcm47xx/setup.c |
| 141 | @@ -1,8 +1,8 @@ |
| 142 | /* |
| 143 | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
| 144 | - * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
| 145 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 146 | * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de> |
| 147 | + * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> |
| 148 | * |
| 149 | * This program is free software; you can redistribute it and/or modify it |
| 150 | * under the terms of the GNU General Public License as published by the |
| 151 | @@ -33,6 +33,7 @@ |
| 152 | #include <asm/time.h> |
| 153 | #include <bcm47xx.h> |
| 154 | #include <asm/fw/cfe/cfe_api.h> |
| 155 | +#include <asm/mach-bcm47xx/nvram.h> |
| 156 | |
| 157 | struct ssb_bus ssb_bcm47xx; |
| 158 | EXPORT_SYMBOL(ssb_bcm47xx); |
| 159 | @@ -81,28 +82,42 @@ static int bcm47xx_get_invariants(struct |
| 160 | /* Fill boardinfo structure */ |
| 161 | memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); |
| 162 | |
| 163 | - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
| 164 | + if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 || |
| 165 | + nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
| 166 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 167 | - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 168 | + if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 || |
| 169 | + nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 170 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 171 | - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 172 | + if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 || |
| 173 | + nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 174 | iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); |
| 175 | |
| 176 | /* Fill sprom structure */ |
| 177 | memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); |
| 178 | iv->sprom.revision = 3; |
| 179 | |
| 180 | - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 181 | + if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || |
| 182 | + nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 183 | str2eaddr(buf, iv->sprom.et0mac); |
| 184 | - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 185 | + |
| 186 | + if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || |
| 187 | + nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 188 | str2eaddr(buf, iv->sprom.et1mac); |
| 189 | - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 190 | - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10); |
| 191 | - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 192 | - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10); |
| 193 | - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 194 | + |
| 195 | + if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || |
| 196 | + nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 197 | + iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); |
| 198 | + |
| 199 | + if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || |
| 200 | + nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 201 | + iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); |
| 202 | + |
| 203 | + if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || |
| 204 | + nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 205 | iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); |
| 206 | - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 207 | + |
| 208 | + if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || |
| 209 | + nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 210 | iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); |
| 211 | |
| 212 | return 0; |
| 213 | --- /dev/null |
| 214 | @@ -0,0 +1,36 @@ |
| 215 | +/* |
| 216 | + * Copyright (C) 2005, Broadcom Corporation |
| 217 | + * Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org> |
| 218 | + * |
| 219 | + * This program is free software; you can redistribute it and/or modify it |
| 220 | + * under the terms of the GNU General Public License as published by the |
| 221 | + * Free Software Foundation; either version 2 of the License, or (at your |
| 222 | + * option) any later version. |
| 223 | + */ |
| 224 | + |
| 225 | +#ifndef __NVRAM_H |
| 226 | +#define __NVRAM_H |
| 227 | + |
| 228 | +#include <linux/types.h> |
| 229 | + |
| 230 | +struct nvram_header { |
| 231 | + u32 magic; |
| 232 | + u32 len; |
| 233 | + u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ |
| 234 | + u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ |
| 235 | + u32 config_ncdl; /* ncdl values for memc */ |
| 236 | +}; |
| 237 | + |
| 238 | +#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ |
| 239 | +#define NVRAM_VERSION 1 |
| 240 | +#define NVRAM_HEADER_SIZE 20 |
| 241 | +#define NVRAM_SPACE 0x8000 |
| 242 | + |
| 243 | +#define FLASH_MIN 0x00020000 /* Minimum flash size */ |
| 244 | + |
| 245 | +#define NVRAM_MAX_VALUE_LEN 255 |
| 246 | +#define NVRAM_MAX_PARAM_LEN 64 |
| 247 | + |
| 248 | +extern int nvram_getenv(char *name, char *val, size_t val_len); |
| 249 | + |
| 250 | +#endif |
target/linux/brcm47xx/patches-2.6.34/012-MIPS-BCM47xx-Fill-more-values-into-ssb-sprom.patch |
| 1 | From d6c049e08568aac29fff854ea0385e63c7150e09 Mon Sep 17 00:00:00 2001 |
| 2 | From: Hauke Mehrtens <hauke@hauke-m.de> |
| 3 | Date: Sun, 18 Jul 2010 13:34:32 +0200 |
| 4 | Subject: [PATCH 2/5] MIPS: BCM47xx: Fill more values into ssb sprom |
| 5 | |
| 6 | Most of the values are stored in the nvram and not in the CFE. At first |
| 7 | the nvram should be read and if there is no value it should look into |
| 8 | the CFE. Now more values are read out because the b43 and b43legacy |
| 9 | drivers needs them. |
| 10 | |
| 11 | Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> |
| 12 | --- |
| 13 | arch/mips/bcm47xx/setup.c | 122 +++++++++++++++++++++++++++++++++------------ |
| 14 | 1 files changed, 89 insertions(+), 33 deletions(-) |
| 15 | |
| 16 | --- a/arch/mips/bcm47xx/setup.c |
| 17 | @@ -74,6 +74,86 @@ static void str2eaddr(char *str, char *d |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) |
| 22 | +{ |
| 23 | + char buf[100]; |
| 24 | + |
| 25 | + memset(sprom, 0, sizeof(struct ssb_sprom)); |
| 26 | + |
| 27 | + sprom->revision = 3; |
| 28 | + if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0 || |
| 29 | + cfe_getenv("il0macaddr", buf, sizeof(buf)) >= 0) |
| 30 | + str2eaddr(buf, sprom->il0mac); |
| 31 | + if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || |
| 32 | + cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 33 | + str2eaddr(buf, sprom->et0mac); |
| 34 | + if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || |
| 35 | + cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 36 | + str2eaddr(buf, sprom->et1mac); |
| 37 | + if (nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || |
| 38 | + cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 39 | + sprom->et0phyaddr = simple_strtoul(buf, NULL, 0); |
| 40 | + if (nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || |
| 41 | + cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 42 | + sprom->et1phyaddr = simple_strtoul(buf, NULL, 0); |
| 43 | + if (nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || |
| 44 | + cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 45 | + sprom->et0mdcport = !!simple_strtoul(buf, NULL, 10); |
| 46 | + if (nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || |
| 47 | + cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 48 | + sprom->et1mdcport = !!simple_strtoul(buf, NULL, 10); |
| 49 | + if (nvram_getenv("pa0b0", buf, sizeof(buf)) >= 0 || |
| 50 | + cfe_getenv("pa0b0", buf, sizeof(buf)) >= 0) |
| 51 | + sprom->pa0b0 = simple_strtoul(buf, NULL, 0); |
| 52 | + if (nvram_getenv("pa0b1", buf, sizeof(buf)) >= 0 || |
| 53 | + cfe_getenv("pa0b1", buf, sizeof(buf)) >= 0) |
| 54 | + sprom->pa0b1 = simple_strtoul(buf, NULL, 0); |
| 55 | + if (nvram_getenv("pa0b2", buf, sizeof(buf)) >= 0 || |
| 56 | + cfe_getenv("pa0b2", buf, sizeof(buf)) >= 0) |
| 57 | + sprom->pa0b2 = simple_strtoul(buf, NULL, 0); |
| 58 | + if (nvram_getenv("pa1b0", buf, sizeof(buf)) >= 0 || |
| 59 | + cfe_getenv("pa1b0", buf, sizeof(buf)) >= 0) |
| 60 | + sprom->pa1b0 = simple_strtoul(buf, NULL, 0); |
| 61 | + if (nvram_getenv("pa1b1", buf, sizeof(buf)) >= 0 || |
| 62 | + cfe_getenv("pa1b1", buf, sizeof(buf)) >= 0) |
| 63 | + sprom->pa1b1 = simple_strtoul(buf, NULL, 0); |
| 64 | + if (nvram_getenv("pa1b2", buf, sizeof(buf)) >= 0 || |
| 65 | + cfe_getenv("pa1b2", buf, sizeof(buf)) >= 0) |
| 66 | + sprom->pa1b2 = simple_strtoul(buf, NULL, 0); |
| 67 | + if (nvram_getenv("wl0gpio0", buf, sizeof(buf)) >= 0 || |
| 68 | + cfe_getenv("wl0gpio0", buf, sizeof(buf)) >= 0) |
| 69 | + sprom->gpio0 = simple_strtoul(buf, NULL, 0); |
| 70 | + if (nvram_getenv("wl0gpio1", buf, sizeof(buf)) >= 0 || |
| 71 | + cfe_getenv("wl0gpio1", buf, sizeof(buf)) >= 0) |
| 72 | + sprom->gpio1 = simple_strtoul(buf, NULL, 0); |
| 73 | + if (nvram_getenv("wl0gpio2", buf, sizeof(buf)) >= 0 || |
| 74 | + cfe_getenv("wl0gpio2", buf, sizeof(buf)) >= 0) |
| 75 | + sprom->gpio2 = simple_strtoul(buf, NULL, 0); |
| 76 | + if (nvram_getenv("wl0gpio3", buf, sizeof(buf)) >= 0 || |
| 77 | + cfe_getenv("wl0gpio3", buf, sizeof(buf)) >= 0) |
| 78 | + sprom->gpio3 = simple_strtoul(buf, NULL, 0); |
| 79 | + if (nvram_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0 || |
| 80 | + cfe_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0) |
| 81 | + sprom->maxpwr_bg = simple_strtoul(buf, NULL, 0); |
| 82 | + if (nvram_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0 || |
| 83 | + cfe_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0) |
| 84 | + sprom->maxpwr_a = simple_strtoul(buf, NULL, 0); |
| 85 | + if (nvram_getenv("pa0itssit", buf, sizeof(buf)) >= 0 || |
| 86 | + cfe_getenv("pa0itssit", buf, sizeof(buf)) >= 0) |
| 87 | + sprom->itssi_bg = simple_strtoul(buf, NULL, 0); |
| 88 | + if (nvram_getenv("pa1itssit", buf, sizeof(buf)) >= 0 || |
| 89 | + cfe_getenv("pa1itssit", buf, sizeof(buf)) >= 0) |
| 90 | + sprom->itssi_a = simple_strtoul(buf, NULL, 0); |
| 91 | + sprom->boardflags_lo = 0; |
| 92 | + if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 || |
| 93 | + cfe_getenv("boardflags", buf, sizeof(buf)) >= 0) |
| 94 | + sprom->boardflags_lo = simple_strtoul(buf, NULL, 0); |
| 95 | + sprom->boardflags_hi = 0; |
| 96 | + if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 || |
| 97 | + cfe_getenv("boardflags", buf, sizeof(buf)) >= 0) |
| 98 | + sprom->boardflags_hi = simple_strtoul(buf, NULL, 0); |
| 99 | +} |
| 100 | + |
| 101 | static int bcm47xx_get_invariants(struct ssb_bus *bus, |
| 102 | struct ssb_init_invariants *iv) |
| 103 | { |
| 104 | @@ -82,43 +162,19 @@ static int bcm47xx_get_invariants(struct |
| 105 | /* Fill boardinfo structure */ |
| 106 | memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); |
| 107 | |
| 108 | - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 || |
| 109 | - nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
| 110 | + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; |
| 111 | + if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0 || |
| 112 | + cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 113 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 114 | - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 || |
| 115 | - nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 116 | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 117 | - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 || |
| 118 | - nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 119 | + if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0 || |
| 120 | + cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 121 | iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); |
| 122 | |
| 123 | - /* Fill sprom structure */ |
| 124 | - memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); |
| 125 | - iv->sprom.revision = 3; |
| 126 | - |
| 127 | - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || |
| 128 | - nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 129 | - str2eaddr(buf, iv->sprom.et0mac); |
| 130 | - |
| 131 | - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || |
| 132 | - nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 133 | - str2eaddr(buf, iv->sprom.et1mac); |
| 134 | - |
| 135 | - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || |
| 136 | - nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 137 | - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); |
| 138 | - |
| 139 | - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || |
| 140 | - nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 141 | - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); |
| 142 | - |
| 143 | - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || |
| 144 | - nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 145 | - iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); |
| 146 | - |
| 147 | - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || |
| 148 | - nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 149 | - iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); |
| 150 | + bcm47xx_fill_sprom(&iv->sprom); |
| 151 | + |
| 152 | + if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0 || |
| 153 | + cfe_getenv("cardbus", buf, sizeof(buf)) >= 0) |
| 154 | + iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); |
| 155 | |
| 156 | return 0; |
| 157 | } |
target/linux/brcm47xx/patches-2.6.34/022-USB-Add-ehci-ssb-driver.patch |
| 1 | From cb269cf1f97c316a5184080814a751687c72b718 Mon Sep 17 00:00:00 2001 |
| 2 | From: Hauke Mehrtens <hauke@hauke-m.de> |
| 3 | Date: Sun, 18 Jul 2010 21:29:40 +0200 |
| 4 | Subject: [PATCH 2/2] USB: Add ehci ssb driver |
| 5 | |
| 6 | Support for the Sonics Silicon Backplane (SSB) attached Broadcom USB EHCI core. |
| 7 | |
| 8 | Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> |
| 9 | --- |
| 10 | drivers/usb/host/Kconfig | 13 ++ |
| 11 | drivers/usb/host/ehci-hcd.c | 23 ++++- |
| 12 | drivers/usb/host/ehci-ssb.c | 258 +++++++++++++++++++++++++++++++++++++++++++ |
| 13 | 3 files changed, 292 insertions(+), 2 deletions(-) |
| 14 | create mode 100644 drivers/usb/host/ehci-ssb.c |
| 15 | |
| 16 | --- a/drivers/usb/host/Kconfig |
| 17 | @@ -150,6 +150,19 @@ config USB_OXU210HP_HCD |
| 18 | To compile this driver as a module, choose M here: the |
| 19 | module will be called oxu210hp-hcd. |
| 20 | |
| 21 | +config USB_EHCI_HCD_SSB |
| 22 | + bool "EHCI support for Broadcom SSB EHCI core" |
| 23 | + depends on USB_EHCI_HCD && (SSB = y || SSB = USB_EHCI_HCD) && EXPERIMENTAL |
| 24 | + default n |
| 25 | + ---help--- |
| 26 | + Support for the Sonics Silicon Backplane (SSB) attached |
| 27 | + Broadcom USB EHCI core. |
| 28 | + |
| 29 | + This device is present in some embedded devices with |
| 30 | + Broadcom based SSB bus. |
| 31 | + |
| 32 | + If unsure, say N. |
| 33 | + |
| 34 | config USB_ISP116X_HCD |
| 35 | tristate "ISP116X HCD support" |
| 36 | depends on USB |
| 37 | --- a/drivers/usb/host/ehci-hcd.c |
| 38 | @@ -1159,8 +1159,14 @@ MODULE_LICENSE ("GPL"); |
| 39 | #define PLATFORM_DRIVER ehci_atmel_driver |
| 40 | #endif |
| 41 | |
| 42 | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
| 43 | +#include "ehci-ssb.c" |
| 44 | +#define SSB_EHCI_DRIVER ssb_ehci_driver |
| 45 | +#endif |
| 46 | + |
| 47 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
| 48 | - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) |
| 49 | + !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
| 50 | + !defined(SSB_EHCI_DRIVER) |
| 51 | #error "missing bus glue for ehci-hcd" |
| 52 | #endif |
| 53 | |
| 54 | @@ -1214,10 +1220,20 @@ static int __init ehci_hcd_init(void) |
| 55 | if (retval < 0) |
| 56 | goto clean3; |
| 57 | #endif |
| 58 | + |
| 59 | +#ifdef SSB_EHCI_DRIVER |
| 60 | + retval = ssb_driver_register(&SSB_EHCI_DRIVER); |
| 61 | + if (retval < 0) |
| 62 | + goto clean4; |
| 63 | +#endif |
| 64 | return retval; |
| 65 | |
| 66 | +#ifdef SSB_EHCI_DRIVER |
| 67 | + /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */ |
| 68 | +clean4: |
| 69 | +#endif |
| 70 | #ifdef OF_PLATFORM_DRIVER |
| 71 | - /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ |
| 72 | + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); |
| 73 | clean3: |
| 74 | #endif |
| 75 | #ifdef PS3_SYSTEM_BUS_DRIVER |
| 76 | @@ -1256,6 +1272,9 @@ static void __exit ehci_hcd_cleanup(void |
| 77 | #ifdef PS3_SYSTEM_BUS_DRIVER |
| 78 | ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); |
| 79 | #endif |
| 80 | +#ifdef SSB_EHCI_DRIVER |
| 81 | + ssb_driver_unregister(&SSB_EHCI_DRIVER); |
| 82 | +#endif |
| 83 | #ifdef DEBUG |
| 84 | debugfs_remove(ehci_debug_root); |
| 85 | #endif |
| 86 | --- /dev/null |
| 87 | @@ -0,0 +1,258 @@ |
| 88 | +/* |
| 89 | + * Sonics Silicon Backplane |
| 90 | + * Broadcom USB-core EHCI driver (SSB bus glue) |
| 91 | + * |
| 92 | + * Copyright 2007 Steven Brown <sbrown@cortland.com> |
| 93 | + * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de> |
| 94 | + * |
| 95 | + * Derived from the OHCI-SSB driver |
| 96 | + * Copyright 2007 Michael Buesch <mb@bu3sch.de> |
| 97 | + * |
| 98 | + * Derived from the EHCI-PCI driver |
| 99 | + * Copyright (c) 2000-2004 by David Brownell |
| 100 | + * |
| 101 | + * Derived from the OHCI-PCI driver |
| 102 | + * Copyright 1999 Roman Weissgaerber |
| 103 | + * Copyright 2000-2002 David Brownell |
| 104 | + * Copyright 1999 Linus Torvalds |
| 105 | + * Copyright 1999 Gregory P. Smith |
| 106 | + * |
| 107 | + * Derived from the USBcore related parts of Broadcom-SB |
| 108 | + * Copyright 2005 Broadcom Corporation |
| 109 | + * |
| 110 | + * Licensed under the GNU/GPL. See COPYING for details. |
| 111 | + */ |
| 112 | +#include <linux/ssb/ssb.h> |
| 113 | + |
| 114 | + |
| 115 | +struct ssb_ehci_device { |
| 116 | + struct ehci_hcd ehci; /* _must_ be at the beginning. */ |
| 117 | +}; |
| 118 | + |
| 119 | +static inline |
| 120 | +struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd) |
| 121 | +{ |
| 122 | + return (struct ssb_ehci_device *)(hcd->hcd_priv); |
| 123 | +} |
| 124 | + |
| 125 | +static int ssb_ehci_reset(struct usb_hcd *hcd) |
| 126 | +{ |
| 127 | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
| 128 | + int err; |
| 129 | + |
| 130 | + ehci->caps = hcd->regs; |
| 131 | + ehci->regs = hcd->regs + |
| 132 | + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
| 133 | + |
| 134 | + dbg_hcs_params(ehci, "reset"); |
| 135 | + dbg_hcc_params(ehci, "reset"); |
| 136 | + |
| 137 | + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
| 138 | + |
| 139 | + err = ehci_halt(ehci); |
| 140 | + |
| 141 | + if (err) |
| 142 | + return err; |
| 143 | + |
| 144 | + err = ehci_init(hcd); |
| 145 | + |
| 146 | + if (err) |
| 147 | + return err; |
| 148 | + |
| 149 | + ehci_reset(ehci); |
| 150 | + |
| 151 | + return err; |
| 152 | +} |
| 153 | + |
| 154 | +static const struct hc_driver ssb_ehci_hc_driver = { |
| 155 | + .description = "ssb-usb-ehci", |
| 156 | + .product_desc = "SSB EHCI Controller", |
| 157 | + .hcd_priv_size = sizeof(struct ssb_ehci_device), |
| 158 | + |
| 159 | + .irq = ehci_irq, |
| 160 | + .flags = HCD_MEMORY | HCD_USB2, |
| 161 | + |
| 162 | + .reset = ssb_ehci_reset, |
| 163 | + .start = ehci_run, |
| 164 | + .stop = ehci_stop, |
| 165 | + .shutdown = ehci_shutdown, |
| 166 | + |
| 167 | + .urb_enqueue = ehci_urb_enqueue, |
| 168 | + .urb_dequeue = ehci_urb_dequeue, |
| 169 | + .endpoint_disable = ehci_endpoint_disable, |
| 170 | + .endpoint_reset = ehci_endpoint_reset, |
| 171 | + |
| 172 | + .get_frame_number = ehci_get_frame, |
| 173 | + |
| 174 | + .hub_status_data = ehci_hub_status_data, |
| 175 | + .hub_control = ehci_hub_control, |
| 176 | +#if defined(CONFIG_PM) |
| 177 | + .bus_suspend = ehci_bus_suspend, |
| 178 | + .bus_resume = ehci_bus_resume, |
| 179 | +#endif |
| 180 | + .relinquish_port = ehci_relinquish_port, |
| 181 | + .port_handed_over = ehci_port_handed_over, |
| 182 | + |
| 183 | + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
| 184 | +}; |
| 185 | + |
| 186 | +static void ssb_ehci_detach(struct ssb_device *dev) |
| 187 | +{ |
| 188 | + struct usb_hcd *hcd = ssb_get_drvdata(dev); |
| 189 | + if (hcd->driver->shutdown) |
| 190 | + hcd->driver->shutdown(hcd); |
| 191 | + |
| 192 | + usb_remove_hcd(hcd); |
| 193 | + iounmap(hcd->regs); |
| 194 | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
| 195 | + usb_put_hcd(hcd); |
| 196 | + ssb_device_disable(dev, 0); |
| 197 | +} |
| 198 | + |
| 199 | +static int ssb_ehci_attach(struct ssb_device *dev) |
| 200 | +{ |
| 201 | + struct ssb_ehci_device *ehcidev; |
| 202 | + struct usb_hcd *hcd; |
| 203 | + int err = -ENOMEM; |
| 204 | + u32 tmp; |
| 205 | + |
| 206 | + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || |
| 207 | + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) |
| 208 | + return -EOPNOTSUPP; |
| 209 | + |
| 210 | + /* |
| 211 | + * USB 2.0 special considerations: |
| 212 | + * |
| 213 | + * 1. Since the core supports both ehci and EHCI functions, it must |
| 214 | + * only be reset once. |
| 215 | + * |
| 216 | + * 2. In addition to the standard SSB reset sequence, the Host Control |
| 217 | + * Register must be programmed to bring the USB core and various |
| 218 | + * phy components out of reset. |
| 219 | + */ |
| 220 | + ssb_device_enable(dev, 0); |
| 221 | + ssb_write32(dev, 0x200, 0x7ff); |
| 222 | + |
| 223 | + /* Change Flush control reg */ |
| 224 | + tmp = ssb_read32(dev, 0x400); |
| 225 | + tmp &= ~8; |
| 226 | + ssb_write32(dev, 0x400, tmp); |
| 227 | + tmp = ssb_read32(dev, 0x400); |
| 228 | + |
| 229 | + /* Change Shim control reg */ |
| 230 | + tmp = ssb_read32(dev, 0x304); |
| 231 | + tmp &= ~0x100; |
| 232 | + ssb_write32(dev, 0x304, tmp); |
| 233 | + tmp = ssb_read32(dev, 0x304); |
| 234 | + |
| 235 | + udelay(1); |
| 236 | + |
| 237 | + /* Work around for 5354 failures */ |
| 238 | + if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) { |
| 239 | + /* Change syn01 reg */ |
| 240 | + tmp = 0x00fe00fe; |
| 241 | + ssb_write32(dev, 0x894, tmp); |
| 242 | + |
| 243 | + /* Change syn03 reg */ |
| 244 | + tmp = ssb_read32(dev, 0x89c); |
| 245 | + tmp |= 0x1; |
| 246 | + ssb_write32(dev, 0x89c, tmp); |
| 247 | + } |
| 248 | + |
| 249 | + hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev, |
| 250 | + dev_name(dev->dev)); |
| 251 | + if (!hcd) |
| 252 | + goto err_dev_disable; |
| 253 | + |
| 254 | + ehcidev = hcd_to_ssb_ehci(hcd); |
| 255 | + tmp = ssb_read32(dev, SSB_ADMATCH0); |
| 256 | + hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ |
| 257 | + hcd->rsrc_len = 0x100; /* ehci reg block size */ |
| 258 | + /* |
| 259 | + * start & size modified per sbutils.c |
| 260 | + */ |
| 261 | + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
| 262 | + if (!hcd->regs) |
| 263 | + goto err_put_hcd; |
| 264 | + err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); |
| 265 | + if (err) |
| 266 | + goto err_iounmap; |
| 267 | + |
| 268 | + ssb_set_drvdata(dev, hcd); |
| 269 | + |
| 270 | + return err; |
| 271 | + |
| 272 | +err_iounmap: |
| 273 | + iounmap(hcd->regs); |
| 274 | +err_put_hcd: |
| 275 | + usb_put_hcd(hcd); |
| 276 | +err_dev_disable: |
| 277 | + ssb_device_disable(dev, 0); |
| 278 | + return err; |
| 279 | +} |
| 280 | + |
| 281 | +static int ssb_ehci_probe(struct ssb_device *dev, |
| 282 | + const struct ssb_device_id *id) |
| 283 | +{ |
| 284 | + int err; |
| 285 | + u16 chipid_top; |
| 286 | + |
| 287 | + /* USBcores are only connected on embedded devices. */ |
| 288 | + chipid_top = (dev->bus->chip_id & 0xFF00); |
| 289 | + if (chipid_top != 0x4700 && chipid_top != 0x5300) |
| 290 | + return -ENODEV; |
| 291 | + |
| 292 | + /* TODO: Probably need checks here; is the core connected? */ |
| 293 | + |
| 294 | + if (usb_disabled()) |
| 295 | + return -ENODEV; |
| 296 | + |
| 297 | + err = ssb_ehci_attach(dev); |
| 298 | + |
| 299 | + return err; |
| 300 | +} |
| 301 | + |
| 302 | +static void ssb_ehci_remove(struct ssb_device *dev) |
| 303 | +{ |
| 304 | + ssb_ehci_detach(dev); |
| 305 | +} |
| 306 | + |
| 307 | +#ifdef CONFIG_PM |
| 308 | + |
| 309 | +static int ssb_ehci_suspend(struct ssb_device *dev, pm_message_t state) |
| 310 | +{ |
| 311 | + ssb_device_disable(dev, 0); |
| 312 | + |
| 313 | + return 0; |
| 314 | +} |
| 315 | + |
| 316 | +static int ssb_ehci_resume(struct ssb_device *dev) |
| 317 | +{ |
| 318 | + struct usb_hcd *hcd = ssb_get_drvdata(dev); |
| 319 | + struct ssb_ehci_device *ehcidev = hcd_to_ssb_ehci(hcd); |
| 320 | + |
| 321 | + ssb_device_enable(dev, 0); |
| 322 | + |
| 323 | + ehci_finish_controller_resume(hcd); |
| 324 | + return 0; |
| 325 | +} |
| 326 | + |
| 327 | +#else /* !CONFIG_PM */ |
| 328 | +#define ssb_ehci_suspend NULL |
| 329 | +#define ssb_ehci_resume NULL |
| 330 | +#endif /* CONFIG_PM */ |
| 331 | + |
| 332 | +static const struct ssb_device_id ssb_ehci_table[] = { |
| 333 | + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), |
| 334 | + SSB_DEVTABLE_END |
| 335 | +}; |
| 336 | +MODULE_DEVICE_TABLE(ssb, ssb_ehci_table); |
| 337 | + |
| 338 | +static struct ssb_driver ssb_ehci_driver = { |
| 339 | + .name = KBUILD_MODNAME, |
| 340 | + .id_table = ssb_ehci_table, |
| 341 | + .probe = ssb_ehci_probe, |
| 342 | + .remove = ssb_ehci_remove, |
| 343 | + .suspend = ssb_ehci_suspend, |
| 344 | + .resume = ssb_ehci_resume, |
| 345 | +}; |
target/linux/brcm47xx/patches-2.6.34/270-ehci-ssb.patch |
1 | | drivers/usb/host/Kconfig | 13 ++ |
2 | | drivers/usb/host/ehci-hcd.c | 12 ++ |
3 | | drivers/usb/host/ehci-ssb.c | 201 ++++++++++++++++++++++++++++++++++++++++++++ |
4 | | drivers/usb/host/ohci-ssb.c | 23 +++++ |
5 | | 4 files changed, 247 insertions(+), 2 deletions(-) |
6 | | |
7 | | +++ b/drivers/usb/host/Kconfig |
8 | | @@ -150,6 +150,19 @@ config USB_OXU210HP_HCD |
9 | | To compile this driver as a module, choose M here: the |
10 | | module will be called oxu210hp-hcd. |
11 | | |
12 | | +config USB_EHCI_HCD_SSB |
13 | | + bool "EHCI support for Broadcom SSB EHCI core" |
14 | | + depends on USB_EHCI_HCD && SSB && EXPERIMENTAL |
15 | | + default n |
16 | | + ---help--- |
17 | | + Support for the Sonics Silicon Backplane (SSB) attached |
18 | | + Broadcom USB EHCI core. |
19 | | + |
20 | | + This device is present in some embedded devices with |
21 | | + Broadcom based SSB bus. |
22 | | + |
23 | | + If unsure, say N. |
24 | | + |
25 | | config USB_ISP116X_HCD |
26 | | tristate "ISP116X HCD support" |
27 | | depends on USB |
28 | | +++ b/drivers/usb/host/ehci-hcd.c |
29 | | @@ -1159,8 +1159,16 @@ MODULE_LICENSE ("GPL"); |
30 | | #define PLATFORM_DRIVER ehci_atmel_driver |
31 | | #endif |
32 | | |
33 | | -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
34 | | - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) |
35 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
36 | | +#include "ehci-ssb.c" |
37 | | +#define SSB_EHCI_DRIVER ssb_ehci_driver |
38 | | +#endif |
39 | | + |
40 | | +#if !defined(PCI_DRIVER) && \ |
41 | | + !defined(PLATFORM_DRIVER) && \ |
42 | | + !defined(PS3_SYSTEM_BUS_DRIVER) && \ |
43 | | + !defined(OF_PLATFORM_DRIVER) && \ |
44 | | + !defined(SSB_EHCI_DRIVER) |
45 | | #error "missing bus glue for ehci-hcd" |
46 | | #endif |
47 | | |
48 | | +++ b/drivers/usb/host/ehci-ssb.c |
49 | | @@ -0,0 +1,158 @@ |
50 | | +/* |
51 | | + * Sonics Silicon Backplane |
52 | | + * Broadcom USB-core EHCI driver (SSB bus glue) |
53 | | + * |
54 | | + * Copyright 2007 Steven Brown <sbrown@cortland.com> |
55 | | + * |
56 | | + * Derived from the OHCI-SSB driver |
57 | | + * Copyright 2007 Michael Buesch <mb@bu3sch.de> |
58 | | + * |
59 | | + * Derived from the EHCI-PCI driver |
60 | | + * Copyright (c) 2000-2004 by David Brownell |
61 | | + * |
62 | | + * Derived from the OHCI-PCI driver |
63 | | + * Copyright 1999 Roman Weissgaerber |
64 | | + * Copyright 2000-2002 David Brownell |
65 | | + * Copyright 1999 Linus Torvalds |
66 | | + * Copyright 1999 Gregory P. Smith |
67 | | + * |
68 | | + * Derived from the USBcore related parts of Broadcom-SB |
69 | | + * Copyright 2005 Broadcom Corporation |
70 | | + * |
71 | | + * Licensed under the GNU/GPL. See COPYING for details. |
72 | | + */ |
73 | | +#include <linux/ssb/ssb.h> |
74 | | + |
75 | | +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) |
76 | | + |
77 | | +struct ssb_ehci_device { |
78 | | + struct ehci_hcd ehci; /* _must_ be at the beginning. */ |
79 | | + |
80 | | + u32 enable_flags; |
81 | | +}; |
82 | | + |
83 | | +static inline |
84 | | +struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd) |
85 | | +{ |
86 | | + return (struct ssb_ehci_device *)(hcd->hcd_priv); |
87 | | +} |
88 | | + |
89 | | +static int ssb_ehci_reset(struct usb_hcd *hcd) |
90 | | +{ |
91 | | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
92 | | + int err; |
93 | | + |
94 | | + ehci->caps = hcd->regs; |
95 | | + ehci->regs = hcd->regs + |
96 | | + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
97 | | + |
98 | | + dbg_hcs_params(ehci, "reset"); |
99 | | + dbg_hcc_params(ehci, "reset"); |
100 | | + |
101 | | + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
102 | | + |
103 | | + err = ehci_halt(ehci); |
104 | | + |
105 | | + if (err) |
106 | | + return err; |
107 | | + |
108 | | + err = ehci_init(hcd); |
109 | | + |
110 | | + if (err) |
111 | | + return err; |
112 | | + |
113 | | + ehci_reset(ehci); |
114 | | + |
115 | | + return err; |
116 | | +} |
117 | | + |
118 | | +static const struct hc_driver ssb_ehci_hc_driver = { |
119 | | + .description = "ssb-usb-ehci", |
120 | | + .product_desc = "SSB EHCI Controller", |
121 | | + .hcd_priv_size = sizeof(struct ssb_ehci_device), |
122 | | + |
123 | | + .irq = ehci_irq, |
124 | | + .flags = HCD_MEMORY | HCD_USB2, |
125 | | + |
126 | | + .reset = ssb_ehci_reset, |
127 | | + .start = ehci_run, |
128 | | + .stop = ehci_stop, |
129 | | + .shutdown = ehci_shutdown, |
130 | | + |
131 | | + .urb_enqueue = ehci_urb_enqueue, |
132 | | + .urb_dequeue = ehci_urb_dequeue, |
133 | | + .endpoint_disable = ehci_endpoint_disable, |
134 | | + .endpoint_reset = ehci_endpoint_reset, |
135 | | + |
136 | | + .get_frame_number = ehci_get_frame, |
137 | | + |
138 | | + .hub_status_data = ehci_hub_status_data, |
139 | | + .hub_control = ehci_hub_control, |
140 | | + .bus_suspend = ehci_bus_suspend, |
141 | | + .bus_resume = ehci_bus_resume, |
142 | | + .relinquish_port = ehci_relinquish_port, |
143 | | + .port_handed_over = ehci_port_handed_over, |
144 | | + |
145 | | + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
146 | | +}; |
147 | | + |
148 | | +static void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd) |
149 | | +{ |
150 | | + if (hcd->driver->shutdown) |
151 | | + hcd->driver->shutdown(hcd); |
152 | | + |
153 | | + usb_remove_hcd(hcd); |
154 | | + |
155 | | + iounmap(hcd->regs); |
156 | | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
157 | | + |
158 | | + usb_put_hcd(hcd); |
159 | | +} |
160 | | +EXPORT_SYMBOL_GPL(ssb_ehci_detach); |
161 | | + |
162 | | +static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd) |
163 | | +{ |
164 | | + struct ssb_ehci_device *ehcidev; |
165 | | + struct usb_hcd *hcd; |
166 | | + int err = -ENOMEM; |
167 | | + u32 tmp, flags = 0; |
168 | | + |
169 | | + hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev, |
170 | | + dev_name(dev->dev)); |
171 | | + if (!hcd) |
172 | | + goto err_dev_disable; |
173 | | + |
174 | | + ehcidev = hcd_to_ssb_ehci(hcd); |
175 | | + ehcidev->enable_flags = flags; |
176 | | + tmp = ssb_read32(dev, SSB_ADMATCH0); |
177 | | + hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ |
178 | | + hcd->rsrc_len = 0x100; /* ehci reg block size */ |
179 | | + /* |
180 | | + * start & size modified per sbutils.c |
181 | | + */ |
182 | | + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
183 | | + if (!hcd->regs) |
184 | | + goto err_put_hcd; |
185 | | + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED | IRQF_DISABLED); |
186 | | + if (err) |
187 | | + goto err_iounmap; |
188 | | + |
189 | | + *ehci_hcd = hcd; |
190 | | + |
191 | | + return err; |
192 | | + |
193 | | +err_iounmap: |
194 | | + iounmap(hcd->regs); |
195 | | +err_put_hcd: |
196 | | + usb_put_hcd(hcd); |
197 | | +err_dev_disable: |
198 | | + ssb_device_disable(dev, flags); |
199 | | + return err; |
200 | | +} |
201 | | +EXPORT_SYMBOL_GPL(ssb_ehci_attach); |
202 | | + |
203 | | +static const struct ssb_device_id ssb_ehci_table[] = { |
204 | | + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), |
205 | | + SSB_DEVTABLE_END |
206 | | +}; |
207 | | +MODULE_DEVICE_TABLE(ssb, ssb_ehci_table); |
208 | | +++ b/drivers/usb/host/ohci-ssb.c |
209 | | @@ -17,6 +17,8 @@ |
210 | | */ |
211 | | #include <linux/ssb/ssb.h> |
212 | | |
213 | | +extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd); |
214 | | +extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd); |
215 | | |
216 | | #define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) |
217 | | |
218 | | @@ -24,6 +26,7 @@ struct ssb_ohci_device { |
219 | | struct ohci_hcd ohci; /* _must_ be at the beginning. */ |
220 | | |
221 | | u32 enable_flags; |
222 | | + struct usb_hcd *ehci_hcd; |
223 | | }; |
224 | | |
225 | | static inline |
226 | | @@ -92,13 +95,25 @@ static const struct hc_driver ssb_ohci_h |
227 | | static void ssb_ohci_detach(struct ssb_device *dev) |
228 | | { |
229 | | struct usb_hcd *hcd = ssb_get_drvdata(dev); |
230 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
231 | | + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); |
232 | | +#endif |
233 | | |
234 | | usb_remove_hcd(hcd); |
235 | | iounmap(hcd->regs); |
236 | | usb_put_hcd(hcd); |
237 | | + |
238 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
239 | | + /* |
240 | | + * Also detach ehci function |
241 | | + */ |
242 | | + if (dev->id.coreid == SSB_DEV_USB20_HOST) |
243 | | + ssb_ehci_detach(dev, ohcidev->ehci_hcd); |
244 | | +#endif |
245 | | ssb_device_disable(dev, 0); |
246 | | } |
247 | | |
248 | | + |
249 | | static int ssb_ohci_attach(struct ssb_device *dev) |
250 | | { |
251 | | struct ssb_ohci_device *ohcidev; |
252 | | @@ -165,6 +180,14 @@ static int ssb_ohci_attach(struct ssb_de |
253 | | |
254 | | ssb_set_drvdata(dev, hcd); |
255 | | |
256 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
257 | | + /* |
258 | | + * attach ehci function in this core |
259 | | + */ |
260 | | + if (dev->id.coreid == SSB_DEV_USB20_HOST) |
261 | | + err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd)); |
262 | | +#endif |
263 | | + |
264 | | return err; |
265 | | |
266 | | err_iounmap: |
target/linux/brcm47xx/patches-2.6.34/400-arch-bcm47xx.patch |
1 | | +++ b/arch/mips/Kconfig |
2 | | @@ -62,6 +62,7 @@ config BCM47XX |
3 | | select SSB_DRIVER_MIPS |
4 | | select SSB_DRIVER_EXTIF |
5 | | select SSB_EMBEDDED |
6 | | + select SSB_B43_PCI_BRIDGE if PCI |
7 | | select SSB_PCICORE_HOSTMODE if PCI |
8 | | select GENERIC_GPIO |
9 | | select SYS_HAS_EARLY_PRINTK |
10 | | +++ b/arch/mips/bcm47xx/Makefile |
11 | | @@ -3,4 +3,4 @@ |
12 | | # under Linux. |
13 | | # |
14 | | |
15 | | -obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o |
16 | | +obj-y := cfe_env.o gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o |
17 | | +++ b/arch/mips/bcm47xx/irq.c |
18 | | @@ -1,5 +1,6 @@ |
19 | | /* |
20 | | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
21 | | + * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de> |
22 | | * |
23 | | * This program is free software; you can redistribute it and/or modify it |
24 | | * under the terms of the GNU General Public License as published by the |
25 | | @@ -23,10 +24,19 @@ |
26 | | */ |
27 | | |
28 | | #include <linux/types.h> |
29 | | +#include <linux/errno.h> |
30 | | +#include <linux/init.h> |
31 | | #include <linux/interrupt.h> |
32 | | #include <linux/irq.h> |
33 | | +#include <linux/pci.h> |
34 | | +#include <linux/ssb/ssb.h> |
35 | | + |
36 | | #include <asm/irq_cpu.h> |
37 | | |
38 | | + |
39 | | +extern struct ssb_bus ssb_bcm47xx; |
40 | | + |
41 | | + |
42 | | void plat_irq_dispatch(void) |
43 | | { |
44 | | u32 cause; |
45 | 1 | --- a/arch/mips/bcm47xx/nvram.c |
46 | 2 | +++ b/arch/mips/bcm47xx/nvram.c |
47 | | @@ -24,10 +24,10 @@ |
48 | | #include <asm/io.h> |
49 | | #include <asm/uaccess.h> |
50 | | |
51 | | -#include <nvram.h> |
52 | | +#include "include/nvram.h" |
53 | | |
54 | | #define MB * 1048576 |
55 | | -extern struct ssb_bus ssb; |
56 | | +extern struct ssb_bus ssb_bcm47xx; |
57 | | |
58 | | static char nvram_buf[NVRAM_SPACE]; |
59 | | static int cfe_env; |
60 | | @@ -36,7 +36,7 @@ extern char *cfe_env_get(char *nv_buf, c |
61 | | /* Probe for NVRAM header */ |
62 | | static void __init early_nvram_init(void) |
63 | | { |
64 | | - struct ssb_mipscore *mcore = &ssb.mipscore; |
65 | | + struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
66 | | struct nvram_header *header; |
67 | | int i; |
68 | | u32 base, lim, off; |
69 | | +++ b/arch/mips/bcm47xx/setup.c |
70 | | @@ -2,7 +2,7 @@ |
71 | | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
72 | | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
73 | | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
74 | | - * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de> |
75 | | + * Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de> |
76 | | * |
77 | | * This program is free software; you can redistribute it and/or modify it |
78 | | * under the terms of the GNU General Public License as published by the |
79 | | @@ -25,18 +25,28 @@ |
80 | | * 675 Mass Ave, Cambridge, MA 02139, USA. |
81 | | */ |
82 | | |
83 | | +#include <linux/init.h> |
84 | | #include <linux/types.h> |
85 | | #include <linux/ssb/ssb.h> |
86 | | #include <linux/ssb/ssb_embedded.h> |
87 | | +#include <linux/tty.h> |
88 | | +#include <linux/serial.h> |
89 | | +#include <linux/serial_core.h> |
90 | | +#include <linux/serial_reg.h> |
91 | | +#include <linux/serial_8250.h> |
92 | | #include <asm/bootinfo.h> |
93 | | #include <asm/reboot.h> |
94 | | #include <asm/time.h> |
95 | | -#include <bcm47xx.h> |
96 | | #include <asm/fw/cfe/cfe_api.h> |
97 | | +#include <linux/pm.h> |
98 | | + |
99 | | +#include "include/nvram.h" |
100 | | |
101 | | struct ssb_bus ssb_bcm47xx; |
102 | | EXPORT_SYMBOL(ssb_bcm47xx); |
103 | | |
104 | | +extern void bcm47xx_pci_init(void); |
105 | | + |
106 | | static void bcm47xx_machine_restart(char *command) |
107 | | { |
108 | | printk(KERN_ALERT "Please stand by while rebooting the system...\n"); |
109 | | @@ -56,7 +66,7 @@ static void bcm47xx_machine_halt(void) |
110 | | cpu_relax(); |
111 | | } |
112 | | |
113 | | -static void str2eaddr(char *str, char *dest) |
114 | | +static void e_aton(char *str, char *dest) |
115 | | { |
116 | | int i = 0; |
117 | | |
118 | | @@ -73,51 +83,142 @@ static void str2eaddr(char *str, char *d |
119 | | } |
| 3 | @@ -92,3 +92,30 @@ int nvram_getenv(char *name, char *val, |
| 4 | return 1; |
120 | 5 | } |
121 | | |
122 | | -static int bcm47xx_get_invariants(struct ssb_bus *bus, |
123 | | - struct ssb_init_invariants *iv) |
124 | | +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) |
125 | | +{ |
126 | | + char *s; |
127 | | + |
128 | | + memset(sprom, 0xFF, sizeof(struct ssb_sprom)); |
129 | | + |
130 | | + sprom->revision = 1; |
131 | | + if ((s = nvram_get("il0macaddr"))) |
132 | | + e_aton(s, sprom->il0mac); |
133 | | + if ((s = nvram_get("et0macaddr"))) |
134 | | + e_aton(s, sprom->et0mac); |
135 | | + if ((s = nvram_get("et1macaddr"))) |
136 | | + e_aton(s, sprom->et1mac); |
137 | | + if ((s = nvram_get("et0phyaddr"))) |
138 | | + sprom->et0phyaddr = simple_strtoul(s, NULL, 0); |
139 | | + if ((s = nvram_get("et1phyaddr"))) |
140 | | + sprom->et1phyaddr = simple_strtoul(s, NULL, 0); |
141 | | + if ((s = nvram_get("et0mdcport"))) |
142 | | + sprom->et0mdcport = !!simple_strtoul(s, NULL, 10); |
143 | | + if ((s = nvram_get("et1mdcport"))) |
144 | | + sprom->et1mdcport = !!simple_strtoul(s, NULL, 10); |
145 | | + if ((s = nvram_get("pa0b0"))) |
146 | | + sprom->pa0b0 = simple_strtoul(s, NULL, 0); |
147 | | + if ((s = nvram_get("pa0b1"))) |
148 | | + sprom->pa0b1 = simple_strtoul(s, NULL, 0); |
149 | | + if ((s = nvram_get("pa0b2"))) |
150 | | + sprom->pa0b2 = simple_strtoul(s, NULL, 0); |
151 | | + if ((s = nvram_get("pa1b0"))) |
152 | | + sprom->pa1b0 = simple_strtoul(s, NULL, 0); |
153 | | + if ((s = nvram_get("pa1b1"))) |
154 | | + sprom->pa1b1 = simple_strtoul(s, NULL, 0); |
155 | | + if ((s = nvram_get("pa1b2"))) |
156 | | + sprom->pa1b2 = simple_strtoul(s, NULL, 0); |
157 | | + if ((s = nvram_get("wl0gpio0"))) |
158 | | + sprom->gpio0 = simple_strtoul(s, NULL, 0); |
159 | | + if ((s = nvram_get("wl0gpio1"))) |
160 | | + sprom->gpio1 = simple_strtoul(s, NULL, 0); |
161 | | + if ((s = nvram_get("wl0gpio2"))) |
162 | | + sprom->gpio2 = simple_strtoul(s, NULL, 0); |
163 | | + if ((s = nvram_get("wl0gpio3"))) |
164 | | + sprom->gpio3 = simple_strtoul(s, NULL, 0); |
165 | | + if ((s = nvram_get("pa0maxpwr"))) |
166 | | + sprom->maxpwr_bg = simple_strtoul(s, NULL, 0); |
167 | | + if ((s = nvram_get("pa1maxpwr"))) |
168 | | + sprom->maxpwr_a = simple_strtoul(s, NULL, 0); |
169 | | + if ((s = nvram_get("pa0itssit"))) |
170 | | + sprom->itssi_bg = simple_strtoul(s, NULL, 0); |
171 | | + if ((s = nvram_get("pa1itssit"))) |
172 | | + sprom->itssi_a = simple_strtoul(s, NULL, 0); |
173 | | + sprom->boardflags_lo = 0; |
174 | | + if ((s = nvram_get("boardflags"))) |
175 | | + sprom->boardflags_lo = simple_strtoul(s, NULL, 0); |
176 | | + sprom->boardflags_hi = 0; |
177 | | + if ((s = nvram_get("boardflags2"))) |
178 | | + sprom->boardflags_hi = simple_strtoul(s, NULL, 0); |
179 | | +} |
| 6 | EXPORT_SYMBOL(nvram_getenv); |
180 | 7 | + |
181 | | +static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) |
182 | | { |
183 | | - char buf[100]; |
184 | | + char *s; |
185 | | + |
186 | | + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; |
187 | | + if ((s = nvram_get("boardtype"))) |
188 | | + iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0); |
189 | | + if ((s = nvram_get("boardrev"))) |
190 | | + iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0); |
191 | | |
192 | | - /* Fill boardinfo structure */ |
193 | | - memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); |
194 | | + bcm47xx_fill_sprom(&iv->sprom); |
195 | | |
196 | | - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
197 | | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
198 | | - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) |
199 | | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
200 | | - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) |
201 | | - iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); |
202 | | - |
203 | | - /* Fill sprom structure */ |
204 | | - memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); |
205 | | - iv->sprom.revision = 3; |
206 | | - |
207 | | - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
208 | | - str2eaddr(buf, iv->sprom.et0mac); |
209 | | - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
210 | | - str2eaddr(buf, iv->sprom.et1mac); |
211 | | - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
212 | | - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10); |
213 | | - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
214 | | - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10); |
215 | | - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
216 | | - iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); |
217 | | - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
218 | | - iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); |
219 | | + if ((s = nvram_get("cardbus"))) |
220 | | + iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10); |
221 | | |
222 | | return 0; |
223 | | } |
224 | | |
225 | | void __init plat_mem_setup(void) |
226 | | { |
227 | | - int err; |
228 | | + int i, err; |
229 | | + char *s; |
230 | | + struct ssb_mipscore *mcore; |
231 | | + |
232 | | + err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants); |
233 | | + if (err) { |
234 | | + const char *msg = "Failed to initialize SSB bus (err %d)\n"; |
235 | | + printk(msg, err); /* Make sure the message gets out of the box. */ |
236 | | + panic(msg, err); |
237 | | + } |
238 | | + mcore = &ssb_bcm47xx.mipscore; |
239 | | |
240 | | - err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, |
241 | | - bcm47xx_get_invariants); |
242 | | - if (err) |
243 | | - panic("Failed to initialize SSB bus (err %d)\n", err); |
244 | | + s = nvram_get("kernel_args"); |
245 | | + if (s && !strncmp(s, "console=ttyS1", 13)) { |
246 | | + struct ssb_serial_port port; |
247 | | + |
248 | | + printk("Swapping serial ports!\n"); |
249 | | + /* swap serial ports */ |
250 | | + memcpy(&port, &mcore->serial_ports[0], sizeof(port)); |
251 | | + memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port)); |
252 | | + memcpy(&mcore->serial_ports[1], &port, sizeof(port)); |
| 8 | +char *nvram_get(const char *name) |
| 9 | +{ |
| 10 | + char *var, *value, *end, *eq; |
| 11 | + |
| 12 | + if (!name) |
| 13 | + return NULL; |
| 14 | + |
| 15 | + if (!nvram_buf[0]) |
| 16 | + early_nvram_init(); |
| 17 | + |
| 18 | + /* Look for name=value and return value */ |
| 19 | + var = &nvram_buf[sizeof(struct nvram_header)]; |
| 20 | + end = nvram_buf + sizeof(nvram_buf) - 2; |
| 21 | + end[0] = end[1] = '\0'; |
| 22 | + for (; *var; var = value + strlen(value) + 1) { |
| 23 | + if (!(eq = strchr(var, '='))) |
| 24 | + break; |
| 25 | + value = eq + 1; |
| 26 | + if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) |
| 27 | + return value; |
253 | 28 | + } |
254 | 29 | + |
255 | | + for (i = 0; i < mcore->nr_serial_ports; i++) { |
256 | | + struct ssb_serial_port *port = &(mcore->serial_ports[i]); |
257 | | + struct uart_port s; |
258 | | + |
259 | | + memset(&s, 0, sizeof(s)); |
260 | | + s.line = i; |
261 | | + s.mapbase = (unsigned int) port->regs; |
262 | | + s.membase = port->regs; |
263 | | + s.irq = port->irq + 2; |
264 | | + s.uartclk = port->baud_base; |
265 | | + s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; |
266 | | + s.iotype = SERIAL_IO_MEM; |
267 | | + s.regshift = port->reg_shift; |
| 30 | + return NULL; |
| 31 | +} |
268 | 32 | + |
269 | | + early_serial_setup(&s); |
270 | | + } |
271 | | + printk("Serial init done.\n"); |
272 | | |
273 | | _machine_restart = bcm47xx_machine_restart; |
| 33 | +EXPORT_SYMBOL(nvram_get); |
| 34 | --- a/arch/mips/bcm47xx/setup.c |
| 35 | @@ -226,3 +226,20 @@ void __init plat_mem_setup(void) |
274 | 36 | _machine_halt = bcm47xx_machine_halt; |
275 | 37 | pm_power_off = bcm47xx_machine_halt; |
276 | 38 | } |
... | ... | |
295 | 54 | + return 0; |
296 | 55 | +} |
297 | 56 | +device_initcall(bcm47xx_register_gpiodev); |
298 | | +++ b/arch/mips/bcm47xx/time.c |
299 | | @@ -22,11 +22,17 @@ |
300 | | * 675 Mass Ave, Cambridge, MA 02139, USA. |
301 | | */ |
302 | | |
303 | | - |
304 | | #include <linux/init.h> |
305 | | +#include <linux/kernel.h> |
306 | | +#include <linux/sched.h> |
307 | | +#include <linux/serial_reg.h> |
308 | | +#include <linux/interrupt.h> |
309 | | #include <linux/ssb/ssb.h> |
310 | | +#include <asm/addrspace.h> |
311 | | +#include <asm/io.h> |
312 | | #include <asm/time.h> |
313 | | -#include <bcm47xx.h> |
314 | | + |
315 | | +extern struct ssb_bus ssb_bcm47xx; |
316 | | |
317 | | void __init plat_time_init(void) |
318 | | { |
target/linux/brcm47xx/patches-2.6.35/012-MIPS-BCM47xx-Fill-more-values-into-ssb-sprom.patch |
| 1 | From d6c049e08568aac29fff854ea0385e63c7150e09 Mon Sep 17 00:00:00 2001 |
| 2 | From: Hauke Mehrtens <hauke@hauke-m.de> |
| 3 | Date: Sun, 18 Jul 2010 13:34:32 +0200 |
| 4 | Subject: [PATCH 2/5] MIPS: BCM47xx: Fill more values into ssb sprom |
| 5 | |
| 6 | Most of the values are stored in the nvram and not in the CFE. At first |
| 7 | the nvram should be read and if there is no value it should look into |
| 8 | the CFE. Now more values are read out because the b43 and b43legacy |
| 9 | drivers needs them. |
| 10 | |
| 11 | Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> |
| 12 | --- |
| 13 | arch/mips/bcm47xx/setup.c | 122 +++++++++++++++++++++++++++++++++------------ |
| 14 | 1 files changed, 89 insertions(+), 33 deletions(-) |
| 15 | |
| 16 | --- a/arch/mips/bcm47xx/setup.c |
| 17 | @@ -74,6 +74,86 @@ static void str2eaddr(char *str, char *d |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) |
| 22 | +{ |
| 23 | + char buf[100]; |
| 24 | + |
| 25 | + memset(sprom, 0, sizeof(struct ssb_sprom)); |
| 26 | + |
| 27 | + sprom->revision = 3; |
| 28 | + if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0 || |
| 29 | + cfe_getenv("il0macaddr", buf, sizeof(buf)) >= 0) |
| 30 | + str2eaddr(buf, sprom->il0mac); |
| 31 | + if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || |
| 32 | + cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 33 | + str2eaddr(buf, sprom->et0mac); |
| 34 | + if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || |
| 35 | + cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 36 | + str2eaddr(buf, sprom->et1mac); |
| 37 | + if (nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || |
| 38 | + cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 39 | + sprom->et0phyaddr = simple_strtoul(buf, NULL, 0); |
| 40 | + if (nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || |
| 41 | + cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 42 | + sprom->et1phyaddr = simple_strtoul(buf, NULL, 0); |
| 43 | + if (nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || |
| 44 | + cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 45 | + sprom->et0mdcport = !!simple_strtoul(buf, NULL, 10); |
| 46 | + if (nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || |
| 47 | + cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 48 | + sprom->et1mdcport = !!simple_strtoul(buf, NULL, 10); |
| 49 | + if (nvram_getenv("pa0b0", buf, sizeof(buf)) >= 0 || |
| 50 | + cfe_getenv("pa0b0", buf, sizeof(buf)) >= 0) |
| 51 | + sprom->pa0b0 = simple_strtoul(buf, NULL, 0); |
| 52 | + if (nvram_getenv("pa0b1", buf, sizeof(buf)) >= 0 || |
| 53 | + cfe_getenv("pa0b1", buf, sizeof(buf)) >= 0) |
| 54 | + sprom->pa0b1 = simple_strtoul(buf, NULL, 0); |
| 55 | + if (nvram_getenv("pa0b2", buf, sizeof(buf)) >= 0 || |
| 56 | + cfe_getenv("pa0b2", buf, sizeof(buf)) >= 0) |
| 57 | + sprom->pa0b2 = simple_strtoul(buf, NULL, 0); |
| 58 | + if (nvram_getenv("pa1b0", buf, sizeof(buf)) >= 0 || |
| 59 | + cfe_getenv("pa1b0", buf, sizeof(buf)) >= 0) |
| 60 | + sprom->pa1b0 = simple_strtoul(buf, NULL, 0); |
| 61 | + if (nvram_getenv("pa1b1", buf, sizeof(buf)) >= 0 || |
| 62 | + cfe_getenv("pa1b1", buf, sizeof(buf)) >= 0) |
| 63 | + sprom->pa1b1 = simple_strtoul(buf, NULL, 0); |
| 64 | + if (nvram_getenv("pa1b2", buf, sizeof(buf)) >= 0 || |
| 65 | + cfe_getenv("pa1b2", buf, sizeof(buf)) >= 0) |
| 66 | + sprom->pa1b2 = simple_strtoul(buf, NULL, 0); |
| 67 | + if (nvram_getenv("wl0gpio0", buf, sizeof(buf)) >= 0 || |
| 68 | + cfe_getenv("wl0gpio0", buf, sizeof(buf)) >= 0) |
| 69 | + sprom->gpio0 = simple_strtoul(buf, NULL, 0); |
| 70 | + if (nvram_getenv("wl0gpio1", buf, sizeof(buf)) >= 0 || |
| 71 | + cfe_getenv("wl0gpio1", buf, sizeof(buf)) >= 0) |
| 72 | + sprom->gpio1 = simple_strtoul(buf, NULL, 0); |
| 73 | + if (nvram_getenv("wl0gpio2", buf, sizeof(buf)) >= 0 || |
| 74 | + cfe_getenv("wl0gpio2", buf, sizeof(buf)) >= 0) |
| 75 | + sprom->gpio2 = simple_strtoul(buf, NULL, 0); |
| 76 | + if (nvram_getenv("wl0gpio3", buf, sizeof(buf)) >= 0 || |
| 77 | + cfe_getenv("wl0gpio3", buf, sizeof(buf)) >= 0) |
| 78 | + sprom->gpio3 = simple_strtoul(buf, NULL, 0); |
| 79 | + if (nvram_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0 || |
| 80 | + cfe_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0) |
| 81 | + sprom->maxpwr_bg = simple_strtoul(buf, NULL, 0); |
| 82 | + if (nvram_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0 || |
| 83 | + cfe_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0) |
| 84 | + sprom->maxpwr_a = simple_strtoul(buf, NULL, 0); |
| 85 | + if (nvram_getenv("pa0itssit", buf, sizeof(buf)) >= 0 || |
| 86 | + cfe_getenv("pa0itssit", buf, sizeof(buf)) >= 0) |
| 87 | + sprom->itssi_bg = simple_strtoul(buf, NULL, 0); |
| 88 | + if (nvram_getenv("pa1itssit", buf, sizeof(buf)) >= 0 || |
| 89 | + cfe_getenv("pa1itssit", buf, sizeof(buf)) >= 0) |
| 90 | + sprom->itssi_a = simple_strtoul(buf, NULL, 0); |
| 91 | + sprom->boardflags_lo = 0; |
| 92 | + if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 || |
| 93 | + cfe_getenv("boardflags", buf, sizeof(buf)) >= 0) |
| 94 | + sprom->boardflags_lo = simple_strtoul(buf, NULL, 0); |
| 95 | + sprom->boardflags_hi = 0; |
| 96 | + if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 || |
| 97 | + cfe_getenv("boardflags", buf, sizeof(buf)) >= 0) |
| 98 | + sprom->boardflags_hi = simple_strtoul(buf, NULL, 0); |
| 99 | +} |
| 100 | + |
| 101 | static int bcm47xx_get_invariants(struct ssb_bus *bus, |
| 102 | struct ssb_init_invariants *iv) |
| 103 | { |
| 104 | @@ -82,43 +162,19 @@ static int bcm47xx_get_invariants(struct |
| 105 | /* Fill boardinfo structure */ |
| 106 | memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); |
| 107 | |
| 108 | - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 || |
| 109 | - nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
| 110 | + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; |
| 111 | + if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0 || |
| 112 | + cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 113 | iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 114 | - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 || |
| 115 | - nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) |
| 116 | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
| 117 | - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 || |
| 118 | - nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 119 | + if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0 || |
| 120 | + cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) |
| 121 | iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); |
| 122 | |
| 123 | - /* Fill sprom structure */ |
| 124 | - memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); |
| 125 | - iv->sprom.revision = 3; |
| 126 | - |
| 127 | - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || |
| 128 | - nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
| 129 | - str2eaddr(buf, iv->sprom.et0mac); |
| 130 | - |
| 131 | - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || |
| 132 | - nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
| 133 | - str2eaddr(buf, iv->sprom.et1mac); |
| 134 | - |
| 135 | - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || |
| 136 | - nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
| 137 | - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); |
| 138 | - |
| 139 | - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || |
| 140 | - nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
| 141 | - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); |
| 142 | - |
| 143 | - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || |
| 144 | - nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
| 145 | - iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); |
| 146 | - |
| 147 | - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || |
| 148 | - nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
| 149 | - iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); |
| 150 | + bcm47xx_fill_sprom(&iv->sprom); |
| 151 | + |
| 152 | + if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0 || |
| 153 | + cfe_getenv("cardbus", buf, sizeof(buf)) >= 0) |
| 154 | + iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); |
| 155 | |
| 156 | return 0; |
| 157 | } |
target/linux/brcm47xx/patches-2.6.35/022-USB-Add-ehci-ssb-driver.patch |
| 1 | From cb269cf1f97c316a5184080814a751687c72b718 Mon Sep 17 00:00:00 2001 |
| 2 | From: Hauke Mehrtens <hauke@hauke-m.de> |
| 3 | Date: Sun, 18 Jul 2010 21:29:40 +0200 |
| 4 | Subject: [PATCH 2/2] USB: Add ehci ssb driver |
| 5 | |
| 6 | Support for the Sonics Silicon Backplane (SSB) attached Broadcom USB EHCI core. |
| 7 | |
| 8 | Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> |
| 9 | --- |
| 10 | drivers/usb/host/Kconfig | 13 ++ |
| 11 | drivers/usb/host/ehci-hcd.c | 23 ++++- |
| 12 | drivers/usb/host/ehci-ssb.c | 258 +++++++++++++++++++++++++++++++++++++++++++ |
| 13 | 3 files changed, 292 insertions(+), 2 deletions(-) |
| 14 | create mode 100644 drivers/usb/host/ehci-ssb.c |
| 15 | |
| 16 | --- a/drivers/usb/host/Kconfig |
| 17 | @@ -150,6 +150,19 @@ config USB_OXU210HP_HCD |
| 18 | To compile this driver as a module, choose M here: the |
| 19 | module will be called oxu210hp-hcd. |
| 20 | |
| 21 | +config USB_EHCI_HCD_SSB |
| 22 | + bool "EHCI support for Broadcom SSB EHCI core" |
| 23 | + depends on USB_EHCI_HCD && (SSB = y || SSB = USB_EHCI_HCD) && EXPERIMENTAL |
| 24 | + default n |
| 25 | + ---help--- |
| 26 | + Support for the Sonics Silicon Backplane (SSB) attached |
| 27 | + Broadcom USB EHCI core. |
| 28 | + |
| 29 | + This device is present in some embedded devices with |
| 30 | + Broadcom based SSB bus. |
| 31 | + |
| 32 | + If unsure, say N. |
| 33 | + |
| 34 | config USB_ISP116X_HCD |
| 35 | tristate "ISP116X HCD support" |
| 36 | depends on USB |
| 37 | --- a/drivers/usb/host/ehci-hcd.c |
| 38 | @@ -1158,9 +1158,14 @@ MODULE_LICENSE ("GPL"); |
| 39 | #define PLATFORM_DRIVER ehci_atmel_driver |
| 40 | #endif |
| 41 | |
| 42 | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
| 43 | +#include "ehci-ssb.c" |
| 44 | +#define SSB_EHCI_DRIVER ssb_ehci_driver |
| 45 | +#endif |
| 46 | + |
| 47 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
| 48 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
| 49 | - !defined(XILINX_OF_PLATFORM_DRIVER) |
| 50 | + !defined(XILINX_OF_PLATFORM_DRIVER) && !defined(SSB_EHCI_DRIVER) |
| 51 | #error "missing bus glue for ehci-hcd" |
| 52 | #endif |
| 53 | |
| 54 | @@ -1220,10 +1225,21 @@ static int __init ehci_hcd_init(void) |
| 55 | if (retval < 0) |
| 56 | goto clean4; |
| 57 | #endif |
| 58 | + |
| 59 | +#ifdef SSB_EHCI_DRIVER |
| 60 | + retval = ssb_driver_register(&SSB_EHCI_DRIVER); |
| 61 | + if (retval < 0) |
| 62 | + goto clean5; |
| 63 | +#endif |
| 64 | + |
| 65 | return retval; |
| 66 | |
| 67 | +#ifdef SSB_EHCI_DRIVER |
| 68 | + /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */ |
| 69 | +clean5: |
| 70 | +#endif |
| 71 | #ifdef XILINX_OF_PLATFORM_DRIVER |
| 72 | - /* of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); */ |
| 73 | + of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); |
| 74 | clean4: |
| 75 | #endif |
| 76 | #ifdef OF_PLATFORM_DRIVER |
| 77 | @@ -1254,6 +1270,9 @@ module_init(ehci_hcd_init); |
| 78 | |
| 79 | static void __exit ehci_hcd_cleanup(void) |
| 80 | { |
| 81 | +#ifdef SSB_EHCI_DRIVER |
| 82 | + ssb_driver_unregister(&SSB_EHCI_DRIVER); |
| 83 | +#endif |
| 84 | #ifdef XILINX_OF_PLATFORM_DRIVER |
| 85 | of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); |
| 86 | #endif |
| 87 | --- /dev/null |
| 88 | @@ -0,0 +1,258 @@ |
| 89 | +/* |
| 90 | + * Sonics Silicon Backplane |
| 91 | + * Broadcom USB-core EHCI driver (SSB bus glue) |
| 92 | + * |
| 93 | + * Copyright 2007 Steven Brown <sbrown@cortland.com> |
| 94 | + * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de> |
| 95 | + * |
| 96 | + * Derived from the OHCI-SSB driver |
| 97 | + * Copyright 2007 Michael Buesch <mb@bu3sch.de> |
| 98 | + * |
| 99 | + * Derived from the EHCI-PCI driver |
| 100 | + * Copyright (c) 2000-2004 by David Brownell |
| 101 | + * |
| 102 | + * Derived from the OHCI-PCI driver |
| 103 | + * Copyright 1999 Roman Weissgaerber |
| 104 | + * Copyright 2000-2002 David Brownell |
| 105 | + * Copyright 1999 Linus Torvalds |
| 106 | + * Copyright 1999 Gregory P. Smith |
| 107 | + * |
| 108 | + * Derived from the USBcore related parts of Broadcom-SB |
| 109 | + * Copyright 2005 Broadcom Corporation |
| 110 | + * |
| 111 | + * Licensed under the GNU/GPL. See COPYING for details. |
| 112 | + */ |
| 113 | +#include <linux/ssb/ssb.h> |
| 114 | + |
| 115 | + |
| 116 | +struct ssb_ehci_device { |
| 117 | + struct ehci_hcd ehci; /* _must_ be at the beginning. */ |
| 118 | +}; |
| 119 | + |
| 120 | +static inline |
| 121 | +struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd) |
| 122 | +{ |
| 123 | + return (struct ssb_ehci_device *)(hcd->hcd_priv); |
| 124 | +} |
| 125 | + |
| 126 | +static int ssb_ehci_reset(struct usb_hcd *hcd) |
| 127 | +{ |
| 128 | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
| 129 | + int err; |
| 130 | + |
| 131 | + ehci->caps = hcd->regs; |
| 132 | + ehci->regs = hcd->regs + |
| 133 | + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
| 134 | + |
| 135 | + dbg_hcs_params(ehci, "reset"); |
| 136 | + dbg_hcc_params(ehci, "reset"); |
| 137 | + |
| 138 | + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
| 139 | + |
| 140 | + err = ehci_halt(ehci); |
| 141 | + |
| 142 | + if (err) |
| 143 | + return err; |
| 144 | + |
| 145 | + err = ehci_init(hcd); |
| 146 | + |
| 147 | + if (err) |
| 148 | + return err; |
| 149 | + |
| 150 | + ehci_reset(ehci); |
| 151 | + |
| 152 | + return err; |
| 153 | +} |
| 154 | + |
| 155 | +static const struct hc_driver ssb_ehci_hc_driver = { |
| 156 | + .description = "ssb-usb-ehci", |
| 157 | + .product_desc = "SSB EHCI Controller", |
| 158 | + .hcd_priv_size = sizeof(struct ssb_ehci_device), |
| 159 | + |
| 160 | + .irq = ehci_irq, |
| 161 | + .flags = HCD_MEMORY | HCD_USB2, |
| 162 | + |
| 163 | + .reset = ssb_ehci_reset, |
| 164 | + .start = ehci_run, |
| 165 | + .stop = ehci_stop, |
| 166 | + .shutdown = ehci_shutdown, |
| 167 | + |
| 168 | + .urb_enqueue = ehci_urb_enqueue, |
| 169 | + .urb_dequeue = ehci_urb_dequeue, |
| 170 | + .endpoint_disable = ehci_endpoint_disable, |
| 171 | + .endpoint_reset = ehci_endpoint_reset, |
| 172 | + |
| 173 | + .get_frame_number = ehci_get_frame, |
| 174 | + |
| 175 | + .hub_status_data = ehci_hub_status_data, |
| 176 | + .hub_control = ehci_hub_control, |
| 177 | +#if defined(CONFIG_PM) |
| 178 | + .bus_suspend = ehci_bus_suspend, |
| 179 | + .bus_resume = ehci_bus_resume, |
| 180 | +#endif |
| 181 | + .relinquish_port = ehci_relinquish_port, |
| 182 | + .port_handed_over = ehci_port_handed_over, |
| 183 | + |
| 184 | + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
| 185 | +}; |
| 186 | + |
| 187 | +static void ssb_ehci_detach(struct ssb_device *dev) |
| 188 | +{ |
| 189 | + struct usb_hcd *hcd = ssb_get_drvdata(dev); |
| 190 | + if (hcd->driver->shutdown) |
| 191 | + hcd->driver->shutdown(hcd); |
| 192 | + |
| 193 | + usb_remove_hcd(hcd); |
| 194 | + iounmap(hcd->regs); |
| 195 | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
| 196 | + usb_put_hcd(hcd); |
| 197 | + ssb_device_disable(dev, 0); |
| 198 | +} |
| 199 | + |
| 200 | +static int ssb_ehci_attach(struct ssb_device *dev) |
| 201 | +{ |
| 202 | + struct ssb_ehci_device *ehcidev; |
| 203 | + struct usb_hcd *hcd; |
| 204 | + int err = -ENOMEM; |
| 205 | + u32 tmp; |
| 206 | + |
| 207 | + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || |
| 208 | + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) |
| 209 | + return -EOPNOTSUPP; |
| 210 | + |
| 211 | + /* |
| 212 | + * USB 2.0 special considerations: |
| 213 | + * |
| 214 | + * 1. Since the core supports both ehci and EHCI functions, it must |
| 215 | + * only be reset once. |
| 216 | + * |
| 217 | + * 2. In addition to the standard SSB reset sequence, the Host Control |
| 218 | + * Register must be programmed to bring the USB core and various |
| 219 | + * phy components out of reset. |
| 220 | + */ |
| 221 | + ssb_device_enable(dev, 0); |
| 222 | + ssb_write32(dev, 0x200, 0x7ff); |
| 223 | + |
| 224 | + /* Change Flush control reg */ |
| 225 | + tmp = ssb_read32(dev, 0x400); |
| 226 | + tmp &= ~8; |
| 227 | + ssb_write32(dev, 0x400, tmp); |
| 228 | + tmp = ssb_read32(dev, 0x400); |
| 229 | + |
| 230 | + /* Change Shim control reg */ |
| 231 | + tmp = ssb_read32(dev, 0x304); |
| 232 | + tmp &= ~0x100; |
| 233 | + ssb_write32(dev, 0x304, tmp); |
| 234 | + tmp = ssb_read32(dev, 0x304); |
| 235 | + |
| 236 | + udelay(1); |
| 237 | + |
| 238 | + /* Work around for 5354 failures */ |
| 239 | + if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) { |
| 240 | + /* Change syn01 reg */ |
| 241 | + tmp = 0x00fe00fe; |
| 242 | + ssb_write32(dev, 0x894, tmp); |
| 243 | + |
| 244 | + /* Change syn03 reg */ |
| 245 | + tmp = ssb_read32(dev, 0x89c); |
| 246 | + tmp |= 0x1; |
| 247 | + ssb_write32(dev, 0x89c, tmp); |
| 248 | + } |
| 249 | + |
| 250 | + hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev, |
| 251 | + dev_name(dev->dev)); |
| 252 | + if (!hcd) |
| 253 | + goto err_dev_disable; |
| 254 | + |
| 255 | + ehcidev = hcd_to_ssb_ehci(hcd); |
| 256 | + tmp = ssb_read32(dev, SSB_ADMATCH0); |
| 257 | + hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ |
| 258 | + hcd->rsrc_len = 0x100; /* ehci reg block size */ |
| 259 | + /* |
| 260 | + * start & size modified per sbutils.c |
| 261 | + */ |
| 262 | + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
| 263 | + if (!hcd->regs) |
| 264 | + goto err_put_hcd; |
| 265 | + err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); |
| 266 | + if (err) |
| 267 | + goto err_iounmap; |
| 268 | + |
| 269 | + ssb_set_drvdata(dev, hcd); |
| 270 | + |
| 271 | + return err; |
| 272 | + |
| 273 | +err_iounmap: |
| 274 | + iounmap(hcd->regs); |
| 275 | +err_put_hcd: |
| 276 | + usb_put_hcd(hcd); |
| 277 | +err_dev_disable: |
| 278 | + ssb_device_disable(dev, 0); |
| 279 | + return err; |
| 280 | +} |
| 281 | + |
| 282 | +static int ssb_ehci_probe(struct ssb_device *dev, |
| 283 | + const struct ssb_device_id *id) |
| 284 | +{ |
| 285 | + int err; |
| 286 | + u16 chipid_top; |
| 287 | + |
| 288 | + /* USBcores are only connected on embedded devices. */ |
| 289 | + chipid_top = (dev->bus->chip_id & 0xFF00); |
| 290 | + if (chipid_top != 0x4700 && chipid_top != 0x5300) |
| 291 | + return -ENODEV; |
| 292 | + |
| 293 | + /* TODO: Probably need checks here; is the core connected? */ |
| 294 | + |
| 295 | + if (usb_disabled()) |
| 296 | + return -ENODEV; |
| 297 | + |
| 298 | + err = ssb_ehci_attach(dev); |
| 299 | + |
| 300 | + return err; |
| 301 | +} |
| 302 | + |
| 303 | +static void ssb_ehci_remove(struct ssb_device *dev) |
| 304 | +{ |
| 305 | + ssb_ehci_detach(dev); |
| 306 | +} |
| 307 | + |
| 308 | +#ifdef CONFIG_PM |
| 309 | + |
| 310 | +static int ssb_ehci_suspend(struct ssb_device *dev, pm_message_t state) |
| 311 | +{ |
| 312 | + ssb_device_disable(dev, 0); |
| 313 | + |
| 314 | + return 0; |
| 315 | +} |
| 316 | + |
| 317 | +static int ssb_ehci_resume(struct ssb_device *dev) |
| 318 | +{ |
| 319 | + struct usb_hcd *hcd = ssb_get_drvdata(dev); |
| 320 | + struct ssb_ehci_device *ehcidev = hcd_to_ssb_ehci(hcd); |
| 321 | + |
| 322 | + ssb_device_enable(dev, 0); |
| 323 | + |
| 324 | + ehci_finish_controller_resume(hcd); |
| 325 | + return 0; |
| 326 | +} |
| 327 | + |
| 328 | +#else /* !CONFIG_PM */ |
| 329 | +#define ssb_ehci_suspend NULL |
| 330 | +#define ssb_ehci_resume NULL |
| 331 | +#endif /* CONFIG_PM */ |
| 332 | + |
| 333 | +static const struct ssb_device_id ssb_ehci_table[] = { |
| 334 | + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), |
| 335 | + SSB_DEVTABLE_END |
| 336 | +}; |
| 337 | +MODULE_DEVICE_TABLE(ssb, ssb_ehci_table); |
| 338 | + |
| 339 | +static struct ssb_driver ssb_ehci_driver = { |
| 340 | + .name = KBUILD_MODNAME, |
| 341 | + .id_table = ssb_ehci_table, |
| 342 | + .probe = ssb_ehci_probe, |
| 343 | + .remove = ssb_ehci_remove, |
| 344 | + .suspend = ssb_ehci_suspend, |
| 345 | + .resume = ssb_ehci_resume, |
| 346 | +}; |
target/linux/brcm47xx/patches-2.6.35/270-ehci-ssb.patch |
1 | | drivers/usb/host/Kconfig | 13 ++ |
2 | | drivers/usb/host/ehci-hcd.c | 12 ++ |
3 | | drivers/usb/host/ehci-ssb.c | 201 ++++++++++++++++++++++++++++++++++++++++++++ |
4 | | drivers/usb/host/ohci-ssb.c | 23 +++++ |
5 | | 4 files changed, 247 insertions(+), 2 deletions(-) |
6 | | |
7 | | +++ b/drivers/usb/host/Kconfig |
8 | | @@ -150,6 +150,19 @@ config USB_OXU210HP_HCD |
9 | | To compile this driver as a module, choose M here: the |
10 | | module will be called oxu210hp-hcd. |
11 | | |
12 | | +config USB_EHCI_HCD_SSB |
13 | | + bool "EHCI support for Broadcom SSB EHCI core" |
14 | | + depends on USB_EHCI_HCD && SSB && EXPERIMENTAL |
15 | | + default n |
16 | | + ---help--- |
17 | | + Support for the Sonics Silicon Backplane (SSB) attached |
18 | | + Broadcom USB EHCI core. |
19 | | + |
20 | | + This device is present in some embedded devices with |
21 | | + Broadcom based SSB bus. |
22 | | + |
23 | | + If unsure, say N. |
24 | | + |
25 | | config USB_ISP116X_HCD |
26 | | tristate "ISP116X HCD support" |
27 | | depends on USB |
28 | | +++ b/drivers/usb/host/ehci-hcd.c |
29 | | @@ -1158,6 +1158,11 @@ MODULE_LICENSE ("GPL"); |
30 | | #define PLATFORM_DRIVER ehci_atmel_driver |
31 | | #endif |
32 | | |
33 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
34 | | +#include "ehci-ssb.c" |
35 | | +#define SSB_EHCI_DRIVER ssb_ehci_driver |
36 | | +#endif |
37 | | + |
38 | | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
39 | | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
40 | | !defined(XILINX_OF_PLATFORM_DRIVER) |
41 | | +++ b/drivers/usb/host/ehci-ssb.c |
42 | | @@ -0,0 +1,158 @@ |
43 | | +/* |
44 | | + * Sonics Silicon Backplane |
45 | | + * Broadcom USB-core EHCI driver (SSB bus glue) |
46 | | + * |
47 | | + * Copyright 2007 Steven Brown <sbrown@cortland.com> |
48 | | + * |
49 | | + * Derived from the OHCI-SSB driver |
50 | | + * Copyright 2007 Michael Buesch <mb@bu3sch.de> |
51 | | + * |
52 | | + * Derived from the EHCI-PCI driver |
53 | | + * Copyright (c) 2000-2004 by David Brownell |
54 | | + * |
55 | | + * Derived from the OHCI-PCI driver |
56 | | + * Copyright 1999 Roman Weissgaerber |
57 | | + * Copyright 2000-2002 David Brownell |
58 | | + * Copyright 1999 Linus Torvalds |
59 | | + * Copyright 1999 Gregory P. Smith |
60 | | + * |
61 | | + * Derived from the USBcore related parts of Broadcom-SB |
62 | | + * Copyright 2005 Broadcom Corporation |
63 | | + * |
64 | | + * Licensed under the GNU/GPL. See COPYING for details. |
65 | | + */ |
66 | | +#include <linux/ssb/ssb.h> |
67 | | + |
68 | | +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) |
69 | | + |
70 | | +struct ssb_ehci_device { |
71 | | + struct ehci_hcd ehci; /* _must_ be at the beginning. */ |
72 | | + |
73 | | + u32 enable_flags; |
74 | | +}; |
75 | | + |
76 | | +static inline |
77 | | +struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd) |
78 | | +{ |
79 | | + return (struct ssb_ehci_device *)(hcd->hcd_priv); |
80 | | +} |
81 | | + |
82 | | +static int ssb_ehci_reset(struct usb_hcd *hcd) |
83 | | +{ |
84 | | + struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
85 | | + int err; |
86 | | + |
87 | | + ehci->caps = hcd->regs; |
88 | | + ehci->regs = hcd->regs + |
89 | | + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
90 | | + |
91 | | + dbg_hcs_params(ehci, "reset"); |
92 | | + dbg_hcc_params(ehci, "reset"); |
93 | | + |
94 | | + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
95 | | + |
96 | | + err = ehci_halt(ehci); |
97 | | + |
98 | | + if (err) |
99 | | + return err; |
100 | | + |
101 | | + err = ehci_init(hcd); |
102 | | + |
103 | | + if (err) |
104 | | + return err; |
105 | | + |
106 | | + ehci_reset(ehci); |
107 | | + |
108 | | + return err; |
109 | | +} |
110 | | + |
111 | | +static const struct hc_driver ssb_ehci_hc_driver = { |
112 | | + .description = "ssb-usb-ehci", |
113 | | + .product_desc = "SSB EHCI Controller", |
114 | | + .hcd_priv_size = sizeof(struct ssb_ehci_device), |
115 | | + |
116 | | + .irq = ehci_irq, |
117 | | + .flags = HCD_MEMORY | HCD_USB2, |
118 | | + |
119 | | + .reset = ssb_ehci_reset, |
120 | | + .start = ehci_run, |
121 | | + .stop = ehci_stop, |
122 | | + .shutdown = ehci_shutdown, |
123 | | + |
124 | | + .urb_enqueue = ehci_urb_enqueue, |
125 | | + .urb_dequeue = ehci_urb_dequeue, |
126 | | + .endpoint_disable = ehci_endpoint_disable, |
127 | | + .endpoint_reset = ehci_endpoint_reset, |
128 | | + |
129 | | + .get_frame_number = ehci_get_frame, |
130 | | + |
131 | | + .hub_status_data = ehci_hub_status_data, |
132 | | + .hub_control = ehci_hub_control, |
133 | | + .bus_suspend = ehci_bus_suspend, |
134 | | + .bus_resume = ehci_bus_resume, |
135 | | + .relinquish_port = ehci_relinquish_port, |
136 | | + .port_handed_over = ehci_port_handed_over, |
137 | | + |
138 | | + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
139 | | +}; |
140 | | + |
141 | | +static void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd) |
142 | | +{ |
143 | | + if (hcd->driver->shutdown) |
144 | | + hcd->driver->shutdown(hcd); |
145 | | + |
146 | | + usb_remove_hcd(hcd); |
147 | | + |
148 | | + iounmap(hcd->regs); |
149 | | + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
150 | | + |
151 | | + usb_put_hcd(hcd); |
152 | | +} |
153 | | +EXPORT_SYMBOL_GPL(ssb_ehci_detach); |
154 | | + |
155 | | +static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd) |
156 | | +{ |
157 | | + struct ssb_ehci_device *ehcidev; |
158 | | + struct usb_hcd *hcd; |
159 | | + int err = -ENOMEM; |
160 | | + u32 tmp, flags = 0; |
161 | | + |
162 | | + hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev, |
163 | | + dev_name(dev->dev)); |
164 | | + if (!hcd) |
165 | | + goto err_dev_disable; |
166 | | + |
167 | | + ehcidev = hcd_to_ssb_ehci(hcd); |
168 | | + ehcidev->enable_flags = flags; |
169 | | + tmp = ssb_read32(dev, SSB_ADMATCH0); |
170 | | + hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ |
171 | | + hcd->rsrc_len = 0x100; /* ehci reg block size */ |
172 | | + /* |
173 | | + * start & size modified per sbutils.c |
174 | | + */ |
175 | | + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
176 | | + if (!hcd->regs) |
177 | | + goto err_put_hcd; |
178 | | + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED | IRQF_DISABLED); |
179 | | + if (err) |
180 | | + goto err_iounmap; |
181 | | + |
182 | | + *ehci_hcd = hcd; |
183 | | + |
184 | | + return err; |
185 | | + |
186 | | +err_iounmap: |
187 | | + iounmap(hcd->regs); |
188 | | +err_put_hcd: |
189 | | + usb_put_hcd(hcd); |
190 | | +err_dev_disable: |
191 | | + ssb_device_disable(dev, flags); |
192 | | + return err; |
193 | | +} |
194 | | +EXPORT_SYMBOL_GPL(ssb_ehci_attach); |
195 | | + |
196 | | +static const struct ssb_device_id ssb_ehci_table[] = { |
197 | | + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), |
198 | | + SSB_DEVTABLE_END |
199 | | +}; |
200 | | +MODULE_DEVICE_TABLE(ssb, ssb_ehci_table); |
201 | | +++ b/drivers/usb/host/ohci-ssb.c |
202 | | @@ -17,6 +17,8 @@ |
203 | | */ |
204 | | #include <linux/ssb/ssb.h> |
205 | | |
206 | | +extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd); |
207 | | +extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd); |
208 | | |
209 | | #define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) |
210 | | |
211 | | @@ -24,6 +26,7 @@ struct ssb_ohci_device { |
212 | | struct ohci_hcd ohci; /* _must_ be at the beginning. */ |
213 | | |
214 | | u32 enable_flags; |
215 | | + struct usb_hcd *ehci_hcd; |
216 | | }; |
217 | | |
218 | | static inline |
219 | | @@ -92,13 +95,25 @@ static const struct hc_driver ssb_ohci_h |
220 | | static void ssb_ohci_detach(struct ssb_device *dev) |
221 | | { |
222 | | struct usb_hcd *hcd = ssb_get_drvdata(dev); |
223 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
224 | | + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); |
225 | | +#endif |
226 | | |
227 | | usb_remove_hcd(hcd); |
228 | | iounmap(hcd->regs); |
229 | | usb_put_hcd(hcd); |
230 | | + |
231 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
232 | | + /* |
233 | | + * Also detach ehci function |
234 | | + */ |
235 | | + if (dev->id.coreid == SSB_DEV_USB20_HOST) |
236 | | + ssb_ehci_detach(dev, ohcidev->ehci_hcd); |
237 | | +#endif |
238 | | ssb_device_disable(dev, 0); |
239 | | } |
240 | | |
241 | | + |
242 | | static int ssb_ohci_attach(struct ssb_device *dev) |
243 | | { |
244 | | struct ssb_ohci_device *ohcidev; |
245 | | @@ -165,6 +180,14 @@ static int ssb_ohci_attach(struct ssb_de |
246 | | |
247 | | ssb_set_drvdata(dev, hcd); |
248 | | |
249 | | +#ifdef CONFIG_USB_EHCI_HCD_SSB |
250 | | + /* |
251 | | + * attach ehci function in this core |
252 | | + */ |
253 | | + if (dev->id.coreid == SSB_DEV_USB20_HOST) |
254 | | + err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd)); |
255 | | +#endif |
256 | | + |
257 | | return err; |
258 | | |
259 | | err_iounmap: |
target/linux/brcm47xx/patches-2.6.35/400-arch-bcm47xx.patch |
1 | | +++ b/arch/mips/Kconfig |
2 | | @@ -62,6 +62,7 @@ config BCM47XX |
3 | | select SSB_DRIVER_MIPS |
4 | | select SSB_DRIVER_EXTIF |
5 | | select SSB_EMBEDDED |
6 | | + select SSB_B43_PCI_BRIDGE if PCI |
7 | | select SSB_PCICORE_HOSTMODE if PCI |
8 | | select GENERIC_GPIO |
9 | | select SYS_HAS_EARLY_PRINTK |
10 | | +++ b/arch/mips/bcm47xx/Makefile |
11 | | @@ -3,4 +3,4 @@ |
12 | | # under Linux. |
13 | | # |
14 | | |
15 | | -obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o |
16 | | +obj-y := cfe_env.o gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o |
17 | | +++ b/arch/mips/bcm47xx/irq.c |
18 | | @@ -1,5 +1,6 @@ |
19 | | /* |
20 | | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
21 | | + * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de> |
22 | | * |
23 | | * This program is free software; you can redistribute it and/or modify it |
24 | | * under the terms of the GNU General Public License as published by the |
25 | | @@ -23,10 +24,19 @@ |
26 | | */ |
27 | | |
28 | | #include <linux/types.h> |
29 | | +#include <linux/errno.h> |
30 | | +#include <linux/init.h> |
31 | | #include <linux/interrupt.h> |
32 | | #include <linux/irq.h> |
33 | | +#include <linux/pci.h> |
34 | | +#include <linux/ssb/ssb.h> |
35 | | + |
36 | | #include <asm/irq_cpu.h> |
37 | | |
38 | | + |
39 | | +extern struct ssb_bus ssb_bcm47xx; |
40 | | + |
41 | | + |
42 | | void plat_irq_dispatch(void) |
43 | | { |
44 | | u32 cause; |
45 | 1 | --- a/arch/mips/bcm47xx/nvram.c |
46 | 2 | +++ b/arch/mips/bcm47xx/nvram.c |
47 | | @@ -24,10 +24,10 @@ |
48 | | #include <asm/io.h> |
49 | | #include <asm/uaccess.h> |
50 | | |
51 | | -#include <nvram.h> |
52 | | +#include "include/nvram.h" |
53 | | |
54 | | #define MB * 1048576 |
55 | | -extern struct ssb_bus ssb; |
56 | | +extern struct ssb_bus ssb_bcm47xx; |
57 | | |
58 | | static char nvram_buf[NVRAM_SPACE]; |
59 | | static int cfe_env; |
60 | | @@ -36,7 +36,7 @@ extern char *cfe_env_get(char *nv_buf, c |
61 | | /* Probe for NVRAM header */ |
62 | | static void __init early_nvram_init(void) |
63 | | { |
64 | | - struct ssb_mipscore *mcore = &ssb.mipscore; |
65 | | + struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
66 | | struct nvram_header *header; |
67 | | int i; |
68 | | u32 base, lim, off; |
69 | | +++ b/arch/mips/bcm47xx/setup.c |
70 | | @@ -2,7 +2,7 @@ |
71 | | * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> |
72 | | * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
73 | | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
74 | | - * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de> |
75 | | + * Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de> |
76 | | * |
77 | | * This program is free software; you can redistribute it and/or modify it |
78 | | * under the terms of the GNU General Public License as published by the |
79 | | @@ -25,18 +25,28 @@ |
80 | | * 675 Mass Ave, Cambridge, MA 02139, USA. |
81 | | */ |
82 | | |
83 | | +#include <linux/init.h> |
84 | | #include <linux/types.h> |
85 | | #include <linux/ssb/ssb.h> |
86 | | #include <linux/ssb/ssb_embedded.h> |
87 | | +#include <linux/tty.h> |
88 | | +#include <linux/serial.h> |
89 | | +#include <linux/serial_core.h> |
90 | | +#include <linux/serial_reg.h> |
91 | | +#include <linux/serial_8250.h> |
92 | | #include <asm/bootinfo.h> |
93 | | #include <asm/reboot.h> |
94 | | #include <asm/time.h> |
95 | | -#include <bcm47xx.h> |
96 | | #include <asm/fw/cfe/cfe_api.h> |
97 | | +#include <linux/pm.h> |
98 | | + |
99 | | +#include "include/nvram.h" |
100 | | |
101 | | struct ssb_bus ssb_bcm47xx; |
102 | | EXPORT_SYMBOL(ssb_bcm47xx); |
103 | | |
104 | | +extern void bcm47xx_pci_init(void); |
105 | | + |
106 | | static void bcm47xx_machine_restart(char *command) |
107 | | { |
108 | | printk(KERN_ALERT "Please stand by while rebooting the system...\n"); |
109 | | @@ -56,7 +66,7 @@ static void bcm47xx_machine_halt(void) |
110 | | cpu_relax(); |
111 | | } |
112 | | |
113 | | -static void str2eaddr(char *str, char *dest) |
114 | | +static void e_aton(char *str, char *dest) |
115 | | { |
116 | | int i = 0; |
117 | | |
118 | | @@ -73,51 +83,142 @@ static void str2eaddr(char *str, char *d |
119 | | } |
| 3 | @@ -92,3 +92,30 @@ int nvram_getenv(char *name, char *val, |
| 4 | return 1; |
120 | 5 | } |
121 | | |
122 | | -static int bcm47xx_get_invariants(struct ssb_bus *bus, |
123 | | - struct ssb_init_invariants *iv) |
124 | | +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) |
125 | | +{ |
126 | | + char *s; |
127 | | + |
128 | | + memset(sprom, 0xFF, sizeof(struct ssb_sprom)); |
129 | | + |
130 | | + sprom->revision = 1; |
131 | | + if ((s = nvram_get("il0macaddr"))) |
132 | | + e_aton(s, sprom->il0mac); |
133 | | + if ((s = nvram_get("et0macaddr"))) |
134 | | + e_aton(s, sprom->et0mac); |
135 | | + if ((s = nvram_get("et1macaddr"))) |
136 | | + e_aton(s, sprom->et1mac); |
137 | | + if ((s = nvram_get("et0phyaddr"))) |
138 | | + sprom->et0phyaddr = simple_strtoul(s, NULL, 0); |
139 | | + if ((s = nvram_get("et1phyaddr"))) |
140 | | + sprom->et1phyaddr = simple_strtoul(s, NULL, 0); |
141 | | + if ((s = nvram_get("et0mdcport"))) |
142 | | + sprom->et0mdcport = !!simple_strtoul(s, NULL, 10); |
143 | | + if ((s = nvram_get("et1mdcport"))) |
144 | | + sprom->et1mdcport = !!simple_strtoul(s, NULL, 10); |
145 | | + if ((s = nvram_get("pa0b0"))) |
146 | | + sprom->pa0b0 = simple_strtoul(s, NULL, 0); |
147 | | + if ((s = nvram_get("pa0b1"))) |
148 | | + sprom->pa0b1 = simple_strtoul(s, NULL, 0); |
149 | | + if ((s = nvram_get("pa0b2"))) |
150 | | + sprom->pa0b2 = simple_strtoul(s, NULL, 0); |
151 | | + if ((s = nvram_get("pa1b0"))) |
152 | | + sprom->pa1b0 = simple_strtoul(s, NULL, 0); |
153 | | + if ((s = nvram_get("pa1b1"))) |
154 | | + sprom->pa1b1 = simple_strtoul(s, NULL, 0); |
155 | | + if ((s = nvram_get("pa1b2"))) |
156 | | + sprom->pa1b2 = simple_strtoul(s, NULL, 0); |
157 | | + if ((s = nvram_get("wl0gpio0"))) |
158 | | + sprom->gpio0 = simple_strtoul(s, NULL, 0); |
159 | | + if ((s = nvram_get("wl0gpio1"))) |
160 | | + sprom->gpio1 = simple_strtoul(s, NULL, 0); |
161 | | + if ((s = nvram_get("wl0gpio2"))) |
162 | | + sprom->gpio2 = simple_strtoul(s, NULL, 0); |
163 | | + if ((s = nvram_get("wl0gpio3"))) |
164 | | + sprom->gpio3 = simple_strtoul(s, NULL, 0); |
165 | | + if ((s = nvram_get("pa0maxpwr"))) |
166 | | + sprom->maxpwr_bg = simple_strtoul(s, NULL, 0); |
167 | | + if ((s = nvram_get("pa1maxpwr"))) |
168 | | + sprom->maxpwr_a = simple_strtoul(s, NULL, 0); |
169 | | + if ((s = nvram_get("pa0itssit"))) |
170 | | + sprom->itssi_bg = simple_strtoul(s, NULL, 0); |
171 | | + if ((s = nvram_get("pa1itssit"))) |
172 | | + sprom->itssi_a = simple_strtoul(s, NULL, 0); |
173 | | + sprom->boardflags_lo = 0; |
174 | | + if ((s = nvram_get("boardflags"))) |
175 | | + sprom->boardflags_lo = simple_strtoul(s, NULL, 0); |
176 | | + sprom->boardflags_hi = 0; |
177 | | + if ((s = nvram_get("boardflags2"))) |
178 | | + sprom->boardflags_hi = simple_strtoul(s, NULL, 0); |
179 | | +} |
| 6 | EXPORT_SYMBOL(nvram_getenv); |
180 | 7 | + |
181 | | +static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) |
182 | | { |
183 | | - char buf[100]; |
184 | | + char *s; |
185 | | + |
186 | | + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; |
187 | | + if ((s = nvram_get("boardtype"))) |
188 | | + iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0); |
189 | | + if ((s = nvram_get("boardrev"))) |
190 | | + iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0); |
191 | | |
192 | | - /* Fill boardinfo structure */ |
193 | | - memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); |
194 | | + bcm47xx_fill_sprom(&iv->sprom); |
195 | | |
196 | | - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0) |
197 | | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
198 | | - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) |
199 | | - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); |
200 | | - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) |
201 | | - iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); |
202 | | - |
203 | | - /* Fill sprom structure */ |
204 | | - memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); |
205 | | - iv->sprom.revision = 3; |
206 | | - |
207 | | - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) |
208 | | - str2eaddr(buf, iv->sprom.et0mac); |
209 | | - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) |
210 | | - str2eaddr(buf, iv->sprom.et1mac); |
211 | | - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) |
212 | | - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10); |
213 | | - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) |
214 | | - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10); |
215 | | - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) |
216 | | - iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); |
217 | | - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) |
218 | | - iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); |
219 | | + if ((s = nvram_get("cardbus"))) |
220 | | + iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10); |
221 | | |
222 | | return 0; |
223 | | } |
224 | | |
225 | | void __init plat_mem_setup(void) |
226 | | { |
227 | | - int err; |
228 | | + int i, err; |
229 | | + char *s; |
230 | | + struct ssb_mipscore *mcore; |
231 | | + |
232 | | + err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants); |
233 | | + if (err) { |
234 | | + const char *msg = "Failed to initialize SSB bus (err %d)\n"; |
235 | | + printk(msg, err); /* Make sure the message gets out of the box. */ |
236 | | + panic(msg, err); |
237 | | + } |
238 | | + mcore = &ssb_bcm47xx.mipscore; |
239 | | |
240 | | - err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, |
241 | | - bcm47xx_get_invariants); |
242 | | - if (err) |
243 | | - panic("Failed to initialize SSB bus (err %d)\n", err); |
244 | | + s = nvram_get("kernel_args"); |
245 | | + if (s && !strncmp(s, "console=ttyS1", 13)) { |
246 | | + struct ssb_serial_port port; |
247 | | + |
248 | | + printk("Swapping serial ports!\n"); |
249 | | + /* swap serial ports */ |
250 | | + memcpy(&port, &mcore->serial_ports[0], sizeof(port)); |
251 | | + memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port)); |
252 | | + memcpy(&mcore->serial_ports[1], &port, sizeof(port)); |
| 8 | +char *nvram_get(const char *name) |
| 9 | +{ |
| 10 | + char *var, *value, *end, *eq; |
| 11 | + |
| 12 | + if (!name) |
| 13 | + return NULL; |
| 14 | + |
| 15 | + if (!nvram_buf[0]) |
| 16 | + early_nvram_init(); |
| 17 | + |
| 18 | + /* Look for name=value and return value */ |
| 19 | + var = &nvram_buf[sizeof(struct nvram_header)]; |
| 20 | + end = nvram_buf + sizeof(nvram_buf) - 2; |
| 21 | + end[0] = end[1] = '\0'; |
| 22 | + for (; *var; var = value + strlen(value) + 1) { |
| 23 | + if (!(eq = strchr(var, '='))) |
| 24 | + break; |
| 25 | + value = eq + 1; |
| 26 | + if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) |
| 27 | + return value; |
253 | 28 | + } |
254 | 29 | + |
255 | | + for (i = 0; i < mcore->nr_serial_ports; i++) { |
256 | | + struct ssb_serial_port *port = &(mcore->serial_ports[i]); |
257 | | + struct uart_port s; |
258 | | + |
259 | | + memset(&s, 0, sizeof(s)); |
260 | | + s.line = i; |
261 | | + s.mapbase = (unsigned int) port->regs; |
262 | | + s.membase = port->regs; |
263 | | + s.irq = port->irq + 2; |
264 | | + s.uartclk = port->baud_base; |
265 | | + s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; |
266 | | + s.iotype = SERIAL_IO_MEM; |
267 | | + s.regshift = port->reg_shift; |
| 30 | + return NULL; |
| 31 | +} |
268 | 32 | + |
269 | | + early_serial_setup(&s); |
270 | | + } |
271 | | + printk("Serial init done.\n"); |
272 | | |
273 | | _machine_restart = bcm47xx_machine_restart; |
| 33 | +EXPORT_SYMBOL(nvram_get); |
| 34 | --- a/arch/mips/bcm47xx/setup.c |
| 35 | @@ -226,3 +226,20 @@ void __init plat_mem_setup(void) |
274 | 36 | _machine_halt = bcm47xx_machine_halt; |
275 | 37 | pm_power_off = bcm47xx_machine_halt; |
276 | 38 | } |
... | ... | |
295 | 54 | + return 0; |
296 | 55 | +} |
297 | 56 | +device_initcall(bcm47xx_register_gpiodev); |
298 | | +++ b/arch/mips/bcm47xx/time.c |
299 | | @@ -22,11 +22,17 @@ |
300 | | * 675 Mass Ave, Cambridge, MA 02139, USA. |
301 | | */ |
302 | | |
303 | | - |
304 | | #include <linux/init.h> |
305 | | +#include <linux/kernel.h> |
306 | | +#include <linux/sched.h> |
307 | | +#include <linux/serial_reg.h> |
308 | | +#include <linux/interrupt.h> |
309 | | #include <linux/ssb/ssb.h> |
310 | | +#include <asm/addrspace.h> |
311 | | +#include <asm/io.h> |
312 | | #include <asm/time.h> |
313 | | -#include <bcm47xx.h> |
314 | | + |
315 | | +extern struct ssb_bus ssb_bcm47xx; |
316 | | |
317 | | void __init plat_time_init(void) |
318 | | { |
target/linux/brcm47xx/patches-2.6.35/700-ssb-gigabit-ethernet-driver.patch |
8 | 8 | |
9 | 9 | #include <net/checksum.h> |
10 | 10 | #include <net/ip.h> |
11 | | @@ -471,8 +472,9 @@ static void _tw32_flush(struct tg3 *tp, |
| 11 | @@ -494,8 +495,9 @@ static void _tw32_flush(struct tg3 *tp, |
12 | 12 | static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) |
13 | 13 | { |
14 | 14 | tp->write32_mbox(tp, off, val); |
... | ... | |
20 | 20 | tp->read32_mbox(tp, off); |
21 | 21 | } |
22 | 22 | |
23 | | @@ -482,7 +484,7 @@ static void tg3_write32_tx_mbox(struct t |
| 23 | @@ -505,7 +507,7 @@ static void tg3_write32_tx_mbox(struct t |
24 | 24 | writel(val, mbox); |
25 | 25 | if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) |
26 | 26 | writel(val, mbox); |
... | ... | |
29 | 29 | readl(mbox); |
30 | 30 | } |
31 | 31 | |
32 | | @@ -783,7 +785,7 @@ static void tg3_switch_clocks(struct tg3 |
| 32 | @@ -807,7 +809,7 @@ static void tg3_switch_clocks(struct tg3 |
33 | 33 | |
34 | 34 | #define PHY_BUSY_LOOPS 5000 |
35 | 35 | |
... | ... | |
38 | 38 | { |
39 | 39 | u32 frame_val; |
40 | 40 | unsigned int loops; |
41 | | @@ -797,7 +799,7 @@ static int tg3_readphy(struct tg3 *tp, i |
| 41 | @@ -821,7 +823,7 @@ static int tg3_readphy(struct tg3 *tp, i |
42 | 42 | |
43 | 43 | *val = 0x0; |
44 | 44 | |
... | ... | |
47 | 47 | MI_COM_PHY_ADDR_MASK); |
48 | 48 | frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & |
49 | 49 | MI_COM_REG_ADDR_MASK); |
50 | | @@ -832,7 +834,12 @@ static int tg3_readphy(struct tg3 *tp, i |
| 50 | @@ -856,7 +858,12 @@ static int tg3_readphy(struct tg3 *tp, i |
51 | 51 | return ret; |
52 | 52 | } |
53 | 53 | |
... | ... | |
61 | 61 | { |
62 | 62 | u32 frame_val; |
63 | 63 | unsigned int loops; |
64 | | @@ -848,7 +855,7 @@ static int tg3_writephy(struct tg3 *tp, |
| 64 | @@ -872,7 +879,7 @@ static int tg3_writephy(struct tg3 *tp, |
65 | 65 | udelay(80); |
66 | 66 | } |
67 | 67 | |
... | ... | |
70 | 70 | MI_COM_PHY_ADDR_MASK); |
71 | 71 | frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & |
72 | 72 | MI_COM_REG_ADDR_MASK); |
73 | | @@ -881,6 +888,11 @@ static int tg3_writephy(struct tg3 *tp, |
| 73 | @@ -905,6 +912,11 @@ static int tg3_writephy(struct tg3 *tp, |
74 | 74 | return ret; |
75 | 75 | } |
76 | 76 | |
... | ... | |
82 | 82 | static int tg3_bmcr_reset(struct tg3 *tp) |
83 | 83 | { |
84 | 84 | u32 phy_control; |
85 | | @@ -2389,6 +2401,9 @@ static int tg3_nvram_read(struct tg3 *tp |
| 85 | @@ -2411,6 +2423,9 @@ static int tg3_nvram_read(struct tg3 *tp |
86 | 86 | { |
87 | 87 | int ret; |
88 | 88 | |
... | ... | |
92 | 92 | if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) |
93 | 93 | return tg3_nvram_read_using_eeprom(tp, offset, val); |
94 | 94 | |
95 | | @@ -2720,8 +2735,10 @@ static int tg3_set_power_state(struct tg |
| 95 | @@ -2742,8 +2757,10 @@ static int tg3_set_power_state(struct tg |
96 | 96 | tg3_frob_aux_power(tp); |
97 | 97 | |
98 | 98 | /* Workaround for unstable PLL clock */ |
... | ... | |
105 | 105 | u32 val = tr32(0x7d00); |
106 | 106 | |
107 | 107 | val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); |
108 | | @@ -3214,6 +3231,14 @@ relink: |
| 108 | @@ -3236,6 +3253,14 @@ relink: |
109 | 109 | |
110 | 110 | tg3_phy_copper_begin(tp); |
111 | 111 | |
... | ... | |
120 | 120 | tg3_readphy(tp, MII_BMSR, &tmp); |
121 | 121 | if (!tg3_readphy(tp, MII_BMSR, &tmp) && |
122 | 122 | (tmp & BMSR_LSTATUS)) |
123 | | @@ -6675,6 +6700,11 @@ static int tg3_poll_fw(struct tg3 *tp) |
| 123 | @@ -6719,6 +6744,11 @@ static int tg3_poll_fw(struct tg3 *tp) |
124 | 124 | int i; |
125 | 125 | u32 val; |
126 | 126 | |
... | ... | |
132 | 132 | if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { |
133 | 133 | /* Wait up to 20ms for init done. */ |
134 | 134 | for (i = 0; i < 200; i++) { |
135 | | @@ -6958,6 +6988,14 @@ static int tg3_chip_reset(struct tg3 *tp |
| 135 | @@ -7002,6 +7032,14 @@ static int tg3_chip_reset(struct tg3 *tp |
136 | 136 | tw32(0x5000, 0x400); |
137 | 137 | } |
138 | 138 | |
... | ... | |
147 | 147 | tw32(GRC_MODE, tp->grc_mode); |
148 | 148 | |
149 | 149 | if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { |
150 | | @@ -7135,9 +7173,12 @@ static int tg3_halt_cpu(struct tg3 *tp, |
| 150 | @@ -7179,9 +7217,12 @@ static int tg3_halt_cpu(struct tg3 *tp, |
151 | 151 | return -ENODEV; |
152 | 152 | } |
153 | 153 | |
... | ... | |
163 | 163 | return 0; |
164 | 164 | } |
165 | 165 | |
166 | | @@ -7199,6 +7240,11 @@ static int tg3_load_5701_a0_firmware_fix |
| 166 | @@ -7244,6 +7285,11 @@ static int tg3_load_5701_a0_firmware_fix |
167 | 167 | const __be32 *fw_data; |
168 | 168 | int err, i; |
169 | 169 | |
... | ... | |
175 | 175 | fw_data = (void *)tp->fw->data; |
176 | 176 | |
177 | 177 | /* Firmware blob starts with version numbers, followed by |
178 | | @@ -7256,6 +7302,11 @@ static int tg3_load_tso_firmware(struct |
| 178 | @@ -7302,6 +7348,11 @@ static int tg3_load_tso_firmware(struct |
179 | 179 | unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size; |
180 | 180 | int err, i; |
181 | 181 | |
... | ... | |
187 | 187 | if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) |
188 | 188 | return 0; |
189 | 189 | |
190 | | @@ -8380,6 +8431,11 @@ static void tg3_timer(unsigned long __op |
| 190 | @@ -8446,6 +8497,11 @@ static void tg3_timer(unsigned long __op |
191 | 191 | |
192 | 192 | spin_lock(&tp->lock); |
193 | 193 | |
... | ... | |
199 | 199 | if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { |
200 | 200 | /* All of this garbage is because when using non-tagged |
201 | 201 | * IRQ status the mailbox/status_block protocol the chip |
202 | | @@ -10279,6 +10335,11 @@ static int tg3_test_nvram(struct tg3 *tp |
| 202 | @@ -10113,6 +10169,11 @@ static int tg3_test_nvram(struct tg3 *tp |
203 | 203 | if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) |
204 | 204 | return 0; |
205 | 205 | |
... | ... | |
211 | 211 | if (tg3_nvram_read(tp, 0, &magic) != 0) |
212 | 212 | return -EIO; |
213 | 213 | |
214 | | @@ -11098,7 +11159,7 @@ static int tg3_ioctl(struct net_device * |
| 214 | @@ -10932,7 +10993,7 @@ static int tg3_ioctl(struct net_device * |
215 | 215 | return -EAGAIN; |
216 | 216 | |
217 | 217 | spin_lock_bh(&tp->lock); |
... | ... | |
220 | 220 | spin_unlock_bh(&tp->lock); |
221 | 221 | |
222 | 222 | data->val_out = mii_regval; |
223 | | @@ -11114,7 +11175,7 @@ static int tg3_ioctl(struct net_device * |
| 223 | @@ -10948,7 +11009,7 @@ static int tg3_ioctl(struct net_device * |
224 | 224 | return -EAGAIN; |
225 | 225 | |
226 | 226 | spin_lock_bh(&tp->lock); |
... | ... | |
229 | 229 | spin_unlock_bh(&tp->lock); |
230 | 230 | |
231 | 231 | return err; |
232 | | @@ -11759,6 +11820,12 @@ static void __devinit tg3_get_5717_nvram |
| 232 | @@ -11593,6 +11654,12 @@ static void __devinit tg3_get_5717_nvram |
233 | 233 | /* Chips other than 5700/5701 use the NVRAM for fetching info. */ |
234 | 234 | static void __devinit tg3_nvram_init(struct tg3 *tp) |
235 | 235 | { |
... | ... | |
242 | 242 | tw32_f(GRC_EEPROM_ADDR, |
243 | 243 | (EEPROM_ADDR_FSM_RESET | |
244 | 244 | (EEPROM_DEFAULT_CLOCK_PERIOD << |
245 | | @@ -12020,6 +12087,9 @@ static int tg3_nvram_write_block(struct |
| 245 | @@ -11855,6 +11922,9 @@ static int tg3_nvram_write_block(struct |
246 | 246 | { |
247 | 247 | int ret; |
248 | 248 | |
... | ... | |
252 | 252 | if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { |
253 | 253 | tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & |
254 | 254 | ~GRC_LCLCTRL_GPIO_OUTPUT1); |
255 | | @@ -13360,6 +13430,11 @@ static int __devinit tg3_get_invariants( |
| 255 | @@ -13227,6 +13297,11 @@ static int __devinit tg3_get_invariants( |
256 | 256 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) |
257 | 257 | tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; |
258 | 258 | |
... | ... | |
264 | 264 | /* Get eeprom hw config before calling tg3_set_power_state(). |
265 | 265 | * In particular, the TG3_FLG2_IS_NIC flag must be |
266 | 266 | * determined before calling tg3_set_power_state() so that |
267 | | @@ -13753,6 +13828,10 @@ static int __devinit tg3_get_device_addr |
| 267 | @@ -13624,6 +13699,10 @@ static int __devinit tg3_get_device_addr |
268 | 268 | } |
269 | 269 | |
270 | 270 | if (!is_valid_ether_addr(&dev->dev_addr[0])) { |
... | ... | |
275 | 275 | #ifdef CONFIG_SPARC |
276 | 276 | if (!tg3_get_default_macaddr_sparc(tp)) |
277 | 277 | return 0; |
278 | | @@ -14272,6 +14351,7 @@ static char * __devinit tg3_phy_string(s |
| 278 | @@ -14144,6 +14223,7 @@ static char * __devinit tg3_phy_string(s |
279 | 279 | case TG3_PHY_ID_BCM5704: return "5704"; |
280 | 280 | case TG3_PHY_ID_BCM5705: return "5705"; |
281 | 281 | case TG3_PHY_ID_BCM5750: return "5750"; |
... | ... | |
283 | 283 | case TG3_PHY_ID_BCM5752: return "5752"; |
284 | 284 | case TG3_PHY_ID_BCM5714: return "5714"; |
285 | 285 | case TG3_PHY_ID_BCM5780: return "5780"; |
286 | | @@ -14481,6 +14561,13 @@ static int __devinit tg3_init_one(struct |
| 286 | @@ -14354,6 +14434,13 @@ static int __devinit tg3_init_one(struct |
287 | 287 | tp->msg_enable = tg3_debug; |
288 | 288 | else |
289 | 289 | tp->msg_enable = TG3_DEF_MSG_ENABLE; |
... | ... | |
309 | 309 | |
310 | 310 | #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 |
311 | 311 | |
312 | | @@ -2930,6 +2933,7 @@ struct tg3 { |
| 312 | @@ -2931,6 +2934,7 @@ struct tg3 { |
313 | 313 | #define TG3_PHY_ID_BCM5704 0x60008190 |
314 | 314 | #define TG3_PHY_ID_BCM5705 0x600081a0 |
315 | 315 | #define TG3_PHY_ID_BCM5750 0x60008180 |
... | ... | |
317 | 317 | #define TG3_PHY_ID_BCM5752 0x60008100 |
318 | 318 | #define TG3_PHY_ID_BCM5714 0x60008340 |
319 | 319 | #define TG3_PHY_ID_BCM5780 0x60008350 |
320 | | @@ -2964,7 +2968,8 @@ struct tg3 { |
| 320 | @@ -2965,7 +2969,8 @@ struct tg3 { |
321 | 321 | (X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \ |
322 | 322 | (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \ |
323 | 323 | (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \ |
target/linux/generic/patches-2.6.34/975-ssb_update.patch |
| 1 | --- a/drivers/net/b44.c |
| 2 | @@ -135,7 +135,6 @@ static void b44_init_rings(struct b44 *) |
| 3 | |
| 4 | static void b44_init_hw(struct b44 *, int); |
| 5 | |
| 6 | -static int dma_desc_align_mask; |
| 7 | static int dma_desc_sync_size; |
| 8 | static int instance; |
| 9 | |
| 10 | @@ -150,9 +149,8 @@ static inline void b44_sync_dma_desc_for |
| 11 | unsigned long offset, |
| 12 | enum dma_data_direction dir) |
| 13 | { |
| 14 | - ssb_dma_sync_single_range_for_device(sdev, dma_base, |
| 15 | - offset & dma_desc_align_mask, |
| 16 | - dma_desc_sync_size, dir); |
| 17 | + dma_sync_single_for_device(sdev->dma_dev, dma_base + offset, |
| 18 | + dma_desc_sync_size, dir); |
| 19 | } |
| 20 | |
| 21 | static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, |
| 22 | @@ -160,9 +158,8 @@ static inline void b44_sync_dma_desc_for |
| 23 | unsigned long offset, |
| 24 | enum dma_data_direction dir) |
| 25 | { |
| 26 | - ssb_dma_sync_single_range_for_cpu(sdev, dma_base, |
| 27 | - offset & dma_desc_align_mask, |
| 28 | - dma_desc_sync_size, dir); |
| 29 | + dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset, |
| 30 | + dma_desc_sync_size, dir); |
| 31 | } |
| 32 | |
| 33 | static inline unsigned long br32(const struct b44 *bp, unsigned long reg) |
| 34 | @@ -608,10 +605,10 @@ static void b44_tx(struct b44 *bp) |
| 35 | |
| 36 | BUG_ON(skb == NULL); |
| 37 | |
| 38 | - ssb_dma_unmap_single(bp->sdev, |
| 39 | - rp->mapping, |
| 40 | - skb->len, |
| 41 | - DMA_TO_DEVICE); |
| 42 | + dma_unmap_single(bp->sdev->dma_dev, |
| 43 | + rp->mapping, |
| 44 | + skb->len, |
| 45 | + DMA_TO_DEVICE); |
| 46 | rp->skb = NULL; |
| 47 | dev_kfree_skb_irq(skb); |
| 48 | } |
| 49 | @@ -648,29 +645,29 @@ static int b44_alloc_rx_skb(struct b44 * |
| 50 | if (skb == NULL) |
| 51 | return -ENOMEM; |
| 52 | |
| 53 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, |
| 54 | - RX_PKT_BUF_SZ, |
| 55 | - DMA_FROM_DEVICE); |
| 56 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, |
| 57 | + RX_PKT_BUF_SZ, |
| 58 | + DMA_FROM_DEVICE); |
| 59 | |
| 60 | /* Hardware bug work-around, the chip is unable to do PCI DMA |
| 61 | to/from anything above 1GB :-( */ |
| 62 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || |
| 63 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || |
| 64 | mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 65 | /* Sigh... */ |
| 66 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 67 | - ssb_dma_unmap_single(bp->sdev, mapping, |
| 68 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 69 | + dma_unmap_single(bp->sdev->dma_dev, mapping, |
| 70 | RX_PKT_BUF_SZ, DMA_FROM_DEVICE); |
| 71 | dev_kfree_skb_any(skb); |
| 72 | skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); |
| 73 | if (skb == NULL) |
| 74 | return -ENOMEM; |
| 75 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, |
| 76 | - RX_PKT_BUF_SZ, |
| 77 | - DMA_FROM_DEVICE); |
| 78 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || |
| 79 | - mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 80 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 81 | - ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); |
| 82 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, |
| 83 | + RX_PKT_BUF_SZ, |
| 84 | + DMA_FROM_DEVICE); |
| 85 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || |
| 86 | + mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 87 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 88 | + dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); |
| 89 | dev_kfree_skb_any(skb); |
| 90 | return -ENOMEM; |
| 91 | } |
| 92 | @@ -745,9 +742,9 @@ static void b44_recycle_rx(struct b44 *b |
| 93 | dest_idx * sizeof(*dest_desc), |
| 94 | DMA_BIDIRECTIONAL); |
| 95 | |
| 96 | - ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping, |
| 97 | - RX_PKT_BUF_SZ, |
| 98 | - DMA_FROM_DEVICE); |
| 99 | + dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping, |
| 100 | + RX_PKT_BUF_SZ, |
| 101 | + DMA_FROM_DEVICE); |
| 102 | } |
| 103 | |
| 104 | static int b44_rx(struct b44 *bp, int budget) |
| 105 | @@ -767,9 +764,9 @@ static int b44_rx(struct b44 *bp, int bu |
| 106 | struct rx_header *rh; |
| 107 | u16 len; |
| 108 | |
| 109 | - ssb_dma_sync_single_for_cpu(bp->sdev, map, |
| 110 | - RX_PKT_BUF_SZ, |
| 111 | - DMA_FROM_DEVICE); |
| 112 | + dma_sync_single_for_cpu(bp->sdev->dma_dev, map, |
| 113 | + RX_PKT_BUF_SZ, |
| 114 | + DMA_FROM_DEVICE); |
| 115 | rh = (struct rx_header *) skb->data; |
| 116 | len = le16_to_cpu(rh->len); |
| 117 | if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || |
| 118 | @@ -801,8 +798,8 @@ static int b44_rx(struct b44 *bp, int bu |
| 119 | skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); |
| 120 | if (skb_size < 0) |
| 121 | goto drop_it; |
| 122 | - ssb_dma_unmap_single(bp->sdev, map, |
| 123 | - skb_size, DMA_FROM_DEVICE); |
| 124 | + dma_unmap_single(bp->sdev->dma_dev, map, |
| 125 | + skb_size, DMA_FROM_DEVICE); |
| 126 | /* Leave out rx_header */ |
| 127 | skb_put(skb, len + RX_PKT_OFFSET); |
| 128 | skb_pull(skb, RX_PKT_OFFSET); |
| 129 | @@ -954,24 +951,24 @@ static netdev_tx_t b44_start_xmit(struct |
| 130 | goto err_out; |
| 131 | } |
| 132 | |
| 133 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE); |
| 134 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 135 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE); |
| 136 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 137 | struct sk_buff *bounce_skb; |
| 138 | |
| 139 | /* Chip can't handle DMA to/from >1GB, use bounce buffer */ |
| 140 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 141 | - ssb_dma_unmap_single(bp->sdev, mapping, len, |
| 142 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 143 | + dma_unmap_single(bp->sdev->dma_dev, mapping, len, |
| 144 | DMA_TO_DEVICE); |
| 145 | |
| 146 | bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA); |
| 147 | if (!bounce_skb) |
| 148 | goto err_out; |
| 149 | |
| 150 | - mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data, |
| 151 | - len, DMA_TO_DEVICE); |
| 152 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 153 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 154 | - ssb_dma_unmap_single(bp->sdev, mapping, |
| 155 | + mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data, |
| 156 | + len, DMA_TO_DEVICE); |
| 157 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 158 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 159 | + dma_unmap_single(bp->sdev->dma_dev, mapping, |
| 160 | len, DMA_TO_DEVICE); |
| 161 | dev_kfree_skb_any(bounce_skb); |
| 162 | goto err_out; |
| 163 | @@ -1014,8 +1011,6 @@ static netdev_tx_t b44_start_xmit(struct |
| 164 | if (TX_BUFFS_AVAIL(bp) < 1) |
| 165 | netif_stop_queue(dev); |
| 166 | |
| 167 | - dev->trans_start = jiffies; |
| 168 | - |
| 169 | out_unlock: |
| 170 | spin_unlock_irqrestore(&bp->lock, flags); |
| 171 | |
| 172 | @@ -1070,8 +1065,8 @@ static void b44_free_rings(struct b44 *b |
| 173 | |
| 174 | if (rp->skb == NULL) |
| 175 | continue; |
| 176 | - ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ, |
| 177 | - DMA_FROM_DEVICE); |
| 178 | + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ, |
| 179 | + DMA_FROM_DEVICE); |
| 180 | dev_kfree_skb_any(rp->skb); |
| 181 | rp->skb = NULL; |
| 182 | } |
| 183 | @@ -1082,8 +1077,8 @@ static void b44_free_rings(struct b44 *b |
| 184 | |
| 185 | if (rp->skb == NULL) |
| 186 | continue; |
| 187 | - ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len, |
| 188 | - DMA_TO_DEVICE); |
| 189 | + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len, |
| 190 | + DMA_TO_DEVICE); |
| 191 | dev_kfree_skb_any(rp->skb); |
| 192 | rp->skb = NULL; |
| 193 | } |
| 194 | @@ -1105,14 +1100,12 @@ static void b44_init_rings(struct b44 *b |
| 195 | memset(bp->tx_ring, 0, B44_TX_RING_BYTES); |
| 196 | |
| 197 | if (bp->flags & B44_FLAG_RX_RING_HACK) |
| 198 | - ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma, |
| 199 | - DMA_TABLE_BYTES, |
| 200 | - DMA_BIDIRECTIONAL); |
| 201 | + dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma, |
| 202 | + DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); |
| 203 | |
| 204 | if (bp->flags & B44_FLAG_TX_RING_HACK) |
| 205 | - ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma, |
| 206 | - DMA_TABLE_BYTES, |
| 207 | - DMA_TO_DEVICE); |
| 208 | + dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma, |
| 209 | + DMA_TABLE_BYTES, DMA_TO_DEVICE); |
| 210 | |
| 211 | for (i = 0; i < bp->rx_pending; i++) { |
| 212 | if (b44_alloc_rx_skb(bp, -1, i) < 0) |
| 213 | @@ -1132,27 +1125,23 @@ static void b44_free_consistent(struct b |
| 214 | bp->tx_buffers = NULL; |
| 215 | if (bp->rx_ring) { |
| 216 | if (bp->flags & B44_FLAG_RX_RING_HACK) { |
| 217 | - ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma, |
| 218 | - DMA_TABLE_BYTES, |
| 219 | - DMA_BIDIRECTIONAL); |
| 220 | + dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma, |
| 221 | + DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); |
| 222 | kfree(bp->rx_ring); |
| 223 | } else |
| 224 | - ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, |
| 225 | - bp->rx_ring, bp->rx_ring_dma, |
| 226 | - GFP_KERNEL); |
| 227 | + dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, |
| 228 | + bp->rx_ring, bp->rx_ring_dma); |
| 229 | bp->rx_ring = NULL; |
| 230 | bp->flags &= ~B44_FLAG_RX_RING_HACK; |
| 231 | } |
| 232 | if (bp->tx_ring) { |
| 233 | if (bp->flags & B44_FLAG_TX_RING_HACK) { |
| 234 | - ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma, |
| 235 | - DMA_TABLE_BYTES, |
| 236 | - DMA_TO_DEVICE); |
| 237 | + dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma, |
| 238 | + DMA_TABLE_BYTES, DMA_TO_DEVICE); |
| 239 | kfree(bp->tx_ring); |
| 240 | } else |
| 241 | - ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, |
| 242 | - bp->tx_ring, bp->tx_ring_dma, |
| 243 | - GFP_KERNEL); |
| 244 | + dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, |
| 245 | + bp->tx_ring, bp->tx_ring_dma); |
| 246 | bp->tx_ring = NULL; |
| 247 | bp->flags &= ~B44_FLAG_TX_RING_HACK; |
| 248 | } |
| 249 | @@ -1177,7 +1166,8 @@ static int b44_alloc_consistent(struct b |
| 250 | goto out_err; |
| 251 | |
| 252 | size = DMA_TABLE_BYTES; |
| 253 | - bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp); |
| 254 | + bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, |
| 255 | + &bp->rx_ring_dma, gfp); |
| 256 | if (!bp->rx_ring) { |
| 257 | /* Allocation may have failed due to pci_alloc_consistent |
| 258 | insisting on use of GFP_DMA, which is more restrictive |
| 259 | @@ -1189,11 +1179,11 @@ static int b44_alloc_consistent(struct b |
| 260 | if (!rx_ring) |
| 261 | goto out_err; |
| 262 | |
| 263 | - rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring, |
| 264 | - DMA_TABLE_BYTES, |
| 265 | - DMA_BIDIRECTIONAL); |
| 266 | + rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring, |
| 267 | + DMA_TABLE_BYTES, |
| 268 | + DMA_BIDIRECTIONAL); |
| 269 | |
| 270 | - if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) || |
| 271 | + if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) || |
| 272 | rx_ring_dma + size > DMA_BIT_MASK(30)) { |
| 273 | kfree(rx_ring); |
| 274 | goto out_err; |
| 275 | @@ -1204,7 +1194,8 @@ static int b44_alloc_consistent(struct b |
| 276 | bp->flags |= B44_FLAG_RX_RING_HACK; |
| 277 | } |
| 278 | |
| 279 | - bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp); |
| 280 | + bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, |
| 281 | + &bp->tx_ring_dma, gfp); |
| 282 | if (!bp->tx_ring) { |
| 283 | /* Allocation may have failed due to ssb_dma_alloc_consistent |
| 284 | insisting on use of GFP_DMA, which is more restrictive |
| 285 | @@ -1216,11 +1207,11 @@ static int b44_alloc_consistent(struct b |
| 286 | if (!tx_ring) |
| 287 | goto out_err; |
| 288 | |
| 289 | - tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring, |
| 290 | - DMA_TABLE_BYTES, |
| 291 | - DMA_TO_DEVICE); |
| 292 | + tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring, |
| 293 | + DMA_TABLE_BYTES, |
| 294 | + DMA_TO_DEVICE); |
| 295 | |
| 296 | - if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) || |
| 297 | + if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) || |
| 298 | tx_ring_dma + size > DMA_BIT_MASK(30)) { |
| 299 | kfree(tx_ring); |
| 300 | goto out_err; |
| 301 | @@ -2178,12 +2169,14 @@ static int __devinit b44_init_one(struct |
| 302 | "Failed to powerup the bus\n"); |
| 303 | goto err_out_free_dev; |
| 304 | } |
| 305 | - err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30)); |
| 306 | - if (err) { |
| 307 | + |
| 308 | + if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) || |
| 309 | + dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) { |
| 310 | dev_err(sdev->dev, |
| 311 | "Required 30BIT DMA mask unsupported by the system\n"); |
| 312 | goto err_out_powerdown; |
| 313 | } |
| 314 | + |
| 315 | err = b44_get_invariants(bp); |
| 316 | if (err) { |
| 317 | dev_err(sdev->dev, |
| 318 | @@ -2346,7 +2339,6 @@ static int __init b44_init(void) |
| 319 | int err; |
| 320 | |
| 321 | /* Setup paramaters for syncing RX/TX DMA descriptors */ |
| 322 | - dma_desc_align_mask = ~(dma_desc_align_size - 1); |
| 323 | dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); |
| 324 | |
| 325 | err = b44_pci_init(); |
1 | 326 | --- a/drivers/ssb/driver_chipcommon.c |
2 | 327 | +++ b/drivers/ssb/driver_chipcommon.c |
3 | | @@ -233,6 +233,8 @@ void ssb_chipcommon_init(struct ssb_chip |
| 328 | @@ -209,6 +209,24 @@ static void chipco_powercontrol_init(str |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | +/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */ |
| 333 | +static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc) |
| 334 | +{ |
| 335 | + struct ssb_bus *bus = cc->dev->bus; |
| 336 | + |
| 337 | + switch (bus->chip_id) { |
| 338 | + case 0x4312: |
| 339 | + case 0x4322: |
| 340 | + case 0x4328: |
| 341 | + return 7000; |
| 342 | + case 0x4325: |
| 343 | + /* TODO: */ |
| 344 | + default: |
| 345 | + return 15000; |
| 346 | + } |
| 347 | +} |
| 348 | + |
| 349 | +/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */ |
| 350 | static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) |
| 351 | { |
| 352 | struct ssb_bus *bus = cc->dev->bus; |
| 353 | @@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(stru |
| 354 | |
| 355 | if (bus->bustype != SSB_BUSTYPE_PCI) |
| 356 | return; |
| 357 | + |
| 358 | + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
| 359 | + cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc); |
| 360 | + return; |
| 361 | + } |
| 362 | + |
| 363 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) |
| 364 | return; |
| 365 | |
| 366 | @@ -233,6 +257,9 @@ void ssb_chipcommon_init(struct ssb_chip |
4 | 367 | { |
5 | 368 | if (!cc->dev) |
6 | 369 | return; /* We don't have a ChipCommon */ |
7 | 370 | + if (cc->dev->id.revision >= 11) |
8 | 371 | + cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); |
| 372 | + ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); |
9 | 373 | ssb_pmu_init(cc); |
10 | 374 | chipco_powercontrol_init(cc); |
11 | 375 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); |
12 | | @@ -370,6 +372,7 @@ u32 ssb_chipco_gpio_control(struct ssb_c |
| 376 | @@ -370,6 +397,7 @@ u32 ssb_chipco_gpio_control(struct ssb_c |
13 | 377 | { |
14 | 378 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); |
15 | 379 | } |
... | ... | |
17 | 382 | |
18 | 383 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) |
19 | 384 | { |
| 385 | --- a/drivers/ssb/driver_chipcommon_pmu.c |
| 386 | @@ -502,9 +502,9 @@ static void ssb_pmu_resources_init(struc |
| 387 | chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk); |
| 388 | } |
| 389 | |
| 390 | +/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */ |
| 391 | void ssb_pmu_init(struct ssb_chipcommon *cc) |
| 392 | { |
| 393 | - struct ssb_bus *bus = cc->dev->bus; |
| 394 | u32 pmucap; |
| 395 | |
| 396 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU)) |
| 397 | @@ -516,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon |
| 398 | ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n", |
| 399 | cc->pmu.rev, pmucap); |
| 400 | |
| 401 | - if (cc->pmu.rev >= 1) { |
| 402 | - if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) { |
| 403 | - chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, |
| 404 | - ~SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 405 | - } else { |
| 406 | - chipco_set32(cc, SSB_CHIPCO_PMU_CTL, |
| 407 | - SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 408 | - } |
| 409 | - } |
| 410 | + if (cc->pmu.rev == 1) |
| 411 | + chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, |
| 412 | + ~SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 413 | + else |
| 414 | + chipco_set32(cc, SSB_CHIPCO_PMU_CTL, |
| 415 | + SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 416 | ssb_pmu_pll_init(cc); |
| 417 | ssb_pmu_resources_init(cc); |
| 418 | } |
20 | 419 | --- a/drivers/ssb/main.c |
21 | 420 | +++ b/drivers/ssb/main.c |
22 | | @@ -834,6 +834,9 @@ int ssb_bus_pcibus_register(struct ssb_b |
| 421 | @@ -486,11 +486,12 @@ static int ssb_devices_register(struct s |
| 422 | #ifdef CONFIG_SSB_PCIHOST |
| 423 | sdev->irq = bus->host_pci->irq; |
| 424 | dev->parent = &bus->host_pci->dev; |
| 425 | + sdev->dma_dev = dev->parent; |
| 426 | #endif |
| 427 | break; |
| 428 | case SSB_BUSTYPE_PCMCIA: |
| 429 | #ifdef CONFIG_SSB_PCMCIAHOST |
| 430 | - sdev->irq = bus->host_pcmcia->irq.AssignedIRQ; |
| 431 | + sdev->irq = bus->host_pcmcia->irq; |
| 432 | dev->parent = &bus->host_pcmcia->dev; |
| 433 | #endif |
| 434 | break; |
| 435 | @@ -501,6 +502,7 @@ static int ssb_devices_register(struct s |
| 436 | break; |
| 437 | case SSB_BUSTYPE_SSB: |
| 438 | dev->dma_mask = &dev->coherent_dma_mask; |
| 439 | + sdev->dma_dev = dev; |
| 440 | break; |
| 441 | } |
| 442 | |
| 443 | @@ -834,6 +836,9 @@ int ssb_bus_pcibus_register(struct ssb_b |
23 | 444 | if (!err) { |
24 | 445 | ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " |
25 | 446 | "PCI device %s\n", dev_name(&host_pci->dev)); |
... | ... | |
29 | 451 | } |
30 | 452 | |
31 | 453 | return err; |
| 454 | @@ -1223,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_devic |
| 455 | } |
| 456 | EXPORT_SYMBOL(ssb_dma_translation); |
| 457 | |
| 458 | -int ssb_dma_set_mask(struct ssb_device *dev, u64 mask) |
| 459 | -{ |
| 460 | -#ifdef CONFIG_SSB_PCIHOST |
| 461 | - int err; |
| 462 | -#endif |
| 463 | - |
| 464 | - switch (dev->bus->bustype) { |
| 465 | - case SSB_BUSTYPE_PCI: |
| 466 | -#ifdef CONFIG_SSB_PCIHOST |
| 467 | - err = pci_set_dma_mask(dev->bus->host_pci, mask); |
| 468 | - if (err) |
| 469 | - return err; |
| 470 | - err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask); |
| 471 | - return err; |
| 472 | -#endif |
| 473 | - case SSB_BUSTYPE_SSB: |
| 474 | - return dma_set_mask(dev->dev, mask); |
| 475 | - default: |
| 476 | - __ssb_dma_not_implemented(dev); |
| 477 | - } |
| 478 | - return -ENOSYS; |
| 479 | -} |
| 480 | -EXPORT_SYMBOL(ssb_dma_set_mask); |
| 481 | - |
| 482 | -void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, |
| 483 | - dma_addr_t *dma_handle, gfp_t gfp_flags) |
| 484 | -{ |
| 485 | - switch (dev->bus->bustype) { |
| 486 | - case SSB_BUSTYPE_PCI: |
| 487 | -#ifdef CONFIG_SSB_PCIHOST |
| 488 | - if (gfp_flags & GFP_DMA) { |
| 489 | - /* Workaround: The PCI API does not support passing |
| 490 | - * a GFP flag. */ |
| 491 | - return dma_alloc_coherent(&dev->bus->host_pci->dev, |
| 492 | - size, dma_handle, gfp_flags); |
| 493 | - } |
| 494 | - return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle); |
| 495 | -#endif |
| 496 | - case SSB_BUSTYPE_SSB: |
| 497 | - return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags); |
| 498 | - default: |
| 499 | - __ssb_dma_not_implemented(dev); |
| 500 | - } |
| 501 | - return NULL; |
| 502 | -} |
| 503 | -EXPORT_SYMBOL(ssb_dma_alloc_consistent); |
| 504 | - |
| 505 | -void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, |
| 506 | - void *vaddr, dma_addr_t dma_handle, |
| 507 | - gfp_t gfp_flags) |
| 508 | -{ |
| 509 | - switch (dev->bus->bustype) { |
| 510 | - case SSB_BUSTYPE_PCI: |
| 511 | -#ifdef CONFIG_SSB_PCIHOST |
| 512 | - if (gfp_flags & GFP_DMA) { |
| 513 | - /* Workaround: The PCI API does not support passing |
| 514 | - * a GFP flag. */ |
| 515 | - dma_free_coherent(&dev->bus->host_pci->dev, |
| 516 | - size, vaddr, dma_handle); |
| 517 | - return; |
| 518 | - } |
| 519 | - pci_free_consistent(dev->bus->host_pci, size, |
| 520 | - vaddr, dma_handle); |
| 521 | - return; |
| 522 | -#endif |
| 523 | - case SSB_BUSTYPE_SSB: |
| 524 | - dma_free_coherent(dev->dev, size, vaddr, dma_handle); |
| 525 | - return; |
| 526 | - default: |
| 527 | - __ssb_dma_not_implemented(dev); |
| 528 | - } |
| 529 | -} |
| 530 | -EXPORT_SYMBOL(ssb_dma_free_consistent); |
| 531 | - |
| 532 | int ssb_bus_may_powerdown(struct ssb_bus *bus) |
| 533 | { |
| 534 | struct ssb_chipcommon *cc; |
32 | 535 | --- a/drivers/ssb/pci.c |
33 | 536 | +++ b/drivers/ssb/pci.c |
34 | 537 | @@ -168,7 +168,7 @@ err_pci: |
... | ... | |
40 | 543 | /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ |
41 | 544 | #define SPEX16(_outvar, _offset, _mask, _shift) \ |
42 | 545 | out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) |
43 | | @@ -254,7 +254,7 @@ static int sprom_do_read(struct ssb_bus |
| 546 | @@ -254,7 +254,7 @@ static int sprom_do_read(struct ssb_bus |
44 | 547 | int i; |
45 | 548 | |
46 | 549 | for (i = 0; i < bus->sprom_size; i++) |
... | ... | |
58 | 561 | mmiowb(); |
59 | 562 | msleep(20); |
60 | 563 | } |
61 | | @@ -621,6 +621,14 @@ static int ssb_pci_sprom_get(struct ssb_ |
| 564 | @@ -621,6 +621,28 @@ static int ssb_pci_sprom_get(struct ssb_ |
62 | 565 | int err = -ENOMEM; |
63 | 566 | u16 *buf; |
64 | 567 | |
... | ... | |
66 | 569 | + ssb_printk(KERN_ERR PFX "No SPROM available!\n"); |
67 | 570 | + return -ENODEV; |
68 | 571 | + } |
69 | | + |
70 | | + bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ? |
71 | | + SSB_SPROM_BASE1 : SSB_SPROM_BASE31; |
| 572 | + if (bus->chipco.dev) { /* can be unavailible! */ |
| 573 | + /* |
| 574 | + * get SPROM offset: SSB_SPROM_BASE1 except for |
| 575 | + * chipcommon rev >= 31 or chip ID is 0x4312 and |
| 576 | + * chipcommon status & 3 == 2 |
| 577 | + */ |
| 578 | + if (bus->chipco.dev->id.revision >= 31) |
| 579 | + bus->sprom_offset = SSB_SPROM_BASE31; |
| 580 | + else if (bus->chip_id == 0x4312 && |
| 581 | + (bus->chipco.status & 0x03) == 2) |
| 582 | + bus->sprom_offset = SSB_SPROM_BASE31; |
| 583 | + else |
| 584 | + bus->sprom_offset = SSB_SPROM_BASE1; |
| 585 | + } else { |
| 586 | + bus->sprom_offset = SSB_SPROM_BASE1; |
| 587 | + } |
| 588 | + ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset); |
72 | 589 | + |
73 | 590 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); |
74 | 591 | if (!buf) |
75 | 592 | goto out; |
76 | 593 | --- a/drivers/ssb/sprom.c |
77 | 594 | +++ b/drivers/ssb/sprom.c |
78 | | @@ -176,3 +176,17 @@ const struct ssb_sprom *ssb_get_fallback |
| 595 | @@ -176,3 +176,18 @@ const struct ssb_sprom *ssb_get_fallback |
79 | 596 | { |
80 | 597 | return fallback_sprom; |
81 | 598 | } |
... | ... | |
88 | 605 | + /* this routine differs from specs as we do not access SPROM directly |
89 | 606 | + on PCMCIA */ |
90 | 607 | + if (bus->bustype == SSB_BUSTYPE_PCI && |
| 608 | + bus->chipco.dev && /* can be unavailible! */ |
91 | 609 | + bus->chipco.dev->id.revision >= 31) |
92 | 610 | + return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; |
93 | 611 | + |
... | ... | |
95 | 613 | +} |
96 | 614 | --- a/include/linux/ssb/ssb.h |
97 | 615 | +++ b/include/linux/ssb/ssb.h |
| 616 | @@ -167,7 +167,7 @@ struct ssb_device { |
| 617 | * is an optimization. */ |
| 618 | const struct ssb_bus_ops *ops; |
| 619 | |
| 620 | - struct device *dev; |
| 621 | + struct device *dev, *dma_dev; |
| 622 | |
| 623 | struct ssb_bus *bus; |
| 624 | struct ssb_device_id id; |
98 | 625 | @@ -305,6 +305,7 @@ struct ssb_bus { |
99 | 626 | /* ID information about the Chip. */ |
100 | 627 | u16 chip_id; |
... | ... | |
113 | 640 | /* Set a fallback SPROM. |
114 | 641 | * See kdoc at the function definition for complete documentation. */ |
115 | 642 | extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); |
| 643 | @@ -466,14 +470,6 @@ extern u32 ssb_dma_translation(struct ss |
| 644 | #define SSB_DMA_TRANSLATION_MASK 0xC0000000 |
| 645 | #define SSB_DMA_TRANSLATION_SHIFT 30 |
| 646 | |
| 647 | -extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask); |
| 648 | - |
| 649 | -extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, |
| 650 | - dma_addr_t *dma_handle, gfp_t gfp_flags); |
| 651 | -extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, |
| 652 | - void *vaddr, dma_addr_t dma_handle, |
| 653 | - gfp_t gfp_flags); |
| 654 | - |
| 655 | static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev) |
| 656 | { |
| 657 | #ifdef CONFIG_SSB_DEBUG |
| 658 | @@ -482,155 +478,6 @@ static inline void __cold __ssb_dma_not_ |
| 659 | #endif /* DEBUG */ |
| 660 | } |
| 661 | |
| 662 | -static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr) |
| 663 | -{ |
| 664 | - switch (dev->bus->bustype) { |
| 665 | - case SSB_BUSTYPE_PCI: |
| 666 | -#ifdef CONFIG_SSB_PCIHOST |
| 667 | - return pci_dma_mapping_error(dev->bus->host_pci, addr); |
| 668 | -#endif |
| 669 | - break; |
| 670 | - case SSB_BUSTYPE_SSB: |
| 671 | - return dma_mapping_error(dev->dev, addr); |
| 672 | - default: |
| 673 | - break; |
| 674 | - } |
| 675 | - __ssb_dma_not_implemented(dev); |
| 676 | - return -ENOSYS; |
| 677 | -} |
| 678 | - |
| 679 | -static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p, |
| 680 | - size_t size, enum dma_data_direction dir) |
| 681 | -{ |
| 682 | - switch (dev->bus->bustype) { |
| 683 | - case SSB_BUSTYPE_PCI: |
| 684 | -#ifdef CONFIG_SSB_PCIHOST |
| 685 | - return pci_map_single(dev->bus->host_pci, p, size, dir); |
| 686 | -#endif |
| 687 | - break; |
| 688 | - case SSB_BUSTYPE_SSB: |
| 689 | - return dma_map_single(dev->dev, p, size, dir); |
| 690 | - default: |
| 691 | - break; |
| 692 | - } |
| 693 | - __ssb_dma_not_implemented(dev); |
| 694 | - return 0; |
| 695 | -} |
| 696 | - |
| 697 | -static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr, |
| 698 | - size_t size, enum dma_data_direction dir) |
| 699 | -{ |
| 700 | - switch (dev->bus->bustype) { |
| 701 | - case SSB_BUSTYPE_PCI: |
| 702 | -#ifdef CONFIG_SSB_PCIHOST |
| 703 | - pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir); |
| 704 | - return; |
| 705 | -#endif |
| 706 | - break; |
| 707 | - case SSB_BUSTYPE_SSB: |
| 708 | - dma_unmap_single(dev->dev, dma_addr, size, dir); |
| 709 | - return; |
| 710 | - default: |
| 711 | - break; |
| 712 | - } |
| 713 | - __ssb_dma_not_implemented(dev); |
| 714 | -} |
| 715 | - |
| 716 | -static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev, |
| 717 | - dma_addr_t dma_addr, |
| 718 | - size_t size, |
| 719 | - enum dma_data_direction dir) |
| 720 | -{ |
| 721 | - switch (dev->bus->bustype) { |
| 722 | - case SSB_BUSTYPE_PCI: |
| 723 | -#ifdef CONFIG_SSB_PCIHOST |
| 724 | - pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, |
| 725 | - size, dir); |
| 726 | - return; |
| 727 | -#endif |
| 728 | - break; |
| 729 | - case SSB_BUSTYPE_SSB: |
| 730 | - dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir); |
| 731 | - return; |
| 732 | - default: |
| 733 | - break; |
| 734 | - } |
| 735 | - __ssb_dma_not_implemented(dev); |
| 736 | -} |
| 737 | - |
| 738 | -static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev, |
| 739 | - dma_addr_t dma_addr, |
| 740 | - size_t size, |
| 741 | - enum dma_data_direction dir) |
| 742 | -{ |
| 743 | - switch (dev->bus->bustype) { |
| 744 | - case SSB_BUSTYPE_PCI: |
| 745 | -#ifdef CONFIG_SSB_PCIHOST |
| 746 | - pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, |
| 747 | - size, dir); |
| 748 | - return; |
| 749 | -#endif |
| 750 | - break; |
| 751 | - case SSB_BUSTYPE_SSB: |
| 752 | - dma_sync_single_for_device(dev->dev, dma_addr, size, dir); |
| 753 | - return; |
| 754 | - default: |
| 755 | - break; |
| 756 | - } |
| 757 | - __ssb_dma_not_implemented(dev); |
| 758 | -} |
| 759 | - |
| 760 | -static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev, |
| 761 | - dma_addr_t dma_addr, |
| 762 | - unsigned long offset, |
| 763 | - size_t size, |
| 764 | - enum dma_data_direction dir) |
| 765 | -{ |
| 766 | - switch (dev->bus->bustype) { |
| 767 | - case SSB_BUSTYPE_PCI: |
| 768 | -#ifdef CONFIG_SSB_PCIHOST |
| 769 | - /* Just sync everything. That's all the PCI API can do. */ |
| 770 | - pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, |
| 771 | - offset + size, dir); |
| 772 | - return; |
| 773 | -#endif |
| 774 | - break; |
| 775 | - case SSB_BUSTYPE_SSB: |
| 776 | - dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset, |
| 777 | - size, dir); |
| 778 | - return; |
| 779 | - default: |
| 780 | - break; |
| 781 | - } |
| 782 | - __ssb_dma_not_implemented(dev); |
| 783 | -} |
| 784 | - |
| 785 | -static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev, |
| 786 | - dma_addr_t dma_addr, |
| 787 | - unsigned long offset, |
| 788 | - size_t size, |
| 789 | - enum dma_data_direction dir) |
| 790 | -{ |
| 791 | - switch (dev->bus->bustype) { |
| 792 | - case SSB_BUSTYPE_PCI: |
| 793 | -#ifdef CONFIG_SSB_PCIHOST |
| 794 | - /* Just sync everything. That's all the PCI API can do. */ |
| 795 | - pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, |
| 796 | - offset + size, dir); |
| 797 | - return; |
| 798 | -#endif |
| 799 | - break; |
| 800 | - case SSB_BUSTYPE_SSB: |
| 801 | - dma_sync_single_range_for_device(dev->dev, dma_addr, offset, |
| 802 | - size, dir); |
| 803 | - return; |
| 804 | - default: |
| 805 | - break; |
| 806 | - } |
| 807 | - __ssb_dma_not_implemented(dev); |
| 808 | -} |
| 809 | - |
| 810 | - |
| 811 | #ifdef CONFIG_SSB_PCIHOST |
| 812 | /* PCI-host wrapper driver */ |
| 813 | extern int ssb_pcihost_register(struct pci_driver *driver); |
116 | 814 | --- a/include/linux/ssb/ssb_driver_chipcommon.h |
117 | 815 | +++ b/include/linux/ssb/ssb_driver_chipcommon.h |
118 | 816 | @@ -53,6 +53,7 @@ |
target/linux/generic/patches-2.6.35/975-ssb_update.patch |
| 1 | --- a/drivers/net/b44.c |
| 2 | @@ -135,7 +135,6 @@ static void b44_init_rings(struct b44 *) |
| 3 | |
| 4 | static void b44_init_hw(struct b44 *, int); |
| 5 | |
| 6 | -static int dma_desc_align_mask; |
| 7 | static int dma_desc_sync_size; |
| 8 | static int instance; |
| 9 | |
| 10 | @@ -150,9 +149,8 @@ static inline void b44_sync_dma_desc_for |
| 11 | unsigned long offset, |
| 12 | enum dma_data_direction dir) |
| 13 | { |
| 14 | - ssb_dma_sync_single_range_for_device(sdev, dma_base, |
| 15 | - offset & dma_desc_align_mask, |
| 16 | - dma_desc_sync_size, dir); |
| 17 | + dma_sync_single_for_device(sdev->dma_dev, dma_base + offset, |
| 18 | + dma_desc_sync_size, dir); |
| 19 | } |
| 20 | |
| 21 | static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, |
| 22 | @@ -160,9 +158,8 @@ static inline void b44_sync_dma_desc_for |
| 23 | unsigned long offset, |
| 24 | enum dma_data_direction dir) |
| 25 | { |
| 26 | - ssb_dma_sync_single_range_for_cpu(sdev, dma_base, |
| 27 | - offset & dma_desc_align_mask, |
| 28 | - dma_desc_sync_size, dir); |
| 29 | + dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset, |
| 30 | + dma_desc_sync_size, dir); |
| 31 | } |
| 32 | |
| 33 | static inline unsigned long br32(const struct b44 *bp, unsigned long reg) |
| 34 | @@ -608,10 +605,10 @@ static void b44_tx(struct b44 *bp) |
| 35 | |
| 36 | BUG_ON(skb == NULL); |
| 37 | |
| 38 | - ssb_dma_unmap_single(bp->sdev, |
| 39 | - rp->mapping, |
| 40 | - skb->len, |
| 41 | - DMA_TO_DEVICE); |
| 42 | + dma_unmap_single(bp->sdev->dma_dev, |
| 43 | + rp->mapping, |
| 44 | + skb->len, |
| 45 | + DMA_TO_DEVICE); |
| 46 | rp->skb = NULL; |
| 47 | dev_kfree_skb_irq(skb); |
| 48 | } |
| 49 | @@ -648,29 +645,29 @@ static int b44_alloc_rx_skb(struct b44 * |
| 50 | if (skb == NULL) |
| 51 | return -ENOMEM; |
| 52 | |
| 53 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, |
| 54 | - RX_PKT_BUF_SZ, |
| 55 | - DMA_FROM_DEVICE); |
| 56 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, |
| 57 | + RX_PKT_BUF_SZ, |
| 58 | + DMA_FROM_DEVICE); |
| 59 | |
| 60 | /* Hardware bug work-around, the chip is unable to do PCI DMA |
| 61 | to/from anything above 1GB :-( */ |
| 62 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || |
| 63 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || |
| 64 | mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 65 | /* Sigh... */ |
| 66 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 67 | - ssb_dma_unmap_single(bp->sdev, mapping, |
| 68 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 69 | + dma_unmap_single(bp->sdev->dma_dev, mapping, |
| 70 | RX_PKT_BUF_SZ, DMA_FROM_DEVICE); |
| 71 | dev_kfree_skb_any(skb); |
| 72 | skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); |
| 73 | if (skb == NULL) |
| 74 | return -ENOMEM; |
| 75 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, |
| 76 | - RX_PKT_BUF_SZ, |
| 77 | - DMA_FROM_DEVICE); |
| 78 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || |
| 79 | - mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 80 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 81 | - ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); |
| 82 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, |
| 83 | + RX_PKT_BUF_SZ, |
| 84 | + DMA_FROM_DEVICE); |
| 85 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || |
| 86 | + mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) { |
| 87 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 88 | + dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); |
| 89 | dev_kfree_skb_any(skb); |
| 90 | return -ENOMEM; |
| 91 | } |
| 92 | @@ -745,9 +742,9 @@ static void b44_recycle_rx(struct b44 *b |
| 93 | dest_idx * sizeof(*dest_desc), |
| 94 | DMA_BIDIRECTIONAL); |
| 95 | |
| 96 | - ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping, |
| 97 | - RX_PKT_BUF_SZ, |
| 98 | - DMA_FROM_DEVICE); |
| 99 | + dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping, |
| 100 | + RX_PKT_BUF_SZ, |
| 101 | + DMA_FROM_DEVICE); |
| 102 | } |
| 103 | |
| 104 | static int b44_rx(struct b44 *bp, int budget) |
| 105 | @@ -767,9 +764,9 @@ static int b44_rx(struct b44 *bp, int bu |
| 106 | struct rx_header *rh; |
| 107 | u16 len; |
| 108 | |
| 109 | - ssb_dma_sync_single_for_cpu(bp->sdev, map, |
| 110 | - RX_PKT_BUF_SZ, |
| 111 | - DMA_FROM_DEVICE); |
| 112 | + dma_sync_single_for_cpu(bp->sdev->dma_dev, map, |
| 113 | + RX_PKT_BUF_SZ, |
| 114 | + DMA_FROM_DEVICE); |
| 115 | rh = (struct rx_header *) skb->data; |
| 116 | len = le16_to_cpu(rh->len); |
| 117 | if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || |
| 118 | @@ -801,8 +798,8 @@ static int b44_rx(struct b44 *bp, int bu |
| 119 | skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); |
| 120 | if (skb_size < 0) |
| 121 | goto drop_it; |
| 122 | - ssb_dma_unmap_single(bp->sdev, map, |
| 123 | - skb_size, DMA_FROM_DEVICE); |
| 124 | + dma_unmap_single(bp->sdev->dma_dev, map, |
| 125 | + skb_size, DMA_FROM_DEVICE); |
| 126 | /* Leave out rx_header */ |
| 127 | skb_put(skb, len + RX_PKT_OFFSET); |
| 128 | skb_pull(skb, RX_PKT_OFFSET); |
| 129 | @@ -954,24 +951,24 @@ static netdev_tx_t b44_start_xmit(struct |
| 130 | goto err_out; |
| 131 | } |
| 132 | |
| 133 | - mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE); |
| 134 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 135 | + mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE); |
| 136 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 137 | struct sk_buff *bounce_skb; |
| 138 | |
| 139 | /* Chip can't handle DMA to/from >1GB, use bounce buffer */ |
| 140 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 141 | - ssb_dma_unmap_single(bp->sdev, mapping, len, |
| 142 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 143 | + dma_unmap_single(bp->sdev->dma_dev, mapping, len, |
| 144 | DMA_TO_DEVICE); |
| 145 | |
| 146 | bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA); |
| 147 | if (!bounce_skb) |
| 148 | goto err_out; |
| 149 | |
| 150 | - mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data, |
| 151 | - len, DMA_TO_DEVICE); |
| 152 | - if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 153 | - if (!ssb_dma_mapping_error(bp->sdev, mapping)) |
| 154 | - ssb_dma_unmap_single(bp->sdev, mapping, |
| 155 | + mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data, |
| 156 | + len, DMA_TO_DEVICE); |
| 157 | + if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) { |
| 158 | + if (!dma_mapping_error(bp->sdev->dma_dev, mapping)) |
| 159 | + dma_unmap_single(bp->sdev->dma_dev, mapping, |
| 160 | len, DMA_TO_DEVICE); |
| 161 | dev_kfree_skb_any(bounce_skb); |
| 162 | goto err_out; |
| 163 | @@ -1068,8 +1065,8 @@ static void b44_free_rings(struct b44 *b |
| 164 | |
| 165 | if (rp->skb == NULL) |
| 166 | continue; |
| 167 | - ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ, |
| 168 | - DMA_FROM_DEVICE); |
| 169 | + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ, |
| 170 | + DMA_FROM_DEVICE); |
| 171 | dev_kfree_skb_any(rp->skb); |
| 172 | rp->skb = NULL; |
| 173 | } |
| 174 | @@ -1080,8 +1077,8 @@ static void b44_free_rings(struct b44 *b |
| 175 | |
| 176 | if (rp->skb == NULL) |
| 177 | continue; |
| 178 | - ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len, |
| 179 | - DMA_TO_DEVICE); |
| 180 | + dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len, |
| 181 | + DMA_TO_DEVICE); |
| 182 | dev_kfree_skb_any(rp->skb); |
| 183 | rp->skb = NULL; |
| 184 | } |
| 185 | @@ -1103,14 +1100,12 @@ static void b44_init_rings(struct b44 *b |
| 186 | memset(bp->tx_ring, 0, B44_TX_RING_BYTES); |
| 187 | |
| 188 | if (bp->flags & B44_FLAG_RX_RING_HACK) |
| 189 | - ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma, |
| 190 | - DMA_TABLE_BYTES, |
| 191 | - DMA_BIDIRECTIONAL); |
| 192 | + dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma, |
| 193 | + DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); |
| 194 | |
| 195 | if (bp->flags & B44_FLAG_TX_RING_HACK) |
| 196 | - ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma, |
| 197 | - DMA_TABLE_BYTES, |
| 198 | - DMA_TO_DEVICE); |
| 199 | + dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma, |
| 200 | + DMA_TABLE_BYTES, DMA_TO_DEVICE); |
| 201 | |
| 202 | for (i = 0; i < bp->rx_pending; i++) { |
| 203 | if (b44_alloc_rx_skb(bp, -1, i) < 0) |
| 204 | @@ -1130,27 +1125,23 @@ static void b44_free_consistent(struct b |
| 205 | bp->tx_buffers = NULL; |
| 206 | if (bp->rx_ring) { |
| 207 | if (bp->flags & B44_FLAG_RX_RING_HACK) { |
| 208 | - ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma, |
| 209 | - DMA_TABLE_BYTES, |
| 210 | - DMA_BIDIRECTIONAL); |
| 211 | + dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma, |
| 212 | + DMA_TABLE_BYTES, DMA_BIDIRECTIONAL); |
| 213 | kfree(bp->rx_ring); |
| 214 | } else |
| 215 | - ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, |
| 216 | - bp->rx_ring, bp->rx_ring_dma, |
| 217 | - GFP_KERNEL); |
| 218 | + dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, |
| 219 | + bp->rx_ring, bp->rx_ring_dma); |
| 220 | bp->rx_ring = NULL; |
| 221 | bp->flags &= ~B44_FLAG_RX_RING_HACK; |
| 222 | } |
| 223 | if (bp->tx_ring) { |
| 224 | if (bp->flags & B44_FLAG_TX_RING_HACK) { |
| 225 | - ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma, |
| 226 | - DMA_TABLE_BYTES, |
| 227 | - DMA_TO_DEVICE); |
| 228 | + dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma, |
| 229 | + DMA_TABLE_BYTES, DMA_TO_DEVICE); |
| 230 | kfree(bp->tx_ring); |
| 231 | } else |
| 232 | - ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES, |
| 233 | - bp->tx_ring, bp->tx_ring_dma, |
| 234 | - GFP_KERNEL); |
| 235 | + dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES, |
| 236 | + bp->tx_ring, bp->tx_ring_dma); |
| 237 | bp->tx_ring = NULL; |
| 238 | bp->flags &= ~B44_FLAG_TX_RING_HACK; |
| 239 | } |
| 240 | @@ -1175,7 +1166,8 @@ static int b44_alloc_consistent(struct b |
| 241 | goto out_err; |
| 242 | |
| 243 | size = DMA_TABLE_BYTES; |
| 244 | - bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp); |
| 245 | + bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, |
| 246 | + &bp->rx_ring_dma, gfp); |
| 247 | if (!bp->rx_ring) { |
| 248 | /* Allocation may have failed due to pci_alloc_consistent |
| 249 | insisting on use of GFP_DMA, which is more restrictive |
| 250 | @@ -1187,11 +1179,11 @@ static int b44_alloc_consistent(struct b |
| 251 | if (!rx_ring) |
| 252 | goto out_err; |
| 253 | |
| 254 | - rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring, |
| 255 | - DMA_TABLE_BYTES, |
| 256 | - DMA_BIDIRECTIONAL); |
| 257 | + rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring, |
| 258 | + DMA_TABLE_BYTES, |
| 259 | + DMA_BIDIRECTIONAL); |
| 260 | |
| 261 | - if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) || |
| 262 | + if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) || |
| 263 | rx_ring_dma + size > DMA_BIT_MASK(30)) { |
| 264 | kfree(rx_ring); |
| 265 | goto out_err; |
| 266 | @@ -1202,7 +1194,8 @@ static int b44_alloc_consistent(struct b |
| 267 | bp->flags |= B44_FLAG_RX_RING_HACK; |
| 268 | } |
| 269 | |
| 270 | - bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp); |
| 271 | + bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size, |
| 272 | + &bp->tx_ring_dma, gfp); |
| 273 | if (!bp->tx_ring) { |
| 274 | /* Allocation may have failed due to ssb_dma_alloc_consistent |
| 275 | insisting on use of GFP_DMA, which is more restrictive |
| 276 | @@ -1214,11 +1207,11 @@ static int b44_alloc_consistent(struct b |
| 277 | if (!tx_ring) |
| 278 | goto out_err; |
| 279 | |
| 280 | - tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring, |
| 281 | - DMA_TABLE_BYTES, |
| 282 | - DMA_TO_DEVICE); |
| 283 | + tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring, |
| 284 | + DMA_TABLE_BYTES, |
| 285 | + DMA_TO_DEVICE); |
| 286 | |
| 287 | - if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) || |
| 288 | + if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) || |
| 289 | tx_ring_dma + size > DMA_BIT_MASK(30)) { |
| 290 | kfree(tx_ring); |
| 291 | goto out_err; |
| 292 | @@ -2176,12 +2169,14 @@ static int __devinit b44_init_one(struct |
| 293 | "Failed to powerup the bus\n"); |
| 294 | goto err_out_free_dev; |
| 295 | } |
| 296 | - err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30)); |
| 297 | - if (err) { |
| 298 | + |
| 299 | + if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) || |
| 300 | + dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) { |
| 301 | dev_err(sdev->dev, |
| 302 | "Required 30BIT DMA mask unsupported by the system\n"); |
| 303 | goto err_out_powerdown; |
| 304 | } |
| 305 | + |
| 306 | err = b44_get_invariants(bp); |
| 307 | if (err) { |
| 308 | dev_err(sdev->dev, |
| 309 | @@ -2344,7 +2339,6 @@ static int __init b44_init(void) |
| 310 | int err; |
| 311 | |
| 312 | /* Setup paramaters for syncing RX/TX DMA descriptors */ |
| 313 | - dma_desc_align_mask = ~(dma_desc_align_size - 1); |
| 314 | dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); |
| 315 | |
| 316 | err = b44_pci_init(); |
| 317 | --- a/drivers/ssb/driver_chipcommon.c |
| 318 | @@ -209,6 +209,24 @@ static void chipco_powercontrol_init(str |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | +/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */ |
| 323 | +static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc) |
| 324 | +{ |
| 325 | + struct ssb_bus *bus = cc->dev->bus; |
| 326 | + |
| 327 | + switch (bus->chip_id) { |
| 328 | + case 0x4312: |
| 329 | + case 0x4322: |
| 330 | + case 0x4328: |
| 331 | + return 7000; |
| 332 | + case 0x4325: |
| 333 | + /* TODO: */ |
| 334 | + default: |
| 335 | + return 15000; |
| 336 | + } |
| 337 | +} |
| 338 | + |
| 339 | +/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */ |
| 340 | static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) |
| 341 | { |
| 342 | struct ssb_bus *bus = cc->dev->bus; |
| 343 | @@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(stru |
| 344 | |
| 345 | if (bus->bustype != SSB_BUSTYPE_PCI) |
| 346 | return; |
| 347 | + |
| 348 | + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
| 349 | + cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc); |
| 350 | + return; |
| 351 | + } |
| 352 | + |
| 353 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) |
| 354 | return; |
| 355 | |
| 356 | @@ -235,6 +259,7 @@ void ssb_chipcommon_init(struct ssb_chip |
| 357 | return; /* We don't have a ChipCommon */ |
| 358 | if (cc->dev->id.revision >= 11) |
| 359 | cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); |
| 360 | + ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); |
| 361 | ssb_pmu_init(cc); |
| 362 | chipco_powercontrol_init(cc); |
| 363 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); |
| 364 | --- a/drivers/ssb/driver_chipcommon_pmu.c |
| 365 | @@ -502,9 +502,9 @@ static void ssb_pmu_resources_init(struc |
| 366 | chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk); |
| 367 | } |
| 368 | |
| 369 | +/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */ |
| 370 | void ssb_pmu_init(struct ssb_chipcommon *cc) |
| 371 | { |
| 372 | - struct ssb_bus *bus = cc->dev->bus; |
| 373 | u32 pmucap; |
| 374 | |
| 375 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU)) |
| 376 | @@ -516,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon |
| 377 | ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n", |
| 378 | cc->pmu.rev, pmucap); |
| 379 | |
| 380 | - if (cc->pmu.rev >= 1) { |
| 381 | - if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) { |
| 382 | - chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, |
| 383 | - ~SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 384 | - } else { |
| 385 | - chipco_set32(cc, SSB_CHIPCO_PMU_CTL, |
| 386 | - SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 387 | - } |
| 388 | - } |
| 389 | + if (cc->pmu.rev == 1) |
| 390 | + chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, |
| 391 | + ~SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 392 | + else |
| 393 | + chipco_set32(cc, SSB_CHIPCO_PMU_CTL, |
| 394 | + SSB_CHIPCO_PMU_CTL_NOILPONW); |
| 395 | ssb_pmu_pll_init(cc); |
| 396 | ssb_pmu_resources_init(cc); |
| 397 | } |
| 398 | --- a/drivers/ssb/main.c |
| 399 | @@ -486,6 +486,7 @@ static int ssb_devices_register(struct s |
| 400 | #ifdef CONFIG_SSB_PCIHOST |
| 401 | sdev->irq = bus->host_pci->irq; |
| 402 | dev->parent = &bus->host_pci->dev; |
| 403 | + sdev->dma_dev = dev->parent; |
| 404 | #endif |
| 405 | break; |
| 406 | case SSB_BUSTYPE_PCMCIA: |
| 407 | @@ -501,6 +502,7 @@ static int ssb_devices_register(struct s |
| 408 | break; |
| 409 | case SSB_BUSTYPE_SSB: |
| 410 | dev->dma_mask = &dev->coherent_dma_mask; |
| 411 | + sdev->dma_dev = dev; |
| 412 | break; |
| 413 | } |
| 414 | |
| 415 | @@ -1226,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_devic |
| 416 | } |
| 417 | EXPORT_SYMBOL(ssb_dma_translation); |
| 418 | |
| 419 | -int ssb_dma_set_mask(struct ssb_device *dev, u64 mask) |
| 420 | -{ |
| 421 | -#ifdef CONFIG_SSB_PCIHOST |
| 422 | - int err; |
| 423 | -#endif |
| 424 | - |
| 425 | - switch (dev->bus->bustype) { |
| 426 | - case SSB_BUSTYPE_PCI: |
| 427 | -#ifdef CONFIG_SSB_PCIHOST |
| 428 | - err = pci_set_dma_mask(dev->bus->host_pci, mask); |
| 429 | - if (err) |
| 430 | - return err; |
| 431 | - err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask); |
| 432 | - return err; |
| 433 | -#endif |
| 434 | - case SSB_BUSTYPE_SSB: |
| 435 | - return dma_set_mask(dev->dev, mask); |
| 436 | - default: |
| 437 | - __ssb_dma_not_implemented(dev); |
| 438 | - } |
| 439 | - return -ENOSYS; |
| 440 | -} |
| 441 | -EXPORT_SYMBOL(ssb_dma_set_mask); |
| 442 | - |
| 443 | -void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, |
| 444 | - dma_addr_t *dma_handle, gfp_t gfp_flags) |
| 445 | -{ |
| 446 | - switch (dev->bus->bustype) { |
| 447 | - case SSB_BUSTYPE_PCI: |
| 448 | -#ifdef CONFIG_SSB_PCIHOST |
| 449 | - if (gfp_flags & GFP_DMA) { |
| 450 | - /* Workaround: The PCI API does not support passing |
| 451 | - * a GFP flag. */ |
| 452 | - return dma_alloc_coherent(&dev->bus->host_pci->dev, |
| 453 | - size, dma_handle, gfp_flags); |
| 454 | - } |
| 455 | - return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle); |
| 456 | -#endif |
| 457 | - case SSB_BUSTYPE_SSB: |
| 458 | - return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags); |
| 459 | - default: |
| 460 | - __ssb_dma_not_implemented(dev); |
| 461 | - } |
| 462 | - return NULL; |
| 463 | -} |
| 464 | -EXPORT_SYMBOL(ssb_dma_alloc_consistent); |
| 465 | - |
| 466 | -void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, |
| 467 | - void *vaddr, dma_addr_t dma_handle, |
| 468 | - gfp_t gfp_flags) |
| 469 | -{ |
| 470 | - switch (dev->bus->bustype) { |
| 471 | - case SSB_BUSTYPE_PCI: |
| 472 | -#ifdef CONFIG_SSB_PCIHOST |
| 473 | - if (gfp_flags & GFP_DMA) { |
| 474 | - /* Workaround: The PCI API does not support passing |
| 475 | - * a GFP flag. */ |
| 476 | - dma_free_coherent(&dev->bus->host_pci->dev, |
| 477 | - size, vaddr, dma_handle); |
| 478 | - return; |
| 479 | - } |
| 480 | - pci_free_consistent(dev->bus->host_pci, size, |
| 481 | - vaddr, dma_handle); |
| 482 | - return; |
| 483 | -#endif |
| 484 | - case SSB_BUSTYPE_SSB: |
| 485 | - dma_free_coherent(dev->dev, size, vaddr, dma_handle); |
| 486 | - return; |
| 487 | - default: |
| 488 | - __ssb_dma_not_implemented(dev); |
| 489 | - } |
| 490 | -} |
| 491 | -EXPORT_SYMBOL(ssb_dma_free_consistent); |
| 492 | - |
| 493 | int ssb_bus_may_powerdown(struct ssb_bus *bus) |
| 494 | { |
| 495 | struct ssb_chipcommon *cc; |
| 496 | --- a/drivers/ssb/pci.c |
| 497 | @@ -626,11 +626,22 @@ static int ssb_pci_sprom_get(struct ssb_ |
| 498 | return -ENODEV; |
| 499 | } |
| 500 | if (bus->chipco.dev) { /* can be unavailible! */ |
| 501 | - bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ? |
| 502 | - SSB_SPROM_BASE1 : SSB_SPROM_BASE31; |
| 503 | + /* |
| 504 | + * get SPROM offset: SSB_SPROM_BASE1 except for |
| 505 | + * chipcommon rev >= 31 or chip ID is 0x4312 and |
| 506 | + * chipcommon status & 3 == 2 |
| 507 | + */ |
| 508 | + if (bus->chipco.dev->id.revision >= 31) |
| 509 | + bus->sprom_offset = SSB_SPROM_BASE31; |
| 510 | + else if (bus->chip_id == 0x4312 && |
| 511 | + (bus->chipco.status & 0x03) == 2) |
| 512 | + bus->sprom_offset = SSB_SPROM_BASE31; |
| 513 | + else |
| 514 | + bus->sprom_offset = SSB_SPROM_BASE1; |
| 515 | } else { |
| 516 | bus->sprom_offset = SSB_SPROM_BASE1; |
| 517 | } |
| 518 | + ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset); |
| 519 | |
| 520 | buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); |
| 521 | if (!buf) |
| 522 | --- a/include/linux/ssb/ssb.h |
| 523 | @@ -167,7 +167,7 @@ struct ssb_device { |
| 524 | * is an optimization. */ |
| 525 | const struct ssb_bus_ops *ops; |
| 526 | |
| 527 | - struct device *dev; |
| 528 | + struct device *dev, *dma_dev; |
| 529 | |
| 530 | struct ssb_bus *bus; |
| 531 | struct ssb_device_id id; |
| 532 | @@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ss |
| 533 | #define SSB_DMA_TRANSLATION_MASK 0xC0000000 |
| 534 | #define SSB_DMA_TRANSLATION_SHIFT 30 |
| 535 | |
| 536 | -extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask); |
| 537 | - |
| 538 | -extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size, |
| 539 | - dma_addr_t *dma_handle, gfp_t gfp_flags); |
| 540 | -extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size, |
| 541 | - void *vaddr, dma_addr_t dma_handle, |
| 542 | - gfp_t gfp_flags); |
| 543 | - |
| 544 | static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev) |
| 545 | { |
| 546 | #ifdef CONFIG_SSB_DEBUG |
| 547 | @@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_ |
| 548 | #endif /* DEBUG */ |
| 549 | } |
| 550 | |
| 551 | -static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr) |
| 552 | -{ |
| 553 | - switch (dev->bus->bustype) { |
| 554 | - case SSB_BUSTYPE_PCI: |
| 555 | -#ifdef CONFIG_SSB_PCIHOST |
| 556 | - return pci_dma_mapping_error(dev->bus->host_pci, addr); |
| 557 | -#endif |
| 558 | - break; |
| 559 | - case SSB_BUSTYPE_SSB: |
| 560 | - return dma_mapping_error(dev->dev, addr); |
| 561 | - default: |
| 562 | - break; |
| 563 | - } |
| 564 | - __ssb_dma_not_implemented(dev); |
| 565 | - return -ENOSYS; |
| 566 | -} |
| 567 | - |
| 568 | -static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p, |
| 569 | - size_t size, enum dma_data_direction dir) |
| 570 | -{ |
| 571 | - switch (dev->bus->bustype) { |
| 572 | - case SSB_BUSTYPE_PCI: |
| 573 | -#ifdef CONFIG_SSB_PCIHOST |
| 574 | - return pci_map_single(dev->bus->host_pci, p, size, dir); |
| 575 | -#endif |
| 576 | - break; |
| 577 | - case SSB_BUSTYPE_SSB: |
| 578 | - return dma_map_single(dev->dev, p, size, dir); |
| 579 | - default: |
| 580 | - break; |
| 581 | - } |
| 582 | - __ssb_dma_not_implemented(dev); |
| 583 | - return 0; |
| 584 | -} |
| 585 | - |
| 586 | -static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr, |
| 587 | - size_t size, enum dma_data_direction dir) |
| 588 | -{ |
| 589 | - switch (dev->bus->bustype) { |
| 590 | - case SSB_BUSTYPE_PCI: |
| 591 | -#ifdef CONFIG_SSB_PCIHOST |
| 592 | - pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir); |
| 593 | - return; |
| 594 | -#endif |
| 595 | - break; |
| 596 | - case SSB_BUSTYPE_SSB: |
| 597 | - dma_unmap_single(dev->dev, dma_addr, size, dir); |
| 598 | - return; |
| 599 | - default: |
| 600 | - break; |
| 601 | - } |
| 602 | - __ssb_dma_not_implemented(dev); |
| 603 | -} |
| 604 | - |
| 605 | -static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev, |
| 606 | - dma_addr_t dma_addr, |
| 607 | - size_t size, |
| 608 | - enum dma_data_direction dir) |
| 609 | -{ |
| 610 | - switch (dev->bus->bustype) { |
| 611 | - case SSB_BUSTYPE_PCI: |
| 612 | -#ifdef CONFIG_SSB_PCIHOST |
| 613 | - pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, |
| 614 | - size, dir); |
| 615 | - return; |
| 616 | -#endif |
| 617 | - break; |
| 618 | - case SSB_BUSTYPE_SSB: |
| 619 | - dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir); |
| 620 | - return; |
| 621 | - default: |
| 622 | - break; |
| 623 | - } |
| 624 | - __ssb_dma_not_implemented(dev); |
| 625 | -} |
| 626 | - |
| 627 | -static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev, |
| 628 | - dma_addr_t dma_addr, |
| 629 | - size_t size, |
| 630 | - enum dma_data_direction dir) |
| 631 | -{ |
| 632 | - switch (dev->bus->bustype) { |
| 633 | - case SSB_BUSTYPE_PCI: |
| 634 | -#ifdef CONFIG_SSB_PCIHOST |
| 635 | - pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, |
| 636 | - size, dir); |
| 637 | - return; |
| 638 | -#endif |
| 639 | - break; |
| 640 | - case SSB_BUSTYPE_SSB: |
| 641 | - dma_sync_single_for_device(dev->dev, dma_addr, size, dir); |
| 642 | - return; |
| 643 | - default: |
| 644 | - break; |
| 645 | - } |
| 646 | - __ssb_dma_not_implemented(dev); |
| 647 | -} |
| 648 | - |
| 649 | -static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev, |
| 650 | - dma_addr_t dma_addr, |
| 651 | - unsigned long offset, |
| 652 | - size_t size, |
| 653 | - enum dma_data_direction dir) |
| 654 | -{ |
| 655 | - switch (dev->bus->bustype) { |
| 656 | - case SSB_BUSTYPE_PCI: |
| 657 | -#ifdef CONFIG_SSB_PCIHOST |
| 658 | - /* Just sync everything. That's all the PCI API can do. */ |
| 659 | - pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr, |
| 660 | - offset + size, dir); |
| 661 | - return; |
| 662 | -#endif |
| 663 | - break; |
| 664 | - case SSB_BUSTYPE_SSB: |
| 665 | - dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset, |
| 666 | - size, dir); |
| 667 | - return; |
| 668 | - default: |
| 669 | - break; |
| 670 | - } |
| 671 | - __ssb_dma_not_implemented(dev); |
| 672 | -} |
| 673 | - |
| 674 | -static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev, |
| 675 | - dma_addr_t dma_addr, |
| 676 | - unsigned long offset, |
| 677 | - size_t size, |
| 678 | - enum dma_data_direction dir) |
| 679 | -{ |
| 680 | - switch (dev->bus->bustype) { |
| 681 | - case SSB_BUSTYPE_PCI: |
| 682 | -#ifdef CONFIG_SSB_PCIHOST |
| 683 | - /* Just sync everything. That's all the PCI API can do. */ |
| 684 | - pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr, |
| 685 | - offset + size, dir); |
| 686 | - return; |
| 687 | -#endif |
| 688 | - break; |
| 689 | - case SSB_BUSTYPE_SSB: |
| 690 | - dma_sync_single_range_for_device(dev->dev, dma_addr, offset, |
| 691 | - size, dir); |
| 692 | - return; |
| 693 | - default: |
| 694 | - break; |
| 695 | - } |
| 696 | - __ssb_dma_not_implemented(dev); |
| 697 | -} |
| 698 | - |
| 699 | - |
| 700 | #ifdef CONFIG_SSB_PCIHOST |
| 701 | /* PCI-host wrapper driver */ |
| 702 | extern int ssb_pcihost_register(struct pci_driver *driver); |