From 44d703160bc3a7598335f7a30703c9a711a6e7ab Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 14 Nov 2014 17:06:04 +0000 Subject: [PATCH] lantiq: Concatenate multiple flash chips for lantiq-flash Signed-off-by: Maikel Bloemendal Tested-by: Eddi De Pieri SVN-Revision: 43272 --- .../0160-owrt-lantiq-multiple-flash.patch | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 target/linux/lantiq/patches-3.14/0160-owrt-lantiq-multiple-flash.patch diff --git a/target/linux/lantiq/patches-3.14/0160-owrt-lantiq-multiple-flash.patch b/target/linux/lantiq/patches-3.14/0160-owrt-lantiq-multiple-flash.patch new file mode 100644 index 0000000000..87e6cbb89a --- /dev/null +++ b/target/linux/lantiq/patches-3.14/0160-owrt-lantiq-multiple-flash.patch @@ -0,0 +1,215 @@ +--- "a/drivers/mtd/maps/lantiq-flash.c" ++++ "b/drivers/mtd/maps/lantiq-flash.c" +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -39,10 +40,12 @@ + LTQ_NOR_NORMAL + }; + ++#define MAX_RESOURCES 4 ++ + struct ltq_mtd { +- struct resource *res; +- struct mtd_info *mtd; +- struct map_info *map; ++ struct mtd_info *mtd[MAX_RESOURCES]; ++ struct mtd_info *cmtd; ++ struct map_info map[MAX_RESOURCES]; + }; + + static const char ltq_map_name[] = "ltq_nor"; +@@ -110,12 +113,39 @@ + } + + static int ++ltq_mtd_remove(struct platform_device *pdev) ++{ ++ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); ++ int i; ++ ++ if (ltq_mtd == NULL) ++ return 0; ++ ++ if (ltq_mtd->cmtd) { ++ mtd_device_unregister(ltq_mtd->cmtd); ++ if (ltq_mtd->cmtd != ltq_mtd->mtd[0]) ++ mtd_concat_destroy(ltq_mtd->cmtd); ++ } ++ ++ for (i = 0; i < MAX_RESOURCES; i++) { ++ if (ltq_mtd->mtd[i] != NULL) ++ map_destroy(ltq_mtd->mtd[i]); ++ } ++ ++ kfree(ltq_mtd); ++ ++ return 0; ++} ++ ++static int + ltq_mtd_probe(struct platform_device *pdev) + { + struct mtd_part_parser_data ppdata; + struct ltq_mtd *ltq_mtd; + struct cfi_private *cfi; +- int err; ++ int err = 0; ++ int i; ++ int devices_found = 0; + + static const char *rom_probe_types[] = { + "cfi_probe", "jedec_probe", NULL +@@ -134,79 +164,88 @@ + + platform_set_drvdata(pdev, ltq_mtd); + +- ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!ltq_mtd->res) { +- dev_err(&pdev->dev, "failed to get memory resource\n"); +- return -ENOENT; ++ for (i = 0; i < pdev->num_resources; i++) { ++ printk(KERN_NOTICE "lantiq nor flash device: %.8llx at %.8llx\n", ++ (unsigned long long)resource_size(&pdev->resource[i]), ++ (unsigned long long)pdev->resource[i].start); ++ ++ if (!devm_request_mem_region(&pdev->dev, ++ pdev->resource[i].start, ++ resource_size(&pdev->resource[i]), ++ dev_name(&pdev->dev))) { ++ dev_err(&pdev->dev, "Could not reserve memory region\n"); ++ return -ENOMEM; ++ } ++ ++ ltq_mtd->map[i].name = ltq_map_name; ++ ltq_mtd->map[i].bankwidth = 2; ++ ltq_mtd->map[i].read = ltq_read16; ++ ltq_mtd->map[i].write = ltq_write16; ++ ltq_mtd->map[i].copy_from = ltq_copy_from; ++ ltq_mtd->map[i].copy_to = ltq_copy_to; ++ ++ if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) ++ ltq_mtd->map[i].phys = NO_XIP; ++ else ++ ltq_mtd->map[i].phys = pdev->resource[i].start; ++ ltq_mtd->map[i].size = resource_size(&pdev->resource[i]); ++ ltq_mtd->map[i].virt = devm_ioremap(&pdev->dev, ltq_mtd->map[i].phys, ++ ltq_mtd->map[i].size); ++ if (IS_ERR(ltq_mtd->map[i].virt)) ++ return PTR_ERR(ltq_mtd->map[i].virt); ++ ++ if (ltq_mtd->map[i].virt == NULL) { ++ dev_err(&pdev->dev, "Failed to ioremap flash region\n"); ++ err = PTR_ERR(ltq_mtd->map[i].virt); ++ goto err_out; ++ } ++ ++ ltq_mtd->map[i].map_priv_1 = LTQ_NOR_PROBING; ++ for (type = rom_probe_types; !ltq_mtd->mtd[i] && *type; type++) ++ ltq_mtd->mtd[i] = do_map_probe(*type, <q_mtd->map[i]); ++ ltq_mtd->map[i].map_priv_1 = LTQ_NOR_NORMAL; ++ ++ if (!ltq_mtd->mtd[i]) { ++ dev_err(&pdev->dev, "probing failed\n"); ++ return -ENXIO; ++ } else { ++ devices_found++; ++ } ++ ++ ltq_mtd->mtd[i]->owner = THIS_MODULE; ++ ltq_mtd->mtd[i]->dev.parent = &pdev->dev; ++ ++ cfi = ltq_mtd->map[i].fldrv_priv; ++ cfi->addr_unlock1 ^= 1; ++ cfi->addr_unlock2 ^= 1; + } + +- ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), +- GFP_KERNEL); +- if (!ltq_mtd->map) +- return -ENOMEM; +- +- if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) +- ltq_mtd->map->phys = NO_XIP; +- else +- ltq_mtd->map->phys = ltq_mtd->res->start; +- 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)) +- return PTR_ERR(ltq_mtd->map->virt); +- +- ltq_mtd->map->name = ltq_map_name; +- ltq_mtd->map->bankwidth = 2; +- ltq_mtd->map->read = ltq_read16; +- ltq_mtd->map->write = ltq_write16; +- ltq_mtd->map->copy_from = ltq_copy_from; +- ltq_mtd->map->copy_to = ltq_copy_to; +- +- ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; +- +- for (type = rom_probe_types; !ltq_mtd->mtd && *type; type++) +- ltq_mtd->mtd = do_map_probe(*type, ltq_mtd->map); +- +- ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; +- +- if (!ltq_mtd->mtd) { +- dev_err(&pdev->dev, "probing failed\n"); +- return -ENXIO; +- } +- +- ltq_mtd->mtd->owner = THIS_MODULE; +- +- cfi = ltq_mtd->map->fldrv_priv; +- cfi->addr_unlock1 ^= 1; +- cfi->addr_unlock2 ^= 1; ++ if (devices_found == 1) { ++ ltq_mtd->cmtd = ltq_mtd->mtd[0]; ++ } else if (devices_found > 1) { ++ /* ++ * We detected multiple devices. Concatenate them together. ++ */ ++ ltq_mtd->cmtd = mtd_concat_create(ltq_mtd->mtd, devices_found, dev_name(&pdev->dev)); ++ if (ltq_mtd->cmtd == NULL) ++ err = -ENXIO; ++ } + + ppdata.of_node = pdev->dev.of_node; +- err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, ++ err = mtd_device_parse_register(ltq_mtd->cmtd, ltq_probe_types, + &ppdata, NULL, 0); + if (err) { + dev_err(&pdev->dev, "failed to add partitions\n"); +- goto err_destroy; ++ goto err_out; + } + + return 0; + +-err_destroy: +- map_destroy(ltq_mtd->mtd); ++err_out: ++ ltq_mtd_remove(pdev); + return err; + } + +-static int +-ltq_mtd_remove(struct platform_device *pdev) +-{ +- struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); +- +- if (ltq_mtd && ltq_mtd->mtd) { +- mtd_device_unregister(ltq_mtd->mtd); +- map_destroy(ltq_mtd->mtd); +- } +- return 0; +-} +- + static const struct of_device_id ltq_mtd_match[] = { + { .compatible = "lantiq,nor" }, + {}, -- 2.30.2