diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2009-03-04 15:01:33 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-03-20 14:09:54 -0400 |
commit | cbf77c1bd9c79d1742976862d0b2bebaff1ea14d (patch) | |
tree | bafc7ee03a3e562ff6ae15f66fced524011a705d /arch/mips/txx9/rbtx4939/setup.c | |
parent | a591f5d35e89be90c04830d7de01c276af68aeb7 (diff) |
[MTD] RBTX4939: add MTD support
Add platform support for NOR flash chips on RBTX4939 board.
This board has complex flash mappings, controlled by its DIPSW setting.
[akpm@linux-foundation.org: Use min_t]
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Ralf Bächle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'arch/mips/txx9/rbtx4939/setup.c')
-rw-r--r-- | arch/mips/txx9/rbtx4939/setup.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c index 74839f2a111e..011e1e332f47 100644 --- a/arch/mips/txx9/rbtx4939/setup.c +++ b/arch/mips/txx9/rbtx4939/setup.c | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/leds.h> | 16 | #include <linux/leds.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/smc91x.h> | 18 | #include <linux/smc91x.h> |
19 | #include <linux/mtd/mtd.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <linux/mtd/map.h> | ||
19 | #include <asm/reboot.h> | 22 | #include <asm/reboot.h> |
20 | #include <asm/txx9/generic.h> | 23 | #include <asm/txx9/generic.h> |
21 | #include <asm/txx9/pci.h> | 24 | #include <asm/txx9/pci.h> |
@@ -282,6 +285,159 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val) | |||
282 | __rbtx4939_7segled_putc(pos, val); | 285 | __rbtx4939_7segled_putc(pos, val); |
283 | } | 286 | } |
284 | 287 | ||
288 | #if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE) | ||
289 | /* special mapping for boot rom */ | ||
290 | static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs) | ||
291 | { | ||
292 | u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f; | ||
293 | unsigned char shift; | ||
294 | |||
295 | if (bdipsw & 8) { | ||
296 | /* BOOT Mode: USER ROM1 / USER ROM2 */ | ||
297 | shift = bdipsw & 3; | ||
298 | /* rotate A[23:22] */ | ||
299 | return (ofs & ~0xc00000) | ((((ofs >> 22) + shift) & 3) << 22); | ||
300 | } | ||
301 | #ifdef __BIG_ENDIAN | ||
302 | if (bdipsw == 0) | ||
303 | /* BOOT Mode: Monitor ROM */ | ||
304 | ofs ^= 0x400000; /* swap A[22] */ | ||
305 | #endif | ||
306 | return ofs; | ||
307 | } | ||
308 | |||
309 | static map_word rbtx4939_flash_read16(struct map_info *map, unsigned long ofs) | ||
310 | { | ||
311 | map_word r; | ||
312 | |||
313 | ofs = rbtx4939_flash_fixup_ofs(ofs); | ||
314 | r.x[0] = __raw_readw(map->virt + ofs); | ||
315 | return r; | ||
316 | } | ||
317 | |||
318 | static void rbtx4939_flash_write16(struct map_info *map, const map_word datum, | ||
319 | unsigned long ofs) | ||
320 | { | ||
321 | ofs = rbtx4939_flash_fixup_ofs(ofs); | ||
322 | __raw_writew(datum.x[0], map->virt + ofs); | ||
323 | mb(); /* see inline_map_write() in mtd/map.h */ | ||
324 | } | ||
325 | |||
326 | static void rbtx4939_flash_copy_from(struct map_info *map, void *to, | ||
327 | unsigned long from, ssize_t len) | ||
328 | { | ||
329 | u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f; | ||
330 | unsigned char shift; | ||
331 | ssize_t curlen; | ||
332 | |||
333 | from += (unsigned long)map->virt; | ||
334 | if (bdipsw & 8) { | ||
335 | /* BOOT Mode: USER ROM1 / USER ROM2 */ | ||
336 | shift = bdipsw & 3; | ||
337 | while (len) { | ||
338 | curlen = min_t(unsigned long, len, | ||
339 | 0x400000 - (from & (0x400000 - 1))); | ||
340 | memcpy(to, | ||
341 | (void *)((from & ~0xc00000) | | ||
342 | ((((from >> 22) + shift) & 3) << 22)), | ||
343 | curlen); | ||
344 | len -= curlen; | ||
345 | from += curlen; | ||
346 | to += curlen; | ||
347 | } | ||
348 | return; | ||
349 | } | ||
350 | #ifdef __BIG_ENDIAN | ||
351 | if (bdipsw == 0) { | ||
352 | /* BOOT Mode: Monitor ROM */ | ||
353 | while (len) { | ||
354 | curlen = min_t(unsigned long, len, | ||
355 | 0x400000 - (from & (0x400000 - 1))); | ||
356 | memcpy(to, (void *)(from ^ 0x400000), curlen); | ||
357 | len -= curlen; | ||
358 | from += curlen; | ||
359 | to += curlen; | ||
360 | } | ||
361 | return; | ||
362 | } | ||
363 | #endif | ||
364 | memcpy(to, (void *)from, len); | ||
365 | } | ||
366 | |||
367 | static void rbtx4939_flash_map_init(struct map_info *map) | ||
368 | { | ||
369 | map->read = rbtx4939_flash_read16; | ||
370 | map->write = rbtx4939_flash_write16; | ||
371 | map->copy_from = rbtx4939_flash_copy_from; | ||
372 | } | ||
373 | |||
374 | static void __init rbtx4939_mtd_init(void) | ||
375 | { | ||
376 | static struct { | ||
377 | struct platform_device dev; | ||
378 | struct resource res; | ||
379 | struct rbtx4939_flash_data data; | ||
380 | } pdevs[4]; | ||
381 | int i; | ||
382 | static char names[4][8]; | ||
383 | static struct mtd_partition parts[4]; | ||
384 | struct rbtx4939_flash_data *boot_pdata = &pdevs[0].data; | ||
385 | u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f; | ||
386 | |||
387 | if (bdipsw & 8) { | ||
388 | /* BOOT Mode: USER ROM1 / USER ROM2 */ | ||
389 | boot_pdata->nr_parts = 4; | ||
390 | for (i = 0; i < boot_pdata->nr_parts; i++) { | ||
391 | sprintf(names[i], "img%d", 4 - i); | ||
392 | parts[i].name = names[i]; | ||
393 | parts[i].size = 0x400000; | ||
394 | parts[i].offset = MTDPART_OFS_NXTBLK; | ||
395 | } | ||
396 | } else if (bdipsw == 0) { | ||
397 | /* BOOT Mode: Monitor ROM */ | ||
398 | boot_pdata->nr_parts = 2; | ||
399 | strcpy(names[0], "big"); | ||
400 | strcpy(names[1], "little"); | ||
401 | for (i = 0; i < boot_pdata->nr_parts; i++) { | ||
402 | parts[i].name = names[i]; | ||
403 | parts[i].size = 0x400000; | ||
404 | parts[i].offset = MTDPART_OFS_NXTBLK; | ||
405 | } | ||
406 | } else { | ||
407 | /* BOOT Mode: ROM Emulator */ | ||
408 | boot_pdata->nr_parts = 2; | ||
409 | parts[0].name = "boot"; | ||
410 | parts[0].offset = 0xc00000; | ||
411 | parts[0].size = 0x400000; | ||
412 | parts[1].name = "user"; | ||
413 | parts[1].offset = 0; | ||
414 | parts[1].size = 0xc00000; | ||
415 | } | ||
416 | boot_pdata->parts = parts; | ||
417 | boot_pdata->map_init = rbtx4939_flash_map_init; | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(pdevs); i++) { | ||
420 | struct resource *r = &pdevs[i].res; | ||
421 | struct platform_device *dev = &pdevs[i].dev; | ||
422 | |||
423 | r->start = 0x1f000000 - i * 0x1000000; | ||
424 | r->end = r->start + 0x1000000 - 1; | ||
425 | r->flags = IORESOURCE_MEM; | ||
426 | pdevs[i].data.width = 2; | ||
427 | dev->num_resources = 1; | ||
428 | dev->resource = r; | ||
429 | dev->id = i; | ||
430 | dev->name = "rbtx4939-flash"; | ||
431 | dev->dev.platform_data = &pdevs[i].data; | ||
432 | platform_device_register(dev); | ||
433 | } | ||
434 | } | ||
435 | #else | ||
436 | static void __init rbtx4939_mtd_init(void) | ||
437 | { | ||
438 | } | ||
439 | #endif | ||
440 | |||
285 | static void __init rbtx4939_arch_init(void) | 441 | static void __init rbtx4939_arch_init(void) |
286 | { | 442 | { |
287 | rbtx4939_pci_setup(); | 443 | rbtx4939_pci_setup(); |
@@ -333,6 +489,7 @@ static void __init rbtx4939_device_init(void) | |||
333 | platform_device_add_data(pdev, &smc_pdata, sizeof(smc_pdata)) || | 489 | platform_device_add_data(pdev, &smc_pdata, sizeof(smc_pdata)) || |
334 | platform_device_add(pdev)) | 490 | platform_device_add(pdev)) |
335 | platform_device_put(pdev); | 491 | platform_device_put(pdev); |
492 | rbtx4939_mtd_init(); | ||
336 | /* TC58DVM82A1FT: tDH=10ns, tWP=tRP=tREADID=35ns */ | 493 | /* TC58DVM82A1FT: tDH=10ns, tWP=tRP=tREADID=35ns */ |
337 | tx4939_ndfmc_init(10, 35, | 494 | tx4939_ndfmc_init(10, 35, |
338 | (1 << 1) | (1 << 2), | 495 | (1 << 1) | (1 << 2), |