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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
/*
* $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
*
* Flash on Momenco Ocelot
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.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
extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
static unsigned int cacheflush = 0;
static struct mtd_info *flash_mtd;
static struct mtd_info *nvram_mtd;
__u8 ocelot_read8(struct map_info *map, unsigned long ofs)
{
return __raw_readb(map->map_priv_1 + ofs);
}
void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr)
{
cacheflush = 1;
__raw_writeb(d, map->map_priv_1 + adr);
mb();
}
void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
if (cacheflush) {
dma_cache_inv(map->map_priv_2, map->size);
cacheflush = 0;
}
memcpy_fromio(to, map->map_priv_1 + from, len);
}
void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
memcpy_fromio(to, map->map_priv_1 + from, len);
}
void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
/* 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 */
while(len) {
__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
from++;
to++;
len--;
}
}
static struct mtd_partition *parsed_parts;
struct map_info ocelot_flash_map = {
name: "Ocelot boot flash",
size: FLASH_WINDOW_SIZE,
buswidth: FLASH_BUSWIDTH,
read8: ocelot_read8,
copy_from: ocelot_copy_from_cache,
write8: ocelot_write8,
};
struct map_info ocelot_nvram_map = {
name: "Ocelot NVRAM",
size: NVRAM_WINDOW_SIZE,
buswidth: NVRAM_BUSWIDTH,
read8: ocelot_read8,
copy_from: ocelot_copy_from,
write8: ocelot_write8,
copy_to: ocelot_copy_to
};
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.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
if (!ocelot_nvram_map.map_priv_1) {
printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
return -EIO;
}
// ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
/* 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->module = THIS_MODULE;
nvram_mtd->erasesize = 16;
/* Now map the flash space */
ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
if (!ocelot_flash_map.map_priv_1) {
printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
goto fail_2;
}
/* Now the cached version */
ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
if (!ocelot_flash_map.map_priv_2) {
/* Doesn't matter if it failed. Just use the uncached version */
ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1;
}
/* 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->module = THIS_MODULE;
nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
if (nr_parts)
add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
else
add_mtd_device(flash_mtd);
return 0;
fail3:
iounmap((void *)ocelot_flash_map.map_priv_1);
if (ocelot_flash_map.map_priv_2 &&
ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
iounmap((void *)ocelot_flash_map.map_priv_2);
fail_2:
map_destroy(nvram_mtd);
fail_1:
iounmap((void *)ocelot_nvram_map.map_priv_1);
return -ENXIO;
}
static void __exit cleanup_ocelot_maps(void)
{
del_mtd_device(nvram_mtd);
map_destroy(nvram_mtd);
iounmap((void *)ocelot_nvram_map.map_priv_1);
if (parsed_parts)
del_mtd_partitions(flash_mtd);
else
del_mtd_device(flash_mtd);
map_destroy(flash_mtd);
iounmap((void *)ocelot_flash_map.map_priv_1);
if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
iounmap((void *)ocelot_flash_map.map_priv_2);
}
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");
|