linux/drivers/mtd/maps/sbc_gxx.c
<<
>>
Prefs
   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");
 225