1/* 2 * Handle mapping of the flash memory access routines 3 * on Amazon based devices. 4 * 5 * Copyright(C) 2004 peng.liu@infineon.com 6 * 7 * This code is GPLed 8 * 9 */ 10// 000005:fchang 2005/6/2 Modified by Bingtao to double check if the EBU is enabled/disabled 11// 506231:tc.chen 2005/06/23 increase firmware partition size form 192KB to 256KB 12// 050701:linmars 2005/07/01 fix flash size wrong alignment after increase firmware partition 13// 165001:henryhsu 2005/8/18 Remove the support for Intel flash because of 2.1 not enough rootfs partition size 14// 165001:henryhsu 2005/9/7 Rolback to support INtel flash 15// 509071:tc.chen 2005/09/07 Reduced flash writing time 16// 511046:linmars 2005/11/04 change bootloader size from 128 into 64 17// 511241:linmars 2005/11/24 merge TaiChen's IRM patch 18 19// copyright 2005 infineon 20 21// copyright 2007 john crispin <blogic@openwrt.org> 22// copyright 2007 felix fietkau <nbd@openwrt.org> 23// copyright 2009 hauke mehrtens <hauke@hauke-m.de> 24 25#include <linux/module.h> 26#include <linux/types.h> 27#include <linux/kernel.h> 28#include <asm/io.h> 29 30#include <linux/init.h> 31#include <linux/mtd/mtd.h> 32#include <linux/mtd/map.h> 33#include <linux/mtd/partitions.h> 34#include <linux/mtd/cfi.h> 35#include <linux/mutex.h> 36#include <linux/platform_device.h> 37#include <asm/amazon/amazon.h> 38 39#define AMAZON_PCI_ARB_CTL_ALT 0xb100205c 40#define AMAZON_MTD_REG32( addr ) (*(volatile u32 *)(addr)) 41 42 43static struct map_info amazon_map = { 44 .name = "AMAZON_FLASH", 45 .bankwidth = 2, 46}; 47 48static map_word amazon_read16(struct map_info * map, unsigned long ofs) 49{ 50 map_word temp; 51 ofs ^= 2; 52 temp.x[0] = *((__u16 *) (map->virt + ofs)); 53 return temp; 54} 55 56static void amazon_write16(struct map_info *map, map_word d, unsigned long adr) 57{ 58 adr ^= 2; 59 *((__u16 *) (map->virt + adr)) = d.x[0]; 60} 61 62void amazon_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 63{ 64 u8 *p; 65 u8 *to_8; 66 from = (unsigned long) (from + map->virt); 67 p = (u8 *) from; 68 to_8 = (u8 *) to; 69 while(len--){ 70 *to_8++ = *p++; 71 } 72} 73 74void amazon_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 75{ 76 u8 *p = (u8*) from; 77 u8 *to_8; 78 to += (unsigned long) map->virt; 79 to_8 = (u8*)to; 80 while(len--){ 81 *p++ = *to_8++; 82 } 83} 84 85#define UBOOT_SIZE 0x40000 86 87static struct mtd_partition amazon_partitions[3] = { 88 { 89 name:"U-Boot", /* U-Boot firmware */ 90 offset:0x00000000, 91 size:UBOOT_SIZE , /* 128k */ 92 }, 93 { 94 name:"kernel", /* firmware */ 95 offset:UBOOT_SIZE, 96 size:0x00100000, /* 192K */ 97 }, 98 { 99 name:"rootfs", /* default partition */ 100 offset:0x00200000, 101 size:0x00200000, 102 }, 103}; 104 105unsigned long uImage_size = 0x10000d; 106 107int find_uImage_size(unsigned long start_offset) 108{ 109 unsigned long magic; 110 unsigned long temp; 111 amazon_copy_from(&amazon_map, &magic, start_offset, 4); 112 if (!(ntohl(magic) == 0x27051956)) { 113 printk(KERN_INFO "amazon_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", ntohl(magic), start_offset); 114 return 0; 115 } 116 amazon_copy_from(&amazon_map, &temp, start_offset + 12, 4); 117 printk(KERN_INFO "amazon_mtd: kernel size is %ld \n", temp + 0x40); 118 return temp + 0x40; 119} 120 121static int amazon_mtd_probe(struct platform_device *dev) 122{ 123 unsigned long uimage_size; 124 struct mtd_info *mymtd = NULL; 125 struct mtd_partition *parts = NULL; 126 127 *AMAZON_EBU_BUSCON0 = 0x1d7ff; 128 129 amazon_map.read = amazon_read16; 130 amazon_map.write = amazon_write16; 131 amazon_map.copy_from = amazon_copy_from; 132 amazon_map.copy_to = amazon_copy_to; 133 134 amazon_map.phys = dev->resource->start; 135 amazon_map.size = dev->resource->end - amazon_map.phys + 1; 136 amazon_map.virt = ioremap_nocache(amazon_map.phys, amazon_map.size); 137 138 if (!amazon_map.virt) { 139 printk(KERN_WARNING "amazon_mtd: Failed to ioremap!\n"); 140 return -EIO; 141 } 142 143 mymtd = (struct mtd_info *) do_map_probe("cfi_probe", &amazon_map); 144 if (!mymtd) { 145 iounmap(amazon_map.virt); 146 printk(KERN_WARNING "amazon_mtd: probing failed\n"); 147 return -ENXIO; 148 } 149 150 mymtd->owner = THIS_MODULE; 151 parts = &amazon_partitions[0]; 152 153 /* Some Samsung devices are containing a 16 MB flash chip with a bigger U-Boot partition. */ 154 if(mymtd->size == 0x01000000 && mymtd->erasesize == 0x00020000) { 155 printk(KERN_INFO "amazon_mtd: Found big flash chip!\n"); 156 amazon_partitions[0].size = 0x60000; 157 amazon_partitions[1].offset = 0x60000; 158 uimage_size = find_uImage_size(amazon_partitions[1].offset); 159 amazon_partitions[1].size = uimage_size; 160 amazon_partitions[2].offset = 0x60000 + uimage_size; 161 amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - mymtd->erasesize; 162 } else { 163 printk(KERN_INFO "amazon_mtd: Found small flash chip!\n"); 164 uimage_size = find_uImage_size(amazon_partitions[1].offset); 165 amazon_partitions[1].size = uimage_size; 166 amazon_partitions[2].offset = UBOOT_SIZE + uimage_size; 167 amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - (2 * mymtd->erasesize); 168 } 169 170 mtd_device_register(mymtd, parts, 3); 171 172 printk(KERN_INFO "amazon_mtd: added %s flash with %dMB\n", 173 amazon_map.name, ((int)mymtd->size) >> 20); 174 return 0; 175} 176 177static struct platform_driver amazon_mtd_driver = { 178 .probe = amazon_mtd_probe, 179 .driver = { 180 .name = "amazon_mtd", 181 .owner = THIS_MODULE, 182 }, 183}; 184 185static int __init amazon_mtd_init(void) 186{ 187 int ret = platform_driver_register(&amazon_mtd_driver); 188 if (ret) 189 printk(KERN_WARNING "amazon_mtd: error registering platfom driver!\n"); 190 return ret; 191} 192 193static void __exit amazon_mtd_cleanup(void) 194{ 195 platform_driver_unregister(&amazon_mtd_driver); 196} 197 198module_init(amazon_mtd_init); 199module_exit(amazon_mtd_cleanup); 200 201MODULE_LICENSE("GPL"); 202MODULE_AUTHOR("john crispin blogic@openwrt.org"); 203MODULE_DESCRIPTION("MTD map driver for AMAZON boards"); 204 205