diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2017-01-27 10:10:37 +0100 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-01-27 10:15:56 +0100 |
commit | 987e079ecab7298cf5d5b43473d25bc31006e0e0 (patch) | |
tree | 64f9827c0605f6393dcca0cf38b7fd3e2e25e66b /drivers/memory | |
parent | 427456e4772caf155c20604a60265dbc5a126267 (diff) | |
download | linux-987e079ecab7298cf5d5b43473d25bc31006e0e0.tar.gz linux-987e079ecab7298cf5d5b43473d25bc31006e0e0.tar.bz2 linux-987e079ecab7298cf5d5b43473d25bc31006e0e0.zip |
memory: atmel-ebi: Properly handle multiple reference to the same CS
Some devices are defining several sub-ranges within the same CS iomem
range. In this case, we should not duplicate the EBI device config.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/memory')
-rw-r--r-- | drivers/memory/atmel-ebi.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index 2c4c9a1978bc..46657eaaedf6 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -449,12 +449,31 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, struct at91_ebi_dev_config conf = { }; struct device *dev = ebi->dev; struct at91_ebi_dev *ebid; - int ret, numcs = 0, i; + unsigned long cslines = 0; + int ret, numcs = 0, nentries, i; bool apply = false; + u32 cs; - numcs = of_property_count_elems_of_size(np, "reg", - reg_cells * sizeof(u32)); - if (numcs <= 0) { + nentries = of_property_count_elems_of_size(np, "reg", + reg_cells * sizeof(u32)); + for (i = 0; i < nentries; i++) { + ret = of_property_read_u32_index(np, "reg", i * reg_cells, + &cs); + if (ret) + return ret; + + if (cs >= AT91_MATRIX_EBI_NUM_CS || + !(ebi->caps->available_cs & BIT(cs))) { + dev_err(dev, "invalid reg property in %s\n", + np->full_name); + return -EINVAL; + } + + if (!test_and_set_bit(cs, &cslines)) + numcs++; + } + + if (!numcs) { dev_err(dev, "invalid reg property in %s\n", np->full_name); return -EINVAL; } @@ -473,21 +492,8 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, else if (ret) apply = true; - for (i = 0; i < numcs; i++) { - u32 cs; - - ret = of_property_read_u32_index(np, "reg", i * reg_cells, - &cs); - if (ret) - return ret; - - if (cs > AT91_MATRIX_EBI_NUM_CS || - !(ebi->caps->available_cs & BIT(cs))) { - dev_err(dev, "invalid reg property in %s\n", - np->full_name); - return -EINVAL; - } - + i = 0; + for_each_set_bit(cs, &cslines, AT91_MATRIX_EBI_NUM_CS) { ebid->configs[i].cs = cs; if (apply) { @@ -506,6 +512,8 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, if (ebi->ebi_csa && apply) regmap_field_update_bits(ebi->ebi_csa, BIT(cs), 0); + + i++; } list_add_tail(&ebid->node, &ebi->devs); |