upgrade wireless-tools and iproute2
[openwrt.git] / package / linux / kernel-source / drivers / mtd / maps / bcm947xx-flash.c
1 /*
2  * Flash mapping for BCM947XX boards
3  *
4  * Copyright 2004, Broadcom Corporation
5  * All Rights Reserved.
6  * 
7  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11  *
12  * $Id$
13  */
14
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <asm/io.h>
19 #include <linux/mtd/mtd.h>
20 #include <linux/mtd/map.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/config.h>
23
24 #include <typedefs.h>
25 #include <bcmnvram.h>
26 #include <bcmutils.h>
27 #include <sbconfig.h>
28 #include <sbchipc.h>
29 #include <sbutils.h>
30 #include <trxhdr.h>
31
32 /* Global SB handle */
33 extern void *bcm947xx_sbh;
34 extern spinlock_t bcm947xx_sbh_lock;
35
36 /* Convenience */
37 #define sbh bcm947xx_sbh
38 #define sbh_lock bcm947xx_sbh_lock
39
40 #ifdef CONFIG_MTD_PARTITIONS
41 extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
42 #endif
43
44 #define WINDOW_ADDR 0x1fc00000
45 #define WINDOW_SIZE 0x400000
46 #define BUSWIDTH 2
47
48 /* e.g., flash=2M or flash=4M */
49 static int flash = 0;
50 MODULE_PARM(flash, "i");
51 static int __init
52 bcm947xx_setup(char *str)
53 {
54         flash = memparse(str, &str);
55         return 1;
56 }
57 __setup("flash=", bcm947xx_setup);
58
59 static struct mtd_info *bcm947xx_mtd;
60
61 __u8 bcm947xx_map_read8(struct map_info *map, unsigned long ofs)
62 {
63         if (map->map_priv_2 == 1)
64                 return __raw_readb(map->map_priv_1 + ofs);
65
66         u16 val = __raw_readw(map->map_priv_1 + (ofs & ~1));
67         if (ofs & 1)
68                 return ((val >> 8) & 0xff);
69         else
70                 return (val & 0xff);
71 }
72
73 __u16 bcm947xx_map_read16(struct map_info *map, unsigned long ofs)
74 {
75         return __raw_readw(map->map_priv_1 + ofs);
76 }
77
78 __u32 bcm947xx_map_read32(struct map_info *map, unsigned long ofs)
79 {
80         return __raw_readl(map->map_priv_1 + ofs);
81 }
82
83 void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
84 {
85         if (len==1) {
86                 memcpy_fromio(to, map->map_priv_1 + from, len);
87         } else {
88                 int i;
89                 u16 *dest = (u16 *) to;
90                 u16 *src  = (u16 *) (map->map_priv_1 + from);
91                 for (i = 0; i < (len / 2); i++) {
92                         dest[i] = src[i];
93                 }
94                 if (len & 1)
95                         *((u8 *)dest+len-1) = src[i] & 0xff;
96         }
97 }
98
99 void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr)
100 {
101         __raw_writeb(d, map->map_priv_1 + adr);
102         mb();
103 }
104
105 void bcm947xx_map_write16(struct map_info *map, __u16 d, unsigned long adr)
106 {
107         __raw_writew(d, map->map_priv_1 + adr);
108         mb();
109 }
110
111 void bcm947xx_map_write32(struct map_info *map, __u32 d, unsigned long adr)
112 {
113         __raw_writel(d, map->map_priv_1 + adr);
114         mb();
115 }
116
117 void bcm947xx_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
118 {
119         memcpy_toio(map->map_priv_1 + to, from, len);
120 }
121
122 struct map_info bcm947xx_map = {
123         name: "Physically mapped flash",
124         size: WINDOW_SIZE,
125         buswidth: BUSWIDTH,
126         read8: bcm947xx_map_read8,
127         read16: bcm947xx_map_read16,
128         read32: bcm947xx_map_read32,
129         copy_from: bcm947xx_map_copy_from,
130         write8: bcm947xx_map_write8,
131         write16: bcm947xx_map_write16,
132         write32: bcm947xx_map_write32,
133         copy_to: bcm947xx_map_copy_to
134 };
135
136 #if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
137 #define init_bcm947xx_map init_module
138 #define cleanup_bcm947xx_map cleanup_module
139 #endif
140
141 mod_init_t init_bcm947xx_map(void)
142 {
143         ulong flags;
144         uint coreidx;
145         chipcregs_t *cc;
146         uint32 fltype;
147         uint window_addr = 0, window_size = 0;
148         size_t size;
149         int ret = 0;
150 #ifdef CONFIG_MTD_PARTITIONS
151         struct mtd_partition *parts;
152         int i;
153 #endif
154
155         spin_lock_irqsave(&sbh_lock, flags);
156         coreidx = sb_coreidx(sbh);
157
158         /* Check strapping option if chipcommon exists */
159         if ((cc = sb_setcore(sbh, SB_CC, 0))) {
160                 fltype = readl(&cc->capabilities) & CAP_FLASH_MASK;
161                 if (fltype == PFLASH) {
162                         bcm947xx_map.map_priv_2 = 1;
163                         window_addr = 0x1c000000;
164                         bcm947xx_map.size = window_size = 32 * 1024 * 1024;
165                         if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
166                                 bcm947xx_map.buswidth = 1;
167                 }
168         } else {
169                 fltype = PFLASH;
170                 bcm947xx_map.map_priv_2 = 0;
171                 window_addr = WINDOW_ADDR;
172                 window_size = WINDOW_SIZE;
173         }
174
175         sb_setcoreidx(sbh, coreidx);
176         spin_unlock_irqrestore(&sbh_lock, flags);
177
178         if (fltype != PFLASH) {
179                 printk(KERN_ERR "pflash: found no supported devices\n");
180                 ret = -ENODEV;
181                 goto fail;
182         }
183
184         bcm947xx_map.map_priv_1 = (unsigned long) ioremap(window_addr, window_size);
185         if (!bcm947xx_map.map_priv_1) {
186                 printk(KERN_ERR "pflash: ioremap failed\n");
187                 ret = -EIO;
188                 goto fail;
189         }
190
191         if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
192                 printk(KERN_ERR "pflash: cfi_probe failed\n");
193                 ret = -ENXIO;
194                 goto fail;
195         }
196
197         bcm947xx_mtd->module = THIS_MODULE;
198
199         /* Allow size override for testing */
200         size = flash ? : bcm947xx_mtd->size;
201
202         printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
203
204 #ifdef CONFIG_MTD_PARTITIONS
205         parts = init_mtd_partitions(bcm947xx_mtd, size);
206         for (i = 0; parts[i].name; i++);
207         ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
208         if (ret) {
209                 printk(KERN_ERR "pflash: add_mtd_partitions failed\n");
210                 goto fail;
211         }
212 #endif
213
214         return 0;
215
216  fail:
217         if (bcm947xx_mtd)
218                 map_destroy(bcm947xx_mtd);
219         if (bcm947xx_map.map_priv_1)
220                 iounmap((void *) bcm947xx_map.map_priv_1);
221         bcm947xx_map.map_priv_1 = 0;
222         return ret;
223 }
224
225 mod_exit_t cleanup_bcm947xx_map(void)
226 {
227 #ifdef CONFIG_MTD_PARTITIONS
228         del_mtd_partitions(bcm947xx_mtd);
229 #endif
230         map_destroy(bcm947xx_mtd);
231         iounmap((void *) bcm947xx_map.map_priv_1);
232         bcm947xx_map.map_priv_1 = 0;
233 }
234
235 module_init(init_bcm947xx_map);
236 module_exit(cleanup_bcm947xx_map);