1/*
2 * $Id: nora.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $
3 *
4 * This is so simple I love it.
5 */
6
7#include <linux/module.h>
8#include <linux/types.h>
9#include <linux/kernel.h>
10
11#include <linux/mtd/mtd.h>
12#include <linux/mtd/map.h>
13
14
15#define WINDOW_ADDR 0xd0000000
16#define WINDOW_SIZE 0x04000000
17
18static struct mtd_info *mymtd;
19
20__u8 nora_read8(struct map_info *map, unsigned long ofs)
21{
22  return *(__u8 *)(WINDOW_ADDR + ofs);
23}
24
25__u16 nora_read16(struct map_info *map, unsigned long ofs)
26{
27  return *(__u16 *)(WINDOW_ADDR + ofs);
28}
29
30__u32 nora_read32(struct map_info *map, unsigned long ofs)
31{
32  return *(__u32 *)(WINDOW_ADDR + ofs);
33}
34
35void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
36{
37  memcpy(to, (void *)(WINDOW_ADDR + from), len);
38}
39
40void nora_write8(struct map_info *map, __u8 d, unsigned long adr)
41{
42  *(__u8 *)(WINDOW_ADDR + adr) = d;
43}
44
45void nora_write16(struct map_info *map, __u16 d, unsigned long adr)
46{
47  *(__u16 *)(WINDOW_ADDR + adr) = d;
48}
49
50void nora_write32(struct map_info *map, __u32 d, unsigned long adr)
51{
52  *(__u32 *)(WINDOW_ADDR + adr) = d;
53}
54
55void nora_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
56{
57  memcpy((void *)(WINDOW_ADDR + to), from, len);
58}
59
60struct map_info nora_map = {
61	name: "NORA",
62	size: WINDOW_SIZE,
63	buswidth: 2,
64	read8: nora_read8,
65	read16: nora_read16,
66	read32: nora_read32,
67	copy_from: nora_copy_from,
68	write8: nora_write8,
69	write16: nora_write16,
70	write32: nora_write32,
71	copy_to: nora_copy_to
72};
73
74
75static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
76{
77	return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
78}
79
80static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
81{
82	return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
83}
84
85static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
86{
87	instr->addr += (unsigned long)mtd->priv;
88	return mymtd->erase(mymtd, instr);
89}
90
91static void nora_mtd_sync (struct mtd_info *mtd)
92{
93	mymtd->sync(mymtd);
94}
95
96static int nora_mtd_suspend (struct mtd_info *mtd)
97{
98	return mymtd->suspend(mymtd);
99}
100
101static void nora_mtd_resume (struct mtd_info *mtd)
102{
103	mymtd->resume(mymtd);
104}
105
106
107static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
108	{
109		type: MTD_NORFLASH,
110		flags: MTD_CAP_NORFLASH,
111		size: 0x60000,
112		erasesize: 0x20000,
113		name: "NORA boot firmware",
114		module: THIS_MODULE,
115		erase: nora_mtd_erase,
116		read: nora_mtd_read,
117		write: nora_mtd_write,
118		suspend: nora_mtd_suspend,
119		resume: nora_mtd_resume,
120		sync: nora_mtd_sync,
121		priv: (void *)0
122	},
123	{
124		type: MTD_NORFLASH,
125		flags: MTD_CAP_NORFLASH,
126		size: 0x0a0000,
127		erasesize: 0x20000,
128		name: "NORA kernel",
129		module: THIS_MODULE,
130		erase: nora_mtd_erase,
131		read: nora_mtd_read,
132		write: nora_mtd_write,
133		suspend: nora_mtd_suspend,
134		resume: nora_mtd_resume,
135		sync: nora_mtd_sync,
136		priv: (void *)0x60000
137	},
138	{
139		type: MTD_NORFLASH,
140		flags: MTD_CAP_NORFLASH,
141		size: 0x900000,
142		erasesize: 0x20000,
143		name: "NORA root filesystem",
144		module: THIS_MODULE,
145		erase: nora_mtd_erase,
146		read: nora_mtd_read,
147		write: nora_mtd_write,
148		suspend: nora_mtd_suspend,
149		resume: nora_mtd_resume,
150		sync: nora_mtd_sync,
151		priv: (void *)0x100000
152	},
153	{
154		type: MTD_NORFLASH,
155		flags: MTD_CAP_NORFLASH,
156		size: 0x1600000,
157		erasesize: 0x20000,
158		name: "NORA second filesystem",
159		module: THIS_MODULE,
160		erase: nora_mtd_erase,
161		read: nora_mtd_read,
162		write: nora_mtd_write,
163		suspend: nora_mtd_suspend,
164		resume: nora_mtd_resume,
165		sync: nora_mtd_sync,
166		priv: (void *)0xa00000
167	}
168};
169
170int __init init_nora(void)
171{
172       	printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
173
174	mymtd = do_map_probe("cfi_probe", &nora_map);
175	if (mymtd) {
176		mymtd->module = THIS_MODULE;
177
178		add_mtd_device(&nora_mtds[2]);
179		add_mtd_device(&nora_mtds[0]);
180		add_mtd_device(&nora_mtds[1]);
181		add_mtd_device(&nora_mtds[3]);
182		return 0;
183	}
184
185	return -ENXIO;
186}
187
188static void __exit cleanup_nora(void)
189{
190	if (mymtd) {
191		del_mtd_device(&nora_mtds[3]);
192		del_mtd_device(&nora_mtds[1]);
193		del_mtd_device(&nora_mtds[0]);
194		del_mtd_device(&nora_mtds[2]);
195		map_destroy(mymtd);
196	}
197}
198
199module_init(init_nora);
200module_exit(cleanup_nora);
201
202MODULE_LICENSE("GPL");
203MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
204MODULE_DESCRIPTION("MTD map driver for Nora board");
205