|
| 1 | +/* |
| 2 | + * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. |
| 3 | + * Config with both CFI and JEDEC device support. |
| 4 | + * |
| 5 | + * Basically physmap.c with the addition of partitions and |
| 6 | + * an array of mapping info to accomodate more than one flash type per board. |
| 7 | + * |
| 8 | + * Copyright 2005-2007 PMC-Sierra, Inc. |
| 9 | + * |
| 10 | + * This program is free software; you can redistribute it and/or modify it |
| 11 | + * under the terms of the GNU General Public License as published by the |
| 12 | + * Free Software Foundation; either version 2 of the License, or (at your |
| 13 | + * option) any later version. |
| 14 | + * |
| 15 | + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 16 | + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 17 | + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| 18 | + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 19 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 20 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 21 | + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 22 | + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 24 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 | + * |
| 26 | + * You should have received a copy of the GNU General Public License along |
| 27 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 28 | + * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 29 | + */ |
| 30 | + |
| 31 | +#include <linux/module.h> |
| 32 | +#include <linux/types.h> |
| 33 | +#include <linux/kernel.h> |
| 34 | +#include <linux/mtd/mtd.h> |
| 35 | +#include <linux/mtd/map.h> |
| 36 | +#include <linux/mtd/partitions.h> |
| 37 | + |
| 38 | +#include <asm/io.h> |
| 39 | + |
| 40 | +#include <msp_prom.h> |
| 41 | +#include <msp_regs.h> |
| 42 | + |
| 43 | + |
| 44 | +static struct mtd_info **msp_flash; |
| 45 | +static struct mtd_partition **msp_parts; |
| 46 | +static struct map_info *msp_maps; |
| 47 | +static int fcnt; |
| 48 | + |
| 49 | +#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__) |
| 50 | + |
| 51 | +int __init init_msp_flash(void) |
| 52 | +{ |
| 53 | + int i, j; |
| 54 | + int offset, coff; |
| 55 | + char *env; |
| 56 | + int pcnt; |
| 57 | + char flash_name[] = "flash0"; |
| 58 | + char part_name[] = "flash0_0"; |
| 59 | + unsigned addr, size; |
| 60 | + |
| 61 | + /* If ELB is disabled by "ful-mux" mode, we can't get at flash */ |
| 62 | + if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) && |
| 63 | + (*ELB_1PC_EN_REG & SINGLE_PCCARD)) { |
| 64 | + printk(KERN_NOTICE "Single PC Card mode: no flash access\n"); |
| 65 | + return -ENXIO; |
| 66 | + } |
| 67 | + |
| 68 | + /* examine the prom environment for flash devices */ |
| 69 | + for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++) |
| 70 | + flash_name[5] = '0' + fcnt + 1; |
| 71 | + |
| 72 | + if (fcnt < 1) |
| 73 | + return -ENXIO; |
| 74 | + |
| 75 | + printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); |
| 76 | + msp_flash = (struct mtd_info **)kmalloc( |
| 77 | + fcnt * sizeof(struct map_info *), GFP_KERNEL); |
| 78 | + msp_parts = (struct mtd_partition **)kmalloc( |
| 79 | + fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); |
| 80 | + msp_maps = (struct map_info *)kmalloc( |
| 81 | + fcnt * sizeof(struct mtd_info), GFP_KERNEL); |
| 82 | + memset(msp_maps, 0, fcnt * sizeof(struct mtd_info)); |
| 83 | + |
| 84 | + /* loop over the flash devices, initializing each */ |
| 85 | + for (i = 0; i < fcnt; i++) { |
| 86 | + /* examine the prom environment for flash partititions */ |
| 87 | + part_name[5] = '0' + i; |
| 88 | + part_name[7] = '0'; |
| 89 | + for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++) |
| 90 | + part_name[7] = '0' + pcnt + 1; |
| 91 | + |
| 92 | + if (pcnt == 0) { |
| 93 | + printk(KERN_NOTICE "Skipping flash device %d " |
| 94 | + "(no partitions defined)\n", i); |
| 95 | + continue; |
| 96 | + } |
| 97 | + |
| 98 | + msp_parts[i] = (struct mtd_partition *)kmalloc( |
| 99 | + pcnt * sizeof(struct mtd_partition), GFP_KERNEL); |
| 100 | + memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition)); |
| 101 | + |
| 102 | + /* now initialize the devices proper */ |
| 103 | + flash_name[5] = '0' + i; |
| 104 | + env = prom_getenv(flash_name); |
| 105 | + |
| 106 | + if (sscanf(env, "%x:%x", &addr, &size) < 2) |
| 107 | + return -ENXIO; |
| 108 | + addr = CPHYSADDR(addr); |
| 109 | + |
| 110 | + printk(KERN_NOTICE |
| 111 | + "MSP flash device \"%s\": 0x%08x at 0x%08x\n", |
| 112 | + flash_name, size, addr); |
| 113 | + /* This must matchs the actual size of the flash chip */ |
| 114 | + msp_maps[i].size = size; |
| 115 | + msp_maps[i].phys = addr; |
| 116 | + |
| 117 | + /* |
| 118 | + * Platforms have a specific limit of the size of memory |
| 119 | + * which may be mapped for flash: |
| 120 | + */ |
| 121 | + if (size > CONFIG_MSP_FLASH_MAP_LIMIT) |
| 122 | + size = CONFIG_MSP_FLASH_MAP_LIMIT; |
| 123 | + msp_maps[i].virt = ioremap(addr, size); |
| 124 | + msp_maps[i].bankwidth = 1; |
| 125 | + msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL), |
| 126 | + flash_name, 7); |
| 127 | + |
| 128 | + if (msp_maps[i].virt == NULL) |
| 129 | + return -ENXIO; |
| 130 | + |
| 131 | + for (j = 0; j < pcnt; j++) { |
| 132 | + part_name[5] = '0' + i; |
| 133 | + part_name[7] = '0' + j; |
| 134 | + |
| 135 | + env = prom_getenv(part_name); |
| 136 | + |
| 137 | + if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2) |
| 138 | + return -ENXIO; |
| 139 | + |
| 140 | + msp_parts[i][j].size = size; |
| 141 | + msp_parts[i][j].offset = offset; |
| 142 | + msp_parts[i][j].name = env + coff; |
| 143 | + } |
| 144 | + |
| 145 | + /* now probe and add the device */ |
| 146 | + simple_map_init(&msp_maps[i]); |
| 147 | + msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]); |
| 148 | + if (msp_flash[i]) { |
| 149 | + msp_flash[i]->owner = THIS_MODULE; |
| 150 | + add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt); |
| 151 | + } else { |
| 152 | + printk(KERN_ERR "map probe failed for flash\n"); |
| 153 | + return -ENXIO; |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + return 0; |
| 158 | +} |
| 159 | + |
| 160 | +static void __exit cleanup_msp_flash(void) |
| 161 | +{ |
| 162 | + int i; |
| 163 | + |
| 164 | + for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) { |
| 165 | + del_mtd_partitions(msp_flash[i]); |
| 166 | + map_destroy(msp_flash[i]); |
| 167 | + iounmap((void *)msp_maps[i].virt); |
| 168 | + |
| 169 | + /* free the memory */ |
| 170 | + kfree(msp_maps[i].name); |
| 171 | + kfree(msp_parts[i]); |
| 172 | + } |
| 173 | + |
| 174 | + kfree(msp_flash); |
| 175 | + kfree(msp_parts); |
| 176 | + kfree(msp_maps); |
| 177 | +} |
| 178 | + |
| 179 | +MODULE_AUTHOR("PMC-Sierra, Inc"); |
| 180 | +MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards"); |
| 181 | +MODULE_LICENSE("GPL"); |
| 182 | + |
| 183 | +module_init(init_msp_flash); |
| 184 | +module_exit(cleanup_msp_flash); |
0 commit comments