aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps/ocelot.c
blob: 82c3070678c5111b4abb69a212dee60f43046ec1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $
 *
 * Flash on Momenco Ocelot
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>

#define OCELOT_PLD 0x2c000000
#define FLASH_WINDOW_ADDR 0x2fc00000
#define FLASH_WINDOW_SIZE 0x00080000
#define FLASH_BUSWIDTH 1
#define NVRAM_WINDOW_ADDR 0x2c800000
#define NVRAM_WINDOW_SIZE 0x00007FF0
#define NVRAM_BUSWIDTH 1

static unsigned int cacheflush = 0;

static struct mtd_info *flash_mtd;
static struct mtd_info *nvram_mtd;

static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
        struct map_info *map = mtd->priv;
	size_t done = 0;

	/* If we use memcpy, it does word-wide writes. Even though we told the 
	   GT64120A that it's an 8-bit wide region, word-wide writes don't work.
	   We end up just writing the first byte of the four to all four bytes.
	   So we have this loop instead */
	*retlen = len;
	while(len) {
		__raw_writeb(*(unsigned char *) from, map->virt + to);
		from++;
		to++;
		len--;
	}
}

static struct mtd_partition *parsed_parts;

struct map_info ocelot_flash_map = {
	.name = "Ocelot boot flash",
	.size = FLASH_WINDOW_SIZE,
	.bankwidth = FLASH_BUSWIDTH,
	.phys = FLASH_WINDOW_ADDR,
};

struct map_info ocelot_nvram_map = {
	.name = "Ocelot NVRAM",
	.size = NVRAM_WINDOW_SIZE,
	.bankwidth = NVRAM_BUSWIDTH,
	.phys = NVRAM_WINDOW_ADDR,
};

static const char *probes[] = { "RedBoot", NULL };

static int __init init_ocelot_maps(void)
{
	void *pld;
	int nr_parts;
	unsigned char brd_status;

       	printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", 
	       FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);

	/* First check whether the flash jumper is present */
	pld = ioremap(OCELOT_PLD, 0x10);
	if (!pld) {
		printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
		return -EIO;
	}
	brd_status = readb(pld+4);
	iounmap(pld);

	/* Now ioremap the NVRAM space */
	ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
	if (!ocelot_nvram_map.virt) {
		printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
		return -EIO;
	}

	simple_map_init(&ocelot_nvram_map);

	/* And do the RAM probe on it to get an MTD device */
	nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
	if (!nvram_mtd) {
		printk("NVRAM probe failed\n");
		goto fail_1;
	}
	nvram_mtd->owner = THIS_MODULE;
	nvram_mtd->erasesize = 16;
	/* Override the write() method */
	nvram_mtd->write = ocelot_ram_write;

	/* Now map the flash space */
	ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
	if (!ocelot_flash_map.virt) {
		printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
		goto fail_2;
	}
	/* Now the cached version */
	ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);

	simple_map_init(&ocelot_flash_map);

	/* Only probe for flash if the write jumper is present */
	if (brd_status & 0x40) {
		flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
	} else {
		printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
	}
	/* If that failed or the jumper's absent, pretend it's ROM */
	if (!flash_mtd) {
		flash_mtd = do_map_probe("map_rom", &ocelot_flash_map);
		/* If we're treating it as ROM, set the erase size */
		if (flash_mtd)
			flash_mtd->erasesize = 0x10000;
	}
	if (!flash_mtd)
		goto fail3;

	add_mtd_device(nvram_mtd);

	flash_mtd->owner = THIS_MODULE;
	nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);

	if (nr_parts > 0)
		add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
	else
		add_mtd_device(flash_mtd);

	return 0;
	
 fail3:	
	iounmap((void *)ocelot_flash_map.virt);
	if (ocelot_flash_map.cached)
			iounmap((void *)ocelot_flash_map.cached);
 fail_2:
	map_destroy(nvram_mtd);
 fail_1:
	iounmap((void *)ocelot_nvram_map.virt);

	return -ENXIO;
}

static void __exit cleanup_ocelot_maps(void)
{
	del_mtd_device(nvram_mtd);
	map_destroy(nvram_mtd);
	iounmap((void *)ocelot_nvram_map.virt);

	if (parsed_parts)
		del_mtd_partitions(flash_mtd);
	else
		del_mtd_device(flash_mtd);
	map_destroy(flash_mtd);
	iounmap((void *)ocelot_flash_map.virt);
	if (ocelot_flash_map.cached)
		iounmap((void *)ocelot_flash_map.cached);
}

module_init(init_ocelot_maps);
module_exit(cleanup_ocelot_maps);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board");