Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* sc520cdp.c -- MTD map driver for AMD SC520 Customer Development Platform
0003  *
0004  * Copyright (C) 2001 Sysgo Real-Time Solutions GmbH
0005  *
0006  * The SC520CDP is an evaluation board for the Elan SC520 processor available
0007  * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size,
0008  * and up to 512 KiB of 8-bit DIL Flash ROM.
0009  * For details see https://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/types.h>
0014 #include <linux/kernel.h>
0015 #include <linux/init.h>
0016 #include <asm/io.h>
0017 #include <linux/mtd/mtd.h>
0018 #include <linux/mtd/map.h>
0019 #include <linux/mtd/concat.h>
0020 
0021 /*
0022 ** The Embedded Systems BIOS decodes the first FLASH starting at
0023 ** 0x8400000. This is a *terrible* place for it because accessing
0024 ** the flash at this location causes the A22 address line to be high
0025 ** (that's what 0x8400000 binary's ought to be). But this is the highest
0026 ** order address line on the raw flash devices themselves!!
0027 ** This causes the top HALF of the flash to be accessed first. Beyond
0028 ** the physical limits of the flash, the flash chip aliases over (to
0029 ** 0x880000 which causes the bottom half to be accessed. This splits the
0030 ** flash into two and inverts it! If you then try to access this from another
0031 ** program that does NOT do this insanity, then you *will* access the
0032 ** first half of the flash, but not find what you expect there. That
0033 ** stuff is in the *second* half! Similarly, the address used by the
0034 ** BIOS for the second FLASH bank is also quite a bad choice.
0035 ** If REPROGRAM_PAR is defined below (the default), then this driver will
0036 ** choose more useful addresses for the FLASH banks by reprogramming the
0037 ** responsible PARxx registers in the SC520's MMCR region. This will
0038 ** cause the settings to be incompatible with the BIOS's settings, which
0039 ** shouldn't be a problem since you are running Linux, (i.e. the BIOS is
0040 ** not much use anyway). However, if you need to be compatible with
0041 ** the BIOS for some reason, just undefine REPROGRAM_PAR.
0042 */
0043 #define REPROGRAM_PAR
0044 
0045 
0046 
0047 #ifdef REPROGRAM_PAR
0048 
0049 /* These are the addresses we want.. */
0050 #define WINDOW_ADDR_0   0x08800000
0051 #define WINDOW_ADDR_1   0x09000000
0052 #define WINDOW_ADDR_2   0x09800000
0053 
0054 /* .. and these are the addresses the BIOS gives us */
0055 #define WINDOW_ADDR_0_BIOS  0x08400000
0056 #define WINDOW_ADDR_1_BIOS  0x08c00000
0057 #define WINDOW_ADDR_2_BIOS  0x09400000
0058 
0059 #else
0060 
0061 #define WINDOW_ADDR_0   0x08400000
0062 #define WINDOW_ADDR_1   0x08C00000
0063 #define WINDOW_ADDR_2   0x09400000
0064 
0065 #endif
0066 
0067 #define WINDOW_SIZE_0   0x00800000
0068 #define WINDOW_SIZE_1   0x00800000
0069 #define WINDOW_SIZE_2   0x00080000
0070 
0071 
0072 static struct map_info sc520cdp_map[] = {
0073     {
0074         .name = "SC520CDP Flash Bank #0",
0075         .size = WINDOW_SIZE_0,
0076         .bankwidth = 4,
0077         .phys = WINDOW_ADDR_0
0078     },
0079     {
0080         .name = "SC520CDP Flash Bank #1",
0081         .size = WINDOW_SIZE_1,
0082         .bankwidth = 4,
0083         .phys = WINDOW_ADDR_1
0084     },
0085     {
0086         .name = "SC520CDP DIL Flash",
0087         .size = WINDOW_SIZE_2,
0088         .bankwidth = 1,
0089         .phys = WINDOW_ADDR_2
0090     },
0091 };
0092 
0093 #define NUM_FLASH_BANKS ARRAY_SIZE(sc520cdp_map)
0094 
0095 static struct mtd_info *mymtd[NUM_FLASH_BANKS];
0096 static struct mtd_info *merged_mtd;
0097 
0098 #ifdef REPROGRAM_PAR
0099 
0100 /*
0101 ** The SC520 MMCR (memory mapped control register) region resides
0102 ** at 0xFFFEF000. The 16 Programmable Address Region (PAR) registers
0103 ** are at offset 0x88 in the MMCR:
0104 */
0105 #define SC520_MMCR_BASE     0xFFFEF000
0106 #define SC520_MMCR_EXTENT   0x1000
0107 #define SC520_PAR(x)        ((0x88/sizeof(unsigned long)) + (x))
0108 #define NUM_SC520_PAR       16  /* total number of PAR registers */
0109 
0110 /*
0111 ** The highest three bits in a PAR register determine what target
0112 ** device is controlled by this PAR. Here, only ROMCS? and BOOTCS
0113 ** devices are of interest.
0114 */
0115 #define SC520_PAR_BOOTCS    (0x4<<29)
0116 #define SC520_PAR_ROMCS0    (0x5<<29)
0117 #define SC520_PAR_ROMCS1    (0x6<<29)
0118 #define SC520_PAR_TRGDEV    (0x7<<29)
0119 
0120 /*
0121 ** Bits 28 thru 26 determine some attributes for the
0122 ** region controlled by the PAR. (We only use non-cacheable)
0123 */
0124 #define SC520_PAR_WRPROT    (1<<26) /* write protected       */
0125 #define SC520_PAR_NOCACHE   (1<<27) /* non-cacheable         */
0126 #define SC520_PAR_NOEXEC    (1<<28) /* code execution denied */
0127 
0128 
0129 /*
0130 ** Bit 25 determines the granularity: 4K or 64K
0131 */
0132 #define SC520_PAR_PG_SIZ4   (0<<25)
0133 #define SC520_PAR_PG_SIZ64  (1<<25)
0134 
0135 /*
0136 ** Build a value to be written into a PAR register.
0137 ** We only need ROM entries, 64K page size:
0138 */
0139 #define SC520_PAR_ENTRY(trgdev, address, size) \
0140     ((trgdev) | SC520_PAR_NOCACHE | SC520_PAR_PG_SIZ64 | \
0141     (address) >> 16 | (((size) >> 16) - 1) << 14)
0142 
0143 struct sc520_par_table
0144 {
0145     unsigned long trgdev;
0146     unsigned long new_par;
0147     unsigned long default_address;
0148 };
0149 
0150 static const struct sc520_par_table par_table[NUM_FLASH_BANKS] =
0151 {
0152     {   /* Flash Bank #0: selected by ROMCS0 */
0153         SC520_PAR_ROMCS0,
0154         SC520_PAR_ENTRY(SC520_PAR_ROMCS0, WINDOW_ADDR_0, WINDOW_SIZE_0),
0155         WINDOW_ADDR_0_BIOS
0156     },
0157     {   /* Flash Bank #1: selected by ROMCS1 */
0158         SC520_PAR_ROMCS1,
0159         SC520_PAR_ENTRY(SC520_PAR_ROMCS1, WINDOW_ADDR_1, WINDOW_SIZE_1),
0160         WINDOW_ADDR_1_BIOS
0161     },
0162     {   /* DIL (BIOS) Flash: selected by BOOTCS */
0163         SC520_PAR_BOOTCS,
0164         SC520_PAR_ENTRY(SC520_PAR_BOOTCS, WINDOW_ADDR_2, WINDOW_SIZE_2),
0165         WINDOW_ADDR_2_BIOS
0166     }
0167 };
0168 
0169 
0170 static void sc520cdp_setup_par(void)
0171 {
0172     unsigned long __iomem *mmcr;
0173     unsigned long mmcr_val;
0174     int i, j;
0175 
0176     /* map in SC520's MMCR area */
0177     mmcr = ioremap(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
0178     if(!mmcr) { /* ioremap failed: skip the PAR reprogramming */
0179         /* force physical address fields to BIOS defaults: */
0180         for(i = 0; i < NUM_FLASH_BANKS; i++)
0181             sc520cdp_map[i].phys = par_table[i].default_address;
0182         return;
0183     }
0184 
0185     /*
0186     ** Find the PARxx registers that are responsible for activating
0187     ** ROMCS0, ROMCS1 and BOOTCS. Reprogram each of these with a
0188     ** new value from the table.
0189     */
0190     for(i = 0; i < NUM_FLASH_BANKS; i++) {      /* for each par_table entry  */
0191         for(j = 0; j < NUM_SC520_PAR; j++) {    /* for each PAR register     */
0192             mmcr_val = readl(&mmcr[SC520_PAR(j)]);
0193             /* if target device field matches, reprogram the PAR */
0194             if((mmcr_val & SC520_PAR_TRGDEV) == par_table[i].trgdev)
0195             {
0196                 writel(par_table[i].new_par, &mmcr[SC520_PAR(j)]);
0197                 break;
0198             }
0199         }
0200         if(j == NUM_SC520_PAR)
0201         {   /* no matching PAR found: try default BIOS address */
0202             printk(KERN_NOTICE "Could not find PAR responsible for %s\n",
0203                 sc520cdp_map[i].name);
0204             printk(KERN_NOTICE "Trying default address 0x%lx\n",
0205                 par_table[i].default_address);
0206             sc520cdp_map[i].phys = par_table[i].default_address;
0207         }
0208     }
0209     iounmap(mmcr);
0210 }
0211 #endif
0212 
0213 
0214 static int __init init_sc520cdp(void)
0215 {
0216     int i, j, devices_found = 0;
0217 
0218 #ifdef REPROGRAM_PAR
0219     /* reprogram PAR registers so flash appears at the desired addresses */
0220     sc520cdp_setup_par();
0221 #endif
0222 
0223     for (i = 0; i < NUM_FLASH_BANKS; i++) {
0224         printk(KERN_NOTICE "SC520 CDP flash device: 0x%Lx at 0x%Lx\n",
0225             (unsigned long long)sc520cdp_map[i].size,
0226             (unsigned long long)sc520cdp_map[i].phys);
0227 
0228         sc520cdp_map[i].virt = ioremap(sc520cdp_map[i].phys, sc520cdp_map[i].size);
0229 
0230         if (!sc520cdp_map[i].virt) {
0231             printk("Failed to ioremap\n");
0232             for (j = 0; j < i; j++) {
0233                 if (mymtd[j]) {
0234                     map_destroy(mymtd[j]);
0235                     iounmap(sc520cdp_map[j].virt);
0236                 }
0237             }
0238             return -EIO;
0239         }
0240 
0241         simple_map_init(&sc520cdp_map[i]);
0242 
0243         mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
0244         if(!mymtd[i])
0245             mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
0246         if(!mymtd[i])
0247             mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
0248 
0249         if (mymtd[i]) {
0250             mymtd[i]->owner = THIS_MODULE;
0251             ++devices_found;
0252         }
0253         else {
0254             iounmap(sc520cdp_map[i].virt);
0255         }
0256     }
0257     if(devices_found >= 2) {
0258         /* Combine the two flash banks into a single MTD device & register it: */
0259         merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1");
0260         if(merged_mtd)
0261             mtd_device_register(merged_mtd, NULL, 0);
0262     }
0263     if(devices_found == 3) /* register the third (DIL-Flash) device */
0264         mtd_device_register(mymtd[2], NULL, 0);
0265     return(devices_found ? 0 : -ENXIO);
0266 }
0267 
0268 static void __exit cleanup_sc520cdp(void)
0269 {
0270     int i;
0271 
0272     if (merged_mtd) {
0273         mtd_device_unregister(merged_mtd);
0274         mtd_concat_destroy(merged_mtd);
0275     }
0276     if (mymtd[2])
0277         mtd_device_unregister(mymtd[2]);
0278 
0279     for (i = 0; i < NUM_FLASH_BANKS; i++) {
0280         if (mymtd[i])
0281             map_destroy(mymtd[i]);
0282         if (sc520cdp_map[i].virt) {
0283             iounmap(sc520cdp_map[i].virt);
0284             sc520cdp_map[i].virt = NULL;
0285         }
0286     }
0287 }
0288 
0289 module_init(init_sc520cdp);
0290 module_exit(cleanup_sc520cdp);
0291 
0292 MODULE_LICENSE("GPL");
0293 MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
0294 MODULE_DESCRIPTION("MTD map driver for AMD SC520 Customer Development Platform");