|
@@ -14,6 +14,7 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_address.h>
|
|
|
+#include <linux/of_platform.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
@@ -67,11 +68,50 @@ static struct exynos_srom_reg_dump *exynos_srom_alloc_reg_dump(
|
|
|
return rd;
|
|
|
}
|
|
|
|
|
|
+static int exynos_srom_configure_bank(struct exynos_srom *srom,
|
|
|
+ struct device_node *np)
|
|
|
+{
|
|
|
+ u32 bank, width, pmc = 0;
|
|
|
+ u32 timing[6];
|
|
|
+ u32 cs, bw;
|
|
|
+
|
|
|
+ if (of_property_read_u32(np, "reg", &bank))
|
|
|
+ return -EINVAL;
|
|
|
+ if (of_property_read_u32(np, "reg-io-width", &width))
|
|
|
+ width = 1;
|
|
|
+ if (of_property_read_bool(np, "samsung,srom-page-mode"))
|
|
|
+ pmc = 1 << EXYNOS_SROM_BCX__PMC__SHIFT;
|
|
|
+ if (of_property_read_u32_array(np, "samsung,srom-timing", timing,
|
|
|
+ ARRAY_SIZE(timing)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ bank *= 4; /* Convert bank into shift/offset */
|
|
|
+
|
|
|
+ cs = 1 << EXYNOS_SROM_BW__BYTEENABLE__SHIFT;
|
|
|
+ if (width == 2)
|
|
|
+ cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT;
|
|
|
+
|
|
|
+ bw = __raw_readl(srom->reg_base + EXYNOS_SROM_BW);
|
|
|
+ bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank);
|
|
|
+ __raw_writel(bw, srom->reg_base + EXYNOS_SROM_BW);
|
|
|
+
|
|
|
+ __raw_writel(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) |
|
|
|
+ (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) |
|
|
|
+ (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) |
|
|
|
+ (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) |
|
|
|
+ (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) |
|
|
|
+ (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT),
|
|
|
+ srom->reg_base + EXYNOS_SROM_BC0 + bank);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int exynos_srom_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct device_node *np;
|
|
|
+ struct device_node *np, *child;
|
|
|
struct exynos_srom *srom;
|
|
|
struct device *dev = &pdev->dev;
|
|
|
+ bool bad_bank_config = false;
|
|
|
|
|
|
np = dev->of_node;
|
|
|
if (!np) {
|
|
@@ -100,7 +140,23 @@ static int exynos_srom_probe(struct platform_device *pdev)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ for_each_child_of_node(np, child) {
|
|
|
+ if (exynos_srom_configure_bank(srom, child)) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Could not decode bank configuration for %s\n",
|
|
|
+ child->name);
|
|
|
+ bad_bank_config = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If any bank failed to configure, we still provide suspend/resume,
|
|
|
+ * but do not probe child devices
|
|
|
+ */
|
|
|
+ if (bad_bank_config)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return of_platform_populate(np, NULL, NULL, dev);
|
|
|
}
|
|
|
|
|
|
static int exynos_srom_remove(struct platform_device *pdev)
|