cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dc21285.c (5547B)


      1/*
      2 * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
      3 *
      4 * (C) 2000  Nicolas Pitre <nico@fluxnic.net>
      5 *
      6 * This code is GPL
      7 */
      8#include <linux/module.h>
      9#include <linux/types.h>
     10#include <linux/kernel.h>
     11#include <linux/init.h>
     12#include <linux/delay.h>
     13#include <linux/slab.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#include <asm/mach-types.h>
     22
     23
     24static struct mtd_info *dc21285_mtd;
     25
     26#ifdef CONFIG_ARCH_NETWINDER
     27/*
     28 * This is really ugly, but it seams to be the only
     29 * realiable way to do it, as the cpld state machine
     30 * is unpredictible. So we have a 25us penalty per
     31 * write access.
     32 */
     33static void nw_en_write(void)
     34{
     35	unsigned long flags;
     36
     37	/*
     38	 * we want to write a bit pattern XXX1 to Xilinx to enable
     39	 * the write gate, which will be open for about the next 2ms.
     40	 */
     41	raw_spin_lock_irqsave(&nw_gpio_lock, flags);
     42	nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
     43	raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
     44
     45	/*
     46	 * let the ISA bus to catch on...
     47	 */
     48	udelay(25);
     49}
     50#else
     51#define nw_en_write() do { } while (0)
     52#endif
     53
     54static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
     55{
     56	map_word val;
     57	val.x[0] = *(uint8_t*)(map->virt + ofs);
     58	return val;
     59}
     60
     61static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
     62{
     63	map_word val;
     64	val.x[0] = *(uint16_t*)(map->virt + ofs);
     65	return val;
     66}
     67
     68static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
     69{
     70	map_word val;
     71	val.x[0] = *(uint32_t*)(map->virt + ofs);
     72	return val;
     73}
     74
     75static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
     76{
     77	memcpy(to, (void*)(map->virt + from), len);
     78}
     79
     80static void dc21285_write8(struct map_info *map, const map_word d, unsigned long adr)
     81{
     82	if (machine_is_netwinder())
     83		nw_en_write();
     84	*CSR_ROMWRITEREG = adr & 3;
     85	adr &= ~3;
     86	*(uint8_t*)(map->virt + adr) = d.x[0];
     87}
     88
     89static void dc21285_write16(struct map_info *map, const map_word d, unsigned long adr)
     90{
     91	if (machine_is_netwinder())
     92		nw_en_write();
     93	*CSR_ROMWRITEREG = adr & 3;
     94	adr &= ~3;
     95	*(uint16_t*)(map->virt + adr) = d.x[0];
     96}
     97
     98static void dc21285_write32(struct map_info *map, const map_word d, unsigned long adr)
     99{
    100	if (machine_is_netwinder())
    101		nw_en_write();
    102	*(uint32_t*)(map->virt + adr) = d.x[0];
    103}
    104
    105static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
    106{
    107	while (len > 0) {
    108		map_word d;
    109		d.x[0] = *((uint32_t*)from);
    110		dc21285_write32(map, d, to);
    111		from += 4;
    112		to += 4;
    113		len -= 4;
    114	}
    115}
    116
    117static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
    118{
    119	while (len > 0) {
    120		map_word d;
    121		d.x[0] = *((uint16_t*)from);
    122		dc21285_write16(map, d, to);
    123		from += 2;
    124		to += 2;
    125		len -= 2;
    126	}
    127}
    128
    129static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
    130{
    131	map_word d;
    132	d.x[0] = *((uint8_t*)from);
    133	dc21285_write8(map, d, to);
    134	from++;
    135	to++;
    136	len--;
    137}
    138
    139static struct map_info dc21285_map = {
    140	.name = "DC21285 flash",
    141	.phys = NO_XIP,
    142	.size = 16*1024*1024,
    143	.copy_from = dc21285_copy_from,
    144};
    145
    146/* Partition stuff */
    147static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
    148
    149static int __init init_dc21285(void)
    150{
    151	/* Determine bankwidth */
    152	switch (*CSR_SA110_CNTL & (3<<14)) {
    153		case SA110_CNTL_ROMWIDTH_8:
    154			dc21285_map.bankwidth = 1;
    155			dc21285_map.read = dc21285_read8;
    156			dc21285_map.write = dc21285_write8;
    157			dc21285_map.copy_to = dc21285_copy_to_8;
    158			break;
    159		case SA110_CNTL_ROMWIDTH_16:
    160			dc21285_map.bankwidth = 2;
    161			dc21285_map.read = dc21285_read16;
    162			dc21285_map.write = dc21285_write16;
    163			dc21285_map.copy_to = dc21285_copy_to_16;
    164			break;
    165		case SA110_CNTL_ROMWIDTH_32:
    166			dc21285_map.bankwidth = 4;
    167			dc21285_map.read = dc21285_read32;
    168			dc21285_map.write = dc21285_write32;
    169			dc21285_map.copy_to = dc21285_copy_to_32;
    170			break;
    171		default:
    172			printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
    173			return -ENXIO;
    174	}
    175	printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
    176		dc21285_map.bankwidth*8);
    177
    178	/* Let's map the flash area */
    179	dc21285_map.virt = ioremap(DC21285_FLASH, 16*1024*1024);
    180	if (!dc21285_map.virt) {
    181		printk("Failed to ioremap\n");
    182		return -EIO;
    183	}
    184
    185	if (machine_is_ebsa285()) {
    186		dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
    187	} else {
    188		dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
    189	}
    190
    191	if (!dc21285_mtd) {
    192		iounmap(dc21285_map.virt);
    193		return -ENXIO;
    194	}
    195
    196	dc21285_mtd->owner = THIS_MODULE;
    197
    198	mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
    199
    200	if(machine_is_ebsa285()) {
    201		/*
    202		 * Flash timing is determined with bits 19-16 of the
    203		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
    204		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
    205		 * Here we use 7 for 140 ns flash chips.
    206		 */
    207		/* access time */
    208		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
    209		/* burst time */
    210		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
    211		/* tristate time */
    212		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
    213	}
    214
    215	return 0;
    216}
    217
    218static void __exit cleanup_dc21285(void)
    219{
    220	mtd_device_unregister(dc21285_mtd);
    221	map_destroy(dc21285_mtd);
    222	iounmap(dc21285_map.virt);
    223}
    224
    225module_init(init_dc21285);
    226module_exit(cleanup_dc21285);
    227
    228
    229MODULE_LICENSE("GPL");
    230MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
    231MODULE_DESCRIPTION("MTD map driver for DC21285 boards");