/*
* MTD map driver for flash on the DC21285 ( the StrongARM - 110 companion chip )
*
* ( C ) 2000 Nicolas Pitre < nico @ fluxnic . net >
*
* This code is GPL
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm /io.h>
#include <asm /hardware/dec21285.h>
#include <asm /mach-types.h>
static struct mtd_info *dc21285_mtd;
#ifdef CONFIG_ARCH_NETWINDER
/*
* This is really ugly , but it seams to be the only
* realiable way to do it , as the cpld state machine
* is unpredictible . So we have a 25 us penalty per
* write access .
*/
static void nw_en_write(void )
{
unsigned long flags;
/*
* we want to write a bit pattern XXX1 to Xilinx to enable
* the write gate , which will be open for about the next 2 ms .
*/
raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
/*
* let the ISA bus to catch on . . .
*/
udelay(25 );
}
#else
#define nw_en_write() do { } while (0 )
#endif
static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
{
map_word val;
val.x[0 ] = *(uint8_t*)(map->virt + ofs);
return val;
}
static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
{
map_word val;
val.x[0 ] = *(uint16_t*)(map->virt + ofs);
return val;
}
static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
{
map_word val;
val.x[0 ] = *(uint32_t*)(map->virt + ofs);
return val;
}
static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
memcpy(to, (void *)(map->virt + from), len);
}
static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
{
if (machine_is_netwinder())
nw_en_write();
*CSR_ROMWRITEREG = adr & 3 ;
adr &= ~3 ;
*(uint8_t*)(map->virt + adr) = d.x[0 ];
}
static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
{
if (machine_is_netwinder())
nw_en_write();
*CSR_ROMWRITEREG = adr & 3 ;
adr &= ~3 ;
*(uint16_t*)(map->virt + adr) = d.x[0 ];
}
static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
{
if (machine_is_netwinder())
nw_en_write();
*(uint32_t*)(map->virt + adr) = d.x[0 ];
}
static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
while (len > 0 ) {
map_word d;
d.x[0 ] = *((uint32_t*)from);
dc21285_write32(map, d, to);
from += 4 ;
to += 4 ;
len -= 4 ;
}
}
static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
while (len > 0 ) {
map_word d;
d.x[0 ] = *((uint16_t*)from);
dc21285_write16(map, d, to);
from += 2 ;
to += 2 ;
len -= 2 ;
}
}
static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
map_word d;
d.x[0 ] = *((uint8_t*)from);
dc21285_write8(map, d, to);
from++;
to++;
len--;
}
static struct map_info dc21285_map = {
.name = "DC21285 flash" ,
.phys = NO_XIP,
.size = 16 *1024 *1024 ,
.copy_from = dc21285_copy_from,
};
/* Partition stuff */
static const char * const probes[] = { "RedBoot" , "cmdlinepart" , NULL };
static int __init init_dc21285(void )
{
/* Determine bankwidth */
switch (*CSR_SA110_CNTL & (3 <<14 )) {
case SA110_CNTL_ROMWIDTH_8:
dc21285_map.bankwidth = 1 ;
dc21285_map.read = dc21285_read8;
dc21285_map.write = dc21285_write8;
dc21285_map.copy_to = dc21285_copy_to_8;
break ;
case SA110_CNTL_ROMWIDTH_16:
dc21285_map.bankwidth = 2 ;
dc21285_map.read = dc21285_read16;
dc21285_map.write = dc21285_write16;
dc21285_map.copy_to = dc21285_copy_to_16;
break ;
case SA110_CNTL_ROMWIDTH_32:
dc21285_map.bankwidth = 4 ;
dc21285_map.read = dc21285_read32;
dc21285_map.write = dc21285_write32;
dc21285_map.copy_to = dc21285_copy_to_32;
break ;
default :
printk (KERN_ERR "DC21285 flash: undefined bankwidth\n" );
return -ENXIO;
}
printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n" ,
dc21285_map.bankwidth*8 );
/* Let's map the flash area */
dc21285_map.virt = ioremap(DC21285_FLASH, 16 *1024 *1024 );
if (!dc21285_map.virt) {
printk("Failed to ioremap\n" );
return -EIO;
}
if (machine_is_ebsa285()) {
dc21285_mtd = do_map_probe("cfi_probe" , &dc21285_map);
} else {
dc21285_mtd = do_map_probe("jedec_probe" , &dc21285_map);
}
if (!dc21285_mtd) {
iounmap(dc21285_map.virt);
return -ENXIO;
}
dc21285_mtd->owner = THIS_MODULE;
mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0 );
if (machine_is_ebsa285()) {
/*
* Flash timing is determined with bits 19 - 16 of the
* CSR_SA110_CNTL . The value is the number of wait cycles , or
* 0 for 16 cycles ( the default ) . Cycles are 20 ns .
* Here we use 7 for 140 ns flash chips .
*/
/* access time */
*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0 x000f0000) | (7 << 16 ));
/* burst time */
*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0 x00f00000) | (7 << 20 ));
/* tristate time */
*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0 x0f000000) | (7 << 24 ));
}
return 0 ;
}
static void __exit cleanup_dc21285(void )
{
mtd_device_unregister(dc21285_mtd);
map_destroy(dc21285_mtd);
iounmap(dc21285_map.virt);
}
module_init(init_dc21285);
module_exit(cleanup_dc21285);
MODULE_LICENSE("GPL" );
MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>" );
MODULE_DESCRIPTION("MTD map driver for DC21285 boards" );
Messung V0.5 in Prozent C=96 H=88 G=91
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland