diff options
Diffstat (limited to 'drivers/mtd/maps/ixp4xx.c')
| -rw-r--r-- | drivers/mtd/maps/ixp4xx.c | 225 |
1 files changed, 114 insertions, 111 deletions
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 5afe660aa2c..6a589f1e288 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -1,6 +1,4 @@ /* - * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ - * * drivers/mtd/maps/ixp4xx.c * * MTD Map file for IXP4XX based systems. Please do not make per-board @@ -15,26 +13,74 @@ * */ +#include <linux/err.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/string.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/platform_device.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <linux/ioport.h> -#include <linux/device.h> + #include <asm/io.h> -#include <asm/mach-types.h> #include <asm/mach/flash.h> #include <linux/reboot.h> +/* + * Read/write a 16 bit word from flash address 'addr'. + * + * When the cpu is in little-endian mode it swizzles the address lines + * ('address coherency') so we need to undo the swizzling to ensure commands + * and the like end up on the correct flash address. + * + * To further complicate matters, due to the way the expansion bus controller + * handles 32 bit reads, the byte stream ABCD is stored on the flash as: + * D15 D0 + * +---+---+ + * | A | B | 0 + * +---+---+ + * | C | D | 2 + * +---+---+ + * This means that on LE systems each 16 bit word must be swapped. Note that + * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI + * data and other flash commands which are always in D7-D0. + */ #ifndef __ARMEB__ +#ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP +# error CONFIG_MTD_CFI_BE_BYTE_SWAP required +#endif + +static inline u16 flash_read16(void __iomem *addr) +{ + return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2))); +} + +static inline void flash_write16(u16 d, void __iomem *addr) +{ + __raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2)); +} + #define BYTE0(h) ((h) & 0xFF) #define BYTE1(h) (((h) >> 8) & 0xFF) + #else + +static inline u16 flash_read16(const void __iomem *addr) +{ + return __raw_readw(addr); +} + +static inline void flash_write16(u16 d, void __iomem *addr) +{ + __raw_writew(d, addr); +} + #define BYTE0(h) (((h) >> 8) & 0xFF) #define BYTE1(h) ((h) & 0xFF) #endif @@ -42,7 +88,7 @@ static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) { map_word val; - val.x[0] = *(__u16 *) (map->map_priv_1 + ofs); + val.x[0] = flash_read16(map->virt + ofs); return val; } @@ -54,95 +100,82 @@ static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) static void ixp4xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { - int i; u8 *dest = (u8 *) to; - u16 *src = (u16 *) (map->map_priv_1 + from); - u16 data; + void __iomem *src = map->virt + from; + + if (len <= 0) + return; + + if (from & 1) { + *dest++ = BYTE1(flash_read16(src-1)); + src++; + --len; + } - for (i = 0; i < (len / 2); i++) { - data = src[i]; - dest[i * 2] = BYTE0(data); - dest[i * 2 + 1] = BYTE1(data); + while (len >= 2) { + u16 data = flash_read16(src); + *dest++ = BYTE0(data); + *dest++ = BYTE1(data); + src += 2; + len -= 2; } - if (len & 1) - dest[len - 1] = BYTE0(src[i]); + if (len > 0) + *dest++ = BYTE0(flash_read16(src)); } -/* +/* * Unaligned writes are ignored, causing the 8-bit * probe to fail and proceed to the 16-bit probe (which succeeds). */ static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) { if (!(adr & 1)) - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + flash_write16(d.x[0], map->virt + adr); } -/* +/* * Fast write16 function without the probing check above */ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) { - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + flash_write16(d.x[0], map->virt + adr); } struct ixp4xx_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; +static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; -static int ixp4xx_flash_remove(struct device *_dev) +static int ixp4xx_flash_remove(struct platform_device *dev) { - struct platform_device *dev = to_platform_device(_dev); - struct flash_platform_data *plat = dev->dev.platform_data; - struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); - map_word d; - - dev_set_drvdata(&dev->dev, NULL); + struct flash_platform_data *plat = dev_get_platdata(&dev->dev); + struct ixp4xx_flash_info *info = platform_get_drvdata(dev); if(!info) return 0; - /* - * This is required for a soft reboot to work. - */ - d.x[0] = 0xff; - ixp4xx_write16(&info->map, d, 0x55 * 0x2); - if (info->mtd) { - del_mtd_partitions(info->mtd); + mtd_device_unregister(info->mtd); map_destroy(info->mtd); } - if (info->map.map_priv_1) - iounmap((void *) info->map.map_priv_1); - - if (info->partitions) - kfree(info->partitions); - - if (info->res) { - release_resource(info->res); - kfree(info->res); - } if (plat->exit) plat->exit(); - /* Disable flash write */ - *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE; - return 0; } -static int ixp4xx_flash_probe(struct device *_dev) +static int ixp4xx_flash_probe(struct platform_device *dev) { - struct platform_device *dev = to_platform_device(_dev); - struct flash_platform_data *plat = dev->dev.platform_data; + struct flash_platform_data *plat = dev_get_platdata(&dev->dev); struct ixp4xx_flash_info *info; + struct mtd_part_parser_data ppdata = { + .origin = dev->resource->start, + }; int err = -1; if (!plat) @@ -154,27 +187,21 @@ static int ixp4xx_flash_probe(struct device *_dev) return err; } - info = kmalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL); + info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info), + GFP_KERNEL); if(!info) { err = -ENOMEM; goto Error; - } - memzero(info, sizeof(struct ixp4xx_flash_info)); + } - dev_set_drvdata(&dev->dev, info); - - /* - * Enable flash write - * TODO: Move this out to board specific code - */ - *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; + platform_set_drvdata(dev, info); /* * Tell the MTD layer we're not 1:1 mapped so that it does * not attempt to do a direct access on us. */ info->map.phys = NO_XIP; - info->map.size = dev->resource->end - dev->resource->start + 1; + info->map.size = resource_size(dev->resource); /* * We only support 16-bit accesses for now. If and when @@ -182,25 +209,14 @@ static int ixp4xx_flash_probe(struct device *_dev) * handle that. */ info->map.bankwidth = 2; - info->map.name = dev->dev.bus_id; - info->map.read = ixp4xx_read16, - info->map.write = ixp4xx_probe_write16, - info->map.copy_from = ixp4xx_copy_from, - - info->res = request_mem_region(dev->resource->start, - dev->resource->end - dev->resource->start + 1, - "IXP4XXFlash"); - if (!info->res) { - printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); - err = -ENOMEM; - goto Error; - } - - info->map.map_priv_1 = ioremap(dev->resource->start, - dev->resource->end - dev->resource->start + 1); - if (!info->map.map_priv_1) { - printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); - err = -EIO; + info->map.name = dev_name(&dev->dev); + info->map.read = ixp4xx_read16; + info->map.write = ixp4xx_probe_write16; + info->map.copy_from = ixp4xx_copy_from; + + info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource); + if (IS_ERR(info->map.virt)) { + err = PTR_ERR(info->map.virt); goto Error; } @@ -211,49 +227,36 @@ static int ixp4xx_flash_probe(struct device *_dev) goto Error; } info->mtd->owner = THIS_MODULE; - - /* Use the fast version */ - info->map.write = ixp4xx_write16, - err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); - if (err > 0) { - err = add_mtd_partitions(info->mtd, info->partitions, err); - if(err) - printk(KERN_ERR "Could not parse partitions\n"); - } + /* Use the fast version */ + info->map.write = ixp4xx_write16; - if (err) + err = mtd_device_parse_register(info->mtd, probes, &ppdata, + plat->parts, plat->nr_parts); + if (err) { + printk(KERN_ERR "Could not parse partitions\n"); goto Error; + } return 0; Error: - ixp4xx_flash_remove(_dev); + ixp4xx_flash_remove(dev); return err; } -static struct device_driver ixp4xx_flash_driver = { - .name = "IXP4XX-Flash", - .bus = &platform_bus_type, +static struct platform_driver ixp4xx_flash_driver = { .probe = ixp4xx_flash_probe, .remove = ixp4xx_flash_remove, + .driver = { + .name = "IXP4XX-Flash", + .owner = THIS_MODULE, + }, }; -static int __init ixp4xx_flash_init(void) -{ - return driver_register(&ixp4xx_flash_driver); -} - -static void __exit ixp4xx_flash_exit(void) -{ - driver_unregister(&ixp4xx_flash_driver); -} - - -module_init(ixp4xx_flash_init); -module_exit(ixp4xx_flash_exit); +module_platform_driver(ixp4xx_flash_driver); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems") +MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); MODULE_AUTHOR("Deepak Saxena"); - +MODULE_ALIAS("platform:IXP4XX-Flash"); |
