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