sbc_gxx.c (5692B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, 3 SBC-GXm and SBC-GX1 series boards. 4 5 Copyright (C) 2001 Arcom Control System Ltd 6 7 8The SBC-MediaGX / SBC-GXx has up to 16 MiB of 9Intel StrataFlash (28F320/28F640) in x8 mode. 10 11This driver uses the CFI probe and Intel Extended Command Set drivers. 12 13The flash is accessed as follows: 14 15 16 KiB memory window at 0xdc000-0xdffff 16 17 Two IO address locations for paging 18 19 0x258 20 bit 0-7: address bit 14-21 21 0x259 22 bit 0-1: address bit 22-23 23 bit 7: 0 - reset/powered down 24 1 - device enabled 25 26The single flash device is divided into 3 partition which appear as 27separate MTD devices. 28 2925/04/2001 AJL (Arcom) Modified signon strings and partition sizes 30 (to support bzImages up to 638KiB-ish) 31*/ 32 33// Includes 34 35#include <linux/module.h> 36#include <linux/ioport.h> 37#include <linux/init.h> 38#include <asm/io.h> 39 40#include <linux/mtd/mtd.h> 41#include <linux/mtd/map.h> 42#include <linux/mtd/partitions.h> 43 44// Defines 45 46// - Hardware specific 47 48#define WINDOW_START 0xdc000 49 50/* Number of bits in offset. */ 51#define WINDOW_SHIFT 14 52#define WINDOW_LENGTH (1 << WINDOW_SHIFT) 53 54/* The bits for the offset into the window. */ 55#define WINDOW_MASK (WINDOW_LENGTH-1) 56#define PAGE_IO 0x258 57#define PAGE_IO_SIZE 2 58 59/* bit 7 of 0x259 must be 1 to enable device. */ 60#define DEVICE_ENABLE 0x8000 61 62// - Flash / Partition sizing 63 64#define MAX_SIZE_KiB 16384 65#define BOOT_PARTITION_SIZE_KiB 768 66#define DATA_PARTITION_SIZE_KiB 1280 67#define APP_PARTITION_SIZE_KiB 6144 68 69// Globals 70 71static volatile int page_in_window = -1; // Current page in window. 72static void __iomem *iomapadr; 73static DEFINE_SPINLOCK(sbc_gxx_spin); 74 75/* partition_info gives details on the logical partitions that the split the 76 * single flash device into. If the size if zero we use up to the end of the 77 * device. */ 78static const struct mtd_partition partition_info[] = { 79 { .name = "SBC-GXx flash boot partition", 80 .offset = 0, 81 .size = BOOT_PARTITION_SIZE_KiB*1024 }, 82 { .name = "SBC-GXx flash data partition", 83 .offset = BOOT_PARTITION_SIZE_KiB*1024, 84 .size = (DATA_PARTITION_SIZE_KiB)*1024 }, 85 { .name = "SBC-GXx flash application partition", 86 .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } 87}; 88 89#define NUM_PARTITIONS 3 90 91static inline void sbc_gxx_page(struct map_info *map, unsigned long ofs) 92{ 93 unsigned long page = ofs >> WINDOW_SHIFT; 94 95 if( page!=page_in_window ) { 96 outw( page | DEVICE_ENABLE, PAGE_IO ); 97 page_in_window = page; 98 } 99} 100 101 102static map_word sbc_gxx_read8(struct map_info *map, unsigned long ofs) 103{ 104 map_word ret; 105 spin_lock(&sbc_gxx_spin); 106 sbc_gxx_page(map, ofs); 107 ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK)); 108 spin_unlock(&sbc_gxx_spin); 109 return ret; 110} 111 112static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 113{ 114 while(len) { 115 unsigned long thislen = len; 116 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) 117 thislen = WINDOW_LENGTH-(from & WINDOW_MASK); 118 119 spin_lock(&sbc_gxx_spin); 120 sbc_gxx_page(map, from); 121 memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); 122 spin_unlock(&sbc_gxx_spin); 123 to += thislen; 124 from += thislen; 125 len -= thislen; 126 } 127} 128 129static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr) 130{ 131 spin_lock(&sbc_gxx_spin); 132 sbc_gxx_page(map, adr); 133 writeb(d.x[0], iomapadr + (adr & WINDOW_MASK)); 134 spin_unlock(&sbc_gxx_spin); 135} 136 137static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 138{ 139 while(len) { 140 unsigned long thislen = len; 141 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) 142 thislen = WINDOW_LENGTH-(to & WINDOW_MASK); 143 144 spin_lock(&sbc_gxx_spin); 145 sbc_gxx_page(map, to); 146 memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); 147 spin_unlock(&sbc_gxx_spin); 148 to += thislen; 149 from += thislen; 150 len -= thislen; 151 } 152} 153 154static struct map_info sbc_gxx_map = { 155 .name = "SBC-GXx flash", 156 .phys = NO_XIP, 157 .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount 158 of flash so the cfi probe routines find all 159 the chips */ 160 .bankwidth = 1, 161 .read = sbc_gxx_read8, 162 .copy_from = sbc_gxx_copy_from, 163 .write = sbc_gxx_write8, 164 .copy_to = sbc_gxx_copy_to 165}; 166 167/* MTD device for all of the flash. */ 168static struct mtd_info *all_mtd; 169 170static void cleanup_sbc_gxx(void) 171{ 172 if( all_mtd ) { 173 mtd_device_unregister(all_mtd); 174 map_destroy( all_mtd ); 175 } 176 177 iounmap(iomapadr); 178 release_region(PAGE_IO,PAGE_IO_SIZE); 179} 180 181static int __init init_sbc_gxx(void) 182{ 183 iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH); 184 if (!iomapadr) { 185 printk( KERN_ERR"%s: failed to ioremap memory region\n", 186 sbc_gxx_map.name ); 187 return -EIO; 188 } 189 190 if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { 191 printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", 192 sbc_gxx_map.name, 193 PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); 194 iounmap(iomapadr); 195 return -EAGAIN; 196 } 197 198 199 printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", 200 sbc_gxx_map.name, 201 PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, 202 WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 ); 203 204 /* Probe for chip. */ 205 all_mtd = do_map_probe( "cfi_probe", &sbc_gxx_map ); 206 if( !all_mtd ) { 207 cleanup_sbc_gxx(); 208 return -ENXIO; 209 } 210 211 all_mtd->owner = THIS_MODULE; 212 213 /* Create MTD devices for each partition. */ 214 mtd_device_register(all_mtd, partition_info, NUM_PARTITIONS); 215 216 return 0; 217} 218 219module_init(init_sbc_gxx); 220module_exit(cleanup_sbc_gxx); 221 222MODULE_LICENSE("GPL"); 223MODULE_AUTHOR("Arcom Control Systems Ltd."); 224MODULE_DESCRIPTION("MTD map driver for SBC-GXm and SBC-GX1 series boards");