1/*
2 * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
3 *
4 * (C) 2000  Nicolas Pitre <nico@cam.org>
5 *
6 * This code is GPL
7 *
8 * $Id: dc21285.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $
9 */
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14
15#include <linux/mtd/mtd.h>
16#include <linux/mtd/map.h>
17#include <linux/mtd/partitions.h>
18
19#include <asm/io.h>
20#include <asm/hardware/dec21285.h>
21
22
23static struct mtd_info *mymtd;
24
25__u8 dc21285_read8(struct map_info *map, unsigned long ofs)
26{
27	return *(__u8*)(map->map_priv_1 + ofs);
28}
29
30__u16 dc21285_read16(struct map_info *map, unsigned long ofs)
31{
32	return *(__u16*)(map->map_priv_1 + ofs);
33}
34
35__u32 dc21285_read32(struct map_info *map, unsigned long ofs)
36{
37	return *(__u32*)(map->map_priv_1 + ofs);
38}
39
40void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
41{
42	memcpy(to, (void*)(map->map_priv_1 + from), len);
43}
44
45void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
46{
47	*CSR_ROMWRITEREG = adr & 3;
48	adr &= ~3;
49	*(__u8*)(map->map_priv_1 + adr) = d;
50}
51
52void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
53{
54	*CSR_ROMWRITEREG = adr & 3;
55	adr &= ~3;
56	*(__u16*)(map->map_priv_1 + adr) = d;
57}
58
59void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
60{
61	*(__u32*)(map->map_priv_1 + adr) = d;
62}
63
64void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
65{
66	switch (map->buswidth) {
67		case 4:
68			while (len > 0) {
69				__u32 d = *((__u32*)from)++;
70				dc21285_write32(map, d, to);
71				to += 4;
72				len -= 4;
73			}
74			break;
75		case 2:
76			while (len > 0) {
77				__u16 d = *((__u16*)from)++;
78				dc21285_write16(map, d, to);
79				to += 2;
80				len -= 2;
81			}
82			break;
83		case 1:
84			while (len > 0) {
85				__u8 d = *((__u8*)from)++;
86				dc21285_write8(map, d, to);
87				to++;
88				len--;
89			}
90			break;
91	}
92}
93
94struct map_info dc21285_map = {
95	name: "DC21285 flash",
96	size: 16*1024*1024,
97	read8: dc21285_read8,
98	read16: dc21285_read16,
99	read32: dc21285_read32,
100	copy_from: dc21285_copy_from,
101	write8: dc21285_write8,
102	write16: dc21285_write16,
103	write32: dc21285_write32,
104	copy_to: dc21285_copy_to
105};
106
107
108/* Partition stuff */
109static struct mtd_partition *dc21285_parts;
110
111extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
112
113int __init init_dc21285(void)
114{
115	/* Determine buswidth */
116	switch (*CSR_SA110_CNTL & (3<<14)) {
117		case SA110_CNTL_ROMWIDTH_8:
118			dc21285_map.buswidth = 1;
119			break;
120		case SA110_CNTL_ROMWIDTH_16:
121			dc21285_map.buswidth = 2;
122			break;
123		case SA110_CNTL_ROMWIDTH_32:
124			dc21285_map.buswidth = 4;
125			break;
126		default:
127			printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
128			return -ENXIO;
129	}
130	printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
131		dc21285_map.buswidth*8);
132
133	/* Let's map the flash area */
134	dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
135	if (!dc21285_map.map_priv_1) {
136		printk("Failed to ioremap\n");
137		return -EIO;
138	}
139
140	mymtd = do_map_probe("cfi_probe", &dc21285_map);
141	if (mymtd) {
142		int nrparts;
143
144		mymtd->module = THIS_MODULE;
145
146		/* partition fixup */
147
148		nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
149		if (nrparts <=0) {
150			printk(KERN_NOTICE "RedBoot partition table failed\n");
151			iounmap((void *)dc21285_map.map_priv_1);
152			return -ENXIO;
153		}
154
155		add_mtd_partitions(mymtd, dc21285_parts, nrparts);
156
157		/*
158		 * Flash timing is determined with bits 19-16 of the
159		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
160		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
161		 * Here we use 7 for 140 ns flash chips.
162		 */
163		/* access time */
164		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
165		/* burst time */
166		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
167		/* tristate time */
168		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
169
170		return 0;
171	}
172
173	iounmap((void *)dc21285_map.map_priv_1);
174	return -ENXIO;
175}
176
177static void __exit cleanup_dc21285(void)
178{
179	if (mymtd) {
180		del_mtd_device(mymtd);
181		map_destroy(mymtd);
182		mymtd = NULL;
183	}
184	if (dc21285_map.map_priv_1) {
185		iounmap((void *)dc21285_map.map_priv_1);
186		dc21285_map.map_priv_1 = 0;
187	}
188	if(dc21285_parts)
189		kfree(dc21285_parts);
190}
191
192module_init(init_dc21285);
193module_exit(cleanup_dc21285);
194
195
196MODULE_LICENSE("GPL");
197MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
198MODULE_DESCRIPTION("MTD map driver for DC21285 boards");
199