--- zzzz-none-000/linux-3.10.107/drivers/mtd/maps/lantiq-flash.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/drivers/mtd/maps/lantiq-flash.c 2021-11-10 11:53:55.000000000 +0000 @@ -24,6 +24,9 @@ #include +#include +#include + /* * The NOR flash is connected to the same external bus unit (EBU) as PCI. * To make PCI work we need to enable the endianness swapping for the address @@ -45,7 +48,6 @@ struct map_info *map; }; -static const char ltq_map_name[] = "ltq_nor"; static const char * const ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL }; static map_word @@ -99,6 +101,7 @@ ltq_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) { +#if 0 unsigned char *f = (unsigned char *)from; unsigned char *t = (unsigned char *)map->virt + to; unsigned long flags; @@ -107,23 +110,113 @@ while (len--) *t++ = *f++; spin_unlock_irqrestore(&ebu_lock, flags); +#else + unsigned short *dest; + unsigned short *source; + unsigned long flags; + + if((unsigned long)to & 0x01) { + printk(KERN_ERR "[%s] unaligned write to 16 Bit device\n", __FUNCTION__); + return; + } + + to = (unsigned long) (to + map->virt); + + spin_lock_irqsave(&ebu_lock, flags); + if((unsigned long)from & 0x01) { + unsigned char *p = (unsigned char *)from; + unsigned short s; + dest = (unsigned short *)to; + while(len) { + s = 0; +#ifdef __BIG_ENDIAN + s |= *p++ << 8; + s |= *p++ & 0xff; +#endif +#ifdef __LITTLE_ENDIAN + s |= *p++ & 0xff; + s |= *p++ << 8; +#endif + if(len == 1) { + *dest = s | 0xff00; + break; + } + *dest++ = s; + len -= 2; + } + spin_unlock_irqrestore(&ebu_lock, flags); + return; + } + dest = (unsigned short *)to; + source = (unsigned short *)from; + + while(len) { + if(len == 1) { + *dest = *source | 0xFF00; + break; + } + *dest++ = *source++; + len -= 2; + } + spin_unlock_irqrestore(&ebu_lock, flags); +#endif +} + +/* Configure EBU */ +static void ltq_mtd_hwinit(struct ltq_mtd *ltq_mtd) { + + unsigned int mask, base, reg; + + mask = fls(ltq_mtd->map->size); + mask -= 13; + mask = ~mask & 0xF; + base = ltq_mtd->res->start >> 12; + + reg = IFX_EBU_ADDSEL0_BASE(base) | IFX_EBU_ADDSEL0_MASK(mask) | IFX_EBU_ADDSEL0_REGEN; + + *IFX_EBU_ADDSEL0 = reg; + + reg = SM(IFX_EBU_BUSCON0_XDM16, IFX_EBU_BUSCON0_XDM) | +#if 0 + IFX_EBU_BUSCON0_ADSWP | /*--- Hardware-Swapping muss in diesem Treiber ausgeschaltet sein, da die Kommando-Adressen explitzit im 2.Bit verXORt werden ---*/ +#endif + SM(IFX_EBU_BUSCON0_ALEC3, IFX_EBU_BUSCON0_ALEC) | + SM(IFX_EBU_BUSCON0_BCGEN_INTEL,IFX_EBU_BUSCON0_BCGEN) | + SM(IFX_EBU_BUSCON0_WAITWRC7, IFX_EBU_BUSCON0_WAITWRC) | + SM(IFX_EBU_BUSCON0_WAITRDC3, IFX_EBU_BUSCON0_WAITRDC) | + SM(IFX_EBU_BUSCON0_HOLDC3, IFX_EBU_BUSCON0_HOLDC) | + SM(IFX_EBU_BUSCON0_RECOVC3, IFX_EBU_BUSCON0_RECOVC); + + reg |= SM(IFX_EBU_BUSCON0_CMULT16, IFX_EBU_BUSCON0_CMULT); + + IFX_REG_W32(reg, IFX_EBU_BUSCON0); + + /*--- pr_debug("{%s} phys 0x%x size 0x%lx virt 0x%p res %s\n", ---*/ + /*--- __func__, ltq_mtd->map->phys, ltq_mtd->map->size, ltq_mtd->map->virt, ltq_mtd->res->name); ---*/ } static int ltq_mtd_probe(struct platform_device *pdev) { + struct physmap_flash_data *pdata; struct mtd_part_parser_data ppdata; struct ltq_mtd *ltq_mtd; struct cfi_private *cfi; int err; - if (of_machine_is_compatible("lantiq,falcon") && - (ltq_boot_select() != BS_FLASH)) { + if (of_machine_is_compatible("lantiq,falcon") && (ltq_boot_select() != BS_FLASH)) { dev_err(&pdev->dev, "invalid bootstrap options\n"); return -ENODEV; } + pdata = pdev->dev.platform_data; + ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); + if ( ! ltq_mtd) { + dev_err(&pdev->dev, "no memory\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, ltq_mtd); ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -134,16 +227,26 @@ } ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + if ( ! ltq_mtd->map) { + dev_err(&pdev->dev, "map - no memory\n"); + err = -ENOMEM; + goto err_out; + } + ltq_mtd->map->phys = ltq_mtd->res->start; ltq_mtd->map->size = resource_size(ltq_mtd->res); + ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); if (IS_ERR(ltq_mtd->map->virt)) { err = PTR_ERR(ltq_mtd->map->virt); - goto err_out; + goto err_free; } - ltq_mtd->map->name = ltq_map_name; - ltq_mtd->map->bankwidth = 2; + ltq_mtd_hwinit(ltq_mtd); + + ltq_mtd->map->name = pdev->name; + ltq_mtd->map->bankwidth = pdata->width; + ltq_mtd->map->read = ltq_read16; ltq_mtd->map->write = ltq_write16; ltq_mtd->map->copy_from = ltq_copy_from; @@ -165,9 +268,12 @@ cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - ppdata.of_node = pdev->dev.of_node; - err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, - &ppdata, NULL, 0); + if (pdata->part_probe_types) { + err = mtd_device_parse_register(ltq_mtd->mtd, pdata->part_probe_types, NULL, NULL, 0); + } else { + ppdata.of_node = pdev->dev.of_node; + err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, &ppdata, NULL, 0); + } if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy;