1*1da177e4SLinus Torvalds /* sc520cdp.c -- MTD map driver for AMD SC520 Customer Development Platform 2*1da177e4SLinus Torvalds * 3*1da177e4SLinus Torvalds * Copyright (C) 2001 Sysgo Real-Time Solutions GmbH 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 6*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 7*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 8*1da177e4SLinus Torvalds * (at your option) any later version. 9*1da177e4SLinus Torvalds * 10*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 11*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*1da177e4SLinus Torvalds * GNU General Public License for more details. 14*1da177e4SLinus Torvalds * 15*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 16*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 17*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 18*1da177e4SLinus Torvalds * 19*1da177e4SLinus Torvalds * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $ 20*1da177e4SLinus Torvalds * 21*1da177e4SLinus Torvalds * 22*1da177e4SLinus Torvalds * The SC520CDP is an evaluation board for the Elan SC520 processor available 23*1da177e4SLinus Torvalds * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size, 24*1da177e4SLinus Torvalds * and up to 512 KiB of 8-bit DIL Flash ROM. 25*1da177e4SLinus Torvalds * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html 26*1da177e4SLinus Torvalds */ 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds #include <linux/config.h> 29*1da177e4SLinus Torvalds #include <linux/module.h> 30*1da177e4SLinus Torvalds #include <linux/types.h> 31*1da177e4SLinus Torvalds #include <linux/kernel.h> 32*1da177e4SLinus Torvalds #include <linux/init.h> 33*1da177e4SLinus Torvalds #include <asm/io.h> 34*1da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 35*1da177e4SLinus Torvalds #include <linux/mtd/map.h> 36*1da177e4SLinus Torvalds #include <linux/mtd/concat.h> 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds /* 39*1da177e4SLinus Torvalds ** The Embedded Systems BIOS decodes the first FLASH starting at 40*1da177e4SLinus Torvalds ** 0x8400000. This is a *terrible* place for it because accessing 41*1da177e4SLinus Torvalds ** the flash at this location causes the A22 address line to be high 42*1da177e4SLinus Torvalds ** (that's what 0x8400000 binary's ought to be). But this is the highest 43*1da177e4SLinus Torvalds ** order address line on the raw flash devices themselves!! 44*1da177e4SLinus Torvalds ** This causes the top HALF of the flash to be accessed first. Beyond 45*1da177e4SLinus Torvalds ** the physical limits of the flash, the flash chip aliases over (to 46*1da177e4SLinus Torvalds ** 0x880000 which causes the bottom half to be accessed. This splits the 47*1da177e4SLinus Torvalds ** flash into two and inverts it! If you then try to access this from another 48*1da177e4SLinus Torvalds ** program that does NOT do this insanity, then you *will* access the 49*1da177e4SLinus Torvalds ** first half of the flash, but not find what you expect there. That 50*1da177e4SLinus Torvalds ** stuff is in the *second* half! Similarly, the address used by the 51*1da177e4SLinus Torvalds ** BIOS for the second FLASH bank is also quite a bad choice. 52*1da177e4SLinus Torvalds ** If REPROGRAM_PAR is defined below (the default), then this driver will 53*1da177e4SLinus Torvalds ** choose more useful addresses for the FLASH banks by reprogramming the 54*1da177e4SLinus Torvalds ** responsible PARxx registers in the SC520's MMCR region. This will 55*1da177e4SLinus Torvalds ** cause the settings to be incompatible with the BIOS's settings, which 56*1da177e4SLinus Torvalds ** shouldn't be a problem since you are running Linux, (i.e. the BIOS is 57*1da177e4SLinus Torvalds ** not much use anyway). However, if you need to be compatible with 58*1da177e4SLinus Torvalds ** the BIOS for some reason, just undefine REPROGRAM_PAR. 59*1da177e4SLinus Torvalds */ 60*1da177e4SLinus Torvalds #define REPROGRAM_PAR 61*1da177e4SLinus Torvalds 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds #ifdef REPROGRAM_PAR 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds /* These are the addresses we want.. */ 67*1da177e4SLinus Torvalds #define WINDOW_ADDR_0 0x08800000 68*1da177e4SLinus Torvalds #define WINDOW_ADDR_1 0x09000000 69*1da177e4SLinus Torvalds #define WINDOW_ADDR_2 0x09800000 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* .. and these are the addresses the BIOS gives us */ 72*1da177e4SLinus Torvalds #define WINDOW_ADDR_0_BIOS 0x08400000 73*1da177e4SLinus Torvalds #define WINDOW_ADDR_1_BIOS 0x08c00000 74*1da177e4SLinus Torvalds #define WINDOW_ADDR_2_BIOS 0x09400000 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds #else 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds #define WINDOW_ADDR_0 0x08400000 79*1da177e4SLinus Torvalds #define WINDOW_ADDR_1 0x08C00000 80*1da177e4SLinus Torvalds #define WINDOW_ADDR_2 0x09400000 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds #endif 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds #define WINDOW_SIZE_0 0x00800000 85*1da177e4SLinus Torvalds #define WINDOW_SIZE_1 0x00800000 86*1da177e4SLinus Torvalds #define WINDOW_SIZE_2 0x00080000 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds static struct map_info sc520cdp_map[] = { 90*1da177e4SLinus Torvalds { 91*1da177e4SLinus Torvalds .name = "SC520CDP Flash Bank #0", 92*1da177e4SLinus Torvalds .size = WINDOW_SIZE_0, 93*1da177e4SLinus Torvalds .bankwidth = 4, 94*1da177e4SLinus Torvalds .phys = WINDOW_ADDR_0 95*1da177e4SLinus Torvalds }, 96*1da177e4SLinus Torvalds { 97*1da177e4SLinus Torvalds .name = "SC520CDP Flash Bank #1", 98*1da177e4SLinus Torvalds .size = WINDOW_SIZE_1, 99*1da177e4SLinus Torvalds .bankwidth = 4, 100*1da177e4SLinus Torvalds .phys = WINDOW_ADDR_1 101*1da177e4SLinus Torvalds }, 102*1da177e4SLinus Torvalds { 103*1da177e4SLinus Torvalds .name = "SC520CDP DIL Flash", 104*1da177e4SLinus Torvalds .size = WINDOW_SIZE_2, 105*1da177e4SLinus Torvalds .bankwidth = 1, 106*1da177e4SLinus Torvalds .phys = WINDOW_ADDR_2 107*1da177e4SLinus Torvalds }, 108*1da177e4SLinus Torvalds }; 109*1da177e4SLinus Torvalds 110*1da177e4SLinus Torvalds #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) 111*1da177e4SLinus Torvalds 112*1da177e4SLinus Torvalds static struct mtd_info *mymtd[NUM_FLASH_BANKS]; 113*1da177e4SLinus Torvalds static struct mtd_info *merged_mtd; 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds #ifdef REPROGRAM_PAR 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds /* 118*1da177e4SLinus Torvalds ** The SC520 MMCR (memory mapped control register) region resides 119*1da177e4SLinus Torvalds ** at 0xFFFEF000. The 16 Programmable Address Region (PAR) registers 120*1da177e4SLinus Torvalds ** are at offset 0x88 in the MMCR: 121*1da177e4SLinus Torvalds */ 122*1da177e4SLinus Torvalds #define SC520_MMCR_BASE 0xFFFEF000 123*1da177e4SLinus Torvalds #define SC520_MMCR_EXTENT 0x1000 124*1da177e4SLinus Torvalds #define SC520_PAR(x) ((0x88/sizeof(unsigned long)) + (x)) 125*1da177e4SLinus Torvalds #define NUM_SC520_PAR 16 /* total number of PAR registers */ 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds /* 128*1da177e4SLinus Torvalds ** The highest three bits in a PAR register determine what target 129*1da177e4SLinus Torvalds ** device is controlled by this PAR. Here, only ROMCS? and BOOTCS 130*1da177e4SLinus Torvalds ** devices are of interest. 131*1da177e4SLinus Torvalds */ 132*1da177e4SLinus Torvalds #define SC520_PAR_BOOTCS (0x4<<29) 133*1da177e4SLinus Torvalds #define SC520_PAR_ROMCS0 (0x5<<29) 134*1da177e4SLinus Torvalds #define SC520_PAR_ROMCS1 (0x6<<29) 135*1da177e4SLinus Torvalds #define SC520_PAR_TRGDEV (0x7<<29) 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds /* 138*1da177e4SLinus Torvalds ** Bits 28 thru 26 determine some attributes for the 139*1da177e4SLinus Torvalds ** region controlled by the PAR. (We only use non-cacheable) 140*1da177e4SLinus Torvalds */ 141*1da177e4SLinus Torvalds #define SC520_PAR_WRPROT (1<<26) /* write protected */ 142*1da177e4SLinus Torvalds #define SC520_PAR_NOCACHE (1<<27) /* non-cacheable */ 143*1da177e4SLinus Torvalds #define SC520_PAR_NOEXEC (1<<28) /* code execution denied */ 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* 147*1da177e4SLinus Torvalds ** Bit 25 determines the granularity: 4K or 64K 148*1da177e4SLinus Torvalds */ 149*1da177e4SLinus Torvalds #define SC520_PAR_PG_SIZ4 (0<<25) 150*1da177e4SLinus Torvalds #define SC520_PAR_PG_SIZ64 (1<<25) 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds /* 153*1da177e4SLinus Torvalds ** Build a value to be written into a PAR register. 154*1da177e4SLinus Torvalds ** We only need ROM entries, 64K page size: 155*1da177e4SLinus Torvalds */ 156*1da177e4SLinus Torvalds #define SC520_PAR_ENTRY(trgdev, address, size) \ 157*1da177e4SLinus Torvalds ((trgdev) | SC520_PAR_NOCACHE | SC520_PAR_PG_SIZ64 | \ 158*1da177e4SLinus Torvalds (address) >> 16 | (((size) >> 16) - 1) << 14) 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds struct sc520_par_table 161*1da177e4SLinus Torvalds { 162*1da177e4SLinus Torvalds unsigned long trgdev; 163*1da177e4SLinus Torvalds unsigned long new_par; 164*1da177e4SLinus Torvalds unsigned long default_address; 165*1da177e4SLinus Torvalds }; 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds static struct sc520_par_table par_table[NUM_FLASH_BANKS] = 168*1da177e4SLinus Torvalds { 169*1da177e4SLinus Torvalds { /* Flash Bank #0: selected by ROMCS0 */ 170*1da177e4SLinus Torvalds SC520_PAR_ROMCS0, 171*1da177e4SLinus Torvalds SC520_PAR_ENTRY(SC520_PAR_ROMCS0, WINDOW_ADDR_0, WINDOW_SIZE_0), 172*1da177e4SLinus Torvalds WINDOW_ADDR_0_BIOS 173*1da177e4SLinus Torvalds }, 174*1da177e4SLinus Torvalds { /* Flash Bank #1: selected by ROMCS1 */ 175*1da177e4SLinus Torvalds SC520_PAR_ROMCS1, 176*1da177e4SLinus Torvalds SC520_PAR_ENTRY(SC520_PAR_ROMCS1, WINDOW_ADDR_1, WINDOW_SIZE_1), 177*1da177e4SLinus Torvalds WINDOW_ADDR_1_BIOS 178*1da177e4SLinus Torvalds }, 179*1da177e4SLinus Torvalds { /* DIL (BIOS) Flash: selected by BOOTCS */ 180*1da177e4SLinus Torvalds SC520_PAR_BOOTCS, 181*1da177e4SLinus Torvalds SC520_PAR_ENTRY(SC520_PAR_BOOTCS, WINDOW_ADDR_2, WINDOW_SIZE_2), 182*1da177e4SLinus Torvalds WINDOW_ADDR_2_BIOS 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds }; 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds static void sc520cdp_setup_par(void) 188*1da177e4SLinus Torvalds { 189*1da177e4SLinus Torvalds volatile unsigned long __iomem *mmcr; 190*1da177e4SLinus Torvalds unsigned long mmcr_val; 191*1da177e4SLinus Torvalds int i, j; 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds /* map in SC520's MMCR area */ 194*1da177e4SLinus Torvalds mmcr = ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT); 195*1da177e4SLinus Torvalds if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */ 196*1da177e4SLinus Torvalds /* force physical address fields to BIOS defaults: */ 197*1da177e4SLinus Torvalds for(i = 0; i < NUM_FLASH_BANKS; i++) 198*1da177e4SLinus Torvalds sc520cdp_map[i].phys = par_table[i].default_address; 199*1da177e4SLinus Torvalds return; 200*1da177e4SLinus Torvalds } 201*1da177e4SLinus Torvalds 202*1da177e4SLinus Torvalds /* 203*1da177e4SLinus Torvalds ** Find the PARxx registers that are reponsible for activating 204*1da177e4SLinus Torvalds ** ROMCS0, ROMCS1 and BOOTCS. Reprogram each of these with a 205*1da177e4SLinus Torvalds ** new value from the table. 206*1da177e4SLinus Torvalds */ 207*1da177e4SLinus Torvalds for(i = 0; i < NUM_FLASH_BANKS; i++) { /* for each par_table entry */ 208*1da177e4SLinus Torvalds for(j = 0; j < NUM_SC520_PAR; j++) { /* for each PAR register */ 209*1da177e4SLinus Torvalds mmcr_val = mmcr[SC520_PAR(j)]; 210*1da177e4SLinus Torvalds /* if target device field matches, reprogram the PAR */ 211*1da177e4SLinus Torvalds if((mmcr_val & SC520_PAR_TRGDEV) == par_table[i].trgdev) 212*1da177e4SLinus Torvalds { 213*1da177e4SLinus Torvalds mmcr[SC520_PAR(j)] = par_table[i].new_par; 214*1da177e4SLinus Torvalds break; 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds if(j == NUM_SC520_PAR) 218*1da177e4SLinus Torvalds { /* no matching PAR found: try default BIOS address */ 219*1da177e4SLinus Torvalds printk(KERN_NOTICE "Could not find PAR responsible for %s\n", 220*1da177e4SLinus Torvalds sc520cdp_map[i].name); 221*1da177e4SLinus Torvalds printk(KERN_NOTICE "Trying default address 0x%lx\n", 222*1da177e4SLinus Torvalds par_table[i].default_address); 223*1da177e4SLinus Torvalds sc520cdp_map[i].phys = par_table[i].default_address; 224*1da177e4SLinus Torvalds } 225*1da177e4SLinus Torvalds } 226*1da177e4SLinus Torvalds iounmap(mmcr); 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds #endif 229*1da177e4SLinus Torvalds 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds static int __init init_sc520cdp(void) 232*1da177e4SLinus Torvalds { 233*1da177e4SLinus Torvalds int i, devices_found = 0; 234*1da177e4SLinus Torvalds 235*1da177e4SLinus Torvalds #ifdef REPROGRAM_PAR 236*1da177e4SLinus Torvalds /* reprogram PAR registers so flash appears at the desired addresses */ 237*1da177e4SLinus Torvalds sc520cdp_setup_par(); 238*1da177e4SLinus Torvalds #endif 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds for (i = 0; i < NUM_FLASH_BANKS; i++) { 241*1da177e4SLinus Torvalds printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", 242*1da177e4SLinus Torvalds sc520cdp_map[i].size, sc520cdp_map[i].phys); 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds sc520cdp_map[i].virt = ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); 245*1da177e4SLinus Torvalds 246*1da177e4SLinus Torvalds if (!sc520cdp_map[i].virt) { 247*1da177e4SLinus Torvalds printk("Failed to ioremap_nocache\n"); 248*1da177e4SLinus Torvalds return -EIO; 249*1da177e4SLinus Torvalds } 250*1da177e4SLinus Torvalds 251*1da177e4SLinus Torvalds simple_map_init(&sc520cdp_map[i]); 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); 254*1da177e4SLinus Torvalds if(!mymtd[i]) 255*1da177e4SLinus Torvalds mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); 256*1da177e4SLinus Torvalds if(!mymtd[i]) 257*1da177e4SLinus Torvalds mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds if (mymtd[i]) { 260*1da177e4SLinus Torvalds mymtd[i]->owner = THIS_MODULE; 261*1da177e4SLinus Torvalds ++devices_found; 262*1da177e4SLinus Torvalds } 263*1da177e4SLinus Torvalds else { 264*1da177e4SLinus Torvalds iounmap(sc520cdp_map[i].virt); 265*1da177e4SLinus Torvalds } 266*1da177e4SLinus Torvalds } 267*1da177e4SLinus Torvalds if(devices_found >= 2) { 268*1da177e4SLinus Torvalds /* Combine the two flash banks into a single MTD device & register it: */ 269*1da177e4SLinus Torvalds merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1"); 270*1da177e4SLinus Torvalds if(merged_mtd) 271*1da177e4SLinus Torvalds add_mtd_device(merged_mtd); 272*1da177e4SLinus Torvalds } 273*1da177e4SLinus Torvalds if(devices_found == 3) /* register the third (DIL-Flash) device */ 274*1da177e4SLinus Torvalds add_mtd_device(mymtd[2]); 275*1da177e4SLinus Torvalds return(devices_found ? 0 : -ENXIO); 276*1da177e4SLinus Torvalds } 277*1da177e4SLinus Torvalds 278*1da177e4SLinus Torvalds static void __exit cleanup_sc520cdp(void) 279*1da177e4SLinus Torvalds { 280*1da177e4SLinus Torvalds int i; 281*1da177e4SLinus Torvalds 282*1da177e4SLinus Torvalds if (merged_mtd) { 283*1da177e4SLinus Torvalds del_mtd_device(merged_mtd); 284*1da177e4SLinus Torvalds mtd_concat_destroy(merged_mtd); 285*1da177e4SLinus Torvalds } 286*1da177e4SLinus Torvalds if (mymtd[2]) 287*1da177e4SLinus Torvalds del_mtd_device(mymtd[2]); 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds for (i = 0; i < NUM_FLASH_BANKS; i++) { 290*1da177e4SLinus Torvalds if (mymtd[i]) 291*1da177e4SLinus Torvalds map_destroy(mymtd[i]); 292*1da177e4SLinus Torvalds if (sc520cdp_map[i].virt) { 293*1da177e4SLinus Torvalds iounmap(sc520cdp_map[i].virt); 294*1da177e4SLinus Torvalds sc520cdp_map[i].virt = NULL; 295*1da177e4SLinus Torvalds } 296*1da177e4SLinus Torvalds } 297*1da177e4SLinus Torvalds } 298*1da177e4SLinus Torvalds 299*1da177e4SLinus Torvalds module_init(init_sc520cdp); 300*1da177e4SLinus Torvalds module_exit(cleanup_sc520cdp); 301*1da177e4SLinus Torvalds 302*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 303*1da177e4SLinus Torvalds MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); 304*1da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD map driver for AMD SC520 Customer Development Platform"); 305