aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/maps')
-rw-r--r--drivers/mtd/maps/bcm963xx-flash.c276
-rw-r--r--drivers/mtd/maps/cdb89712.c278
-rw-r--r--drivers/mtd/maps/ceiva.c341
-rw-r--r--drivers/mtd/maps/edb7312.c134
-rw-r--r--drivers/mtd/maps/fortunet.c277
-rw-r--r--drivers/mtd/maps/tegra_nor.c483
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c181
7 files changed, 1970 insertions, 0 deletions
diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c
new file mode 100644
index 00000000000..608967fe74c
--- /dev/null
+++ b/drivers/mtd/maps/bcm963xx-flash.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
3 * Mike Albon <malbon@openwrt.org>
4 * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/slab.h>
24#include <linux/mtd/map.h>
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/partitions.h>
27#include <linux/vmalloc.h>
28#include <linux/platform_device.h>
29#include <linux/io.h>
30
31#include <asm/mach-bcm63xx/bcm963xx_tag.h>
32
33#define BCM63XX_BUSWIDTH 2 /* Buswidth */
34#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
35
36#define PFX KBUILD_MODNAME ": "
37
38static struct mtd_partition *parsed_parts;
39
40static struct mtd_info *bcm963xx_mtd_info;
41
42static struct map_info bcm963xx_map = {
43 .name = "bcm963xx",
44 .bankwidth = BCM63XX_BUSWIDTH,
45};
46
47static int parse_cfe_partitions(struct mtd_info *master,
48 struct mtd_partition **pparts)
49{
50 /* CFE, NVRAM and global Linux are always present */
51 int nrparts = 3, curpart = 0;
52 struct bcm_tag *buf;
53 struct mtd_partition *parts;
54 int ret;
55 size_t retlen;
56 unsigned int rootfsaddr, kerneladdr, spareaddr;
57 unsigned int rootfslen, kernellen, sparelen, totallen;
58 int namelen = 0;
59 int i;
60 char *boardid;
61 char *tagversion;
62
63 /* Allocate memory for buffer */
64 buf = vmalloc(sizeof(struct bcm_tag));
65 if (!buf)
66 return -ENOMEM;
67
68 /* Get the tag */
69 ret = master->read(master, master->erasesize, sizeof(struct bcm_tag),
70 &retlen, (void *)buf);
71 if (retlen != sizeof(struct bcm_tag)) {
72 vfree(buf);
73 return -EIO;
74 }
75
76 sscanf(buf->kernel_address, "%u", &kerneladdr);
77 sscanf(buf->kernel_length, "%u", &kernellen);
78 sscanf(buf->total_length, "%u", &totallen);
79 tagversion = &(buf->tag_version[0]);
80 boardid = &(buf->board_id[0]);
81
82 printk(KERN_INFO PFX "CFE boot tag found with version %s "
83 "and board type %s\n", tagversion, boardid);
84
85 kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
86 rootfsaddr = kerneladdr + kernellen;
87 spareaddr = roundup(totallen, master->erasesize) + master->erasesize;
88 sparelen = master->size - spareaddr - master->erasesize;
89 rootfslen = spareaddr - rootfsaddr;
90
91 /* Determine number of partitions */
92 namelen = 8;
93 if (rootfslen > 0) {
94 nrparts++;
95 namelen += 6;
96 };
97 if (kernellen > 0) {
98 nrparts++;
99 namelen += 6;
100 };
101
102 /* Ask kernel for more memory */
103 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
104 if (!parts) {
105 vfree(buf);
106 return -ENOMEM;
107 };
108
109 /* Start building partition list */
110 parts[curpart].name = "CFE";
111 parts[curpart].offset = 0;
112 parts[curpart].size = master->erasesize;
113 curpart++;
114
115 if (kernellen > 0) {
116 parts[curpart].name = "kernel";
117 parts[curpart].offset = kerneladdr;
118 parts[curpart].size = kernellen;
119 curpart++;
120 };
121
122 if (rootfslen > 0) {
123 parts[curpart].name = "rootfs";
124 parts[curpart].offset = rootfsaddr;
125 parts[curpart].size = rootfslen;
126 if (sparelen > 0)
127 parts[curpart].size += sparelen;
128 curpart++;
129 };
130
131 parts[curpart].name = "nvram";
132 parts[curpart].offset = master->size - master->erasesize;
133 parts[curpart].size = master->erasesize;
134
135 /* Global partition "linux" to make easy firmware upgrade */
136 curpart++;
137 parts[curpart].name = "linux";
138 parts[curpart].offset = parts[0].size;
139 parts[curpart].size = master->size - parts[0].size - parts[3].size;
140
141 for (i = 0; i < nrparts; i++)
142 printk(KERN_INFO PFX "Partition %d is %s offset %lx and "
143 "length %lx\n", i, parts[i].name,
144 (long unsigned int)(parts[i].offset),
145 (long unsigned int)(parts[i].size));
146
147 printk(KERN_INFO PFX "Spare partition is %x offset and length %x\n",
148 spareaddr, sparelen);
149 *pparts = parts;
150 vfree(buf);
151
152 return nrparts;
153};
154
155static int bcm963xx_detect_cfe(struct mtd_info *master)
156{
157 int idoffset = 0x4e0;
158 static char idstring[8] = "CFE1CFE1";
159 char buf[9];
160 int ret;
161 size_t retlen;
162
163 ret = master->read(master, idoffset, 8, &retlen, (void *)buf);
164 buf[retlen] = 0;
165 printk(KERN_INFO PFX "Read Signature value of %s\n", buf);
166
167 return strncmp(idstring, buf, 8);
168}
169
170static int bcm963xx_probe(struct platform_device *pdev)
171{
172 int err = 0;
173 int parsed_nr_parts = 0;
174 char *part_type;
175 struct resource *r;
176
177 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
178 if (!r) {
179 dev_err(&pdev->dev, "no resource supplied\n");
180 return -ENODEV;
181 }
182
183 bcm963xx_map.phys = r->start;
184 bcm963xx_map.size = resource_size(r);
185 bcm963xx_map.virt = ioremap(r->start, resource_size(r));
186 if (!bcm963xx_map.virt) {
187 dev_err(&pdev->dev, "failed to ioremap\n");
188 return -EIO;
189 }
190
191 dev_info(&pdev->dev, "0x%08lx at 0x%08x\n",
192 bcm963xx_map.size, bcm963xx_map.phys);
193
194 simple_map_init(&bcm963xx_map);
195
196 bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map);
197 if (!bcm963xx_mtd_info) {
198 dev_err(&pdev->dev, "failed to probe using CFI\n");
199 bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map);
200 if (bcm963xx_mtd_info)
201 goto probe_ok;
202 dev_err(&pdev->dev, "failed to probe using JEDEC\n");
203 err = -EIO;
204 goto err_probe;
205 }
206
207probe_ok:
208 bcm963xx_mtd_info->owner = THIS_MODULE;
209
210 /* This is mutually exclusive */
211 if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) {
212 dev_info(&pdev->dev, "CFE bootloader detected\n");
213 if (parsed_nr_parts == 0) {
214 int ret = parse_cfe_partitions(bcm963xx_mtd_info,
215 &parsed_parts);
216 if (ret > 0) {
217 part_type = "CFE";
218 parsed_nr_parts = ret;
219 }
220 }
221 } else {
222 dev_info(&pdev->dev, "unsupported bootloader\n");
223 err = -ENODEV;
224 goto err_probe;
225 }
226
227 return mtd_device_register(bcm963xx_mtd_info, parsed_parts,
228 parsed_nr_parts);
229
230err_probe:
231 iounmap(bcm963xx_map.virt);
232 return err;
233}
234
235static int bcm963xx_remove(struct platform_device *pdev)
236{
237 if (bcm963xx_mtd_info) {
238 mtd_device_unregister(bcm963xx_mtd_info);
239 map_destroy(bcm963xx_mtd_info);
240 }
241
242 if (bcm963xx_map.virt) {
243 iounmap(bcm963xx_map.virt);
244 bcm963xx_map.virt = 0;
245 }
246
247 return 0;
248}
249
250static struct platform_driver bcm63xx_mtd_dev = {
251 .probe = bcm963xx_probe,
252 .remove = bcm963xx_remove,
253 .driver = {
254 .name = "bcm963xx-flash",
255 .owner = THIS_MODULE,
256 },
257};
258
259static int __init bcm963xx_mtd_init(void)
260{
261 return platform_driver_register(&bcm63xx_mtd_dev);
262}
263
264static void __exit bcm963xx_mtd_exit(void)
265{
266 platform_driver_unregister(&bcm63xx_mtd_dev);
267}
268
269module_init(bcm963xx_mtd_init);
270module_exit(bcm963xx_mtd_exit);
271
272MODULE_LICENSE("GPL");
273MODULE_DESCRIPTION("Broadcom BCM63xx MTD driver for CFE and RedBoot");
274MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
275MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
276MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c
new file mode 100644
index 00000000000..c29cbf87ea0
--- /dev/null
+++ b/drivers/mtd/maps/cdb89712.c
@@ -0,0 +1,278 @@
1/*
2 * Flash on Cirrus CDB89712
3 *
4 */
5
6#include <linux/module.h>
7#include <linux/types.h>
8#include <linux/kernel.h>
9#include <linux/ioport.h>
10#include <linux/init.h>
11#include <asm/io.h>
12#include <mach/hardware.h>
13#include <linux/mtd/mtd.h>
14#include <linux/mtd/map.h>
15#include <linux/mtd/partitions.h>
16
17/* dynamic ioremap() areas */
18#define FLASH_START 0x00000000
19#define FLASH_SIZE 0x800000
20#define FLASH_WIDTH 4
21
22#define SRAM_START 0x60000000
23#define SRAM_SIZE 0xc000
24#define SRAM_WIDTH 4
25
26#define BOOTROM_START 0x70000000
27#define BOOTROM_SIZE 0x80
28#define BOOTROM_WIDTH 4
29
30
31static struct mtd_info *flash_mtd;
32
33struct map_info cdb89712_flash_map = {
34 .name = "flash",
35 .size = FLASH_SIZE,
36 .bankwidth = FLASH_WIDTH,
37 .phys = FLASH_START,
38};
39
40struct resource cdb89712_flash_resource = {
41 .name = "Flash",
42 .start = FLASH_START,
43 .end = FLASH_START + FLASH_SIZE - 1,
44 .flags = IORESOURCE_IO | IORESOURCE_BUSY,
45};
46
47static int __init init_cdb89712_flash (void)
48{
49 int err;
50
51 if (request_resource (&ioport_resource, &cdb89712_flash_resource)) {
52 printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n");
53 err = -EBUSY;
54 goto out;
55 }
56
57 cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE);
58 if (!cdb89712_flash_map.virt) {
59 printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
60 err = -EIO;
61 goto out_resource;
62 }
63 simple_map_init(&cdb89712_flash_map);
64 flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map);
65 if (!flash_mtd) {
66 flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map);
67 if (flash_mtd)
68 flash_mtd->erasesize = 0x10000;
69 }
70 if (!flash_mtd) {
71 printk("FLASH probe failed\n");
72 err = -ENXIO;
73 goto out_ioremap;
74 }
75
76 flash_mtd->owner = THIS_MODULE;
77
78 if (mtd_device_register(flash_mtd, NULL, 0)) {
79 printk("FLASH device addition failed\n");
80 err = -ENOMEM;
81 goto out_probe;
82 }
83
84 return 0;
85
86out_probe:
87 map_destroy(flash_mtd);
88 flash_mtd = 0;
89out_ioremap:
90 iounmap((void *)cdb89712_flash_map.virt);
91out_resource:
92 release_resource (&cdb89712_flash_resource);
93out:
94 return err;
95}
96
97
98
99
100
101static struct mtd_info *sram_mtd;
102
103struct map_info cdb89712_sram_map = {
104 .name = "SRAM",
105 .size = SRAM_SIZE,
106 .bankwidth = SRAM_WIDTH,
107 .phys = SRAM_START,
108};
109
110struct resource cdb89712_sram_resource = {
111 .name = "SRAM",
112 .start = SRAM_START,
113 .end = SRAM_START + SRAM_SIZE - 1,
114 .flags = IORESOURCE_IO | IORESOURCE_BUSY,
115};
116
117static int __init init_cdb89712_sram (void)
118{
119 int err;
120
121 if (request_resource (&ioport_resource, &cdb89712_sram_resource)) {
122 printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n");
123 err = -EBUSY;
124 goto out;
125 }
126
127 cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE);
128 if (!cdb89712_sram_map.virt) {
129 printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
130 err = -EIO;
131 goto out_resource;
132 }
133 simple_map_init(&cdb89712_sram_map);
134 sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map);
135 if (!sram_mtd) {
136 printk("SRAM probe failed\n");
137 err = -ENXIO;
138 goto out_ioremap;
139 }
140
141 sram_mtd->owner = THIS_MODULE;
142 sram_mtd->erasesize = 16;
143
144 if (mtd_device_register(sram_mtd, NULL, 0)) {
145 printk("SRAM device addition failed\n");
146 err = -ENOMEM;
147 goto out_probe;
148 }
149
150 return 0;
151
152out_probe:
153 map_destroy(sram_mtd);
154 sram_mtd = 0;
155out_ioremap:
156 iounmap((void *)cdb89712_sram_map.virt);
157out_resource:
158 release_resource (&cdb89712_sram_resource);
159out:
160 return err;
161}
162
163
164
165
166
167
168
169static struct mtd_info *bootrom_mtd;
170
171struct map_info cdb89712_bootrom_map = {
172 .name = "BootROM",
173 .size = BOOTROM_SIZE,
174 .bankwidth = BOOTROM_WIDTH,
175 .phys = BOOTROM_START,
176};
177
178struct resource cdb89712_bootrom_resource = {
179 .name = "BootROM",
180 .start = BOOTROM_START,
181 .end = BOOTROM_START + BOOTROM_SIZE - 1,
182 .flags = IORESOURCE_IO | IORESOURCE_BUSY,
183};
184
185static int __init init_cdb89712_bootrom (void)
186{
187 int err;
188
189 if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) {
190 printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n");
191 err = -EBUSY;
192 goto out;
193 }
194
195 cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE);
196 if (!cdb89712_bootrom_map.virt) {
197 printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
198 err = -EIO;
199 goto out_resource;
200 }
201 simple_map_init(&cdb89712_bootrom_map);
202 bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map);
203 if (!bootrom_mtd) {
204 printk("BootROM probe failed\n");
205 err = -ENXIO;
206 goto out_ioremap;
207 }
208
209 bootrom_mtd->owner = THIS_MODULE;
210 bootrom_mtd->erasesize = 0x10000;
211
212 if (mtd_device_register(bootrom_mtd, NULL, 0)) {
213 printk("BootROM device addition failed\n");
214 err = -ENOMEM;
215 goto out_probe;
216 }
217
218 return 0;
219
220out_probe:
221 map_destroy(bootrom_mtd);
222 bootrom_mtd = 0;
223out_ioremap:
224 iounmap((void *)cdb89712_bootrom_map.virt);
225out_resource:
226 release_resource (&cdb89712_bootrom_resource);
227out:
228 return err;
229}
230
231
232
233
234
235static int __init init_cdb89712_maps(void)
236{
237
238 printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n",
239 FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START);
240
241 init_cdb89712_flash();
242 init_cdb89712_sram();
243 init_cdb89712_bootrom();
244
245 return 0;
246}
247
248
249static void __exit cleanup_cdb89712_maps(void)
250{
251 if (sram_mtd) {
252 mtd_device_unregister(sram_mtd);
253 map_destroy(sram_mtd);
254 iounmap((void *)cdb89712_sram_map.virt);
255 release_resource (&cdb89712_sram_resource);
256 }
257
258 if (flash_mtd) {
259 mtd_device_unregister(flash_mtd);
260 map_destroy(flash_mtd);
261 iounmap((void *)cdb89712_flash_map.virt);
262 release_resource (&cdb89712_flash_resource);
263 }
264
265 if (bootrom_mtd) {
266 mtd_device_unregister(bootrom_mtd);
267 map_destroy(bootrom_mtd);
268 iounmap((void *)cdb89712_bootrom_map.virt);
269 release_resource (&cdb89712_bootrom_resource);
270 }
271}
272
273module_init(init_cdb89712_maps);
274module_exit(cleanup_cdb89712_maps);
275
276MODULE_AUTHOR("Ray L");
277MODULE_DESCRIPTION("ARM CDB89712 map driver");
278MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
new file mode 100644
index 00000000000..06f9c981572
--- /dev/null
+++ b/drivers/mtd/maps/ceiva.c
@@ -0,0 +1,341 @@
1/*
2 * Ceiva flash memory driver.
3 * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
4 *
5 * Note: this driver supports jedec compatible devices. Modification
6 * for CFI compatible devices should be straight forward: change
7 * jedec_probe to cfi_probe.
8 *
9 * Based on: sa1100-flash.c, which has the following copyright:
10 * Flash memory access on SA11x0 based devices
11 *
12 * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/types.h>
18#include <linux/ioport.h>
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22
23#include <linux/mtd/mtd.h>
24#include <linux/mtd/map.h>
25#include <linux/mtd/partitions.h>
26#include <linux/mtd/concat.h>
27
28#include <mach/hardware.h>
29#include <asm/mach-types.h>
30#include <asm/io.h>
31#include <asm/sizes.h>
32
33/*
34 * This isn't complete yet, so...
35 */
36#define CONFIG_MTD_CEIVA_STATICMAP
37
38#ifdef CONFIG_MTD_CEIVA_STATICMAP
39/*
40 * See include/linux/mtd/partitions.h for definition of the mtd_partition
41 * structure.
42 *
43 * Please note:
44 * 1. The flash size given should be the largest flash size that can
45 * be accommodated.
46 *
47 * 2. The bus width must defined in clps_setup_flash.
48 *
49 * The MTD layer will detect flash chip aliasing and reduce the size of
50 * the map accordingly.
51 *
52 */
53
54#ifdef CONFIG_ARCH_CEIVA
55/* Flash / Partition sizing */
56/* For the 28F8003, we use the block mapping to calcuate the sizes */
57#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128))
58#define BOOT_PARTITION_SIZE_KiB (16)
59#define PARAMS_PARTITION_SIZE_KiB (8)
60#define KERNEL_PARTITION_SIZE_KiB (4*128)
61/* Use both remaining portion of first flash, and all of second flash */
62#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128)
63
64static struct mtd_partition ceiva_partitions[] = {
65 {
66 .name = "Ceiva BOOT partition",
67 .size = BOOT_PARTITION_SIZE_KiB*1024,
68 .offset = 0,
69
70 },{
71 .name = "Ceiva parameters partition",
72 .size = PARAMS_PARTITION_SIZE_KiB*1024,
73 .offset = (16 + 8) * 1024,
74 },{
75 .name = "Ceiva kernel partition",
76 .size = (KERNEL_PARTITION_SIZE_KiB)*1024,
77 .offset = 0x20000,
78
79 },{
80 .name = "Ceiva root filesystem partition",
81 .offset = MTDPART_OFS_APPEND,
82 .size = (ROOT_PARTITION_SIZE_KiB)*1024,
83 }
84};
85#endif
86
87static int __init clps_static_partitions(struct mtd_partition **parts)
88{
89 int nb_parts = 0;
90
91#ifdef CONFIG_ARCH_CEIVA
92 if (machine_is_ceiva()) {
93 *parts = ceiva_partitions;
94 nb_parts = ARRAY_SIZE(ceiva_partitions);
95 }
96#endif
97 return nb_parts;
98}
99#endif
100
101struct clps_info {
102 unsigned long base;
103 unsigned long size;
104 int width;
105 void *vbase;
106 struct map_info *map;
107 struct mtd_info *mtd;
108 struct resource *res;
109};
110
111#define NR_SUBMTD 4
112
113static struct clps_info info[NR_SUBMTD];
114
115static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
116{
117 struct mtd_info *subdev[nr];
118 struct map_info *maps;
119 int i, found = 0, ret = 0;
120
121 /*
122 * Allocate the map_info structs in one go.
123 */
124 maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
125 if (!maps)
126 return -ENOMEM;
127 /*
128 * Claim and then map the memory regions.
129 */
130 for (i = 0; i < nr; i++) {
131 if (clps[i].base == (unsigned long)-1)
132 break;
133
134 clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
135 if (!clps[i].res) {
136 ret = -EBUSY;
137 break;
138 }
139
140 clps[i].map = maps + i;
141
142 clps[i].map->name = "clps flash";
143 clps[i].map->phys = clps[i].base;
144
145 clps[i].vbase = ioremap(clps[i].base, clps[i].size);
146 if (!clps[i].vbase) {
147 ret = -ENOMEM;
148 break;
149 }
150
151 clps[i].map->virt = (void __iomem *)clps[i].vbase;
152 clps[i].map->bankwidth = clps[i].width;
153 clps[i].map->size = clps[i].size;
154
155 simple_map_init(&clps[i].map);
156
157 clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
158 if (clps[i].mtd == NULL) {
159 ret = -ENXIO;
160 break;
161 }
162 clps[i].mtd->owner = THIS_MODULE;
163 subdev[i] = clps[i].mtd;
164
165 printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
166 "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
167 clps[i].width * 8);
168 found += 1;
169 }
170
171 /*
172 * ENXIO is special. It means we didn't find a chip when
173 * we probed. We need to tear down the mapping, free the
174 * resource and mark it as such.
175 */
176 if (ret == -ENXIO) {
177 iounmap(clps[i].vbase);
178 clps[i].vbase = NULL;
179 release_resource(clps[i].res);
180 clps[i].res = NULL;
181 }
182
183 /*
184 * If we found one device, don't bother with concat support.
185 * If we found multiple devices, use concat if we have it
186 * available, otherwise fail.
187 */
188 if (ret == 0 || ret == -ENXIO) {
189 if (found == 1) {
190 *rmtd = subdev[0];
191 ret = 0;
192 } else if (found > 1) {
193 /*
194 * We detected multiple devices. Concatenate
195 * them together.
196 */
197 *rmtd = mtd_concat_create(subdev, found,
198 "clps flash");
199 if (*rmtd == NULL)
200 ret = -ENXIO;
201 }
202 }
203
204 /*
205 * If we failed, clean up.
206 */
207 if (ret) {
208 do {
209 if (clps[i].mtd)
210 map_destroy(clps[i].mtd);
211 if (clps[i].vbase)
212 iounmap(clps[i].vbase);
213 if (clps[i].res)
214 release_resource(clps[i].res);
215 } while (i--);
216
217 kfree(maps);
218 }
219
220 return ret;
221}
222
223static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
224{
225 int i;
226
227 mtd_device_unregister(mtd);
228
229 if (mtd != clps[0].mtd)
230 mtd_concat_destroy(mtd);
231
232 for (i = NR_SUBMTD; i >= 0; i--) {
233 if (clps[i].mtd)
234 map_destroy(clps[i].mtd);
235 if (clps[i].vbase)
236 iounmap(clps[i].vbase);
237 if (clps[i].res)
238 release_resource(clps[i].res);
239 }
240 kfree(clps[0].map);
241}
242
243/*
244 * We define the memory space, size, and width for the flash memory
245 * space here.
246 */
247
248static int __init clps_setup_flash(void)
249{
250 int nr = 0;
251
252#ifdef CONFIG_ARCH_CEIVA
253 if (machine_is_ceiva()) {
254 info[0].base = CS0_PHYS_BASE;
255 info[0].size = SZ_32M;
256 info[0].width = CEIVA_FLASH_WIDTH;
257 info[1].base = CS1_PHYS_BASE;
258 info[1].size = SZ_32M;
259 info[1].width = CEIVA_FLASH_WIDTH;
260 nr = 2;
261 }
262#endif
263 return nr;
264}
265
266static struct mtd_partition *parsed_parts;
267static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
268
269static void __init clps_locate_partitions(struct mtd_info *mtd)
270{
271 const char *part_type = NULL;
272 int nr_parts = 0;
273 do {
274 /*
275 * Partition selection stuff.
276 */
277 nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
278 if (nr_parts > 0) {
279 part_type = "command line";
280 break;
281 }
282#ifdef CONFIG_MTD_CEIVA_STATICMAP
283 nr_parts = clps_static_partitions(&parsed_parts);
284 if (nr_parts > 0) {
285 part_type = "static";
286 break;
287 }
288 printk("found: %d partitions\n", nr_parts);
289#endif
290 } while (0);
291
292 if (nr_parts == 0) {
293 printk(KERN_NOTICE "clps flash: no partition info "
294 "available, registering whole flash\n");
295 mtd_device_register(mtd, NULL, 0);
296 } else {
297 printk(KERN_NOTICE "clps flash: using %s partition "
298 "definition\n", part_type);
299 mtd_device_register(mtd, parsed_parts, nr_parts);
300 }
301
302 /* Always succeeds. */
303}
304
305static void __exit clps_destroy_partitions(void)
306{
307 kfree(parsed_parts);
308}
309
310static struct mtd_info *mymtd;
311
312static int __init clps_mtd_init(void)
313{
314 int ret;
315 int nr;
316
317 nr = clps_setup_flash();
318 if (nr < 0)
319 return nr;
320
321 ret = clps_setup_mtd(info, nr, &mymtd);
322 if (ret)
323 return ret;
324
325 clps_locate_partitions(mymtd);
326
327 return 0;
328}
329
330static void __exit clps_mtd_cleanup(void)
331{
332 clps_destroy_mtd(info, mymtd);
333 clps_destroy_partitions();
334}
335
336module_init(clps_mtd_init);
337module_exit(clps_mtd_cleanup);
338
339MODULE_AUTHOR("Rob Scott");
340MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
341MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
new file mode 100644
index 00000000000..fe42a212bb3
--- /dev/null
+++ b/drivers/mtd/maps/edb7312.c
@@ -0,0 +1,134 @@
1/*
2 * Handle mapping of the NOR flash on Cogent EDB7312 boards
3 *
4 * Copyright 2002 SYSGO Real-Time Solutions GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <asm/io.h>
16#include <linux/mtd/mtd.h>
17#include <linux/mtd/map.h>
18#include <linux/mtd/partitions.h>
19
20#define WINDOW_ADDR 0x00000000 /* physical properties of flash */
21#define WINDOW_SIZE 0x01000000
22#define BUSWIDTH 2
23#define FLASH_BLOCKSIZE_MAIN 0x20000
24#define FLASH_NUMBLOCKS_MAIN 128
25/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
26#define PROBETYPES { "cfi_probe", NULL }
27
28#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */
29#define MTDID "edb7312-nor" /* for mtdparts= partitioning */
30
31static struct mtd_info *mymtd;
32
33struct map_info edb7312nor_map = {
34 .name = "NOR flash on EDB7312",
35 .size = WINDOW_SIZE,
36 .bankwidth = BUSWIDTH,
37 .phys = WINDOW_ADDR,
38};
39
40/*
41 * MTD partitioning stuff
42 */
43static struct mtd_partition static_partitions[3] =
44{
45 {
46 .name = "ARMboot",
47 .size = 0x40000,
48 .offset = 0
49 },
50 {
51 .name = "Kernel",
52 .size = 0x200000,
53 .offset = 0x40000
54 },
55 {
56 .name = "RootFS",
57 .size = 0xDC0000,
58 .offset = 0x240000
59 },
60};
61
62static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
63
64static int mtd_parts_nb = 0;
65static struct mtd_partition *mtd_parts = 0;
66
67static int __init init_edb7312nor(void)
68{
69 static const char *rom_probe_types[] = PROBETYPES;
70 const char **type;
71 const char *part_type = 0;
72
73 printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
74 WINDOW_SIZE, WINDOW_ADDR);
75 edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
76
77 if (!edb7312nor_map.virt) {
78 printk(MSG_PREFIX "failed to ioremap\n");
79 return -EIO;
80 }
81
82 simple_map_init(&edb7312nor_map);
83
84 mymtd = 0;
85 type = rom_probe_types;
86 for(; !mymtd && *type; type++) {
87 mymtd = do_map_probe(*type, &edb7312nor_map);
88 }
89 if (mymtd) {
90 mymtd->owner = THIS_MODULE;
91
92 mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
93 if (mtd_parts_nb > 0)
94 part_type = "detected";
95
96 if (mtd_parts_nb == 0) {
97 mtd_parts = static_partitions;
98 mtd_parts_nb = ARRAY_SIZE(static_partitions);
99 part_type = "static";
100 }
101
102 if (mtd_parts_nb == 0)
103 printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
104 else
105 printk(KERN_NOTICE MSG_PREFIX
106 "using %s partition definition\n", part_type);
107 /* Register the whole device first. */
108 mtd_device_register(mymtd, NULL, 0);
109 mtd_device_register(mymtd, mtd_parts, mtd_parts_nb);
110 return 0;
111 }
112
113 iounmap((void *)edb7312nor_map.virt);
114 return -ENXIO;
115}
116
117static void __exit cleanup_edb7312nor(void)
118{
119 if (mymtd) {
120 mtd_device_unregister(mymtd);
121 map_destroy(mymtd);
122 }
123 if (edb7312nor_map.virt) {
124 iounmap((void *)edb7312nor_map.virt);
125 edb7312nor_map.virt = 0;
126 }
127}
128
129module_init(init_edb7312nor);
130module_exit(cleanup_edb7312nor);
131
132MODULE_LICENSE("GPL");
133MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
134MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
new file mode 100644
index 00000000000..956e2e4f30e
--- /dev/null
+++ b/drivers/mtd/maps/fortunet.c
@@ -0,0 +1,277 @@
1/* fortunet.c memory map
2 *
3 */
4
5#include <linux/module.h>
6#include <linux/types.h>
7#include <linux/kernel.h>
8#include <linux/init.h>
9#include <linux/string.h>
10
11#include <linux/mtd/mtd.h>
12#include <linux/mtd/map.h>
13#include <linux/mtd/partitions.h>
14
15#include <asm/io.h>
16
17#define MAX_NUM_REGIONS 4
18#define MAX_NUM_PARTITIONS 8
19
20#define DEF_WINDOW_ADDR_PHY 0x00000000
21#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes
22
23#define MTD_FORTUNET_PK "MTD FortuNet: "
24
25#define MAX_NAME_SIZE 128
26
27struct map_region
28{
29 int window_addr_physical;
30 int altbankwidth;
31 struct map_info map_info;
32 struct mtd_info *mymtd;
33 struct mtd_partition parts[MAX_NUM_PARTITIONS];
34 char map_name[MAX_NAME_SIZE];
35 char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
36};
37
38static struct map_region map_regions[MAX_NUM_REGIONS];
39static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
40static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
41
42
43
44struct map_info default_map = {
45 .size = DEF_WINDOW_SIZE,
46 .bankwidth = 4,
47};
48
49static char * __init get_string_option(char *dest,int dest_size,char *sor)
50{
51 if(!dest_size)
52 return sor;
53 dest_size--;
54 while(*sor)
55 {
56 if(*sor==',')
57 {
58 sor++;
59 break;
60 }
61 else if(*sor=='\"')
62 {
63 sor++;
64 while(*sor)
65 {
66 if(*sor=='\"')
67 {
68 sor++;
69 break;
70 }
71 *dest = *sor;
72 dest++;
73 sor++;
74 dest_size--;
75 if(!dest_size)
76 {
77 *dest = 0;
78 return sor;
79 }
80 }
81 }
82 else
83 {
84 *dest = *sor;
85 dest++;
86 sor++;
87 dest_size--;
88 if(!dest_size)
89 {
90 *dest = 0;
91 return sor;
92 }
93 }
94 }
95 *dest = 0;
96 return sor;
97}
98
99static int __init MTD_New_Region(char *line)
100{
101 char string[MAX_NAME_SIZE];
102 int params[6];
103 get_options (get_string_option(string,sizeof(string),line),6,params);
104 if(params[0]<1)
105 {
106 printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
107 " name,region-number[,base,size,bankwidth,altbankwidth]\n");
108 return 1;
109 }
110 if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
111 {
112 printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
113 params[1],MAX_NUM_REGIONS-1);
114 return 1;
115 }
116 memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
117 memcpy(&map_regions[params[1]].map_info,
118 &default_map,sizeof(map_regions[params[1]].map_info));
119 map_regions_set[params[1]] = 1;
120 map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
121 map_regions[params[1]].altbankwidth = 2;
122 map_regions[params[1]].mymtd = NULL;
123 map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
124 strcpy(map_regions[params[1]].map_info.name,string);
125 if(params[0]>1)
126 {
127 map_regions[params[1]].window_addr_physical = params[2];
128 }
129 if(params[0]>2)
130 {
131 map_regions[params[1]].map_info.size = params[3];
132 }
133 if(params[0]>3)
134 {
135 map_regions[params[1]].map_info.bankwidth = params[4];
136 }
137 if(params[0]>4)
138 {
139 map_regions[params[1]].altbankwidth = params[5];
140 }
141 return 1;
142}
143
144static int __init MTD_New_Partition(char *line)
145{
146 char string[MAX_NAME_SIZE];
147 int params[4];
148 get_options (get_string_option(string,sizeof(string),line),4,params);
149 if(params[0]<3)
150 {
151 printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
152 " name,region-number,size,offset\n");
153 return 1;
154 }
155 if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
156 {
157 printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
158 params[1],MAX_NUM_REGIONS-1);
159 return 1;
160 }
161 if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
162 {
163 printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
164 return 1;
165 }
166 map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
167 map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
168 strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
169 map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
170 params[2];
171 map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
172 params[3];
173 map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
174 map_regions_parts[params[1]]++;
175 return 1;
176}
177
178__setup("MTD_Region=", MTD_New_Region);
179__setup("MTD_Partition=", MTD_New_Partition);
180
181/* Backwards-spelling-compatibility */
182__setup("MTD_Partion=", MTD_New_Partition);
183
184static int __init init_fortunet(void)
185{
186 int ix,iy;
187 for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
188 {
189 if(map_regions_parts[ix]&&(!map_regions_set[ix]))
190 {
191 printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
192 ix);
193 memset(&map_regions[ix],0,sizeof(map_regions[ix]));
194 memcpy(&map_regions[ix].map_info,&default_map,
195 sizeof(map_regions[ix].map_info));
196 map_regions_set[ix] = 1;
197 map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
198 map_regions[ix].altbankwidth = 2;
199 map_regions[ix].mymtd = NULL;
200 map_regions[ix].map_info.name = map_regions[ix].map_name;
201 strcpy(map_regions[ix].map_info.name,"FORTUNET");
202 }
203 if(map_regions_set[ix])
204 {
205 iy++;
206 printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
207 " address %x size %x\n",
208 map_regions[ix].map_info.name,
209 map_regions[ix].window_addr_physical,
210 map_regions[ix].map_info.size);
211
212 map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
213
214 map_regions[ix].map_info.virt =
215 ioremap_nocache(
216 map_regions[ix].window_addr_physical,
217 map_regions[ix].map_info.size);
218 if(!map_regions[ix].map_info.virt)
219 {
220 int j = 0;
221 printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
222 map_regions[ix].map_info.name);
223 for (j = 0 ; j < ix; j++)
224 iounmap(map_regions[j].map_info.virt);
225 return -ENXIO;
226 }
227 simple_map_init(&map_regions[ix].map_info);
228
229 printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
230 map_regions[ix].map_info.name,
231 map_regions[ix].map_info.virt);
232 map_regions[ix].mymtd = do_map_probe("cfi_probe",
233 &map_regions[ix].map_info);
234 if((!map_regions[ix].mymtd)&&(
235 map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
236 {
237 printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
238 "for %s flash.\n",
239 map_regions[ix].map_info.name);
240 map_regions[ix].map_info.bankwidth =
241 map_regions[ix].altbankwidth;
242 map_regions[ix].mymtd = do_map_probe("cfi_probe",
243 &map_regions[ix].map_info);
244 }
245 map_regions[ix].mymtd->owner = THIS_MODULE;
246 mtd_device_register(map_regions[ix].mymtd,
247 map_regions[ix].parts,
248 map_regions_parts[ix]);
249 }
250 }
251 if(iy)
252 return 0;
253 return -ENXIO;
254}
255
256static void __exit cleanup_fortunet(void)
257{
258 int ix;
259 for(ix=0;ix<MAX_NUM_REGIONS;ix++)
260 {
261 if(map_regions_set[ix])
262 {
263 if( map_regions[ix].mymtd )
264 {
265 mtd_device_unregister(map_regions[ix].mymtd);
266 map_destroy( map_regions[ix].mymtd );
267 }
268 iounmap((void *)map_regions[ix].map_info.virt);
269 }
270 }
271}
272
273module_init(init_fortunet);
274module_exit(cleanup_fortunet);
275
276MODULE_AUTHOR("FortuNet, Inc.");
277MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff --git a/drivers/mtd/maps/tegra_nor.c b/drivers/mtd/maps/tegra_nor.c
new file mode 100644
index 00000000000..b455fd5e1c0
--- /dev/null
+++ b/drivers/mtd/maps/tegra_nor.c
@@ -0,0 +1,483 @@
1/*
2 * drivers/mtd/maps/tegra_nor.c
3 *
4 * MTD mapping driver for the internal SNOR controller in Tegra SoCs
5 *
6 * Copyright (C) 2009 - 2012 NVIDIA Corporation
7 *
8 * Author:
9 * Raghavendra VK <rvk@nvidia.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 */
25
26#include <linux/platform_device.h>
27#include <linux/module.h>
28#include <linux/types.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/ioport.h>
32#include <linux/slab.h>
33#include <linux/interrupt.h>
34#include <linux/irq.h>
35#include <linux/mutex.h>
36#include <linux/mtd/mtd.h>
37#include <linux/mtd/map.h>
38#include <linux/mtd/partitions.h>
39#include <linux/dma-mapping.h>
40#include <linux/proc_fs.h>
41#include <linux/io.h>
42#include <linux/uaccess.h>
43#include <linux/clk.h>
44#include <linux/platform_data/tegra_nor.h>
45#include <asm/cacheflush.h>
46
47#define __BITMASK0(len) (BIT(len) - 1)
48#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start))
49#define REG_GET_FIELD(val, start, len) (((val) >> (start)) & __BITMASK0(len))
50
51/* tegra gmi registers... */
52#define TEGRA_SNOR_CONFIG_REG 0x00
53#define TEGRA_SNOR_NOR_ADDR_PTR_REG 0x08
54#define TEGRA_SNOR_AHB_ADDR_PTR_REG 0x0C
55#define TEGRA_SNOR_TIMING0_REG 0x10
56#define TEGRA_SNOR_TIMING1_REG 0x14
57#define TEGRA_SNOR_DMA_CFG_REG 0x20
58
59/* config register */
60#define TEGRA_SNOR_CONFIG_GO BIT(31)
61#define TEGRA_SNOR_CONFIG_WORDWIDE BIT(30)
62#define TEGRA_SNOR_CONFIG_DEVICE_TYPE BIT(29)
63#define TEGRA_SNOR_CONFIG_MUX_MODE BIT(28)
64#define TEGRA_SNOR_CONFIG_BURST_LEN(val) REG_FIELD((val), 26, 2)
65#define TEGRA_SNOR_CONFIG_RDY_ACTIVE BIT(24)
66#define TEGRA_SNOR_CONFIG_RDY_POLARITY BIT(23)
67#define TEGRA_SNOR_CONFIG_ADV_POLARITY BIT(22)
68#define TEGRA_SNOR_CONFIG_OE_WE_POLARITY BIT(21)
69#define TEGRA_SNOR_CONFIG_CS_POLARITY BIT(20)
70#define TEGRA_SNOR_CONFIG_NOR_DPD BIT(19)
71#define TEGRA_SNOR_CONFIG_WP BIT(15)
72#define TEGRA_SNOR_CONFIG_PAGE_SZ(val) REG_FIELD((val), 8, 2)
73#define TEGRA_SNOR_CONFIG_MST_ENB BIT(7)
74#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 2)
75#define TEGRA_SNOR_CONFIG_CE_LAST REG_FIELD(3)
76#define TEGRA_SNOR_CONFIG_CE_FIRST REG_FIELD(2)
77#define TEGRA_SNOR_CONFIG_DEVICE_MODE(val) REG_FIELD((val), 0, 2)
78
79/* dma config register */
80#define TEGRA_SNOR_DMA_CFG_GO BIT(31)
81#define TEGRA_SNOR_DMA_CFG_BSY BIT(30)
82#define TEGRA_SNOR_DMA_CFG_DIR BIT(29)
83#define TEGRA_SNOR_DMA_CFG_INT_ENB BIT(28)
84#define TEGRA_SNOR_DMA_CFG_INT_STA BIT(27)
85#define TEGRA_SNOR_DMA_CFG_BRST_SZ(val) REG_FIELD((val), 24, 3)
86#define TEGRA_SNOR_DMA_CFG_WRD_CNT(val) REG_FIELD((val), 2, 14)
87
88/* timing 0 register */
89#define TEGRA_SNOR_TIMING0_PG_RDY(val) REG_FIELD((val), 28, 4)
90#define TEGRA_SNOR_TIMING0_PG_SEQ(val) REG_FIELD((val), 20, 4)
91#define TEGRA_SNOR_TIMING0_MUX(val) REG_FIELD((val), 12, 4)
92#define TEGRA_SNOR_TIMING0_HOLD(val) REG_FIELD((val), 8, 4)
93#define TEGRA_SNOR_TIMING0_ADV(val) REG_FIELD((val), 4, 4)
94#define TEGRA_SNOR_TIMING0_CE(val) REG_FIELD((val), 0, 4)
95
96/* timing 1 register */
97#define TEGRA_SNOR_TIMING1_WE(val) REG_FIELD((val), 16, 8)
98#define TEGRA_SNOR_TIMING1_OE(val) REG_FIELD((val), 8, 8)
99#define TEGRA_SNOR_TIMING1_WAIT(val) REG_FIELD((val), 0, 8)
100
101/* SNOR DMA supports 2^14 AHB (32-bit words)
102 * Maximum data in one transfer = 2^16 bytes
103 */
104#define TEGRA_SNOR_DMA_LIMIT 0x10000
105#define TEGRA_SNOR_DMA_LIMIT_WORDS (TEGRA_SNOR_DMA_LIMIT >> 2)
106
107/* Even if BW is 1 MB/s, maximum time to
108 * transfer SNOR_DMA_LIMIT bytes is 66 ms
109 */
110#define TEGRA_SNOR_DMA_TIMEOUT_MS 67
111
112struct tegra_nor_info {
113 struct tegra_nor_platform_data *plat;
114 struct device *dev;
115 struct clk *clk;
116 struct mtd_partition *parts;
117 struct mtd_info *mtd;
118 struct map_info map;
119 struct completion dma_complete;
120 void __iomem *base;
121 void *dma_virt_buffer;
122 dma_addr_t dma_phys_buffer;
123 u32 init_config;
124 u32 timing0_default, timing1_default;
125 u32 timing0_read, timing1_read;
126};
127
128static inline unsigned long snor_tegra_readl(struct tegra_nor_info *tnor,
129 unsigned long reg)
130{
131 return readl(tnor->base + reg);
132}
133
134static inline void snor_tegra_writel(struct tegra_nor_info *tnor,
135 unsigned long val, unsigned long reg)
136{
137 writel(val, tnor->base + reg);
138}
139
140#define DRV_NAME "tegra-nor"
141
142static const char * const part_probes[] = { "cmdlinepart", NULL };
143
144static int wait_for_dma_completion(struct tegra_nor_info *info)
145{
146 unsigned long dma_timeout;
147 int ret;
148
149 dma_timeout = msecs_to_jiffies(TEGRA_SNOR_DMA_TIMEOUT_MS);
150 ret = wait_for_completion_timeout(&info->dma_complete, dma_timeout);
151 return ret ? 0 : -ETIMEDOUT;
152}
153
154static void tegra_flash_dma(struct map_info *map,
155 void *to, unsigned long from, ssize_t len)
156{
157 u32 snor_config, dma_config = 0;
158 int dma_transfer_count = 0, word32_count = 0;
159 u32 nor_address, current_transfer = 0;
160 u32 copy_to = (u32)to;
161 struct tegra_nor_info *c =
162 container_of(map, struct tegra_nor_info, map);
163 unsigned int bytes_remaining = len;
164
165 snor_config = c->init_config;
166 snor_tegra_writel(c, c->timing0_read, TEGRA_SNOR_TIMING0_REG);
167 snor_tegra_writel(c, c->timing1_read, TEGRA_SNOR_TIMING1_REG);
168
169 if (len > 32) {
170 word32_count = len >> 2;
171 bytes_remaining = len & 0x00000003;
172 /*
173 * The parameters can be setup in any order since we write to
174 * controller register only after all parameters are set.
175 */
176 /* SNOR CONFIGURATION SETUP */
177 snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1);
178 /* 8 word page */
179 snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(2);
180 snor_config |= TEGRA_SNOR_CONFIG_MST_ENB;
181 /* SNOR DMA CONFIGURATION SETUP */
182 /* NOR -> AHB */
183 dma_config &= ~TEGRA_SNOR_DMA_CFG_DIR;
184 /* One word burst */
185 dma_config |= TEGRA_SNOR_DMA_CFG_BRST_SZ(4);
186
187 for (nor_address = (unsigned int)(map->phys + from);
188 word32_count > 0;
189 word32_count -= current_transfer,
190 dma_transfer_count += current_transfer,
191 nor_address += (current_transfer * 4),
192 copy_to += (current_transfer * 4)) {
193
194 current_transfer =
195 (word32_count > TEGRA_SNOR_DMA_LIMIT_WORDS)
196 ? (TEGRA_SNOR_DMA_LIMIT_WORDS) : word32_count;
197 /* Start NOR operation */
198 snor_config |= TEGRA_SNOR_CONFIG_GO;
199 dma_config |= TEGRA_SNOR_DMA_CFG_GO;
200 /* Enable interrupt before every transaction since the
201 * interrupt handler disables it */
202 dma_config |= TEGRA_SNOR_DMA_CFG_INT_ENB;
203 /* Num of AHB (32-bit) words to transferred minus 1 */
204 dma_config |=
205 TEGRA_SNOR_DMA_CFG_WRD_CNT(current_transfer - 1);
206 snor_tegra_writel(c, c->dma_phys_buffer,
207 TEGRA_SNOR_AHB_ADDR_PTR_REG);
208 snor_tegra_writel(c, nor_address,
209 TEGRA_SNOR_NOR_ADDR_PTR_REG);
210 snor_tegra_writel(c, snor_config,
211 TEGRA_SNOR_CONFIG_REG);
212 snor_tegra_writel(c, dma_config,
213 TEGRA_SNOR_DMA_CFG_REG);
214 if (wait_for_dma_completion(c)) {
215 dev_err(c->dev, "timout waiting for DMA\n");
216 /* Transfer the remaining words by memcpy */
217 bytes_remaining += (word32_count << 2);
218 break;
219 }
220 memcpy((char *)(copy_to), (char *)(c->dma_virt_buffer),
221 (current_transfer << 2));
222
223 }
224 }
225 /* Put the controller back into slave mode. */
226 snor_config = snor_tegra_readl(c, TEGRA_SNOR_CONFIG_REG);
227 snor_config &= ~TEGRA_SNOR_CONFIG_MST_ENB;
228 snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0);
229 snor_tegra_writel(c, snor_config, TEGRA_SNOR_CONFIG_REG);
230
231 memcpy_fromio(((char *)to + (dma_transfer_count << 2)),
232 ((char *)(map->virt + from) + (dma_transfer_count << 2)),
233 bytes_remaining);
234
235 snor_tegra_writel(c, c->timing0_default, TEGRA_SNOR_TIMING0_REG);
236 snor_tegra_writel(c, c->timing1_default, TEGRA_SNOR_TIMING1_REG);
237}
238
239static irqreturn_t tegra_nor_isr(int flag, void *dev_id)
240{
241 struct tegra_nor_info *info = (struct tegra_nor_info *)dev_id;
242 u32 dma_config = snor_tegra_readl(info, TEGRA_SNOR_DMA_CFG_REG);
243 if (dma_config & TEGRA_SNOR_DMA_CFG_INT_STA) {
244 /* Disable interrupts. WAR for BUG:821560 */
245 dma_config &= ~TEGRA_SNOR_DMA_CFG_INT_ENB;
246 snor_tegra_writel(info, dma_config, TEGRA_SNOR_DMA_CFG_REG);
247 complete(&info->dma_complete);
248 } else {
249 pr_err("%s: Spurious interrupt\n", __func__);
250 }
251 return IRQ_HANDLED;
252}
253
254static int tegra_snor_controller_init(struct tegra_nor_info *info)
255{
256 struct tegra_nor_chip_parms *chip_parm = &info->plat->chip_parms;
257 u32 width = info->plat->flash.width;
258 u32 config = 0;
259
260 config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0);
261 config |= TEGRA_SNOR_CONFIG_SNOR_CS(0);
262 config &= ~TEGRA_SNOR_CONFIG_DEVICE_TYPE; /* Select NOR */
263 config |= TEGRA_SNOR_CONFIG_WP; /* Enable writes */
264 switch (width) {
265 case 2:
266 config &= ~TEGRA_SNOR_CONFIG_WORDWIDE; /* 16 bit */
267 break;
268 case 4:
269 config |= TEGRA_SNOR_CONFIG_WORDWIDE; /* 32 bit */
270 break;
271 default:
272 return -EINVAL;
273 }
274 config |= TEGRA_SNOR_CONFIG_BURST_LEN(0);
275 config &= ~TEGRA_SNOR_CONFIG_MUX_MODE;
276 snor_tegra_writel(info, config, TEGRA_SNOR_CONFIG_REG);
277 info->init_config = config;
278
279 info->timing0_default = chip_parm->timing_default.timing0;
280 info->timing0_read = chip_parm->timing_read.timing0;
281 info->timing1_default = chip_parm->timing_default.timing1;
282 info->timing1_read = chip_parm->timing_read.timing0;
283
284 snor_tegra_writel(info, info->timing1_default, TEGRA_SNOR_TIMING1_REG);
285 snor_tegra_writel(info, info->timing0_default, TEGRA_SNOR_TIMING0_REG);
286 return 0;
287}
288
289static int tegra_nor_probe(struct platform_device *pdev)
290{
291 int err = 0;
292 struct tegra_nor_platform_data *plat = pdev->dev.platform_data;
293 struct tegra_nor_info *info = NULL;
294 struct device *dev = &pdev->dev;
295 struct resource *res;
296 int irq;
297
298 if (!plat) {
299 pr_err("%s: no platform device info\n", __func__);
300 err = -EINVAL;
301 goto fail;
302 }
303
304 info = devm_kzalloc(dev, sizeof(struct tegra_nor_info),
305 GFP_KERNEL);
306 if (!info) {
307 err = -ENOMEM;
308 goto fail;
309 }
310
311 /* Get NOR controller & map the same */
312 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
313 if (!res) {
314 dev_err(dev, "no mem resource?\n");
315 err = -ENODEV;
316 goto fail;
317 }
318
319 if (!devm_request_mem_region(dev, res->start, resource_size(res),
320 dev_name(&pdev->dev))) {
321 dev_err(dev, "NOR region already claimed\n");
322 err = -EBUSY;
323 goto fail;
324 }
325
326 info->base = devm_ioremap(dev, res->start, resource_size(res));
327 if (!info->base) {
328 dev_err(dev, "Can't ioremap NOR region\n");
329 err = -ENOMEM;
330 goto fail;
331 }
332
333 /* Get NOR flash aperture & map the same */
334 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
335 if (!res) {
336 dev_err(dev, "no mem resource?\n");
337 err = -ENODEV;
338 goto fail;
339 }
340
341 if (!devm_request_mem_region(dev, res->start, resource_size(res),
342 dev_name(dev))) {
343 dev_err(dev, "NOR region already claimed\n");
344 err = -EBUSY;
345 goto fail;
346 }
347
348 info->map.virt = devm_ioremap(dev, res->start,
349 resource_size(res));
350 if (!info->map.virt) {
351 dev_err(dev, "Can't ioremap NOR region\n");
352 err = -ENOMEM;
353 goto fail;
354 }
355
356 info->plat = plat;
357 info->dev = dev;
358 info->map.bankwidth = plat->flash.width;
359 info->map.name = dev_name(dev);
360 info->map.phys = res->start;
361 info->map.size = resource_size(res);
362
363 info->clk = clk_get(dev, NULL);
364 if (IS_ERR(info->clk)) {
365 err = PTR_ERR(info->clk);
366 goto fail;
367 }
368
369 err = clk_enable(info->clk);
370 if (err != 0)
371 goto out_clk_put;
372
373 simple_map_init(&info->map);
374 info->map.copy_from = tegra_flash_dma;
375
376 /* Intialise the SNOR controller before probe */
377 err = tegra_snor_controller_init(info);
378 if (err) {
379 dev_err(dev, "Error initializing controller\n");
380 goto out_clk_disable;
381 }
382
383 init_completion(&info->dma_complete);
384
385 irq = platform_get_irq(pdev, 0);
386 if (!irq) {
387 dev_err(dev, "no irq resource?\n");
388 err = -ENODEV;
389 goto out_clk_disable;
390 }
391
392 /* Register SNOR DMA completion interrupt */
393 err = devm_request_irq(dev, irq, tegra_nor_isr, IRQF_DISABLED,
394 dev_name(dev), info);
395 if (err) {
396 dev_err(dev, "Failed to request irq %i\n", irq);
397 goto out_clk_disable;
398 }
399 info->dma_virt_buffer = dma_alloc_coherent(dev,
400 TEGRA_SNOR_DMA_LIMIT,
401 &info->dma_phys_buffer,
402 GFP_KERNEL);
403 if (info->dma_virt_buffer == NULL) {
404 dev_err(&pdev->dev, "Could not allocate buffer for DMA");
405 err = -ENOMEM;
406 goto out_clk_disable;
407 }
408
409 info->mtd = do_map_probe(plat->flash.map_name, &info->map);
410 if (!info->mtd) {
411 err = -EIO;
412 goto out_dma_free_coherent;
413 }
414 info->mtd->owner = THIS_MODULE;
415 info->parts = NULL;
416
417 platform_set_drvdata(pdev, info);
418 err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
419 if (err > 0)
420 err = mtd_device_register(info->mtd, info->parts, err);
421 else if (err <= 0 && plat->flash.parts)
422 err =
423 mtd_device_register(info->mtd, plat->flash.parts,
424 plat->flash.nr_parts);
425 else
426 mtd_device_register(info->mtd, NULL, 0);
427
428 return 0;
429
430out_dma_free_coherent:
431 dma_free_coherent(dev, TEGRA_SNOR_DMA_LIMIT,
432 info->dma_virt_buffer, info->dma_phys_buffer);
433out_clk_disable:
434 clk_disable(info->clk);
435out_clk_put:
436 clk_put(info->clk);
437fail:
438 pr_err("Tegra NOR probe failed\n");
439 return err;
440}
441
442static int tegra_nor_remove(struct platform_device *pdev)
443{
444 struct tegra_nor_info *info = platform_get_drvdata(pdev);
445
446 mtd_device_unregister(info->mtd);
447 if (info->parts)
448 kfree(info->parts);
449 dma_free_coherent(&pdev->dev, TEGRA_SNOR_DMA_LIMIT,
450 info->dma_virt_buffer, info->dma_phys_buffer);
451 map_destroy(info->mtd);
452 clk_disable(info->clk);
453 clk_put(info->clk);
454
455 return 0;
456}
457
458static struct platform_driver __refdata tegra_nor_driver = {
459 .probe = tegra_nor_probe,
460 .remove = __devexit_p(tegra_nor_remove),
461 .driver = {
462 .name = DRV_NAME,
463 .owner = THIS_MODULE,
464 },
465};
466
467static int __init tegra_nor_init(void)
468{
469 return platform_driver_register(&tegra_nor_driver);
470}
471
472static void __exit tegra_nor_exit(void)
473{
474 platform_driver_unregister(&tegra_nor_driver);
475}
476
477module_init(tegra_nor_init);
478module_exit(tegra_nor_exit);
479
480MODULE_AUTHOR("Raghavendra VK <rvk@nvidia.com>");
481MODULE_DESCRIPTION("NOR Flash mapping driver for NVIDIA Tegra based boards");
482MODULE_LICENSE("GPL");
483MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
new file mode 100644
index 00000000000..901ce968efa
--- /dev/null
+++ b/drivers/mtd/maps/wr_sbc82xx_flash.c
@@ -0,0 +1,181 @@
1/*
2 * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
3 *
4 * Copyright (C) 2004 Red Hat, Inc.
5 *
6 * Author: David Woodhouse <dwmw2@infradead.org>
7 *
8 */
9
10#include <linux/module.h>
11#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <asm/io.h>
16#include <linux/mtd/mtd.h>
17#include <linux/mtd/map.h>
18#include <linux/mtd/partitions.h>
19
20#include <asm/immap_cpm2.h>
21
22static struct mtd_info *sbcmtd[3];
23static struct mtd_partition *sbcmtd_parts[3];
24
25struct map_info sbc82xx_flash_map[3] = {
26 {.name = "Boot flash"},
27 {.name = "Alternate boot flash"},
28 {.name = "User flash"}
29};
30
31static struct mtd_partition smallflash_parts[] = {
32 {
33 .name = "space",
34 .size = 0x100000,
35 .offset = 0,
36 }, {
37 .name = "bootloader",
38 .size = MTDPART_SIZ_FULL,
39 .offset = MTDPART_OFS_APPEND,
40 }
41};
42
43static struct mtd_partition bigflash_parts[] = {
44 {
45 .name = "bootloader",
46 .size = 0x00100000,
47 .offset = 0,
48 }, {
49 .name = "file system",
50 .size = 0x01f00000,
51 .offset = MTDPART_OFS_APPEND,
52 }, {
53 .name = "boot config",
54 .size = 0x00100000,
55 .offset = MTDPART_OFS_APPEND,
56 }, {
57 .name = "space",
58 .size = 0x01f00000,
59 .offset = MTDPART_OFS_APPEND,
60 }
61};
62
63static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
64
65#define init_sbc82xx_one_flash(map, br, or) \
66do { \
67 (map).phys = (br & 1) ? (br & 0xffff8000) : 0; \
68 (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0; \
69 switch (br & 0x00001800) { \
70 case 0x00000000: \
71 case 0x00000800: (map).bankwidth = 1; break; \
72 case 0x00001000: (map).bankwidth = 2; break; \
73 case 0x00001800: (map).bankwidth = 4; break; \
74 } \
75} while (0);
76
77static int __init init_sbc82xx_flash(void)
78{
79 volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
80 int bigflash;
81 int i;
82
83#ifdef CONFIG_SBC8560
84 mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
85#else
86 mc = &cpm2_immr->im_memctl;
87#endif
88
89 bigflash = 1;
90 if ((mc->memc_br0 & 0x00001800) == 0x00001800)
91 bigflash = 0;
92
93 init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
94 init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
95 init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
96
97#ifdef CONFIG_SBC8560
98 iounmap((void *) mc);
99#endif
100
101 for (i=0; i<3; i++) {
102 int8_t flashcs[3] = { 0, 6, 1 };
103 int nr_parts;
104
105 printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
106 sbc82xx_flash_map[i].name,
107 (sbc82xx_flash_map[i].size >> 20),
108 flashcs[i]);
109 if (!sbc82xx_flash_map[i].phys) {
110 /* We know it can't be at zero. */
111 printk("): disabled by bootloader.\n");
112 continue;
113 }
114 printk(" at %08lx)\n", sbc82xx_flash_map[i].phys);
115
116 sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size);
117
118 if (!sbc82xx_flash_map[i].virt) {
119 printk("Failed to ioremap\n");
120 continue;
121 }
122
123 simple_map_init(&sbc82xx_flash_map[i]);
124
125 sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
126
127 if (!sbcmtd[i])
128 continue;
129
130 sbcmtd[i]->owner = THIS_MODULE;
131
132 nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes,
133 &sbcmtd_parts[i], 0);
134 if (nr_parts > 0) {
135 mtd_device_register(sbcmtd[i], sbcmtd_parts[i],
136 nr_parts);
137 continue;
138 }
139
140 /* No partitioning detected. Use default */
141 if (i == 2) {
142 mtd_device_register(sbcmtd[i], NULL, 0);
143 } else if (i == bigflash) {
144 mtd_device_register(sbcmtd[i], bigflash_parts,
145 ARRAY_SIZE(bigflash_parts));
146 } else {
147 mtd_device_register(sbcmtd[i], smallflash_parts,
148 ARRAY_SIZE(smallflash_parts));
149 }
150 }
151 return 0;
152}
153
154static void __exit cleanup_sbc82xx_flash(void)
155{
156 int i;
157
158 for (i=0; i<3; i++) {
159 if (!sbcmtd[i])
160 continue;
161
162 if (i<2 || sbcmtd_parts[i])
163 mtd_device_unregister(sbcmtd[i]);
164 else
165 mtd_device_unregister(sbcmtd[i]);
166
167 kfree(sbcmtd_parts[i]);
168 map_destroy(sbcmtd[i]);
169
170 iounmap((void *)sbc82xx_flash_map[i].virt);
171 sbc82xx_flash_map[i].virt = 0;
172 }
173}
174
175module_init(init_sbc82xx_flash);
176module_exit(cleanup_sbc82xx_flash);
177
178
179MODULE_LICENSE("GPL");
180MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
181MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");