File: /usr/src/linux/drivers/mtd/maps/sun_uflash.c
1 /* $Id: sun_uflash.c,v 1.2 2001/04/26 15:40:23 dwmw2 Exp $
2 *
3 * sun_uflash - Driver implementation for user-programmable flash
4 * present on many Sun Microsystems SME boardsets.
5 *
6 * This driver does NOT provide access to the OBP-flash for
7 * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
8 *
9 * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
10 *
11 */
12
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/version.h>
16 #include <linux/fs.h>
17 #include <linux/errno.h>
18 #include <linux/init.h>
19 #include <linux/ioport.h>
20 #include <asm/ebus.h>
21 #include <asm/oplib.h>
22 #include <asm/uaccess.h>
23 #include <asm/io.h>
24
25 #include <linux/mtd/mtd.h>
26 #include <linux/mtd/map.h>
27
28 #define UFLASH_OBPNAME "flashprom"
29 #define UFLASH_DEVNAME "userflash"
30
31 #define UFLASH_WINDOW_SIZE 0x200000
32 #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */
33
34 MODULE_AUTHOR
35 ("Eric Brower <ebrower@usa.net>");
36 MODULE_DESCRIPTION
37 ("User-programmable flash device on Sun Microsystems boardsets");
38 MODULE_SUPPORTED_DEVICE
39 ("userflash");
40
41 static LIST_HEAD(device_list);
42 struct uflash_dev {
43 char * name; /* device name */
44 struct map_info map; /* mtd map info */
45 struct mtd_info * mtd; /* mtd info */
46 struct list_head list;
47 };
48
49 __u8 uflash_read8(struct map_info *map, unsigned long ofs)
50 {
51 return(__raw_readb(map->map_priv_1 + ofs));
52 }
53
54 __u16 uflash_read16(struct map_info *map, unsigned long ofs)
55 {
56 return(__raw_readw(map->map_priv_1 + ofs));
57 }
58
59 __u32 uflash_read32(struct map_info *map, unsigned long ofs)
60 {
61 return(__raw_readl(map->map_priv_1 + ofs));
62 }
63
64 void uflash_copy_from(struct map_info *map, void *to, unsigned long from,
65 ssize_t len)
66 {
67 memcpy_fromio(to, map->map_priv_1 + from, len);
68 }
69
70 void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
71 {
72 __raw_writeb(d, map->map_priv_1 + adr);
73 }
74
75 void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
76 {
77 __raw_writew(d, map->map_priv_1 + adr);
78 }
79
80 void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
81 {
82 __raw_writel(d, map->map_priv_1 + adr);
83 }
84
85 void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
86 ssize_t len)
87 {
88 memcpy_toio(map->map_priv_1 + to, from, len);
89 }
90
91 struct map_info uflash_map_templ = {
92 name: "SUNW,???-????",
93 size: UFLASH_WINDOW_SIZE,
94 buswidth: UFLASH_BUSWIDTH,
95 read8: uflash_read8,
96 read16: uflash_read16,
97 read32: uflash_read32,
98 copy_from: uflash_copy_from,
99 write8: uflash_write8,
100 write16: uflash_write16,
101 write32: uflash_write32,
102 copy_to: uflash_copy_to
103 };
104
105 int uflash_devinit(struct linux_ebus_device* edev)
106 {
107 int iTmp, nregs;
108 struct linux_prom_registers regs[2];
109 struct uflash_dev *pdev;
110
111 iTmp = prom_getproperty(
112 edev->prom_node, "reg", (void *)regs, sizeof(regs));
113 if ((iTmp % sizeof(regs[0])) != 0) {
114 printk("%s: Strange reg property size %d\n",
115 UFLASH_DEVNAME, iTmp);
116 return -ENODEV;
117 }
118
119 nregs = iTmp / sizeof(regs[0]);
120
121 if (nregs != 1) {
122 /* Non-CFI userflash device-- once I find one we
123 * can work on supporting it.
124 */
125 printk("%s: unsupported device at 0x%lx (%d regs): "
126 "email ebrower@usa.net\n",
127 UFLASH_DEVNAME, edev->resource[0].start, nregs);
128 return -ENODEV;
129 }
130
131 if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
132 printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
133 return(-ENOMEM);
134 }
135
136 /* copy defaults and tweak parameters */
137 memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
138 pdev->map.size = regs[0].reg_size;
139
140 iTmp = prom_getproplen(edev->prom_node, "model");
141 pdev->name = kmalloc(iTmp, GFP_KERNEL);
142 prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
143 if(0 != pdev->name && 0 < strlen(pdev->name)) {
144 pdev->map.name = pdev->name;
145 }
146
147 pdev->map.map_priv_1 =
148 (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
149 if(0 == pdev->map.map_priv_1) {
150 printk("%s: failed to map device\n", __FUNCTION__);
151 kfree(pdev->name);
152 kfree(pdev);
153 return(-1);
154 }
155
156 /* MTD registration */
157 pdev->mtd = do_map_probe("cfi", &pdev->map);
158 if(0 == pdev->mtd) {
159 iounmap((void *)pdev->map.map_priv_1);
160 kfree(pdev->name);
161 kfree(pdev);
162 return(-ENXIO);
163 }
164
165 list_add(&pdev->list, &device_list);
166
167 pdev->mtd->module = THIS_MODULE;
168
169 add_mtd_device(pdev->mtd);
170 return(0);
171 }
172
173 static int __init uflash_init(void)
174 {
175 struct linux_ebus *ebus = NULL;
176 struct linux_ebus_device *edev = NULL;
177
178 for_each_ebus(ebus) {
179 for_each_ebusdev(edev, ebus) {
180 if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
181 if(0 > prom_getproplen(edev->prom_node, "user")) {
182 DEBUG(2, "%s: ignoring device at 0x%lx\n",
183 UFLASH_DEVNAME, edev->resource[0].start);
184 } else {
185 uflash_devinit(edev);
186 }
187 }
188 }
189 }
190
191 if(list_empty(&device_list)) {
192 printk("%s: unable to locate device\n", UFLASH_DEVNAME);
193 return -ENODEV;
194 }
195 return(0);
196 }
197
198 static void __exit uflash_cleanup(void)
199 {
200 struct list_head *udevlist;
201 struct uflash_dev *udev;
202
203 list_for_each(udevlist, &device_list) {
204 udev = list_entry(udevlist, struct uflash_dev, list);
205 DEBUG(2, "%s: removing device %s\n",
206 UFLASH_DEVNAME, udev->name);
207
208 if(0 != udev->mtd) {
209 del_mtd_device(udev->mtd);
210 map_destroy(udev->mtd);
211 }
212 if(0 != udev->map.map_priv_1) {
213 iounmap((void*)udev->map.map_priv_1);
214 udev->map.map_priv_1 = 0;
215 }
216 if(0 != udev->name) {
217 kfree(udev->name);
218 }
219 kfree(udev);
220 }
221 }
222
223 module_init(uflash_init);
224 module_exit(uflash_cleanup);
225