Blame view
drivers/mtd/maps/pmcmsp-flash.c
6.02 KB
68aa0fa87
|
1 2 3 4 5 |
/* * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. * Config with both CFI and JEDEC device support. * * Basically physmap.c with the addition of partitions and |
25985edce
|
6 |
* an array of mapping info to accommodate more than one flash type per board. |
68aa0fa87
|
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
* * Copyright 2005-2007 PMC-Sierra, Inc. * * 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. * * 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. */ |
5a0e3ad6a
|
30 |
#include <linux/slab.h> |
68aa0fa87
|
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <asm/io.h> #include <msp_prom.h> #include <msp_regs.h> static struct mtd_info **msp_flash; static struct mtd_partition **msp_parts; static struct map_info *msp_maps; static int fcnt; |
cb53b3b99
|
48 49 |
#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d] ", __func__, __LINE__) |
68aa0fa87
|
50 |
|
6127cfcd3
|
51 |
static int __init init_msp_flash(void) |
68aa0fa87
|
52 |
{ |
2c78c4436
|
53 |
int i, j, ret = -ENOMEM; |
68aa0fa87
|
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
int offset, coff; char *env; int pcnt; char flash_name[] = "flash0"; char part_name[] = "flash0_0"; unsigned addr, size; /* If ELB is disabled by "ful-mux" mode, we can't get at flash */ if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) && (*ELB_1PC_EN_REG & SINGLE_PCCARD)) { printk(KERN_NOTICE "Single PC Card mode: no flash access "); return -ENXIO; } /* examine the prom environment for flash devices */ for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++) flash_name[5] = '0' + fcnt + 1; if (fcnt < 1) return -ENXIO; printk(KERN_NOTICE "Found %d PMC flash devices ", fcnt); |
4fb4caa63
|
78 |
|
79ad07d45
|
79 |
msp_flash = kcalloc(fcnt, sizeof(*msp_flash), GFP_KERNEL); |
2c78c4436
|
80 81 |
if (!msp_flash) return -ENOMEM; |
79ad07d45
|
82 |
msp_parts = kcalloc(fcnt, sizeof(*msp_parts), GFP_KERNEL); |
2c78c4436
|
83 84 |
if (!msp_parts) goto free_msp_flash; |
79ad07d45
|
85 |
msp_maps = kcalloc(fcnt, sizeof(*msp_maps), GFP_KERNEL); |
2c78c4436
|
86 87 |
if (!msp_maps) goto free_msp_parts; |
68aa0fa87
|
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/* loop over the flash devices, initializing each */ for (i = 0; i < fcnt; i++) { /* examine the prom environment for flash partititions */ part_name[5] = '0' + i; part_name[7] = '0'; for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++) part_name[7] = '0' + pcnt + 1; if (pcnt == 0) { printk(KERN_NOTICE "Skipping flash device %d " "(no partitions defined) ", i); continue; } |
4fb4caa63
|
103 104 |
msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition), GFP_KERNEL); |
2c78c4436
|
105 106 |
if (!msp_parts[i]) goto cleanup_loop; |
68aa0fa87
|
107 108 109 110 |
/* now initialize the devices proper */ flash_name[5] = '0' + i; env = prom_getenv(flash_name); |
2c78c4436
|
111 112 113 114 115 |
if (sscanf(env, "%x:%x", &addr, &size) < 2) { ret = -ENXIO; kfree(msp_parts[i]); goto cleanup_loop; } |
68aa0fa87
|
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
addr = CPHYSADDR(addr); printk(KERN_NOTICE "MSP flash device \"%s\": 0x%08x at 0x%08x ", flash_name, size, addr); /* This must matchs the actual size of the flash chip */ msp_maps[i].size = size; msp_maps[i].phys = addr; /* * Platforms have a specific limit of the size of memory * which may be mapped for flash: */ if (size > CONFIG_MSP_FLASH_MAP_LIMIT) size = CONFIG_MSP_FLASH_MAP_LIMIT; |
2c78c4436
|
132 |
|
68aa0fa87
|
133 |
msp_maps[i].virt = ioremap(addr, size); |
2c78c4436
|
134 135 136 137 138 |
if (msp_maps[i].virt == NULL) { ret = -ENXIO; kfree(msp_parts[i]); goto cleanup_loop; } |
68aa0fa87
|
139 |
msp_maps[i].bankwidth = 1; |
906b26847
|
140 |
msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL); |
2c78c4436
|
141 142 143 144 145 |
if (!msp_maps[i].name) { iounmap(msp_maps[i].virt); kfree(msp_parts[i]); goto cleanup_loop; } |
68aa0fa87
|
146 |
|
68aa0fa87
|
147 148 149 150 151 |
for (j = 0; j < pcnt; j++) { part_name[5] = '0' + i; part_name[7] = '0' + j; env = prom_getenv(part_name); |
2c78c4436
|
152 153 154 155 156 157 158 159 |
if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2) { ret = -ENXIO; kfree(msp_maps[i].name); iounmap(msp_maps[i].virt); kfree(msp_parts[i]); goto cleanup_loop; } |
68aa0fa87
|
160 161 162 163 164 165 166 167 168 169 170 |
msp_parts[i][j].size = size; msp_parts[i][j].offset = offset; msp_parts[i][j].name = env + coff; } /* now probe and add the device */ simple_map_init(&msp_maps[i]); msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]); if (msp_flash[i]) { msp_flash[i]->owner = THIS_MODULE; |
ee0e87b17
|
171 |
mtd_device_register(msp_flash[i], msp_parts[i], pcnt); |
68aa0fa87
|
172 173 174 |
} else { printk(KERN_ERR "map probe failed for flash "); |
2c78c4436
|
175 176 177 178 179 |
ret = -ENXIO; kfree(msp_maps[i].name); iounmap(msp_maps[i].virt); kfree(msp_parts[i]); goto cleanup_loop; |
68aa0fa87
|
180 181 182 183 |
} } return 0; |
2c78c4436
|
184 185 186 |
cleanup_loop: while (i--) { |
ee0e87b17
|
187 |
mtd_device_unregister(msp_flash[i]); |
2c78c4436
|
188 189 190 191 192 193 194 195 196 197 198 |
map_destroy(msp_flash[i]); kfree(msp_maps[i].name); iounmap(msp_maps[i].virt); kfree(msp_parts[i]); } kfree(msp_maps); free_msp_parts: kfree(msp_parts); free_msp_flash: kfree(msp_flash); return ret; |
68aa0fa87
|
199 200 201 202 203 |
} static void __exit cleanup_msp_flash(void) { int i; |
2c78c4436
|
204 |
for (i = 0; i < fcnt; i++) { |
ee0e87b17
|
205 |
mtd_device_unregister(msp_flash[i]); |
68aa0fa87
|
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
map_destroy(msp_flash[i]); iounmap((void *)msp_maps[i].virt); /* free the memory */ kfree(msp_maps[i].name); kfree(msp_parts[i]); } kfree(msp_flash); kfree(msp_parts); kfree(msp_maps); } MODULE_AUTHOR("PMC-Sierra, Inc"); MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards"); MODULE_LICENSE("GPL"); module_init(init_msp_flash); module_exit(cleanup_msp_flash); |