0001
0002
0003
0004
0005
0006
0007
0008
0009
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
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #define REPROGRAM_PAR
0044
0045
0046
0047 #ifdef REPROGRAM_PAR
0048
0049
0050 #define WINDOW_ADDR_0 0x08800000
0051 #define WINDOW_ADDR_1 0x09000000
0052 #define WINDOW_ADDR_2 0x09800000
0053
0054
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
0102
0103
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
0109
0110
0111
0112
0113
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
0122
0123
0124 #define SC520_PAR_WRPROT (1<<26)
0125 #define SC520_PAR_NOCACHE (1<<27)
0126 #define SC520_PAR_NOEXEC (1<<28)
0127
0128
0129
0130
0131
0132 #define SC520_PAR_PG_SIZ4 (0<<25)
0133 #define SC520_PAR_PG_SIZ64 (1<<25)
0134
0135
0136
0137
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 {
0153 SC520_PAR_ROMCS0,
0154 SC520_PAR_ENTRY(SC520_PAR_ROMCS0, WINDOW_ADDR_0, WINDOW_SIZE_0),
0155 WINDOW_ADDR_0_BIOS
0156 },
0157 {
0158 SC520_PAR_ROMCS1,
0159 SC520_PAR_ENTRY(SC520_PAR_ROMCS1, WINDOW_ADDR_1, WINDOW_SIZE_1),
0160 WINDOW_ADDR_1_BIOS
0161 },
0162 {
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
0177 mmcr = ioremap(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
0178 if(!mmcr) {
0179
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
0187
0188
0189
0190 for(i = 0; i < NUM_FLASH_BANKS; i++) {
0191 for(j = 0; j < NUM_SC520_PAR; j++) {
0192 mmcr_val = readl(&mmcr[SC520_PAR(j)]);
0193
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 {
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
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
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)
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");