diff options
author | Florian Fainelli <florian@openwrt.org> | 2014-08-16 18:09:31 +0000 |
---|---|---|
committer | Florian Fainelli <florian@openwrt.org> | 2014-08-16 18:09:31 +0000 |
commit | 4147bca9ac63b950cc816e77e1756aff94145313 (patch) | |
tree | 07e73d5c080189a971cc0a111102b924ac0c33ba /target/linux/adm8668/files/drivers | |
parent | 21fde478d9330462b4d4c925c7812d011c75b028 (diff) | |
download | upstream-4147bca9ac63b950cc816e77e1756aff94145313.tar.gz upstream-4147bca9ac63b950cc816e77e1756aff94145313.tar.bz2 upstream-4147bca9ac63b950cc816e77e1756aff94145313.zip |
adm8668: revert changeset 34554
The conversion was not 100% correct and leads to u-boot failing to
verify the CRC, revert that change for now.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
SVN-Revision: 42170
Diffstat (limited to 'target/linux/adm8668/files/drivers')
-rw-r--r-- | target/linux/adm8668/files/drivers/mtd/maps/adm8668.c | 329 |
1 files changed, 199 insertions, 130 deletions
diff --git a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c index e07bb40a45..e360a0d78c 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 @@ /* - * Infineon/ADMTek ADM8668 (WildPass) partition parser support + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) * - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> + * original functions for finding root filesystem from Mike Baker * - * original functions for finding root filesystem from Mike Baker + * 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. * - * 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. + * 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 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. + * 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,6 +34,9 @@ * 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 <linux/module.h> @@ -42,13 +45,16 @@ #include <linux/sched.h> #include <linux/wait.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/vmalloc.h> +#include <linux/mtd/map.h> #include <linux/slab.h> +#include <linux/mtd/partitions.h> #include <linux/crc32.h> #include <linux/magic.h> +#include <asm/io.h> -#define PFX "adm8668-part: " +#define WINDOW_ADDR 0x10000000 +#define WINDOW_SIZE 0x800000 +#define BANKWIDTH 2 /* first a little bit about the headers i need.. */ @@ -75,122 +81,176 @@ 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 adm8668_parse_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) +static int __init +init_mtd_partitions(struct mtd_info *mtd, size_t size) { - 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 = 0x40000; off < master->size; off += blocksize) { + for (off = adm8668_parts[PART_LINUX].offset; off < size; off += blocksize) { /* * Read into buffer */ - if (mtd_read(master, off, sizeof(shdr), &len, (char *)&shdr) || + if (mtd->read(mtd, 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; - pr_info(PFX "filesystem type: squashfs, size=%dkB\n", - fs_size >> 10); + printk(KERN_INFO "%s: Filesystem type: squashfs, size=%dkB\n", + mtd->name, 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 = master->size - + adm8668_parts[PART_ROOTFS].size = mtd->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; - - adm8668_parts[PART_LINUX].size = master->size - +#if 1 + adm8668_parts[PART_LINUX].size = mtd->size - adm8668_parts[PART_LINUX].offset; +#else + adm8668_parts[PART_LINUX].size = linux_len; +#endif goto found; } } - pr_err(PFX "could't find root filesystem\n"); + printk(KERN_NOTICE + "%s: Couldn't find root filesystem\n", + mtd->name); return NR_PARTS; -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"); + found: + if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || + len != sizeof(uhdr)) return NR_PARTS; - } - if (uhdr.ih_magic != IH_MAGIC) { - pr_info(PFX "invalid u-boot magic detected?!?!\n"); + /* that's odd. how'd ya boot it then */ + if (uhdr.ih_magic != IH_MAGIC) return NR_PARTS; - } if (be32_to_cpu(uhdr.ih_size) != (linux_len - sizeof(uhdr))) { - u32 data; - size_t data_len = 0; - unsigned char *block; + unsigned char *block, *data; unsigned int offset; offset = adm8668_parts[PART_LINUX].offset + sizeof(struct uboot_header); + data = (unsigned char *)(WINDOW_ADDR | 0xA0000000 | offset); - pr_info(PFX "Updating U-boot image:\n"); - pr_info(PFX " old: [size: %8d crc32: 0x%08x]\n", + printk(KERN_NOTICE "Updating U-boot image:\n"); + printk(KERN_NOTICE " 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, (char *)&data, linux_len - sizeof(uhdr)) ^ (~0); + uhdr.ih_dcrc = crc32_le(~0, data, linux_len - sizeof(uhdr)) ^ (~0); uhdr.ih_dcrc = cpu_to_be32(uhdr.ih_dcrc); - pr_info(PFX " new: [size: %8d crc32: 0x%08x]\n", + printk(KERN_NOTICE " new: [size: %8d crc32: 0x%08x]\n", be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); /* update header's crc... */ @@ -200,66 +260,75 @@ found: uhdr.ih_hcrc = cpu_to_be32(uhdr.ih_hcrc); /* read first eraseblock from the image */ - 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"); + 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"); return 0; } /* Write updated header to the flash */ memcpy(block, &uhdr, sizeof(uhdr)); - 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"); + 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"); } - *pparts = adm8668_parts; - return NR_PARTS; } -static struct mtd_part_parser adm8668_parser = { - .owner = THIS_MODULE, - .parse_fn = adm8668_parse_partitions, - .name = "adm8668part", -}; - -static int __init adm8668_parser_init(void) +int __init init_adm8668_map(void) { - register_mtd_parser(&adm8668_parser); + 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; + + fail: + if (adm8668_mtd) + map_destroy(adm8668_mtd); + if (adm8668_map.virt) + iounmap((void *) adm8668_map.virt); + adm8668_map.virt = 0; + return ret; } -static void __exit adm8668_parser_exit(void) +void __exit cleanup_adm8668_map(void) { - deregister_mtd_parser(&adm8668_parser); + mtd_device_unregister(adm8668_mtd); + map_destroy(adm8668_mtd); + iounmap((void *) adm8668_map.virt); + adm8668_map.virt = 0; } -module_init(adm8668_parser_init); -module_exit(adm8668_parser_exit); +module_init(init_adm8668_map); +module_exit(cleanup_adm8668_map); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); -MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); -MODULE_DESCRIPTION("MTD partition parser for ADM8668"); +MODULE_DESCRIPTION("MTD map driver for ADM8668 NOR Flash"); |