| 1 | /* |
|---|
| 2 | * This file contains glue for Atheros ar7100 spi flash interface |
|---|
| 3 | * Primitives are ar7100_spi_* |
|---|
| 4 | * mtd flash implements are ar7100_flash_* |
|---|
| 5 | */ |
|---|
| 6 | #include <linux/kernel.h> |
|---|
| 7 | #include <linux/module.h> |
|---|
| 8 | #include <linux/types.h> |
|---|
| 9 | #include <linux/errno.h> |
|---|
| 10 | #include <linux/slab.h> |
|---|
| 11 | #include <linux/mtd/mtd.h> |
|---|
| 12 | #include <linux/mtd/partitions.h> |
|---|
| 13 | #include "../mtdcore.h" |
|---|
| 14 | #include <asm/delay.h> |
|---|
| 15 | #include <asm/io.h> |
|---|
| 16 | #include <linux/semaphore.h> |
|---|
| 17 | #include <linux/squashfs_fs.h> |
|---|
| 18 | |
|---|
| 19 | #include "ar7100.h" |
|---|
| 20 | #include "ar7100_flash.h" |
|---|
| 21 | |
|---|
| 22 | /* this is passed in as a boot parameter by bootloader */ |
|---|
| 23 | //extern int __ath_flash_size; |
|---|
| 24 | |
|---|
| 25 | /* |
|---|
| 26 | * statics |
|---|
| 27 | */ |
|---|
| 28 | static void ar7100_spi_write_enable(void); |
|---|
| 29 | static void ar7100_spi_poll(void); |
|---|
| 30 | static void ar7100_spi_write_page(uint32_t addr, uint8_t * data, int len); |
|---|
| 31 | static void ar7100_spi_sector_erase(uint32_t addr); |
|---|
| 32 | |
|---|
| 33 | static const char *part_probes[] __initdata = |
|---|
| 34 | { "cmdlinepart", "RedBoot", NULL }; |
|---|
| 35 | |
|---|
| 36 | #define down mutex_lock |
|---|
| 37 | #define up mutex_unlock |
|---|
| 38 | #define init_MUTEX mutex_init |
|---|
| 39 | #define DECLARE_MUTEX(a) struct mutex a |
|---|
| 40 | |
|---|
| 41 | static DECLARE_MUTEX(ar7100_flash_sem); |
|---|
| 42 | |
|---|
| 43 | /* GLOBAL FUNCTIONS */ |
|---|
| 44 | void ar7100_flash_spi_down(void) |
|---|
| 45 | { |
|---|
| 46 | //printk(KERN_EMERG "spi down\n"); |
|---|
| 47 | down(&ar7100_flash_sem); |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | void ar7100_flash_spi_up(void) |
|---|
| 51 | { |
|---|
| 52 | //printk(KERN_EMERG "spi up\n"); |
|---|
| 53 | up(&ar7100_flash_sem); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | EXPORT_SYMBOL(ar7100_flash_spi_down); |
|---|
| 57 | EXPORT_SYMBOL(ar7100_flash_spi_up); |
|---|
| 58 | |
|---|
| 59 | #define AR7100_FLASH_SIZE_2MB (2*1024*1024) |
|---|
| 60 | #define AR7100_FLASH_SIZE_4MB (4*1024*1024) |
|---|
| 61 | #define AR7100_FLASH_SIZE_8MB (8*1024*1024) |
|---|
| 62 | #define AR7100_FLASH_SIZE_16MB (16*1024*1024) |
|---|
| 63 | #define AR7100_FLASH_SECTOR_SIZE_64KB (64*1024) |
|---|
| 64 | #define AR7100_FLASH_PG_SIZE_256B 256 |
|---|
| 65 | #define AR7100_FLASH_NAME "ar7100-nor0" |
|---|
| 66 | |
|---|
| 67 | /* |
|---|
| 68 | * bank geometry |
|---|
| 69 | */ |
|---|
| 70 | typedef struct ar7100_flash_geom { |
|---|
| 71 | uint32_t size; |
|---|
| 72 | uint32_t sector_size; |
|---|
| 73 | uint32_t nsectors; |
|---|
| 74 | uint32_t pgsize; |
|---|
| 75 | } ar7100_flash_geom_t; |
|---|
| 76 | |
|---|
| 77 | ar7100_flash_geom_t flash_geom_tbl[AR7100_FLASH_MAX_BANKS] = { |
|---|
| 78 | { |
|---|
| 79 | #ifdef CONFIG_MTD_FLASH_16MB |
|---|
| 80 | .size = AR7100_FLASH_SIZE_16MB, |
|---|
| 81 | #elif CONFIG_MTD_FLASH_8MB |
|---|
| 82 | .size = AR7100_FLASH_SIZE_8MB, |
|---|
| 83 | #else |
|---|
| 84 | .size = AR7100_FLASH_SIZE_4MB, |
|---|
| 85 | #endif |
|---|
| 86 | .sector_size = AR7100_FLASH_SECTOR_SIZE_64KB, |
|---|
| 87 | .pgsize = AR7100_FLASH_PG_SIZE_256B} |
|---|
| 88 | }; |
|---|
| 89 | |
|---|
| 90 | static int ar7100_flash_probe() |
|---|
| 91 | { |
|---|
| 92 | return 0; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | static int ar7100_flash_erase(struct mtd_info *mtd, struct erase_info *instr) |
|---|
| 96 | { |
|---|
| 97 | int nsect, s_curr, s_last; |
|---|
| 98 | uint64_t res; |
|---|
| 99 | if (instr->addr + instr->len > mtd->size) |
|---|
| 100 | return (-EINVAL); |
|---|
| 101 | |
|---|
| 102 | ar7100_flash_spi_down(); |
|---|
| 103 | |
|---|
| 104 | res = instr->len; |
|---|
| 105 | do_div(res, mtd->erasesize); |
|---|
| 106 | nsect = res; |
|---|
| 107 | |
|---|
| 108 | if (((uint32_t)instr->len) % mtd->erasesize) |
|---|
| 109 | nsect++; |
|---|
| 110 | |
|---|
| 111 | res = instr->addr; |
|---|
| 112 | do_div(res,mtd->erasesize); |
|---|
| 113 | s_curr = res; |
|---|
| 114 | s_last = s_curr + nsect; |
|---|
| 115 | |
|---|
| 116 | do { |
|---|
| 117 | ar7100_spi_sector_erase(s_curr * AR7100_SPI_SECTOR_SIZE); |
|---|
| 118 | } while (++s_curr < s_last); |
|---|
| 119 | |
|---|
| 120 | ar7100_spi_done(); |
|---|
| 121 | |
|---|
| 122 | ar7100_flash_spi_up(); |
|---|
| 123 | |
|---|
| 124 | if (instr->callback) { |
|---|
| 125 | instr->state = MTD_ERASE_DONE; |
|---|
| 126 | instr->callback(instr); |
|---|
| 127 | } |
|---|
| 128 | //printk(KERN_EMERG "done\n"); |
|---|
| 129 | return 0; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | static int |
|---|
| 133 | ar7100_flash_read(struct mtd_info *mtd, loff_t from, size_t len, |
|---|
| 134 | size_t *retlen, u_char * buf) |
|---|
| 135 | { |
|---|
| 136 | uint32_t addr = from | 0xbf000000; |
|---|
| 137 | |
|---|
| 138 | // printk(KERN_EMERG "read block %X:%X\n",from,len); |
|---|
| 139 | if (!len) |
|---|
| 140 | return (0); |
|---|
| 141 | if (from + len > mtd->size) |
|---|
| 142 | return (-EINVAL); |
|---|
| 143 | |
|---|
| 144 | // ar7100_flash_spi_down(); |
|---|
| 145 | |
|---|
| 146 | memcpy(buf, (uint8_t *) (addr), len); |
|---|
| 147 | *retlen = len; |
|---|
| 148 | |
|---|
| 149 | // ar7100_flash_spi_up(); |
|---|
| 150 | // printk(KERN_EMERG "read block %X:%X done\n",from,len); |
|---|
| 151 | |
|---|
| 152 | return 0; |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | static int |
|---|
| 156 | ar7100_flash_write(struct mtd_info *mtd, loff_t to, size_t len, |
|---|
| 157 | size_t *retlen, const u_char * buf) |
|---|
| 158 | { |
|---|
| 159 | int total = 0, len_this_lp, bytes_this_page; |
|---|
| 160 | uint32_t addr = 0; |
|---|
| 161 | u_char *mem; |
|---|
| 162 | // printk(KERN_EMERG "write block %X:%X\n",to,len); |
|---|
| 163 | |
|---|
| 164 | ar7100_flash_spi_down(); |
|---|
| 165 | |
|---|
| 166 | while (total < len) { |
|---|
| 167 | mem = buf + total; |
|---|
| 168 | addr = to + total; |
|---|
| 169 | bytes_this_page = |
|---|
| 170 | AR7100_SPI_PAGE_SIZE - (addr % AR7100_SPI_PAGE_SIZE); |
|---|
| 171 | len_this_lp = min((len - total), bytes_this_page); |
|---|
| 172 | |
|---|
| 173 | ar7100_spi_write_page(addr, mem, len_this_lp); |
|---|
| 174 | total += len_this_lp; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | ar7100_spi_done(); |
|---|
| 178 | |
|---|
| 179 | ar7100_flash_spi_up(); |
|---|
| 180 | |
|---|
| 181 | *retlen = len; |
|---|
| 182 | return 0; |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | static int zcom=0; |
|---|
| 186 | static unsigned int zcomoffset = 0; |
|---|
| 187 | int guessbootsize(void *offset, unsigned int maxscan) |
|---|
| 188 | { |
|---|
| 189 | unsigned int i,a; |
|---|
| 190 | unsigned int *ofs = (unsigned int *)offset; |
|---|
| 191 | maxscan -= 65536; |
|---|
| 192 | maxscan /= 4; |
|---|
| 193 | zcom=0; |
|---|
| 194 | for (i = 0; i < maxscan; i += 16384) { |
|---|
| 195 | if (ofs[i] == 0x6d000080) { |
|---|
| 196 | printk(KERN_EMERG "redboot or compatible detected\n"); |
|---|
| 197 | return i * 4; // redboot, lzma image |
|---|
| 198 | } |
|---|
| 199 | if (ofs[i] == 0x27051956) { |
|---|
| 200 | printk(KERN_EMERG "uboot detected\n"); |
|---|
| 201 | return i * 4; // uboot, lzma image |
|---|
| 202 | } |
|---|
| 203 | if (ofs[i] == 0x33373030) { |
|---|
| 204 | printk(KERN_EMERG "WNDR3700 uboot detected\n"); |
|---|
| 205 | return 0x70000; // uboot, lzma image |
|---|
| 206 | } |
|---|
| 207 | if (ofs[i] == 0x33373031) { |
|---|
| 208 | printk(KERN_EMERG "WNDR3700v2 uboot detected\n"); |
|---|
| 209 | return 0x70000; // uboot, lzma image |
|---|
| 210 | } |
|---|
| 211 | if (ofs[i] == 0x01000000 && ofs[i+1] == 0x44442d57) { |
|---|
| 212 | printk(KERN_EMERG "tplink uboot detected\n"); |
|---|
| 213 | return i * 4; // uboot, lzma image |
|---|
| 214 | } |
|---|
| 215 | if (ofs[i + 15] == 0x27051956) { |
|---|
| 216 | printk(KERN_EMERG "WRT160NL/E2100L uboot detected\n"); |
|---|
| 217 | return i * 4; // uboot, lzma image |
|---|
| 218 | } |
|---|
| 219 | if (ofs[i] == SQUASHFS_MAGIC) { |
|---|
| 220 | printk(KERN_EMERG "ZCom quirk found\n"); |
|---|
| 221 | zcom=1; |
|---|
| 222 | for (a = i; a < maxscan; a += 16384) { |
|---|
| 223 | if (ofs[a] == 0x27051956) { |
|---|
| 224 | printk(KERN_EMERG "ZCom quirk kernel offset %d\n",a*4); |
|---|
| 225 | zcomoffset = a * 4; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | } |
|---|
| 229 | return i * 4; // filesys starts earlier |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | } |
|---|
| 233 | return -1; |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | static unsigned int guessflashsize(void *base) |
|---|
| 237 | { |
|---|
| 238 | unsigned int size; |
|---|
| 239 | unsigned int *guess = (unsigned int *)base; |
|---|
| 240 | unsigned int max = 16 << 20; |
|---|
| 241 | //check 3 patterns since we can't write. |
|---|
| 242 | unsigned int p1 = guess[0]; |
|---|
| 243 | unsigned int p2 = guess[4096]; |
|---|
| 244 | unsigned int p3 = guess[8192]; |
|---|
| 245 | unsigned int c1; |
|---|
| 246 | unsigned int c2; |
|---|
| 247 | unsigned int c3; |
|---|
| 248 | for (size = 2 << 20; size <= (max >> 1); size <<= 1) { |
|---|
| 249 | unsigned int ofs = size / 4; |
|---|
| 250 | c1 = guess[ofs]; |
|---|
| 251 | c2 = guess[ofs + 4096]; |
|---|
| 252 | c3 = guess[ofs + 8192]; |
|---|
| 253 | if (p1 == c1 && p2 == c2 && p3 == c3) // mirror found |
|---|
| 254 | { |
|---|
| 255 | break; |
|---|
| 256 | } |
|---|
| 257 | } |
|---|
| 258 | printk(KERN_EMERG "guessed flashsize = %dM\n", size >> 20); |
|---|
| 259 | return size; |
|---|
| 260 | |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | static struct mtd_partition dir_parts[] = { |
|---|
| 264 | #ifdef CONFIG_MTD_FLASH_16MB |
|---|
| 265 | {name: "RedBoot", offset: 0, size:0x40000,}, |
|---|
| 266 | //, mask_flags: MTD_WRITEABLE, }, |
|---|
| 267 | {name: "linux", offset: 0x30000, size:0xf90000,}, |
|---|
| 268 | #elif CONFIG_MTD_FLASH_8MB |
|---|
| 269 | #ifdef CONFIG_AR7100_LOW |
|---|
| 270 | {name: "RedBoot", offset: 0, size:0x50000,}, |
|---|
| 271 | {name: "linux", offset: 0x50000, size:0x770000,}, |
|---|
| 272 | #elif CONFIG_AR9100 //, mask_flags: MTD_WRITEABLE, } |
|---|
| 273 | {name: "RedBoot", offset: 0, size:0x40000,}, |
|---|
| 274 | {name: "linux", offset: 0x40000, size:0x7a0000,}, |
|---|
| 275 | #else //, mask_flags: MTD_WRITEABLE, }, |
|---|
| 276 | {name: "RedBoot", offset: 0, size:0x30000,}, |
|---|
| 277 | {name: "linux", offset: 0x30000, size:0x790000,}, |
|---|
| 278 | #endif |
|---|
| 279 | |
|---|
| 280 | #else |
|---|
| 281 | {name: "RedBoot", offset: 0, size:0x40000,}, |
|---|
| 282 | //, mask_flags: MTD_WRITEABLE, }, |
|---|
| 283 | {name: "linux", offset: 0x40000, size:0x390000,}, |
|---|
| 284 | #endif |
|---|
| 285 | {name: "rootfs", offset: 0x0, size:0x2b0000,}, |
|---|
| 286 | //must be detected |
|---|
| 287 | {name: "ddwrt", offset: 0x0, size:0x2b0000,}, |
|---|
| 288 | //must be detected |
|---|
| 289 | {name: "nvram", offset: 0x3d0000, size:0x10000,}, |
|---|
| 290 | {name: "FIS directory", offset: 0x3e0000, size:0x10000,}, |
|---|
| 291 | {name: "board_config", offset: 0x3f0000, size:0x10000,}, |
|---|
| 292 | {name: "fullflash", offset: 0x3f0000, size:0x10000,}, |
|---|
| 293 | {name:NULL,}, |
|---|
| 294 | }; |
|---|
| 295 | |
|---|
| 296 | struct fis_image_desc { |
|---|
| 297 | unsigned char name[16]; // Null terminated name |
|---|
| 298 | unsigned long flash_base; // Address within FLASH of image |
|---|
| 299 | unsigned long mem_base; // Address in memory where it executes |
|---|
| 300 | unsigned long size; // Length of image |
|---|
| 301 | unsigned long entry_point; // Execution entry point |
|---|
| 302 | unsigned long data_length; // Length of actual data |
|---|
| 303 | unsigned char _pad[256 - (16 + 7 * sizeof(unsigned long))]; |
|---|
| 304 | unsigned long desc_cksum; // Checksum over image descriptor |
|---|
| 305 | unsigned long file_cksum; // Checksum over image data |
|---|
| 306 | }; |
|---|
| 307 | |
|---|
| 308 | /* |
|---|
| 309 | * sets up flash_info and returns size of FLASH (bytes) |
|---|
| 310 | */ |
|---|
| 311 | static int __init ar7100_flash_init(void) |
|---|
| 312 | { |
|---|
| 313 | int i, np; |
|---|
| 314 | ar7100_flash_geom_t *geom; |
|---|
| 315 | struct mtd_info *mtd; |
|---|
| 316 | struct mtd_partition *mtd_parts; |
|---|
| 317 | uint8_t index; |
|---|
| 318 | int result = -1; |
|---|
| 319 | char *buf; |
|---|
| 320 | struct fis_image_desc *fis; |
|---|
| 321 | unsigned char *p; |
|---|
| 322 | int offset = 0; |
|---|
| 323 | struct squashfs_super_block *sb; |
|---|
| 324 | size_t rootsize; |
|---|
| 325 | size_t len; |
|---|
| 326 | |
|---|
| 327 | init_MUTEX(&ar7100_flash_sem); |
|---|
| 328 | |
|---|
| 329 | ar7100_reg_wr_nf(AR7100_SPI_CLOCK, 0x43); |
|---|
| 330 | |
|---|
| 331 | buf = 0xbf000000; |
|---|
| 332 | int fsize = guessflashsize(buf); |
|---|
| 333 | |
|---|
| 334 | for (i = 0; i < AR7100_FLASH_MAX_BANKS; i++) { |
|---|
| 335 | |
|---|
| 336 | index = ar7100_flash_probe(); |
|---|
| 337 | geom = &flash_geom_tbl[index]; |
|---|
| 338 | |
|---|
| 339 | /* set flash size to value from bootloader if it passed valid value */ |
|---|
| 340 | /* otherwise use the default 4MB. */ |
|---|
| 341 | //if (__ath_flash_size >= 4 && __ath_flash_size <= 16) |
|---|
| 342 | // geom->size = __ath_flash_size * 1024 * 1024; |
|---|
| 343 | |
|---|
| 344 | mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); |
|---|
| 345 | if (!mtd) { |
|---|
| 346 | printk("Cant allocate mtd stuff\n"); |
|---|
| 347 | return -1; |
|---|
| 348 | } |
|---|
| 349 | memset(mtd, 0, sizeof(struct mtd_info)); |
|---|
| 350 | |
|---|
| 351 | mtd->name = AR7100_FLASH_NAME; |
|---|
| 352 | mtd->type = MTD_NORFLASH; |
|---|
| 353 | mtd->flags = (MTD_CAP_NORFLASH | MTD_WRITEABLE); |
|---|
| 354 | mtd->size = fsize;; |
|---|
| 355 | mtd->erasesize = geom->sector_size; |
|---|
| 356 | mtd->numeraseregions = 0; |
|---|
| 357 | mtd->eraseregions = NULL; |
|---|
| 358 | mtd->owner = THIS_MODULE; |
|---|
| 359 | mtd->erase = ar7100_flash_erase; |
|---|
| 360 | mtd->read = ar7100_flash_read; |
|---|
| 361 | mtd->write = ar7100_flash_write; |
|---|
| 362 | |
|---|
| 363 | printk(KERN_EMERG "scanning for root partition\n"); |
|---|
| 364 | |
|---|
| 365 | offset = 0; |
|---|
| 366 | |
|---|
| 367 | int compex = 0; |
|---|
| 368 | if (!strncmp((char *)(buf + 0x295a), "myloram.bin", 11)) { |
|---|
| 369 | printk(KERN_EMERG "Compex WP543 device detected\n"); |
|---|
| 370 | dir_parts[0].size = 0x30000; |
|---|
| 371 | dir_parts[0].offset = 0; |
|---|
| 372 | dir_parts[7].size = mtd->size; |
|---|
| 373 | dir_parts[7].offset = 0; |
|---|
| 374 | |
|---|
| 375 | dir_parts[6].size = mtd->erasesize; |
|---|
| 376 | dir_parts[6].offset = mtd->size - mtd->erasesize; |
|---|
| 377 | compex = 1; |
|---|
| 378 | } else { |
|---|
| 379 | int guess = guessbootsize(buf, mtd->size); |
|---|
| 380 | if (guess > 0) { |
|---|
| 381 | printk(KERN_EMERG "bootloader size = %X\n", |
|---|
| 382 | guess); |
|---|
| 383 | dir_parts[0].size = guess; |
|---|
| 384 | dir_parts[0].offset = 0; |
|---|
| 385 | dir_parts[1].offset = guess; |
|---|
| 386 | dir_parts[1].size = 0; |
|---|
| 387 | } |
|---|
| 388 | |
|---|
| 389 | } |
|---|
| 390 | |
|---|
| 391 | while ((offset + mtd->erasesize) < mtd->size) { |
|---|
| 392 | //printk(KERN_EMERG "[0x%08X] = [0x%08X]!=[0x%08X]\n",offset,*((unsigned int *) buf),SQUASHFS_MAGIC); |
|---|
| 393 | if (*((__u32 *)buf) == SQUASHFS_MAGIC) { |
|---|
| 394 | printk(KERN_EMERG "\nfound squashfs at %X\n", |
|---|
| 395 | offset); |
|---|
| 396 | sb = (struct squashfs_super_block *)buf; |
|---|
| 397 | dir_parts[2].offset = offset; |
|---|
| 398 | |
|---|
| 399 | dir_parts[2].size = sb->bytes_used; |
|---|
| 400 | len = dir_parts[2].offset + dir_parts[2].size; |
|---|
| 401 | len += (mtd->erasesize - 1); |
|---|
| 402 | len &= ~(mtd->erasesize - 1); |
|---|
| 403 | dir_parts[2].size = |
|---|
| 404 | (len & 0x1ffffff) - dir_parts[2].offset; |
|---|
| 405 | #if defined(CONFIG_DIR825) |
|---|
| 406 | dir_parts[3].offset = 0x670000; |
|---|
| 407 | #else |
|---|
| 408 | dir_parts[3].offset = |
|---|
| 409 | dir_parts[2].offset + dir_parts[2].size; |
|---|
| 410 | #endif |
|---|
| 411 | dir_parts[6].offset = mtd->size - mtd->erasesize; // board config |
|---|
| 412 | dir_parts[6].size = mtd->erasesize; |
|---|
| 413 | #ifdef CONFIG_MTD_FLASH_16MB |
|---|
| 414 | #ifdef CONFIG_MTD_PB44 |
|---|
| 415 | dir_parts[5].offset = dir_parts[6].offset - mtd->erasesize; //fis config |
|---|
| 416 | #else |
|---|
| 417 | dir_parts[5].offset = dir_parts[6].offset; //fis config |
|---|
| 418 | #endif |
|---|
| 419 | dir_parts[5].offset = mtd->size - mtd->erasesize; //fis config |
|---|
| 420 | dir_parts[5].size = mtd->erasesize; |
|---|
| 421 | #elif CONFIG_AR9100 |
|---|
| 422 | dir_parts[5].offset = dir_parts[6].offset; //fis config |
|---|
| 423 | dir_parts[5].size = mtd->erasesize; |
|---|
| 424 | #elif CONFIG_MTD_FLASH_8MB |
|---|
| 425 | dir_parts[5].offset = dir_parts[6].offset; //fis config |
|---|
| 426 | dir_parts[5].size = mtd->erasesize; |
|---|
| 427 | #else |
|---|
| 428 | dir_parts[5].offset = dir_parts[6].offset - mtd->erasesize; //fis config |
|---|
| 429 | dir_parts[5].size = mtd->erasesize; |
|---|
| 430 | #endif |
|---|
| 431 | if (compex) |
|---|
| 432 | dir_parts[4].offset = mtd->size - mtd->erasesize; //nvram |
|---|
| 433 | else |
|---|
| 434 | dir_parts[4].offset = dir_parts[5].offset - mtd->erasesize; //nvram |
|---|
| 435 | dir_parts[4].size = mtd->erasesize; |
|---|
| 436 | dir_parts[3].size = dir_parts[4].offset - dir_parts[3].offset; |
|---|
| 437 | rootsize = dir_parts[4].offset - offset; //size of rootfs aligned to nvram offset |
|---|
| 438 | #ifdef CONFIG_AR9100 |
|---|
| 439 | // dir_parts[1].offset = 0x40000; |
|---|
| 440 | dir_parts[1].size = (dir_parts[2].offset -dir_parts[1].offset) + rootsize; |
|---|
| 441 | if (zcom) |
|---|
| 442 | { |
|---|
| 443 | dir_parts[1].size = 0x7d0000 - 0x50000; |
|---|
| 444 | dir_parts[1].offset = 0x50000; |
|---|
| 445 | dir_parts[2].size = sb->bytes_used; |
|---|
| 446 | dir_parts[2].offset = 0x50000; |
|---|
| 447 | len = dir_parts[2].offset + dir_parts[2].size; |
|---|
| 448 | len += (mtd->erasesize - 1); |
|---|
| 449 | len &= ~(mtd->erasesize - 1); |
|---|
| 450 | dir_parts[2].size = (len & 0x1ffffff) - dir_parts[2].offset; |
|---|
| 451 | dir_parts[3].offset = dir_parts[2].offset + dir_parts[2].size; |
|---|
| 452 | dir_parts[3].size = 0x7d0000 - dir_parts[3].offset; |
|---|
| 453 | dir_parts[6].offset = mtd->size - mtd->erasesize; // board config |
|---|
| 454 | dir_parts[6].size = mtd->erasesize; |
|---|
| 455 | dir_parts[5].offset = dir_parts[6].offset; //fis config |
|---|
| 456 | dir_parts[4].offset = dir_parts[5].offset - mtd->erasesize; //nvram |
|---|
| 457 | } |
|---|
| 458 | break; |
|---|
| 459 | #else |
|---|
| 460 | //now scan for linux offset |
|---|
| 461 | if (compex) { |
|---|
| 462 | dir_parts[1].offset = 0x30000; |
|---|
| 463 | dir_parts[1].size = |
|---|
| 464 | (dir_parts[2].offset - |
|---|
| 465 | dir_parts[1].offset) + rootsize; |
|---|
| 466 | break; |
|---|
| 467 | } else { |
|---|
| 468 | p = (unsigned char *)(0xbf000000 + |
|---|
| 469 | dir_parts |
|---|
| 470 | [5].offset); |
|---|
| 471 | fis = (struct fis_image_desc *)p; |
|---|
| 472 | while (1) { |
|---|
| 473 | if (fis->name[0] == 0xff) { |
|---|
| 474 | goto def; |
|---|
| 475 | } |
|---|
| 476 | if (!strcmp |
|---|
| 477 | (fis->name, "RedBoot")) { |
|---|
| 478 | printk(KERN_EMERG |
|---|
| 479 | "found RedBoot partition at [0x%08lX]\n", |
|---|
| 480 | fis->flash_base); |
|---|
| 481 | dir_parts[0].size = |
|---|
| 482 | fis->size; |
|---|
| 483 | dir_parts[7].offset = |
|---|
| 484 | dir_parts[0].size; |
|---|
| 485 | } |
|---|
| 486 | if (!strncmp |
|---|
| 487 | (fis->name, "linux", 5) |
|---|
| 488 | || !strncmp(fis->name, |
|---|
| 489 | "vmlinux", 7) |
|---|
| 490 | || !strncmp(fis->name, |
|---|
| 491 | "kernel", 6)) { |
|---|
| 492 | printk(KERN_EMERG |
|---|
| 493 | "found linux partition at [0x%08lX]\n", |
|---|
| 494 | fis->flash_base); |
|---|
| 495 | dir_parts[1].offset = |
|---|
| 496 | fis->flash_base & |
|---|
| 497 | (mtd->size - 1); |
|---|
| 498 | dir_parts[1].size = |
|---|
| 499 | (dir_parts[2].offset |
|---|
| 500 | - |
|---|
| 501 | dir_parts |
|---|
| 502 | [1].offset) + |
|---|
| 503 | rootsize; |
|---|
| 504 | } |
|---|
| 505 | p += sizeof(struct |
|---|
| 506 | fis_image_desc); |
|---|
| 507 | fis = |
|---|
| 508 | (struct fis_image_desc *)p; |
|---|
| 509 | } |
|---|
| 510 | break; |
|---|
| 511 | } |
|---|
| 512 | #endif |
|---|
| 513 | } |
|---|
| 514 | offset += 4096; |
|---|
| 515 | buf += 4096; |
|---|
| 516 | } |
|---|
| 517 | def:; |
|---|
| 518 | dir_parts[7].offset = 0; // linux + nvram = phy size |
|---|
| 519 | dir_parts[7].size = mtd->size; // linux + nvram = phy size |
|---|
| 520 | result = add_mtd_partitions(mtd, dir_parts, 8); |
|---|
| 521 | } |
|---|
| 522 | |
|---|
| 523 | return 0; |
|---|
| 524 | } |
|---|
| 525 | |
|---|
| 526 | static void __exit ar7100_flash_exit(void) |
|---|
| 527 | { |
|---|
| 528 | /* |
|---|
| 529 | * nothing to do |
|---|
| 530 | */ |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | /* |
|---|
| 534 | * Primitives to implement flash operations |
|---|
| 535 | */ |
|---|
| 536 | static void ar7100_spi_write_enable() |
|---|
| 537 | { |
|---|
| 538 | ar7100_reg_wr_nf(AR7100_SPI_FS, 1); |
|---|
| 539 | ar7100_reg_wr_nf(AR7100_SPI_WRITE, AR7100_SPI_CS_DIS); |
|---|
| 540 | ar7100_spi_bit_banger(AR7100_SPI_CMD_WREN); |
|---|
| 541 | ar7100_spi_go(); |
|---|
| 542 | } |
|---|
| 543 | |
|---|
| 544 | static void ar7100_spi_poll() |
|---|
| 545 | { |
|---|
| 546 | int rd; |
|---|
| 547 | |
|---|
| 548 | do { |
|---|
| 549 | ar7100_reg_wr_nf(AR7100_SPI_WRITE, AR7100_SPI_CS_DIS); |
|---|
| 550 | ar7100_spi_bit_banger(AR7100_SPI_CMD_RD_STATUS); |
|---|
| 551 | ar7100_spi_delay_8(); |
|---|
| 552 | rd = (ar7100_reg_rd(AR7100_SPI_RD_STATUS) & 1); |
|---|
| 553 | } while (rd); |
|---|
| 554 | } |
|---|
| 555 | |
|---|
| 556 | static void ar7100_spi_write_page(uint32_t addr, uint8_t * data, int len) |
|---|
| 557 | { |
|---|
| 558 | int i; |
|---|
| 559 | uint8_t ch; |
|---|
| 560 | |
|---|
| 561 | ar7100_spi_write_enable(); |
|---|
| 562 | ar7100_spi_bit_banger(AR7100_SPI_CMD_PAGE_PROG); |
|---|
| 563 | ar7100_spi_send_addr(addr); |
|---|
| 564 | |
|---|
| 565 | for (i = 0; i < len; i++) { |
|---|
| 566 | ch = *(data + i); |
|---|
| 567 | ar7100_spi_bit_banger(ch); |
|---|
| 568 | } |
|---|
| 569 | |
|---|
| 570 | ar7100_spi_go(); |
|---|
| 571 | ar7100_spi_poll(); |
|---|
| 572 | } |
|---|
| 573 | |
|---|
| 574 | static void ar7100_spi_sector_erase(uint32_t addr) |
|---|
| 575 | { |
|---|
| 576 | ar7100_spi_write_enable(); |
|---|
| 577 | ar7100_spi_bit_banger(AR7100_SPI_CMD_SECTOR_ERASE); |
|---|
| 578 | ar7100_spi_send_addr(addr); |
|---|
| 579 | ar7100_spi_go(); |
|---|
| 580 | // display(0x7d); |
|---|
| 581 | ar7100_spi_poll(); |
|---|
| 582 | } |
|---|
| 583 | |
|---|
| 584 | module_init(ar7100_flash_init); |
|---|
| 585 | module_exit(ar7100_flash_exit); |
|---|