225 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* 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 Ltd6 7 8The SBC-MediaGX / SBC-GXx has up to 16 MiB of9Intel 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-0xdffff16 17 Two IO address locations for paging18 19 0x25820 bit 0-7: address bit 14-2121 0x25922 bit 0-1: address bit 22-2323 bit 7: 0 - reset/powered down24 1 - device enabled25 26The single flash device is divided into 3 partition which appear as27separate MTD devices.28 2925/04/2001 AJL (Arcom) Modified signon strings and partition sizes30 (to support bzImages up to 638KiB-ish)31*/32 33// Includes34 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// Defines45 46// - Hardware specific47 48#define WINDOW_START 0xdc00049 50/* Number of bits in offset. */51#define WINDOW_SHIFT 1452#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 0x25857#define PAGE_IO_SIZE 258 59/* bit 7 of 0x259 must be 1 to enable device. */60#define DEVICE_ENABLE 0x800061 62// - Flash / Partition sizing63 64#define MAX_SIZE_KiB 1638465#define BOOT_PARTITION_SIZE_KiB 76866#define DATA_PARTITION_SIZE_KiB 128067#define APP_PARTITION_SIZE_KiB 614468 69// Globals70 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 the76 * single flash device into. If the size if zero we use up to the end of the77 * 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 390 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 amount158 of flash so the cfi probe routines find all159 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_to165};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");225