xref: /openbmc/linux/drivers/mtd/maps/dc21285.c (revision e5babdf9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
31da177e4SLinus Torvalds  *
42f82af08SNicolas Pitre  * (C) 2000  Nicolas Pitre <nico@fluxnic.net>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This code is GPL
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/init.h>
121da177e4SLinus Torvalds #include <linux/delay.h>
134e57b681STim Schmielau #include <linux/slab.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
161da177e4SLinus Torvalds #include <linux/mtd/map.h>
171da177e4SLinus Torvalds #include <linux/mtd/partitions.h>
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <asm/io.h>
201da177e4SLinus Torvalds #include <asm/hardware/dec21285.h>
211da177e4SLinus Torvalds #include <asm/mach-types.h>
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds static struct mtd_info *dc21285_mtd;
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #ifdef CONFIG_ARCH_NETWINDER
271da177e4SLinus Torvalds /*
281da177e4SLinus Torvalds  * This is really ugly, but it seams to be the only
291da177e4SLinus Torvalds  * realiable way to do it, as the cpld state machine
301da177e4SLinus Torvalds  * is unpredictible. So we have a 25us penalty per
311da177e4SLinus Torvalds  * write access.
321da177e4SLinus Torvalds  */
nw_en_write(void)331da177e4SLinus Torvalds static void nw_en_write(void)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds 	unsigned long flags;
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	/*
381da177e4SLinus Torvalds 	 * we want to write a bit pattern XXX1 to Xilinx to enable
391da177e4SLinus Torvalds 	 * the write gate, which will be open for about the next 2ms.
401da177e4SLinus Torvalds 	 */
41e5babdf9SUwe Kleine-König 	raw_spin_lock_irqsave(&nw_gpio_lock, flags);
4270d13e08SRussell King 	nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
43e5babdf9SUwe Kleine-König 	raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	/*
461da177e4SLinus Torvalds 	 * let the ISA bus to catch on...
471da177e4SLinus Torvalds 	 */
481da177e4SLinus Torvalds 	udelay(25);
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds #else
511da177e4SLinus Torvalds #define nw_en_write() do { } while (0)
521da177e4SLinus Torvalds #endif
531da177e4SLinus Torvalds 
dc21285_read8(struct map_info * map,unsigned long ofs)541da177e4SLinus Torvalds static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds 	map_word val;
571da177e4SLinus Torvalds 	val.x[0] = *(uint8_t*)(map->virt + ofs);
581da177e4SLinus Torvalds 	return val;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
dc21285_read16(struct map_info * map,unsigned long ofs)611da177e4SLinus Torvalds static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	map_word val;
641da177e4SLinus Torvalds 	val.x[0] = *(uint16_t*)(map->virt + ofs);
651da177e4SLinus Torvalds 	return val;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
dc21285_read32(struct map_info * map,unsigned long ofs)681da177e4SLinus Torvalds static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	map_word val;
711da177e4SLinus Torvalds 	val.x[0] = *(uint32_t*)(map->virt + ofs);
721da177e4SLinus Torvalds 	return val;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
dc21285_copy_from(struct map_info * map,void * to,unsigned long from,ssize_t len)751da177e4SLinus Torvalds static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
761da177e4SLinus Torvalds {
771da177e4SLinus Torvalds 	memcpy(to, (void*)(map->virt + from), len);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
dc21285_write8(struct map_info * map,const map_word d,unsigned long adr)801da177e4SLinus Torvalds static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	if (machine_is_netwinder())
831da177e4SLinus Torvalds 		nw_en_write();
841da177e4SLinus Torvalds 	*CSR_ROMWRITEREG = adr & 3;
851da177e4SLinus Torvalds 	adr &= ~3;
861da177e4SLinus Torvalds 	*(uint8_t*)(map->virt + adr) = d.x[0];
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
dc21285_write16(struct map_info * map,const map_word d,unsigned long adr)891da177e4SLinus Torvalds static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	if (machine_is_netwinder())
921da177e4SLinus Torvalds 		nw_en_write();
931da177e4SLinus Torvalds 	*CSR_ROMWRITEREG = adr & 3;
941da177e4SLinus Torvalds 	adr &= ~3;
951da177e4SLinus Torvalds 	*(uint16_t*)(map->virt + adr) = d.x[0];
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
dc21285_write32(struct map_info * map,const map_word d,unsigned long adr)981da177e4SLinus Torvalds static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	if (machine_is_netwinder())
1011da177e4SLinus Torvalds 		nw_en_write();
1021da177e4SLinus Torvalds 	*(uint32_t*)(map->virt + adr) = d.x[0];
1031da177e4SLinus Torvalds }
1041da177e4SLinus Torvalds 
dc21285_copy_to_32(struct map_info * map,unsigned long to,const void * from,ssize_t len)1051da177e4SLinus Torvalds static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds 	while (len > 0) {
1081da177e4SLinus Torvalds 		map_word d;
10975b84e94SMartin Michlmayr 		d.x[0] = *((uint32_t*)from);
1101da177e4SLinus Torvalds 		dc21285_write32(map, d, to);
11175b84e94SMartin Michlmayr 		from += 4;
1121da177e4SLinus Torvalds 		to += 4;
1131da177e4SLinus Torvalds 		len -= 4;
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
dc21285_copy_to_16(struct map_info * map,unsigned long to,const void * from,ssize_t len)1171da177e4SLinus Torvalds static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	while (len > 0) {
1201da177e4SLinus Torvalds 		map_word d;
12175b84e94SMartin Michlmayr 		d.x[0] = *((uint16_t*)from);
1221da177e4SLinus Torvalds 		dc21285_write16(map, d, to);
12375b84e94SMartin Michlmayr 		from += 2;
1241da177e4SLinus Torvalds 		to += 2;
1251da177e4SLinus Torvalds 		len -= 2;
1261da177e4SLinus Torvalds 	}
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds 
dc21285_copy_to_8(struct map_info * map,unsigned long to,const void * from,ssize_t len)1291da177e4SLinus Torvalds static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 	map_word d;
13275b84e94SMartin Michlmayr 	d.x[0] = *((uint8_t*)from);
1331da177e4SLinus Torvalds 	dc21285_write8(map, d, to);
13475b84e94SMartin Michlmayr 	from++;
1351da177e4SLinus Torvalds 	to++;
1361da177e4SLinus Torvalds 	len--;
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds static struct map_info dc21285_map = {
1401da177e4SLinus Torvalds 	.name = "DC21285 flash",
1411da177e4SLinus Torvalds 	.phys = NO_XIP,
1421da177e4SLinus Torvalds 	.size = 16*1024*1024,
1431da177e4SLinus Torvalds 	.copy_from = dc21285_copy_from,
1441da177e4SLinus Torvalds };
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* Partition stuff */
1470984c891SArtem Bityutskiy static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
1481da177e4SLinus Torvalds 
init_dc21285(void)1491da177e4SLinus Torvalds static int __init init_dc21285(void)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	/* Determine bankwidth */
1521da177e4SLinus Torvalds 	switch (*CSR_SA110_CNTL & (3<<14)) {
1531da177e4SLinus Torvalds 		case SA110_CNTL_ROMWIDTH_8:
1541da177e4SLinus Torvalds 			dc21285_map.bankwidth = 1;
1551da177e4SLinus Torvalds 			dc21285_map.read = dc21285_read8;
1561da177e4SLinus Torvalds 			dc21285_map.write = dc21285_write8;
1571da177e4SLinus Torvalds 			dc21285_map.copy_to = dc21285_copy_to_8;
1581da177e4SLinus Torvalds 			break;
1591da177e4SLinus Torvalds 		case SA110_CNTL_ROMWIDTH_16:
1601da177e4SLinus Torvalds 			dc21285_map.bankwidth = 2;
1611da177e4SLinus Torvalds 			dc21285_map.read = dc21285_read16;
1621da177e4SLinus Torvalds 			dc21285_map.write = dc21285_write16;
1631da177e4SLinus Torvalds 			dc21285_map.copy_to = dc21285_copy_to_16;
1641da177e4SLinus Torvalds 			break;
1651da177e4SLinus Torvalds 		case SA110_CNTL_ROMWIDTH_32:
1661da177e4SLinus Torvalds 			dc21285_map.bankwidth = 4;
1671da177e4SLinus Torvalds 			dc21285_map.read = dc21285_read32;
1681da177e4SLinus Torvalds 			dc21285_map.write = dc21285_write32;
1691da177e4SLinus Torvalds 			dc21285_map.copy_to = dc21285_copy_to_32;
1701da177e4SLinus Torvalds 			break;
1711da177e4SLinus Torvalds 		default:
1721da177e4SLinus Torvalds 			printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
1731da177e4SLinus Torvalds 			return -ENXIO;
1741da177e4SLinus Torvalds 	}
1751da177e4SLinus Torvalds 	printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
1761da177e4SLinus Torvalds 		dc21285_map.bankwidth*8);
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	/* Let's map the flash area */
1791da177e4SLinus Torvalds 	dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024);
1801da177e4SLinus Torvalds 	if (!dc21285_map.virt) {
1811da177e4SLinus Torvalds 		printk("Failed to ioremap\n");
1821da177e4SLinus Torvalds 		return -EIO;
1831da177e4SLinus Torvalds 	}
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	if (machine_is_ebsa285()) {
1861da177e4SLinus Torvalds 		dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
1871da177e4SLinus Torvalds 	} else {
1881da177e4SLinus Torvalds 		dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	if (!dc21285_mtd) {
1921da177e4SLinus Torvalds 		iounmap(dc21285_map.virt);
1931da177e4SLinus Torvalds 		return -ENXIO;
1941da177e4SLinus Torvalds 	}
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	dc21285_mtd->owner = THIS_MODULE;
1971da177e4SLinus Torvalds 
19842d7fbe2SArtem Bityutskiy 	mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	if(machine_is_ebsa285()) {
2011da177e4SLinus Torvalds 		/*
2021da177e4SLinus Torvalds 		 * Flash timing is determined with bits 19-16 of the
2031da177e4SLinus Torvalds 		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
2041da177e4SLinus Torvalds 		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
2051da177e4SLinus Torvalds 		 * Here we use 7 for 140 ns flash chips.
2061da177e4SLinus Torvalds 		 */
2071da177e4SLinus Torvalds 		/* access time */
2081da177e4SLinus Torvalds 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
2091da177e4SLinus Torvalds 		/* burst time */
2101da177e4SLinus Torvalds 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
2111da177e4SLinus Torvalds 		/* tristate time */
2121da177e4SLinus Torvalds 		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	return 0;
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds 
cleanup_dc21285(void)2181da177e4SLinus Torvalds static void __exit cleanup_dc21285(void)
2191da177e4SLinus Torvalds {
220bc2ffddcSJamie Iles 	mtd_device_unregister(dc21285_mtd);
2211da177e4SLinus Torvalds 	map_destroy(dc21285_mtd);
2221da177e4SLinus Torvalds 	iounmap(dc21285_map.virt);
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds module_init(init_dc21285);
2261da177e4SLinus Torvalds module_exit(cleanup_dc21285);
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
2302f82af08SNicolas Pitre MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
2311da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD map driver for DC21285 boards");
232