xref: /OK3568_Linux_fs/kernel/drivers/mtd/maps/dc21285.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) 2000  Nicolas Pitre <nico@fluxnic.net>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This code is GPL
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/types.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
16*4882a593Smuzhiyun #include <linux/mtd/map.h>
17*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <asm/io.h>
20*4882a593Smuzhiyun #include <asm/hardware/dec21285.h>
21*4882a593Smuzhiyun #include <asm/mach-types.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static struct mtd_info *dc21285_mtd;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #ifdef CONFIG_ARCH_NETWINDER
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * This is really ugly, but it seams to be the only
29*4882a593Smuzhiyun  * realiable way to do it, as the cpld state machine
30*4882a593Smuzhiyun  * is unpredictible. So we have a 25us penalty per
31*4882a593Smuzhiyun  * write access.
32*4882a593Smuzhiyun  */
nw_en_write(void)33*4882a593Smuzhiyun static void nw_en_write(void)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	unsigned long flags;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	/*
38*4882a593Smuzhiyun 	 * we want to write a bit pattern XXX1 to Xilinx to enable
39*4882a593Smuzhiyun 	 * the write gate, which will be open for about the next 2ms.
40*4882a593Smuzhiyun 	 */
41*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&nw_gpio_lock, flags);
42*4882a593Smuzhiyun 	nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
43*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/*
46*4882a593Smuzhiyun 	 * let the ISA bus to catch on...
47*4882a593Smuzhiyun 	 */
48*4882a593Smuzhiyun 	udelay(25);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun #else
51*4882a593Smuzhiyun #define nw_en_write() do { } while (0)
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun 
dc21285_read8(struct map_info * map,unsigned long ofs)54*4882a593Smuzhiyun static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	map_word val;
57*4882a593Smuzhiyun 	val.x[0] = *(uint8_t*)(map->virt + ofs);
58*4882a593Smuzhiyun 	return val;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
dc21285_read16(struct map_info * map,unsigned long ofs)61*4882a593Smuzhiyun static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	map_word val;
64*4882a593Smuzhiyun 	val.x[0] = *(uint16_t*)(map->virt + ofs);
65*4882a593Smuzhiyun 	return val;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
dc21285_read32(struct map_info * map,unsigned long ofs)68*4882a593Smuzhiyun static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	map_word val;
71*4882a593Smuzhiyun 	val.x[0] = *(uint32_t*)(map->virt + ofs);
72*4882a593Smuzhiyun 	return val;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
dc21285_copy_from(struct map_info * map,void * to,unsigned long from,ssize_t len)75*4882a593Smuzhiyun static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	memcpy(to, (void*)(map->virt + from), len);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
dc21285_write8(struct map_info * map,const map_word d,unsigned long adr)80*4882a593Smuzhiyun static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	if (machine_is_netwinder())
83*4882a593Smuzhiyun 		nw_en_write();
84*4882a593Smuzhiyun 	*CSR_ROMWRITEREG = adr & 3;
85*4882a593Smuzhiyun 	adr &= ~3;
86*4882a593Smuzhiyun 	*(uint8_t*)(map->virt + adr) = d.x[0];
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
dc21285_write16(struct map_info * map,const map_word d,unsigned long adr)89*4882a593Smuzhiyun static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	if (machine_is_netwinder())
92*4882a593Smuzhiyun 		nw_en_write();
93*4882a593Smuzhiyun 	*CSR_ROMWRITEREG = adr & 3;
94*4882a593Smuzhiyun 	adr &= ~3;
95*4882a593Smuzhiyun 	*(uint16_t*)(map->virt + adr) = d.x[0];
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
dc21285_write32(struct map_info * map,const map_word d,unsigned long adr)98*4882a593Smuzhiyun static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	if (machine_is_netwinder())
101*4882a593Smuzhiyun 		nw_en_write();
102*4882a593Smuzhiyun 	*(uint32_t*)(map->virt + adr) = d.x[0];
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
dc21285_copy_to_32(struct map_info * map,unsigned long to,const void * from,ssize_t len)105*4882a593Smuzhiyun static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	while (len > 0) {
108*4882a593Smuzhiyun 		map_word d;
109*4882a593Smuzhiyun 		d.x[0] = *((uint32_t*)from);
110*4882a593Smuzhiyun 		dc21285_write32(map, d, to);
111*4882a593Smuzhiyun 		from += 4;
112*4882a593Smuzhiyun 		to += 4;
113*4882a593Smuzhiyun 		len -= 4;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
dc21285_copy_to_16(struct map_info * map,unsigned long to,const void * from,ssize_t len)117*4882a593Smuzhiyun static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	while (len > 0) {
120*4882a593Smuzhiyun 		map_word d;
121*4882a593Smuzhiyun 		d.x[0] = *((uint16_t*)from);
122*4882a593Smuzhiyun 		dc21285_write16(map, d, to);
123*4882a593Smuzhiyun 		from += 2;
124*4882a593Smuzhiyun 		to += 2;
125*4882a593Smuzhiyun 		len -= 2;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
dc21285_copy_to_8(struct map_info * map,unsigned long to,const void * from,ssize_t len)129*4882a593Smuzhiyun static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	map_word d;
132*4882a593Smuzhiyun 	d.x[0] = *((uint8_t*)from);
133*4882a593Smuzhiyun 	dc21285_write8(map, d, to);
134*4882a593Smuzhiyun 	from++;
135*4882a593Smuzhiyun 	to++;
136*4882a593Smuzhiyun 	len--;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun static struct map_info dc21285_map = {
140*4882a593Smuzhiyun 	.name = "DC21285 flash",
141*4882a593Smuzhiyun 	.phys = NO_XIP,
142*4882a593Smuzhiyun 	.size = 16*1024*1024,
143*4882a593Smuzhiyun 	.copy_from = dc21285_copy_from,
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /* Partition stuff */
147*4882a593Smuzhiyun static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
148*4882a593Smuzhiyun 
init_dc21285(void)149*4882a593Smuzhiyun static int __init init_dc21285(void)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	/* Determine bankwidth */
152*4882a593Smuzhiyun 	switch (*CSR_SA110_CNTL & (3<<14)) {
153*4882a593Smuzhiyun 		case SA110_CNTL_ROMWIDTH_8:
154*4882a593Smuzhiyun 			dc21285_map.bankwidth = 1;
155*4882a593Smuzhiyun 			dc21285_map.read = dc21285_read8;
156*4882a593Smuzhiyun 			dc21285_map.write = dc21285_write8;
157*4882a593Smuzhiyun 			dc21285_map.copy_to = dc21285_copy_to_8;
158*4882a593Smuzhiyun 			break;
159*4882a593Smuzhiyun 		case SA110_CNTL_ROMWIDTH_16:
160*4882a593Smuzhiyun 			dc21285_map.bankwidth = 2;
161*4882a593Smuzhiyun 			dc21285_map.read = dc21285_read16;
162*4882a593Smuzhiyun 			dc21285_map.write = dc21285_write16;
163*4882a593Smuzhiyun 			dc21285_map.copy_to = dc21285_copy_to_16;
164*4882a593Smuzhiyun 			break;
165*4882a593Smuzhiyun 		case SA110_CNTL_ROMWIDTH_32:
166*4882a593Smuzhiyun 			dc21285_map.bankwidth = 4;
167*4882a593Smuzhiyun 			dc21285_map.read = dc21285_read32;
168*4882a593Smuzhiyun 			dc21285_map.write = dc21285_write32;
169*4882a593Smuzhiyun 			dc21285_map.copy_to = dc21285_copy_to_32;
170*4882a593Smuzhiyun 			break;
171*4882a593Smuzhiyun 		default:
172*4882a593Smuzhiyun 			printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
173*4882a593Smuzhiyun 			return -ENXIO;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 	printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
176*4882a593Smuzhiyun 		dc21285_map.bankwidth*8);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/* Let's map the flash area */
179*4882a593Smuzhiyun 	dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024);
180*4882a593Smuzhiyun 	if (!dc21285_map.virt) {
181*4882a593Smuzhiyun 		printk("Failed to ioremap\n");
182*4882a593Smuzhiyun 		return -EIO;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (machine_is_ebsa285()) {
186*4882a593Smuzhiyun 		dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
187*4882a593Smuzhiyun 	} else {
188*4882a593Smuzhiyun 		dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (!dc21285_mtd) {
192*4882a593Smuzhiyun 		iounmap(dc21285_map.virt);
193*4882a593Smuzhiyun 		return -ENXIO;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	dc21285_mtd->owner = THIS_MODULE;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if(machine_is_ebsa285()) {
201*4882a593Smuzhiyun 		/*
202*4882a593Smuzhiyun 		 * Flash timing is determined with bits 19-16 of the
203*4882a593Smuzhiyun 		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
204*4882a593Smuzhiyun 		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
205*4882a593Smuzhiyun 		 * Here we use 7 for 140 ns flash chips.
206*4882a593Smuzhiyun 		 */
207*4882a593Smuzhiyun 		/* access time */
208*4882a593Smuzhiyun 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
209*4882a593Smuzhiyun 		/* burst time */
210*4882a593Smuzhiyun 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
211*4882a593Smuzhiyun 		/* tristate time */
212*4882a593Smuzhiyun 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
cleanup_dc21285(void)218*4882a593Smuzhiyun static void __exit cleanup_dc21285(void)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	mtd_device_unregister(dc21285_mtd);
221*4882a593Smuzhiyun 	map_destroy(dc21285_mtd);
222*4882a593Smuzhiyun 	iounmap(dc21285_map.virt);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun module_init(init_dc21285);
226*4882a593Smuzhiyun module_exit(cleanup_dc21285);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun MODULE_LICENSE("GPL");
230*4882a593Smuzhiyun MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
231*4882a593Smuzhiyun MODULE_DESCRIPTION("MTD map driver for DC21285 boards");
232