| 1 | /*====================================================================== |
|---|
| 2 | |
|---|
| 3 | This program is free software; you can redistribute it and/or modify |
|---|
| 4 | it under the terms of the GNU General Public License as published by |
|---|
| 5 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 6 | (at your option) any later version. |
|---|
| 7 | |
|---|
| 8 | This program is distributed in the hope that it will be useful, |
|---|
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | GNU General Public License for more details. |
|---|
| 12 | |
|---|
| 13 | You should have received a copy of the GNU General Public License |
|---|
| 14 | along with this program; if not, write to the Free Software |
|---|
| 15 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 16 | ======================================================================*/ |
|---|
| 17 | |
|---|
| 18 | #include <linux/module.h> |
|---|
| 19 | #include <linux/types.h> |
|---|
| 20 | #include <linux/kernel.h> |
|---|
| 21 | #include <linux/slab.h> |
|---|
| 22 | #include <linux/ioport.h> |
|---|
| 23 | #include <linux/init.h> |
|---|
| 24 | #include <linux/string.h> |
|---|
| 25 | |
|---|
| 26 | #include <linux/mtd/mtd.h> |
|---|
| 27 | #include <linux/mtd/map.h> |
|---|
| 28 | #include <linux/mtd/partitions.h> |
|---|
| 29 | |
|---|
| 30 | #include <asm/hardware.h> |
|---|
| 31 | #include <asm/io.h> |
|---|
| 32 | #include <asm/system.h> |
|---|
| 33 | #include <asm/arch/sl2312.h> |
|---|
| 34 | #include <linux/mtd/kvctl.h> |
|---|
| 35 | #include "sl2312_flashmap.h" |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | //extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **); |
|---|
| 39 | |
|---|
| 40 | /* the base address of FLASH control register */ |
|---|
| 41 | #define FLASH_CONTROL_BASE_ADDR (IO_ADDRESS(SL2312_FLASH_CTRL_BASE)) |
|---|
| 42 | #define SL2312_GLOBAL_BASE_ADDR (IO_ADDRESS(SL2312_GLOBAL_BASE)) |
|---|
| 43 | |
|---|
| 44 | /* define read/write register utility */ |
|---|
| 45 | #define FLASH_READ_REG(offset) (__raw_readl(offset+FLASH_CONTROL_BASE_ADDR)) |
|---|
| 46 | #define FLASH_WRITE_REG(offset,val) (__raw_writel(val,offset+FLASH_CONTROL_BASE_ADDR)) |
|---|
| 47 | |
|---|
| 48 | /* the offset of FLASH control register */ |
|---|
| 49 | enum EMAC_REGISTER { |
|---|
| 50 | FLASH_ID = 0x0000, |
|---|
| 51 | FLASH_STATUS = 0x0008, |
|---|
| 52 | FLASH_TYPE = 0x000c, |
|---|
| 53 | FLASH_ACCESS = 0x0020, |
|---|
| 54 | FLASH_ADDRESS = 0x0024, |
|---|
| 55 | FLASH_DATA = 0x0028, |
|---|
| 56 | FLASH_TIMING = 0x002c, |
|---|
| 57 | }; |
|---|
| 58 | |
|---|
| 59 | //#define FLASH_BASE FLASH_CONTROL_BASE_ADDR |
|---|
| 60 | //#define FLASH_SIZE 0x00800000 //INTEGRATOR_FLASH_SIZE |
|---|
| 61 | |
|---|
| 62 | //#define FLASH_PART_SIZE 8388608 |
|---|
| 63 | |
|---|
| 64 | static unsigned int flash_indirect_access = 0; |
|---|
| 65 | |
|---|
| 66 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 67 | static unsigned int chip_en = 0x00000000; |
|---|
| 68 | |
|---|
| 69 | void sl2312flash_enable_parallel_flash(void) |
|---|
| 70 | { |
|---|
| 71 | unsigned int reg_val; |
|---|
| 72 | |
|---|
| 73 | reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 74 | reg_val = reg_val & 0xfffffffd; |
|---|
| 75 | writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 76 | return; |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | void sl2312flash_disable_parallel_flash(void) |
|---|
| 80 | { |
|---|
| 81 | unsigned int reg_val; |
|---|
| 82 | |
|---|
| 83 | reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 84 | reg_val = reg_val | 0x00000002; |
|---|
| 85 | writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 86 | return; |
|---|
| 87 | } |
|---|
| 88 | #endif |
|---|
| 89 | |
|---|
| 90 | |
|---|
| 91 | static struct map_info sl2312flash_map = |
|---|
| 92 | { |
|---|
| 93 | name: "SL2312 CFI Flash", |
|---|
| 94 | size: FLASH_SIZE, |
|---|
| 95 | bankwidth: 2, |
|---|
| 96 | //bankwidth: 1, //for 8 bits width |
|---|
| 97 | phys: SL2312_FLASH_BASE, |
|---|
| 98 | }; |
|---|
| 99 | |
|---|
| 100 | static struct mtd_info *mtd; |
|---|
| 101 | #if 0 |
|---|
| 102 | static struct mtd_partition sl2312_partitions[] = { |
|---|
| 103 | /* boot code */ |
|---|
| 104 | { |
|---|
| 105 | name: "bootloader", |
|---|
| 106 | offset: 0x00000000, |
|---|
| 107 | size: 0x20000, |
|---|
| 108 | // mask_flags: MTD_WRITEABLE, |
|---|
| 109 | }, |
|---|
| 110 | /* kernel image */ |
|---|
| 111 | { |
|---|
| 112 | name: "kerel image", |
|---|
| 113 | offset: 0x00020000, |
|---|
| 114 | size: 0x2E0000 |
|---|
| 115 | }, |
|---|
| 116 | /* All else is writable (e.g. JFFS) */ |
|---|
| 117 | { |
|---|
| 118 | name: "user data", |
|---|
| 119 | offset: 0x00300000, |
|---|
| 120 | size: 0x00100000, |
|---|
| 121 | } |
|---|
| 122 | }; |
|---|
| 123 | #endif |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | |
|---|
| 127 | static int __init sl2312flash_init(void) |
|---|
| 128 | { |
|---|
| 129 | struct mtd_partition *parts; |
|---|
| 130 | int nr_parts = 0; |
|---|
| 131 | int ret; |
|---|
| 132 | #ifndef CONFIG_SL2312_SHARE_PIN |
|---|
| 133 | unsigned int reg_val; |
|---|
| 134 | #endif |
|---|
| 135 | |
|---|
| 136 | printk("SL2312 MTD Driver Init.......\n"); |
|---|
| 137 | |
|---|
| 138 | #ifndef CONFIG_SL2312_SHARE_PIN |
|---|
| 139 | /* enable flash */ |
|---|
| 140 | reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 141 | reg_val = reg_val & 0xfffffffd; |
|---|
| 142 | writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); |
|---|
| 143 | #else |
|---|
| 144 | sl2312flash_enable_parallel_flash(); /* enable Parallel FLASH */ |
|---|
| 145 | #endif |
|---|
| 146 | FLASH_WRITE_REG(FLASH_ACCESS,0x00004000); /* parallel flash direct access mode */ |
|---|
| 147 | ret = FLASH_READ_REG(FLASH_ACCESS); |
|---|
| 148 | if (ret == 0x00004000) |
|---|
| 149 | { |
|---|
| 150 | flash_indirect_access = 0; /* parallel flash direct access */ |
|---|
| 151 | } |
|---|
| 152 | else |
|---|
| 153 | { |
|---|
| 154 | flash_indirect_access = 1; /* parallel flash indirect access */ |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | /* |
|---|
| 158 | * Also, the CFI layer automatically works out what size |
|---|
| 159 | * of chips we have, and does the necessary identification |
|---|
| 160 | * for us automatically. |
|---|
| 161 | */ |
|---|
| 162 | #ifdef CONFIG_GEMINI_IPI |
|---|
| 163 | sl2312flash_map.virt = FLASH_VBASE;//(unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE); |
|---|
| 164 | #else |
|---|
| 165 | sl2312flash_map.virt = (unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE); |
|---|
| 166 | #endif |
|---|
| 167 | //printk("sl2312flash_map.virt = %08x\n",(unsigned int)sl2312flash_map.virt); |
|---|
| 168 | |
|---|
| 169 | // simple_map_init(&sl2312flash_map); |
|---|
| 170 | |
|---|
| 171 | mtd = do_map_probe("cfi_probe", &sl2312flash_map); |
|---|
| 172 | if (!mtd) |
|---|
| 173 | { |
|---|
| 174 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 175 | sl2312flash_disable_parallel_flash(); /* disable Parallel FLASH */ |
|---|
| 176 | #endif |
|---|
| 177 | return -ENXIO; |
|---|
| 178 | } |
|---|
| 179 | mtd->owner = THIS_MODULE; |
|---|
| 180 | // mtd->erase = flash_erase; |
|---|
| 181 | // mtd->read = flash_read; |
|---|
| 182 | // mtd->write = flash_write; |
|---|
| 183 | |
|---|
| 184 | parts = sl2312_partitions; |
|---|
| 185 | nr_parts = sizeof(sl2312_partitions)/sizeof(*parts); |
|---|
| 186 | ret = add_mtd_partitions(mtd, parts, nr_parts); |
|---|
| 187 | /*If we got an error, free all resources.*/ |
|---|
| 188 | if (ret < 0) { |
|---|
| 189 | del_mtd_partitions(mtd); |
|---|
| 190 | map_destroy(mtd); |
|---|
| 191 | } |
|---|
| 192 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 193 | sl2312flash_disable_parallel_flash(); /* disable Parallel FLASH */ |
|---|
| 194 | #endif |
|---|
| 195 | printk("SL2312 MTD Driver Init Success ......\n"); |
|---|
| 196 | return ret; |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | static void __exit sl2312flash_exit(void) |
|---|
| 200 | { |
|---|
| 201 | if (mtd) { |
|---|
| 202 | del_mtd_partitions(mtd); |
|---|
| 203 | map_destroy(mtd); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | if (sl2312flash_map.virt) { |
|---|
| 207 | iounmap((void *)sl2312flash_map.virt); |
|---|
| 208 | sl2312flash_map.virt = 0; |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | char chrtohex(char c) |
|---|
| 213 | { |
|---|
| 214 | char val; |
|---|
| 215 | if ((c >= '0') && (c <= '9')) |
|---|
| 216 | { |
|---|
| 217 | val = c - '0'; |
|---|
| 218 | return val; |
|---|
| 219 | } |
|---|
| 220 | else if ((c >= 'a') && (c <= 'f')) |
|---|
| 221 | { |
|---|
| 222 | val = 10 + (c - 'a'); |
|---|
| 223 | return val; |
|---|
| 224 | } |
|---|
| 225 | else if ((c >= 'A') && (c <= 'F')) |
|---|
| 226 | { |
|---|
| 227 | val = 10 + (c - 'A'); |
|---|
| 228 | return val; |
|---|
| 229 | } |
|---|
| 230 | printk("<1>Error number\n"); |
|---|
| 231 | return 0; |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | |
|---|
| 235 | int get_vlaninfo(vlaninfo* vlan) |
|---|
| 236 | { |
|---|
| 237 | vctl_mheader head; |
|---|
| 238 | vctl_entry entry; |
|---|
| 239 | struct mtd_info *mymtd=NULL; |
|---|
| 240 | int i, j, loc = 0; |
|---|
| 241 | char *payload=0, *tmp1, *tmp2, tmp3[9]; |
|---|
| 242 | size_t retlen; |
|---|
| 243 | |
|---|
| 244 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 245 | sl2312flash_enable_parallel_flash(); |
|---|
| 246 | #endif |
|---|
| 247 | for(i=0;i<MAX_MTD_DEVICES;i++) |
|---|
| 248 | { |
|---|
| 249 | mymtd=get_mtd_device(NULL,i); |
|---|
| 250 | // printk("mymtd->name: %s\n", mymtd->name); |
|---|
| 251 | if(mymtd && !strcmp(mymtd->name,"VCTL")) |
|---|
| 252 | { |
|---|
| 253 | // printk("%s\n", mymtd->name); |
|---|
| 254 | break; |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | if( i >= MAX_MTD_DEVICES) |
|---|
| 258 | { |
|---|
| 259 | printk("Can't find version control\n"); |
|---|
| 260 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 261 | sl2312flash_disable_parallel_flash(); |
|---|
| 262 | #endif |
|---|
| 263 | return 0; |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | if (!mymtd | !mymtd->read) |
|---|
| 267 | { |
|---|
| 268 | printk("<1>Can't read Version Configuration\n"); |
|---|
| 269 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 270 | sl2312flash_disable_parallel_flash(); |
|---|
| 271 | #endif |
|---|
| 272 | return 0; |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | mymtd->read(mymtd, 0, VCTL_HEAD_SIZE, &retlen, (u_char*)&head); |
|---|
| 276 | // printk("entry header: %c%c%c%c\n", head.header[0], head.header[1], head.header[2], head.header[3]); |
|---|
| 277 | // printk("entry number: %x\n", head.entry_num); |
|---|
| 278 | if ( strncmp(head.header, "FLFM", 4) ) |
|---|
| 279 | { |
|---|
| 280 | printk("VCTL is a erase block\n"); |
|---|
| 281 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 282 | sl2312flash_disable_parallel_flash(); |
|---|
| 283 | #endif |
|---|
| 284 | return 0; |
|---|
| 285 | } |
|---|
| 286 | loc += retlen; |
|---|
| 287 | for (i = 0; i < head.entry_num; i++) |
|---|
| 288 | { |
|---|
| 289 | mymtd->read(mymtd, loc, VCTL_ENTRY_LEN, &retlen, (u_char*)&entry); |
|---|
| 290 | // printk("type: %x\n", entry.type); |
|---|
| 291 | // printk("size: %x\n", entry.size); |
|---|
| 292 | strncpy(tmp3, entry.header, 4); |
|---|
| 293 | if (entry.type == VCT_VLAN) |
|---|
| 294 | { |
|---|
| 295 | for (j = 0; j < 6 ; j++) |
|---|
| 296 | { |
|---|
| 297 | vlan[0].mac[j] = 0; |
|---|
| 298 | vlan[1].mac[j] = 0; |
|---|
| 299 | } |
|---|
| 300 | vlan[0].vlanid = 1; |
|---|
| 301 | vlan[1].vlanid = 2; |
|---|
| 302 | vlan[0].vlanmap = 0x7F; |
|---|
| 303 | vlan[1].vlanmap = 0x80; |
|---|
| 304 | |
|---|
| 305 | payload = (char *)kmalloc(entry.size - VCTL_ENTRY_LEN, GFP_KERNEL); |
|---|
| 306 | loc += VCTL_ENTRY_LEN; |
|---|
| 307 | mymtd->read(mymtd, loc, entry.size - VCTL_ENTRY_LEN, &retlen, payload); |
|---|
| 308 | // printk("%s\n", payload); |
|---|
| 309 | tmp1 = strstr(payload, "MAC1:"); |
|---|
| 310 | tmp2 = strstr(payload, "MAC2:"); |
|---|
| 311 | if(!tmp1||!tmp2){ |
|---|
| 312 | kfree(payload); |
|---|
| 313 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 314 | sl2312flash_disable_parallel_flash(); |
|---|
| 315 | #endif |
|---|
| 316 | printk("Error VCTL format!!\n"); |
|---|
| 317 | return 0; |
|---|
| 318 | } |
|---|
| 319 | tmp1 += 7; |
|---|
| 320 | tmp2 += 7; |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | for (j = 0; j < 6; j++) |
|---|
| 324 | { |
|---|
| 325 | vlan[0].mac[j] = chrtohex(tmp1[2*j])*16 + chrtohex(tmp1[(2*j)+1]); |
|---|
| 326 | vlan[1].mac[j] = chrtohex(tmp2[2*j])*16 + chrtohex(tmp2[(2*j)+1]); |
|---|
| 327 | } |
|---|
| 328 | tmp1 = strstr(payload, "ID1:"); |
|---|
| 329 | tmp2 = strstr(payload, "ID2:"); |
|---|
| 330 | tmp1 += 4; |
|---|
| 331 | tmp2 += 4; |
|---|
| 332 | vlan[0].vlanid = tmp1[0] - '0'; |
|---|
| 333 | vlan[1].vlanid = tmp2[0] - '0'; |
|---|
| 334 | tmp1 = strstr(payload, "MAP1:"); |
|---|
| 335 | tmp2 = strstr(payload, "MAP2:"); |
|---|
| 336 | tmp1 += 7; |
|---|
| 337 | tmp2 += 7; |
|---|
| 338 | vlan[0].vlanmap = chrtohex(tmp1[0]) * 16 + chrtohex(tmp1[1]); |
|---|
| 339 | vlan[1].vlanmap = chrtohex(tmp2[0]) * 16 + chrtohex(tmp2[1]); |
|---|
| 340 | // printk("Vlan1 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[0].vlanid, vlan[0].vlanmap, vlan[0].mac[0], vlan[0].mac[1], vlan[0].mac[2], vlan[0].mac[3], vlan[0].mac[4], vlan[0].mac[5]); |
|---|
| 341 | // printk("Vlan2 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[1].vlanid, vlan[1].vlanmap, vlan[1].mac[0], vlan[1].mac[1], vlan[1].mac[2], vlan[1].mac[3], vlan[1].mac[4], vlan[1].mac[5]); |
|---|
| 342 | break; |
|---|
| 343 | } |
|---|
| 344 | loc += entry.size; |
|---|
| 345 | } |
|---|
| 346 | if ( entry.type == VCT_VLAN ) |
|---|
| 347 | { |
|---|
| 348 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 349 | sl2312flash_disable_parallel_flash(); |
|---|
| 350 | #endif |
|---|
| 351 | kfree(payload); |
|---|
| 352 | return 1; |
|---|
| 353 | } |
|---|
| 354 | if (i >= head.entry_num) |
|---|
| 355 | printk("Can't find vlan information\n"); |
|---|
| 356 | #ifdef CONFIG_SL2312_SHARE_PIN |
|---|
| 357 | sl2312flash_disable_parallel_flash(); |
|---|
| 358 | #endif |
|---|
| 359 | return 0; |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | EXPORT_SYMBOL(get_vlaninfo); |
|---|
| 363 | |
|---|
| 364 | |
|---|
| 365 | module_init(sl2312flash_init); |
|---|
| 366 | module_exit(sl2312flash_exit); |
|---|
| 367 | |
|---|
| 368 | MODULE_AUTHOR("Storlink Ltd"); |
|---|
| 369 | MODULE_DESCRIPTION("CFI map driver"); |
|---|
| 370 | MODULE_LICENSE("GPL"); |
|---|