From e9824bd88f25c41db1a09e1752d44c4edb5fff48 Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 6 Dec 2012 22:40:17 +0000 Subject: [adm8668] replace the custom mtd driver with a partition parser Signed-off-by: Florian Fainelli git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34554 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../linux/adm8668/files/drivers/mtd/maps/adm8668.c | 331 ++++++++------------- 1 file changed, 130 insertions(+), 201 deletions(-) (limited to 'target/linux/adm8668/files/drivers') diff --git a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c index e360a0d78c..7ef0adac4b 100644 --- a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c +++ b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c @@ -1,30 +1,30 @@ /* - * Copyright (C) 2010 Scott Nicholas - * Copyright (C) 2006 Felix Fietkau - * Copyright (C) 2005 Waldemar Brodkorb - * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Infineon/ADMTek ADM8668 (WildPass) partition parser support * - * original functions for finding root filesystem from Mike Baker + * Copyright (C) 2010 Scott Nicholas + * Copyright (C) 2012 Florian Fainelli * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * original functions for finding root filesystem from Mike Baker * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. * * * Copyright 2004, Broadcom Corporation @@ -34,9 +34,6 @@ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * - * Flash mapping for adm8668 boards - * */ #include @@ -45,16 +42,13 @@ #include #include #include -#include -#include #include +#include +#include #include #include -#include -#define WINDOW_ADDR 0x10000000 -#define WINDOW_SIZE 0x800000 -#define BANKWIDTH 2 +#define PFX "adm8668-part: " /* first a little bit about the headers i need.. */ @@ -81,176 +75,122 @@ struct uboot_header { char ih_name[32]; /* image name */ }; -/************************************************/ - -static struct mtd_info *adm8668_mtd; - -struct map_info adm8668_map = { - name: "adm8668-nor", - size: WINDOW_SIZE, - phys: WINDOW_ADDR, - bankwidth: BANKWIDTH, -}; - -/* - * Copied from mtdblock.c - * - * Cache stuff... - * - * Since typical flash erasable sectors are much larger than what Linux's - * buffer cache can handle, we must implement read-modify-write on flash - * sectors for each block write requests. To avoid over-erasing flash sectors - * and to speed things up, we locally cache a whole flash sector while it is - * being written to until a different sector is required. - */ - -static void erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - -static int erase_write (struct mtd_info *mtd, unsigned long pos, - int len, const char *buf) -{ - struct erase_info erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - size_t retlen; - int ret; - - /* - * First, let's erase the flash block. - */ - - init_waitqueue_head(&wait_q); - erase.mtd = mtd; - erase.callback = erase_callback; - erase.addr = pos; - erase.len = len; - erase.priv = (u_long)&wait_q; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - ret = mtd->erase(mtd, &erase); - if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " - "on \"%s\" failed\n", - pos, len, mtd->name); - return ret; - } - - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - - /* - * Next, write data to flash. - */ - - ret = mtd->write (mtd, pos, len, &retlen, buf); - if (ret) - return ret; - if (retlen != len) - return -EIO; - return 0; -} - -/* decent defaults in case... shrug */ -static struct mtd_partition adm8668_parts[] = { - { name: "linux", offset: 0x40000, size: WINDOW_SIZE-0x40000, }, - { name: "rootfs", offset: 0xe0000, size: 0x140000, }, - { name: "uboot_env", offset: 0x20000, size: 0x20000, }, - { name: NULL, }, -}; - /* in case i wanna change stuff later, and to clarify the math section... */ #define PART_LINUX 0 #define PART_ROOTFS 1 +#define PART_UBOOT_ENV 2 #define NR_PARTS 3 -static int __init -init_mtd_partitions(struct mtd_info *mtd, size_t size) +static int adm8668_parse_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { + int ret; struct uboot_header uhdr; int off, blocksize; size_t len, linux_len; struct squashfs_super_block shdr; + struct erase_info erase_info; + struct mtd_partition *adm8668_parts; + + memset(&erase_info, 0, sizeof(erase_info)); + + blocksize = master->erasesize; - blocksize = mtd->erasesize; if (blocksize < 0x10000) blocksize = 0x10000; + adm8668_parts = kzalloc(sizeof(*adm8668_parts) * NR_PARTS, GFP_KERNEL); + if (!adm8668_parts) + return -ENOMEM; + + adm8668_parts[PART_LINUX].name = kstrdup("linux", GFP_KERNEL); + adm8668_parts[PART_LINUX].offset = 0x40000; + adm8668_parts[PART_LINUX].size = master->size - 0x40000; + adm8668_parts[PART_ROOTFS].name = kstrdup("rootfs", GFP_KERNEL); + adm8668_parts[PART_ROOTFS].offset = 0xe0000; + adm8668_parts[PART_ROOTFS].size = 0x140000; + adm8668_parts[PART_UBOOT_ENV].name = kstrdup("uboot_env", GFP_KERNEL); + adm8668_parts[PART_UBOOT_ENV].offset = 0x20000; + adm8668_parts[PART_UBOOT_ENV].size = 0x20000; + /* now find squashfs */ memset(&shdr, 0xe5, sizeof(shdr)); - for (off = adm8668_parts[PART_LINUX].offset; off < size; off += blocksize) { + + for (off = 0x40000; off < master->size; off += blocksize) { /* * Read into buffer */ - if (mtd->read(mtd, off, sizeof(shdr), &len, (char *)&shdr) || + if (mtd_read(master, off, sizeof(shdr), &len, (char *)&shdr) || len != sizeof(shdr)) continue; if (shdr.s_magic == SQUASHFS_MAGIC) { uint32_t fs_size = (uint32_t)shdr.bytes_used; - printk(KERN_INFO "%s: Filesystem type: squashfs, size=%dkB\n", - mtd->name, fs_size>>10); + pr_info(PFX "filesystem type: squashfs, size=%dkB\n", + fs_size >> 10); - /* Update rootfs based on the superblock info, and - * stretch to end of MTD. rootfs_split will split it */ + /* + * Update rootfs based on the superblock info, and + * stretch to end of MTD. rootfs_split will split it + */ adm8668_parts[PART_ROOTFS].offset = off; - adm8668_parts[PART_ROOTFS].size = mtd->size - + adm8668_parts[PART_ROOTFS].size = master->size - adm8668_parts[PART_ROOTFS].offset; - /* kernel ends where rootfs starts - * but we'll keep it full-length for upgrades */ - linux_len = adm8668_parts[PART_LINUX+1].offset - + /* + * kernel ends where rootfs starts + * but we'll keep it full-length for upgrades + */ + linux_len = adm8668_parts[PART_LINUX + 1].offset - adm8668_parts[PART_LINUX].offset; -#if 1 - adm8668_parts[PART_LINUX].size = mtd->size - + + adm8668_parts[PART_LINUX].size = master->size - adm8668_parts[PART_LINUX].offset; -#else - adm8668_parts[PART_LINUX].size = linux_len; -#endif goto found; } } - printk(KERN_NOTICE - "%s: Couldn't find root filesystem\n", - mtd->name); + pr_err(PFX "could't find root filesystem\n"); return NR_PARTS; - found: - if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || - len != sizeof(uhdr)) +found: + if (mtd_read(master, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || + len != sizeof(uhdr)) { + pr_err(PFX "failed to read u-boot header\n"); return NR_PARTS; + } - /* that's odd. how'd ya boot it then */ - if (uhdr.ih_magic != IH_MAGIC) + if (uhdr.ih_magic != IH_MAGIC) { + pr_info(PFX "invalid u-boot magic detected?!?!\n"); return NR_PARTS; + } if (be32_to_cpu(uhdr.ih_size) != (linux_len - sizeof(uhdr))) { - unsigned char *block, *data; + u32 data; + size_t data_len = 0; + unsigned char *block; unsigned int offset; offset = adm8668_parts[PART_LINUX].offset + sizeof(struct uboot_header); - data = (unsigned char *)(WINDOW_ADDR | 0xA0000000 | offset); - printk(KERN_NOTICE "Updating U-boot image:\n"); - printk(KERN_NOTICE " old: [size: %8d crc32: 0x%08x]\n", + pr_info(PFX "Updating U-boot image:\n"); + pr_info(PFX " old: [size: %8d crc32: 0x%08x]\n", be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); + if (mtd_read(master, offset, sizeof(data), &data_len, (char *)&data)) { + pr_err(PFX "failed to read data\n"); + goto out; + } + /* Update the data length & crc32 */ uhdr.ih_size = cpu_to_be32(linux_len - sizeof(uhdr)); - uhdr.ih_dcrc = crc32_le(~0, data, linux_len - sizeof(uhdr)) ^ (~0); + uhdr.ih_dcrc = crc32_le(~0, (char *)&data, linux_len - sizeof(uhdr)) ^ (~0); uhdr.ih_dcrc = cpu_to_be32(uhdr.ih_dcrc); - printk(KERN_NOTICE " new: [size: %8d crc32: 0x%08x]\n", + pr_info(PFX " new: [size: %8d crc32: 0x%08x]\n", be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); /* update header's crc... */ @@ -260,75 +200,64 @@ init_mtd_partitions(struct mtd_info *mtd, size_t size) uhdr.ih_hcrc = cpu_to_be32(uhdr.ih_hcrc); /* read first eraseblock from the image */ - block = kmalloc(mtd->erasesize, GFP_KERNEL); - if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, &len, block) || len != mtd->erasesize) { - printk("Error copying first eraseblock\n"); + block = vmalloc(master->erasesize); + if (!block) + return -ENOMEM; + + if (mtd_read(master, adm8668_parts[PART_LINUX].offset, master->erasesize, &len, block) + || len != master->erasesize) { + pr_err(PFX "error copying first eraseblock\n"); return 0; } /* Write updated header to the flash */ memcpy(block, &uhdr, sizeof(uhdr)); - if (mtd->unlock) - mtd->unlock(mtd, off, mtd->erasesize); - erase_write(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, block); - if (mtd->sync) - mtd->sync(mtd); - kfree(block); - printk(KERN_NOTICE "Done\n"); + if (master->unlock) + master->unlock(master, off, master->erasesize); + + erase_info.mtd = master; + erase_info.addr = (uint64_t)adm8668_parts[PART_LINUX].offset; + erase_info.len = master->erasesize; + ret = mtd_erase(master, &erase_info); + if (!ret) { + if (mtd_write(master, adm8668_parts[PART_LINUX].offset, master->erasesize, + &len, block)) + pr_err(PFX "write failed"); + } else + pr_err(PFX "erase failed"); + + mtd_sync(master); +out: + if (block) + vfree(block); + pr_info(PFX "done\n"); } + *pparts = adm8668_parts; + return NR_PARTS; } -int __init init_adm8668_map(void) -{ - int nr_parts, ret; - - adm8668_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!adm8668_map.virt) { - printk(KERN_ERR "Failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&adm8668_map); - if (!(adm8668_mtd = do_map_probe("cfi_probe", &adm8668_map))) { - printk(KERN_ERR "cfi_probe failed\n"); - iounmap((void *)adm8668_map.virt); - return -ENXIO; - } - - adm8668_mtd->owner = THIS_MODULE; - - nr_parts = init_mtd_partitions(adm8668_mtd, adm8668_mtd->size); - ret = mtd_device_register(adm8668_mtd, adm8668_parts, nr_parts); - if (ret) { - printk(KERN_ERR "Flash: mtd_device_register failed\n"); - goto fail; - } - - return 0; +static struct mtd_part_parser adm8668_parser = { + .owner = THIS_MODULE, + .parse_fn = adm8668_parse_partitions, + .name = "adm8668part", +}; - fail: - if (adm8668_mtd) - map_destroy(adm8668_mtd); - if (adm8668_map.virt) - iounmap((void *) adm8668_map.virt); - adm8668_map.virt = 0; - return ret; +static int __init adm8668_parser_init(void) +{ + return register_mtd_parser(&adm8668_parser); } -void __exit cleanup_adm8668_map(void) +static void __exit adm8668_parser_exit(void) { - mtd_device_unregister(adm8668_mtd); - map_destroy(adm8668_mtd); - iounmap((void *) adm8668_map.virt); - adm8668_map.virt = 0; + deregister_mtd_parser(&adm8668_parser); } -module_init(init_adm8668_map); -module_exit(cleanup_adm8668_map); +module_init(adm8668_parser_init); +module_exit(adm8668_parser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Scott Nicholas "); -MODULE_DESCRIPTION("MTD map driver for ADM8668 NOR Flash"); +MODULE_AUTHOR("Florian Fainelli "); +MODULE_DESCRIPTION("MTD partition parser for ADM8668"); -- cgit v1.2.3