/* * ---------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ---------------------------------------------------------------------------- * */ /************************************************************************** * Included Files **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #define DO_MTD #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_FUSIV_VX185 #include #include #include #include #endif /*--- #define FUSIV_MTD_DEBUG ---*/ #if defined(FUSIV_MTD_DEBUG) #define DEBUG_MTD(fmt, arg...) pr_err("[%d:%s/%d] " fmt "\n", smp_processor_id(), __func__, __LINE__, ##arg); #else #define DEBUG_MTD(fmt, arg...) #endif #if defined(CONFIG_FUSIV_VX185) #elif defined(CONFIG_FUSIV_VX180) #endif /*-------------------------------------------------------------------------------------*\ * Zuerst wird das JFFS2 gesucht, dann das Squash-FS! \*-------------------------------------------------------------------------------------*/ static const char *probes[] = { "find_squashfs", NULL }; void fusiv_ram_mtd_set_rw(struct device *pdev, int); extern int __init root_dev_setup(char *line); static unsigned int flash_erase_block_size = (1U << 16); #if defined(CONFIG_FUSIV_VX180) static unsigned int fusiv_nor_flashsize; extern unsigned long g_fusiv_nor_flash_start; extern unsigned long g_fusiv_nor_flash_size; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _nmi_vector_location { unsigned int firmware_length; unsigned int vector_gap; char vector_id[32]; }; struct _nmi_vector_location *nmi_vector_location = (struct _nmi_vector_location *) 0xbfc00040; extern void set_nmi_vetor_gap(unsigned int start, unsigned int firmware_size, unsigned int gap_size); #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum _flash_map_enum { MAP_UNKNOWN, MAP_RAM, MAP_NOR_FLASH, MAP_NAND_FLASH, MAP_SPI_FLASH }; #if defined(CONFIG_FUSIV_VX180) #define FUSIV_MTD_NAND_PARTS 1 #define FUSIV_MTD_NOR_PARTS 6 #define FUSIV_MTD_JFFS2_MIN_SIZE 6 #define FUSIV_MTD_JFFS2_MAX_SIZE 16 /*------------------------------------------------------------------------------------------*\ * NOR \*------------------------------------------------------------------------------------------*/ struct mtd_partition fusiv_nor_partitions[FUSIV_MTD_NOR_PARTS]; static struct resource fusiv_nor_resource[] ={ { .start = 0, .end = 0 + (128), /* 128 MB */ .flags = IORESOURCE_MEM, .parent = &iomem_resource }, }; static struct physmap_flash_data fusiv_nor_data ={ .width = 2, .parts = fusiv_nor_partitions, .nr_parts = ARRAY_SIZE(fusiv_nor_partitions), .probes = probes }; struct platform_device fusiv_nor_device[] ={ { .name = "physmap-flash", .id = -1, .dev ={ .platform_data = &fusiv_nor_data, }, .num_resources = 1, .resource = &fusiv_nor_resource[0], } }; /*------------------------------------------------------------------------------------------*\ * NAND \*------------------------------------------------------------------------------------------*/ struct mtd_partition fusiv_nand_partitions[FUSIV_MTD_NAND_PARTS]; static struct resource fusiv_nand_resource[] ={ [0] ={ .start = CONFIG_MTD_NAND_DIRECT_AVM_DATA, .end = CONFIG_MTD_NAND_DIRECT_AVM_DATA + (16<<20)-1, .flags = IORESOURCE_MEM, }, #if defined(CONFIG_MTD_NAND_DIRECT_AVM_ADDR) [1] ={ .start = CONFIG_MTD_NAND_DIRECT_AVM_CONTROL, .end = CONFIG_MTD_NAND_DIRECT_AVM_CONTROL + (16 << 20) - 1, .flags = IORESOURCE_MEM, }, #endif /*--- #if defined(CONFIG_MTD_NAND_DIRECT_AVM_ADDR) ---*/ }; static struct direct_avm_nand_platdata direct_avm_nand_platform_data ={ #if defined(CONFIG_MTD_NAND_DIRECT_AVM_ADDR) .addr_nce = (1 << 16), .addr_nwp = (1 << 18), .addr_cle = (1 << 17), .addr_ale = (1 << 15), #endif /*--- #if defined(CONFIG_MTD_NAND_DIRECT_AVM_ADDR) ---*/ #if defined(CONFIG_MTD_NAND_DIRECT_AVM_GPIO) || defined(CONFIG_MTD_NAND_COMPLETE_AVM) .gpio_rdy0 = CONFIG_MTD_NAND_DIRECT_AVM_READY0, .gpio_rdy1 = CONFIG_MTD_NAND_DIRECT_AVM_READY1, .gpio_nwp = CONFIG_MTD_NAND_DIRECT_AVM_NWP, .gpio_nce0 = CONFIG_MTD_NAND_DIRECT_AVM_NCE0, .gpio_nce1 = CONFIG_MTD_NAND_DIRECT_AVM_NCE1, .gpio_cle = CONFIG_MTD_NAND_DIRECT_AVM_CLE, .gpio_ale = CONFIG_MTD_NAND_DIRECT_AVM_ALE, #endif /*--- #if defined(CONFIG_MTD_NAND_DIRECT_AVM_GPIO) || defined(CONFIG_MTD_NAND_COMPLETE_AVM) ---*/ /*--- .adjust_parts = direct_avm_nand_adjust_partitions, ---*//*--- => NOP aus platform.c ---*/ .parts = fusiv_nand_partitions, .num_parts = ARRAY_SIZE(fusiv_nand_partitions), .options = 0, /*--- NAND_USE_FLASH_BBT | NAND_BBT_SCANALLPAGES | NAND_BBT_SCANEMPTY, ---*/ .chip_delay = 0 }; struct platform_device fusiv_nand_device[] ={ { .name = "direct-avm-nand", .id = -1, .dev ={ .platform_data = &direct_avm_nand_platform_data }, .num_resources = ARRAY_SIZE(fusiv_nand_resource), .resource = &fusiv_nand_resource[0], } }; #elif defined(CONFIG_FUSIV_VX185) #define FUSIV_MTD_NAND_PARTS 6 #define FUSIV_MTD_SPI_PARTS 3 struct mtd_partition fusiv_nand_partitions[FUSIV_MTD_NAND_PARTS]; static struct resource fusiv_nand_resources[] = { [0] = { .start = NFC_BASEADDR + NFC_DATA, .end = NFC_BASEADDR + NFC_SECT7_SYNDROME78, .flags = IORESOURCE_MEM, }, [1] = { .start = NAND_FLASH_INT, .end = NAND_FLASH_INT, .flags = IORESOURCE_IRQ, }, }; static struct fusiv_nand_platform nand_platform_data = { .partitions = fusiv_nand_partitions, .nr_partitions = ARRAY_SIZE(fusiv_nand_partitions), }; static struct platform_device fusiv_nand_device[] = { { .name = "fusiv-nand", .id = 0, .dev = { .platform_data = &nand_platform_data, }, .num_resources = ARRAY_SIZE(fusiv_nand_resources), .resource = fusiv_nand_resources, } }; /*------------------------------------------------------------------------------------------*\ * SPI \*------------------------------------------------------------------------------------------*/ struct mtd_partition fusiv_spi_partitions[FUSIV_MTD_SPI_PARTS]; static struct vx185_snor_platform vx185_snor_data = { .partitions = fusiv_spi_partitions, .nr_partitions = ARRAY_SIZE(fusiv_spi_partitions), }; struct platform_device fusiv_spi_device[] = { { .name = "vx185_snor", .id = -1, .dev = { .platform_data = &vx185_snor_data, }, } }; #if defined(CONFIG_TFFS_PANIC_LOG) struct mtd_info *fusiv_tffs_mtd[2]; EXPORT_SYMBOL(fusiv_tffs_mtd); #endif #endif // #if defined(FUSIV_VX180) #elif defined(CONFIG_FUSIV_VX185) /*------------------------------------------------------------------------------------------*\ * RAM \*------------------------------------------------------------------------------------------*/ static struct mtd_partition fusiv_ram_partitions[2]; static struct resource fusiv_ram_resource[] = { { /* für ins RAM geladenes Filesystem */ .start = 0, .end = 0 + (32 << 20), .flags = IORESOURCE_MEM, } }; static struct platdata_mtd_ram fusiv_ram_data = { .mapname = "ram-filesystem", .bankwidth = 4, .partitions = fusiv_ram_partitions, .nr_partitions = 0, // wird im setup richtig gesetzt .set_rw = fusiv_ram_mtd_set_rw, .probes = probes }; struct platform_device fusiv_ram_device = { .name = "mtd-ram", .id = -1, .dev = { .platform_data = &fusiv_ram_data, }, .num_resources = 1, .resource = &fusiv_ram_resource[0], }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int fusiv_squashfs_parser_function(struct mtd_info *mtd, struct mtd_partition **p_mtd_pat, unsigned long param) { enum _flash_map_enum maptype; struct mtd_partition *kernel_part, *fs_part; size_t readlen; loff_t curr_offset; int count; uint32_t magic; #if defined(FUSIV_MTD_DEBUG) pr_err("[%s] mtd_info->name %s mtd_info->index %u param=%lu p_mtd_pat=0x%p\n", __func__, mtd->name, mtd->index, param, p_mtd_pat); #endif count = 0; maptype = MAP_UNKNOWN; kernel_part = NULL; fs_part = NULL; if(!strcmp(mtd->name, "ram-filesystem") || !strcmp(mtd->name, "mtd-ram")){ maptype = MAP_RAM; }else if(!strcmp(mtd->name, "physmap-flash")){ maptype = MAP_NOR_FLASH; flash_erase_block_size = mtd->erasesize; }else if(!strcmp(mtd->name, "mtd-spi_nor")){ maptype = MAP_SPI_FLASH; flash_erase_block_size = mtd->erasesize; }else{ pr_warning("[fusiv_squashfs_parser_function] with unknown mtd type %s\n", mtd->name); goto done; } if(p_mtd_pat == NULL){ pr_err("[%s] Invalid partition table pointer.\n", __func__); goto done; } if(*p_mtd_pat){ printk("[fusiv_squashfs_parser_function] (*p_mtd_pat)[0].name %s\n", (*p_mtd_pat)[0].name); } switch(maptype){ #if defined(CONFIG_FUSIV_VX180) case MAP_NOR_FLASH: if(*p_mtd_pat == NULL){ *p_mtd_pat = fusiv_nor_partitions; } count = ARRAY_SIZE(fusiv_nor_partitions); break; #endif case MAP_RAM: if(*p_mtd_pat == NULL ){ *p_mtd_pat = fusiv_ram_partitions; } // we can only be sure to have the filesystem. count = 1; break; #if defined(CONFIG_FUSIV_VX185) case MAP_SPI_FLASH: if(*p_mtd_pat == NULL ){ *p_mtd_pat = fusiv_spi_partitions; } count = ARRAY_SIZE(fusiv_spi_partitions); goto done; #endif default: pr_err("[%s] unknown map type for mtd %s\n", __func__, mtd->name); goto done; } #if defined(FUSIV_MTD_DEBUG) printk("[fusiv_squashfs_parser_function] try partition %s (offset 0x%x len %u blocksize=%x)\n", (*p_mtd_pat)[0].name, (*p_mtd_pat)[0].offset, (*p_mtd_pat)[0].size, mtd->erasesize); #endif /* * we can get here only for RAM and NOR MTDs. In the former case the MTD * might contain a combined Kernel+FS image and has to be split up. * This is always the case for a NOR MTD, which might also contain a jffs2 */ kernel_part = &((*p_mtd_pat)[1]); fs_part = &((*p_mtd_pat)[0]); curr_offset = 0; while(curr_offset < kernel_part->size){ mtd->read(mtd, kernel_part->offset + curr_offset, sizeof(magic), &readlen, (u_char*) &magic); /*--- printk("[fusiv_squashfs_parser_function] read %u bytes, magic = 0x%08x index %u pos 0x%x\n", readlen, magic, mtd->index, (unsigned int)pos); ---*/ if(magic == 0x73717368){ /*-------------------------------------------------------------------------------------*\ * * +---+---------------------+-----------------------+--------------------+ * | | Kernel | SquashFS | JFFS2 | * +---+---------------------+-----------------------+--------------------+ * A ^_pos E * * Zu Beginn ist das Layout obiges: * start_offset = A * MTD1 mit Kernel reicht von A bis E * MTD5 für JFFS2 kann gesetzt sein, wenn JFFS2 Parser vorher schon was gefunden hat * * Wenn SquashFS gefunden wird, wird MTD1 auf den Kernel verkleinert, * MTD0 für das FS wird von pos bis E angelegt * Wenn noch kein MTD5 mit JFFS2 existiert wird dieses innerhalb von MTD0 angelegt * \*-------------------------------------------------------------------------------------*/ fs_part->offset += curr_offset; fs_part->size -= curr_offset; kernel_part->size = curr_offset; printk("[%s] magic found @offset 0x%llx\n", __func__, curr_offset); if(maptype == MAP_NOR_FLASH){ // FIXME: why not name them right at setup?! kernel_part->name = "kernel"; fs_part->name = "rootfs"; } else if(maptype == MAP_RAM && curr_offset > 0){ ++count; } break; } curr_offset += 256; } // TODO: jffs stuff done: return count; } #if 0 #define JFFS_NODES ( JFFS2_NODETYPE_DIRENT | JFFS2_NODETYPE_INODE | JFFS2_NODETYPE_CLEANMARKER | JFFS2_NODETYPE_PADDING | JFFS2_NODETYPE_SUMMARY | JFFS2_NODETYPE_XATTR | JFFS2_NODETYPE_XREF) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int fusiv_jffs2_parser_function(struct mtd_info *mtd, struct mtd_partition **p_mtd_pat, unsigned long param) { enum _flash_map_enum maptype = MAP_UNKNOWN; unsigned int count = 1; DEBUG_MTD("mtd_info->name %s mtd_info->index %u param=%lu p_mtd_pat=0x%p\n", mtd->name, mtd->index, param, p_mtd_pat); if(!strcmp(mtd->name, "ram-filesystem")){ maptype = MAP_RAM; }else if(!strcmp(mtd->name, "physmap-flash")){ maptype = MAP_NOR_FLASH; }else{ pr_warning("[%s] with unknown mtd type %s\n", __func__, mtd->name); return 0; } if(p_mtd_pat){ unsigned int magic = 0, readlen = 0; loff_t pos; if(*p_mtd_pat) printk("[%s] *p_mtd_pat->name %s\n", __func__, (*p_mtd_pat)->name); switch(maptype){ case MAP_NOR_FLASH: if(*p_mtd_pat == NULL ){ *p_mtd_pat = fusiv_nor_partitions; } break; case MAP_RAM: count = 2; if(*p_mtd_pat == NULL ){ *p_mtd_pat = fusiv_ram_partitions; } //return 0; /* nicht im RAM suchen */ break; default: break; } #if defined(FUSIV_MTD_DEBUG) printk("[%s] try partition %s (offset 0x%x len %u)\n", __func__, (*p_mtd_pat)[count].name, (*p_mtd_pat)[count].offset, (*p_mtd_pat)[count].size); #endif pos = (*p_mtd_pat)[count].offset; while(pos < (*p_mtd_pat)[count].offset + (*p_mtd_pat)[count].size){ mtd->read(mtd, (loff_t) pos, sizeof(unsigned int), &readlen, (u_char*) &magic); printk("[%s] read %u bytes, magic = 0x%08x index %u pos 0x%llx\n", __func__, readlen, magic, mtd->index, pos); #ifdef __LITTLE_ENDIAN if ((((magic >> 16) & ~JFFS_NODES) == 0) && ((magic & 0xFFFF) == JFFS2_MAGIC_BITMASK)){ #else if(((magic >> 16) == JFFS2_MAGIC_BITMASK) && (((magic & 0xFFFF) & ~JFFS_NODES)== 0)){ #endif switch(maptype){ case MAP_NOR_FLASH: (*p_mtd_pat)[5].size = (*p_mtd_pat)[1].offset + (*p_mtd_pat)[1].size - pos; (*p_mtd_pat)[5].offset = pos; (*p_mtd_pat)[5].name = "jffs2"; /*--- printk("mtd1: size %d\n", (*p_mtd_pat)[1].size); ---*/ printk("[%s] magic %04x found @pos 0x%x, size %d\n", __func__, magic, (unsigned int) pos, (*p_mtd_pat)[5].size); break; case MAP_RAM: (*p_mtd_pat)[2].size = (*p_mtd_pat)[count].offset + (*p_mtd_pat)[count].size - pos; (*p_mtd_pat)[2].offset = pos; (*p_mtd_pat)[2].name = "ram-jffs2"; /*--- printk("mtd1: size %d\n", (*p_mtd_pat)[1].size); ---*/ printk("[%s] magic %04x found @pos 0x%x, size %d\n", __func__, magic, (unsigned int) pos, (*p_mtd_pat)[2].size); break; default: break; } return 0; } pos += mtd->erasesize; } } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct mtd_part_parser fusiv_jffs2_parser = { .name = "find_jffs2", .parse_fn = fusiv_jffs2_parser_function }; #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct mtd_part_parser fusiv_squashfs_parser = { .name = "find_squashfs", .parse_fn = fusiv_squashfs_parser_function }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct platform_device *fusiv_platform_devices[20]; unsigned int fusiv_platform_devices_count = 0; void add_to_platform_device_list(struct platform_device *device) { pr_info("[FUSIV] add %s to the platform device list\n", device->name); fusiv_platform_devices[fusiv_platform_devices_count++] = device; } /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ void fusiv_init_platform_devices(void) { pr_info("[FUSIV] register %d platform device(s)\n", fusiv_platform_devices_count); platform_add_devices(fusiv_platform_devices, fusiv_platform_devices_count); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static inline unsigned int get_flash_base(unsigned int flash_size) { return 0x48000000; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void fusiv_ram_mtd_set_rw(struct device *pdev, int mode) { if(mode == PLATRAM_RO){ DEBUG_MTD("PLATRAM_RO"); }else if(mode == PLATRAM_RW){ DEBUG_MTD("PLATRAM_RW"); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int get_erase_block_size_on_ram_device(struct mtd_info *mtd) { unsigned int readlen = 0; loff_t pos = 0; unsigned int value1, value2; mtd->read(mtd, pos, sizeof(unsigned int), &readlen, (u_char*) &value1); if(readlen != sizeof(unsigned int)) return 0; /*--- DEBUG_MTD("name=%s pos=0x%x value=0x%x" , mtd->name, pos, value1); ---*/ pos += 0x10000ULL; mtd->read(mtd, pos, sizeof(unsigned int), &readlen, (u_char*) &value2); if(readlen != sizeof(unsigned int)) return 0; /*--- DEBUG_MTD("name=%s pos=0x%x value2=0x%x" , mtd->name, pos, value2); ---*/ if(value1 == value2){ pos += 0x10000ULL; mtd->read(mtd, pos, sizeof(unsigned int), &readlen, (u_char*) &value2); if(readlen != sizeof(unsigned int)) return 0; /*--- DEBUG_MTD("name=%s pos=0x%x value2=0x%x (check)" , mtd->name, pos, value2); ---*/ if(value1 == value2){ DEBUG_MTD("eraseblocksize=0x10000"); return 0x10000; } return 0; } pos += 0x10000ULL; mtd->read(mtd, pos, sizeof(unsigned int), &readlen, (u_char*) &value2); if(readlen != sizeof(unsigned int)) return 0; DEBUG_MTD("name=%s pos=0x%Lx value2=0x%x", mtd->name, pos, value2); if(value1 == value2){ DEBUG_MTD("eraseblocksize=0x20000"); return 0x20000; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int get_partition_index(struct mtd_info *mtd) { extern struct mtd_info *mtd_table[MAX_MTD_DEVICES]; unsigned int i; for(i = 0; i < MAX_MTD_DEVICES; i++){ if(mtd_table[i] == mtd){ return i; } } return -1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ extern struct mtd_info *mtd_table[MAX_MTD_DEVICES]; extern int tffs_mtd[2]; extern int tffs_mtd_offset[2]; static int found_rootfs_ram = 0; char *str_rootfs[] = { "rootfs_ram", "rootfs", "filesystem" }; struct mtd_info *fusiv_urlader_mtd; void fusiv_mtd_add_notifier(struct mtd_info *mtd) { int i, index; if(!mtd->name){ DEBUG_MTD("Leeres MTD übergeben!"); return; } DEBUG_MTD("name %s", mtd->name); for(i = 0; i < sizeof(str_rootfs) / sizeof(char*); i++){ if(!strcmp(mtd->name, str_rootfs[i])){ DEBUG_MTD("found %s", mtd->name); if(found_rootfs_ram) /*--- we found a rootfs in RAM and use only this ---*/ return; if(!strcmp(mtd->name, str_rootfs[0])) found_rootfs_ram = 1; /*--- signal that we found a rootfs in RAM ---*/ index = get_partition_index(mtd); DEBUG_MTD("use %s", mtd->name); if(index >= 0){ static char root_device[64]; sprintf(root_device, "/dev/mtdblock%d", index); DEBUG_MTD("root device: %s (%s)", root_device, mtd_table[index]->name); root_dev_setup(root_device); return; }else{ DEBUG_MTD("error: could not find any root device for %s", mtd->name); } } } if(!strcmp(mtd->name, "urlader")){ DEBUG_MTD("set fusiv_urlader_mtd"); fusiv_urlader_mtd = mtd; #if defined(CONFIG_TFFS) }else if(!strcmp(mtd->name, "tffs (1)")){ index = get_partition_index(mtd); if(index >= 0){ #if defined(CONFIG_FUSIV_VX185) && defined(CONFIG_TFFS_PANIC_LOG) fusiv_tffs_mtd[0] = mtd; #endif DEBUG_MTD("tffs (1) on Index %d", index); tffs_mtd[0] = index; } }else if(!strcmp(mtd->name, "tffs (2)")){ index = get_partition_index(mtd); if(index >= 0){ #if defined(CONFIG_FUSIV_VX185) && defined(CONFIG_TFFS_PANIC_LOG) fusiv_tffs_mtd[1] = mtd; #endif DEBUG_MTD("tffs (2) on Index %d", index); tffs_mtd[1] = index; } #endif /*--- #if defined(CONFIG_TFFS) ---*/ }else{ DEBUG_MTD("skip %s", mtd->name); } } void fusiv_mtd_rm_notifier(struct mtd_info *mtd) { DEBUG_MTD("ignore %s", mtd->name); } struct mtd_notifier fusiv_mtd_notifier = { .add = fusiv_mtd_add_notifier, .remove = fusiv_mtd_rm_notifier }; #if defined(CONFIG_FUSIV_VX180) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void find_nmi_vector(void) { unsigned int len; if(strcmp(nmi_vector_location->vector_id, "NMI Boot Vector")){ pr_err("[%s] no nmi vector found\n", __FUNCTION__); return; } len = (nmi_vector_location->firmware_length + flash_erase_block_size) & ~(flash_erase_block_size - 1); pr_err("[%s] nmi vector found. Firmware length 0x%x bytes (erase block align 0x%x) vector gap size 0x%x bytes.\n", __FUNCTION__, nmi_vector_location->firmware_length, len, nmi_vector_location->vector_gap); len += fusiv_nor_partitions[2].size; /*--- urlader size ---*/ pr_err("[%s] add '%s' size 0x%x to length\n", __FUNCTION__, fusiv_nor_partitions[2].name, fusiv_nor_partitions[2].size); set_nmi_vetor_gap(0xbfc00000, len, nmi_vector_location->vector_gap); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void find_nmi_vector_gap(unsigned int base, unsigned int end) { unsigned int len; struct _nmi_vector_location *first_loc = (struct _nmi_vector_location *) (base + 0x40); struct _nmi_vector_location *last_loc = (struct _nmi_vector_location *) (base + 0xbe0040); while((unsigned long) first_loc <= (unsigned long) last_loc){ /*--- if(((unsigned long)first_loc > 0x87d95a00UL) && ((unsigned long)first_loc < 0x87d96000UL)) ---*/ /*--- pr_err("[NMI] %p => %10pB\n", first_loc, first_loc); ---*/ if(!strcmp(first_loc->vector_id, "NMI Boot Vector")){ len = end - ((unsigned int) first_loc - 0x40) + first_loc->vector_gap; pr_err("[%s] nmi vector found. Firmware length 0x%x bytes (move length 0x%x) vector gap size 0x%x bytes.\n", __FUNCTION__, first_loc->firmware_length, len, first_loc->vector_gap); memmove((void *) ((unsigned int) first_loc - 0x40), (void *) ((unsigned int) first_loc + first_loc->vector_gap - 0x40), len); return; } first_loc = (struct _nmi_vector_location *) ((unsigned int) first_loc + 256); } pr_err("[%s] no nmi vector found at base 0x%x\n", __FUNCTION__, base); } #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int __init fusiv_mtd_init(void) { register_mtd_user(&fusiv_mtd_notifier); register_mtd_parser(&fusiv_squashfs_parser); fusiv_init_platform_devices(); #if defined(CONFIG_FUSIV_VX180) find_nmi_vector(); #endif return 0; } subsys_initcall(fusiv_mtd_init); /*------------------------------------------------------------------------------------------*\ * Parst die erste Größe in einem Größenangaben String vom Urlader * Format der Größenangaben: xxx_size={,KB,MB} \*------------------------------------------------------------------------------------------*/ unsigned long long parse_mtd_size(char *p) { unsigned long long size; DEBUG_MTD("'%s'", p); if((p[0] == '0') && (p[1] == 'x')){ size = simple_strtoul(p, NULL, 16); }else{ size = simple_strtoul(p, NULL, 10); } p = strchr(p, 'B'); if(p){ /*--- Die Größe enthält mindestens eine KB Angabe ---*/ size *= 1024; if(p[-1] == 'M'){ size *= 1024; } } return size; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int __init mtdram_setup(char *p) { char *start; resource_size_t mem_start, mem_end, size; if(!p){ pr_debug("[%s] Invalid parameter\n", __func__); goto err_out; } start = prom_getenv("linux_fs_start"); if(start && !strcmp(start, "nfs")){ pr_info("dont use RAM filesystem, use NFS\n"); goto err_out; } pr_debug("[%s] mtdram1 %s", __func__, p); mem_start = CPHYSADDR((unsigned int)simple_strtoul(p, NULL, 16)); p = strchr(p, ','); if(p){ p++; mem_end = CPHYSADDR((unsigned int)simple_strtoul(p, NULL, 16)); }else{ mem_start = 0; } if(mem_start == 0 || mem_end == 0){ pr_err("[%s] Invalid memory addresses\n", __func__); goto err_out; } fusiv_ram_resource[0].start = mem_start; fusiv_ram_resource[0].end = mem_end; fusiv_ram_resource[0].flags = IORESOURCE_MEM; size = mem_end - mem_start + 1; pr_debug("mtdram1 0x%08x - 0x%08x", fusiv_ram_resource[0].start, fusiv_ram_resource[0].end); fusiv_ram_partitions[0].name = "rootfs_ram"; fusiv_ram_partitions[0].offset = 0; fusiv_ram_partitions[0].size = size; fusiv_ram_partitions[0].mask_flags = MTD_ROM; fusiv_ram_partitions[1].name = "kernel_ram"; fusiv_ram_partitions[1].offset = 0; fusiv_ram_partitions[1].size = size; fusiv_ram_partitions[1].mask_flags = MTD_ROM; add_to_platform_device_list(&fusiv_ram_device); #if defined(CONFIG_FUSIV_VX180) find_nmi_vector_gap(fusiv_ram_resource[0].start | 0x80000000, fusiv_ram_resource[0].end | 0x80000000); #endif err_out: return 0; } __setup("mtdram1=", mtdram_setup); #if defined(CONFIG_FUSIV_VX180) /*------------------------------------------------------------------------------------------*\ * NAND Parameter parsen \*------------------------------------------------------------------------------------------*/ static int __init mtdnand_setup(char *p){ unsigned long long flashsize_nand = parse_mtd_size(p); fusiv_nand_partitions[0].name = (char *)"nand-filesystem"; fusiv_nand_partitions[0].size = flashsize_nand; fusiv_nand_partitions[0].offset = 0; DEBUG_MTD("nand_size = 0x%llx" , flashsize_nand); add_to_platform_device_list(&fusiv_nand_device[0]); return 0; } __setup("nand_size=", mtdnand_setup); #elif defined(CONFIG_FUSIV_VX185) /*------------------------------------------------------------------------------------------*\ * NAND Parameter parsen \*------------------------------------------------------------------------------------------*/ static int __init mtdnand_setup(char *p) { unsigned long mtd_start, mtd_end; unsigned long long fusiv_flashsize_nand; char *_start; unsigned int config_size = 0, kernel_size = 0, filesystem_size = 0, current_offset = 0; unsigned int skip_size = 0; int i; static unsigned int init_done = 0; if(init_done) return 0; if(!p) return 0; _start = prom_getenv("linux_fs_start"); if(!_start) _start = "0"; /*--- default setzen ---*/ switch(_start[0]){ case '0': fusiv_nand_partitions[0].name = (char *) "kernel"; fusiv_nand_partitions[1].name = (char *) "filesystem"; fusiv_nand_partitions[2].name = (char *) "reserved-kernel"; fusiv_nand_partitions[3].name = (char *) "reserved-filesystem"; break; case '1': fusiv_nand_partitions[0].name = (char *) "reserved-kernel"; fusiv_nand_partitions[1].name = (char *) "reserved-filesystem"; fusiv_nand_partitions[2].name = (char *) "kernel"; fusiv_nand_partitions[3].name = (char *) "filesystem"; break; default: fusiv_nand_partitions[0].name = (char *) "kernel (1)"; fusiv_nand_partitions[1].name = (char *) "filesystem (1)"; fusiv_nand_partitions[2].name = (char *) "kernel (2)"; fusiv_nand_partitions[3].name = (char *) "filesystem (2)"; break; } fusiv_nand_partitions[4].name = (char *) "config"; fusiv_nand_partitions[5].name = (char *) "nand-filesystem"; fusiv_flashsize_nand = parse_mtd_size(p); DEBUG_MTD("nand_size = 0x%llx", fusiv_flashsize_nand); pr_err("[NAND] nand_size = 0x%llx\n", fusiv_flashsize_nand); if(fusiv_flashsize_nand == 0){ return 0; } /*--------------------------------------------------------------------------------------*\ * Größen ermitteln \*--------------------------------------------------------------------------------------*/ p = prom_getenv("mtd1"); if(p){ DEBUG_MTD("mtd1 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); kernel_size = mtd_end - mtd_start; } } p = prom_getenv("mtd0"); if(p){ DEBUG_MTD("mtd0 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); filesystem_size = mtd_end - mtd_start; } } p = prom_getenv("mtd5"); if(p){ DEBUG_MTD("mtd5 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); config_size = mtd_end - mtd_start; } } /*--------------------------------------------------------------------------------------*\ * prüfen ob die einzelnen Teile in das Flash passen \*--------------------------------------------------------------------------------------*/ if(filesystem_size * 2 + kernel_size * 2 + config_size + skip_size > fusiv_flashsize_nand){ panic("Filesystem and Kernel dont fit in to NAND device\n"); } /*--------------------------------------------------------------------------------------*\ * Groessen aufsetzen \*--------------------------------------------------------------------------------------*/ fusiv_nand_partitions[0].size = kernel_size; fusiv_nand_partitions[0].offset = current_offset; fusiv_flashsize_nand -= kernel_size; current_offset += kernel_size; fusiv_nand_partitions[1].size = filesystem_size; fusiv_nand_partitions[1].offset = current_offset; fusiv_flashsize_nand -= filesystem_size; current_offset += filesystem_size; fusiv_nand_partitions[2].size = kernel_size; fusiv_nand_partitions[2].offset = current_offset; fusiv_flashsize_nand -= kernel_size; current_offset += kernel_size; fusiv_nand_partitions[3].size = filesystem_size; fusiv_nand_partitions[3].offset = current_offset; fusiv_flashsize_nand -= filesystem_size; current_offset += filesystem_size; if(config_size){ fusiv_nand_partitions[4].size = config_size; fusiv_nand_partitions[4].offset = current_offset; fusiv_flashsize_nand -= config_size; current_offset += config_size; } if(fusiv_flashsize_nand){ fusiv_nand_partitions[5].size = fusiv_flashsize_nand; fusiv_nand_partitions[5].offset = current_offset; } for(i = 0; i <= 5; ++i){ DEBUG_MTD("mtd%d: %08x - %08x", i, fusiv_nand_partitions[i].offset, fusiv_nand_partitions[i].offset + fusiv_nand_partitions[i].size - 1); } add_to_platform_device_list(&fusiv_nand_device[0]); init_done = 1; return 0; } __setup("nand_size=", mtdnand_setup) ; #endif /* CONFIG_FUSIV_VX185 */ #ifdef CONFIG_FUSIV_VX180 extern void tffs_panic_log_register_nor(void); /*------------------------------------------------------------------------------------------*\ * NOR Parameter parsen \*------------------------------------------------------------------------------------------*/ static int __init mtdnor_setup(char *p){ unsigned long flashsize_nor; unsigned long mtd_start, mtd_end; unsigned long flashoffset_nor = 0; if(!p){ return 0; } fusiv_nor_partitions[0].name = (char *)"filesystem"; fusiv_nor_partitions[1].name = (char *)"kernel"; fusiv_nor_partitions[2].name = (char *)"urlader"; fusiv_nor_partitions[3].name = (char *)"tffs (1)"; fusiv_nor_partitions[4].name = (char *)"tffs (2)"; fusiv_nor_partitions[5].name = (char *)"reserved"; /* Nie mit "jffs2" initialisieren! */ /* Die mtds werden vom Userland nach jffs2 gegrept und ggf. beschrieben, daher das * mtd nie jffs2 nennen, solange die Position/Größe noch nicht stimmt. */ flashsize_nor = parse_mtd_size(p); DEBUG_MTD("nor_size = 0x%lx" , flashsize_nor); /*--------------------------------------------------------------------------------------*\ * Größen ermitteln \*--------------------------------------------------------------------------------------*/ p = prom_getenv("mtd2"); if(p){ DEBUG_MTD("mtd2 = %s", p); mtd_start = (unsigned int)simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int)simple_strtoul(p, NULL, 16); flashoffset_nor = mtd_start; g_fusiv_nor_flash_start = mtd_start; fusiv_nor_partitions[2].size = mtd_end - mtd_start; fusiv_nor_partitions[2].offset = mtd_start - flashoffset_nor; fusiv_nor_resource[0].start = mtd_start & ~0xE0000000; fusiv_nor_resource[0].end = fusiv_nor_resource[0].start + flashsize_nor; } } p = prom_getenv("mtd1"); if(p){ DEBUG_MTD("mtd1 = %s", p); mtd_start = (unsigned int)simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int)simple_strtoul(p, NULL, 16); fusiv_nor_partitions[1].size = mtd_end - mtd_start; fusiv_nor_partitions[1].offset = mtd_start - flashoffset_nor; /*------------------------------------------------------------------------------------------*\ * mtd0 is an afterthought to enable splitting the firmware partition * into kernel and root fs. If it does not exist, default to the same * size and offset as mtd1 and let the partition parser adjust its values * we don't need to parse for mtd0 ! \*------------------------------------------------------------------------------------------*/ fusiv_nor_partitions[0].size = fusiv_nor_partitions[1].size; fusiv_nor_partitions[0].offset = fusiv_nor_partitions[1].offset; } } p = prom_getenv("mtd3"); if(p){ DEBUG_MTD("mtd3 = %s", p); mtd_start = (unsigned int)simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int)simple_strtoul(p, NULL, 16); fusiv_nor_partitions[3].size = mtd_end - mtd_start; fusiv_nor_partitions[3].offset = mtd_start - flashoffset_nor; } } p = prom_getenv("mtd4"); if(p){ DEBUG_MTD("mtd4 = %s", p); mtd_start = (unsigned int)simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int)simple_strtoul(p, NULL, 16); fusiv_nor_partitions[4].size = mtd_end - mtd_start; fusiv_nor_partitions[4].offset = mtd_start - flashoffset_nor; } } p = prom_getenv("mtd5"); if(p){ DEBUG_MTD("mtd5 = %s", p); mtd_start = (unsigned int)simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int)simple_strtoul(p, NULL, 16); fusiv_nor_partitions[5].size = mtd_end - mtd_start; fusiv_nor_partitions[5].offset = mtd_start - flashoffset_nor; } } fusiv_nor_flashsize = flashsize_nor; g_fusiv_nor_flash_size = flashsize_nor; add_to_platform_device_list(&fusiv_nor_device[0]); /*--- MTD-Offsets für Adressierung = MTD-Offset[3/4] - Urlader-Offset ---*/ tffs_mtd_offset[0] = fusiv_nor_partitions[3].offset - fusiv_nor_partitions[2].offset; tffs_mtd_offset[1] = fusiv_nor_partitions[4].offset - fusiv_nor_partitions[2].offset; #if defined(CONFIG_TFFS) && defined(CONFIG_TFFS_PANIC_LOG) tffs_panic_log_register_nor(); #endif return 0; } __setup("nor_size=", mtdnor_setup); #endif #if defined(CONFIG_FUSIV_VX185) /*------------------------------------------------------------------------------------------*\ * SPI Flash Parameter parsen \*------------------------------------------------------------------------------------------*/ static int __init mtdspi_setup(char *p) { unsigned long flashsize_spi, mtd_start, mtd_end; if(!p) return 0; flashsize_spi = (unsigned long) parse_mtd_size(p); DEBUG_MTD("sflash_size = 0x%lx", flashsize_spi); p = prom_getenv("mtd2"); if(p){ DEBUG_MTD("mtd2 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); if(mtd_end && (mtd_end - mtd_start <= flashsize_spi)){ fusiv_spi_partitions[0].name = (char*) "urlader"; fusiv_spi_partitions[0].offset = mtd_start; fusiv_spi_partitions[0].size = mtd_end - mtd_start; fusiv_spi_partitions[0].mask_flags = 0; } } } p = prom_getenv("mtd3"); if(p){ DEBUG_MTD("mtd3 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); if(mtd_end && (mtd_end - mtd_start <= flashsize_spi)){ fusiv_spi_partitions[1].name = (char*) "tffs (1)"; fusiv_spi_partitions[1].size = mtd_end - mtd_start; fusiv_spi_partitions[1].offset = mtd_start; fusiv_spi_partitions[1].mask_flags = 0; } } } p = prom_getenv("mtd4"); if(p){ DEBUG_MTD("mtd4 = %s", p); mtd_start = (unsigned int) simple_strtoul(p, NULL, 16); p = strchr(p, ','); if(p){ p++; mtd_end = (unsigned int) simple_strtoul(p, NULL, 16); if(mtd_end && (mtd_end - mtd_start <= flashsize_spi)){ fusiv_spi_partitions[2].name = (char*) "tffs (2)"; fusiv_spi_partitions[2].size = mtd_end - mtd_start; fusiv_spi_partitions[2].offset = mtd_start; fusiv_spi_partitions[2].mask_flags = 0; } } } add_to_platform_device_list(&fusiv_spi_device[0]); #if defined(CONFIG_TFFS) && defined(CONFIG_TFFS_PANIC_LOG) tffs_panic_log_register_spi(); #endif return 0; } __setup("sflash_size=", mtdspi_setup); #endif