11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ######################################################################
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
369f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner   Octagon 5066 MTD Driver.
469f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   is replacable by flash. Both units are mapped through a multiplexer
869f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner   into a 32k memory window at 0xe8000. The control register for the
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   multiplexing unit is located at IO 0x208 with a bit map of
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     0-5 Page Selection in 32k increments
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     6-7 Device selection:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        00 SSD off
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        01 SSD 0 (Socket)
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        10 SSD 1 (Flash chip)
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        11 undefined
1669f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   On each SSD, the first 128k is reserved for use by the bios
1869f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner   (actually it IS the bios..) This only matters if you are booting off the
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   flash, you must not put a file system starting there.
2069f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The driver tries to do a detection algorithm to guess what sort of devices
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   are plugged into the sockets.
2369f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ##################################################################### */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/map.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINDOW_START 0xe8000
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINDOW_LENGTH 0x8000
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINDOW_SHIFT 27
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINDOW_MASK 0x7FFF
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PAGE_IO 0x208
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic volatile char page_n_dev = 0;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long iomapadr;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(oct5066_spin);
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We use map_priv_1 to identify which device we are.
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __oct5066_page(struct map_info *map, __u8 byte)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(byte,PAGE_IO);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	page_n_dev = byte;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void oct5066_page(struct map_info *map, unsigned long ofs)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
5769f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (page_n_dev != byte)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__oct5066_page(map, byte);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic map_word oct5066_read8(struct map_info *map, unsigned long ofs)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map_word ret;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&oct5066_spin);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oct5066_page(map, ofs);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&oct5066_spin);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(len) {
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long thislen = len;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
7969f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock(&oct5066_spin);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		oct5066_page(map, from);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy_fromio(to, iomapadr + from, thislen);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&oct5066_spin);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to += thislen;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += thislen;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len -= thislen;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&oct5066_spin);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oct5066_page(map, adr);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&oct5066_spin);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(len) {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long thislen = len;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
10469f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock(&oct5066_spin);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		oct5066_page(map, to);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy_toio(iomapadr + to, from, thislen);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&oct5066_spin);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to += thislen;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += thislen;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len -= thislen;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct map_info oct5066_map[2] = {
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Octagon 5066 Socket",
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.phys = NO_XIP,
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.size = 512 * 1024,
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.bankwidth = 1,
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.read = oct5066_read8,
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.copy_from = oct5066_copy_from,
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.write = oct5066_write8,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.copy_to = oct5066_copy_to,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.map_priv_1 = 1<<6
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Octagon 5066 Internal Flash",
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.phys = NO_XIP,
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.size = 2 * 1024 * 1024,
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.bankwidth = 1,
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.read = oct5066_read8,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.copy_from = oct5066_copy_from,
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.write = oct5066_write8,
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.copy_to = oct5066_copy_to,
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.map_priv_1 = 2<<6
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// OctProbe - Sense if this is an octagon card
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// ---------------------------------------------------------------------
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Perform a simple validity test, we map the window select SSD0 and
14569f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner   change pages while monitoring the window. A change in the window,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   controlled by the PAGE_IO port is a functioning 5066 board. This will
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   fail if the thing in the socket is set to a uniform value. */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init OctProbe(void)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   unsigned int Base = (1 << 6);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   unsigned long I;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   unsigned long Values[10];
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   for (I = 0; I != 20; I++)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   {
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      outb(Base + (I%10),PAGE_IO);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if (I < 10)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      {
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 // Record the value and check for uniqueness
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 Values[I%10] = readl(iomapadr);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 if (I > 0 && Values[I%10] == Values[0])
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    return -EAGAIN;
16269f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner      }
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      else
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 // Make sure we get the same values on the second pass
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 if (Values[I%10] != readl(iomapadr))
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    return -EAGAIN;
16869f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner      }
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   }
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   return 0;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cleanup_oct5066(void)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<2; i++) {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (oct5066_mtd[i]) {
178ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles			mtd_device_unregister(oct5066_mtd[i]);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			map_destroy(oct5066_mtd[i]);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap((void *)iomapadr);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(PAGE_IO, 1);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
186d849257c428bf9f06f25fa3dea14cd1e7650948dDmitri Vorobievstatic int __init init_oct5066(void)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Do an autoprobe sequence
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_region(PAGE_IO,1,"Octagon SSD")) {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "5066: Page Register in Use\n");
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!iomapadr) {
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "Failed to ioremap memory region\n");
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EIO;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_rel;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (OctProbe() != 0) {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap((void *)iomapadr);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EAGAIN;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_unmap;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20869f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Print out our little header..
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       WINDOW_START+WINDOW_LENGTH);
21269f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<2; i++) {
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!oct5066_mtd[i])
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!oct5066_mtd[i])
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!oct5066_mtd[i])
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (oct5066_mtd[i]) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oct5066_mtd[i]->owner = THIS_MODULE;
223ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles			mtd_device_register(oct5066_mtd[i], NULL, 0);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22669f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cleanup_oct5066();
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
23069f34c98c1416eb74c55e38a21dbf3e294966514Thomas Gleixner	}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_unmap:
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap((void *)iomapadr);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_rel:
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(PAGE_IO, 1);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_oct5066);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_oct5066);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");
247