We're going to add interconnect support to the EMC driver. Once this
support will be added, the Tegra20 devfreq driver will no longer be
able to use clk_round_rate(emc) for building up OPP table. It's quite
handy that struct tegra_mc contains memory timings which could be used
by the devfreq drivers instead of the clk rate-rounding. The tegra_mc
timings are populated by the MC driver only for Tegra30+ SoCs, hence
the Tegra20 EMC could populate timings by itself.

Signed-off-by: Dmitry Osipenko <dig...@gmail.com>
---
 drivers/memory/tegra/tegra20-emc.c | 47 ++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 035d9251e28a..a95522020a25 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -15,12 +15,15 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/sort.h>
 #include <linux/types.h>
 
 #include <soc/tegra/fuse.h>
 
+#include "mc.h"
+
 #define EMC_INTSTATUS                          0x000
 #define EMC_INTMASK                            0x004
 #define EMC_DBG                                        0x008
@@ -650,6 +653,38 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
                            emc, &tegra_emc_debug_max_rate_fops);
 }
 
+static int tegra_emc_init_mc_timings(struct tegra_emc *emc)
+{
+       struct tegra_mc_timing *timing;
+       struct platform_device *pdev;
+       struct device_node *np;
+       struct tegra_mc *mc;
+       unsigned int i;
+
+       np = of_find_compatible_node(NULL, NULL, "nvidia,tegra20-mc-gart");
+       if (!np)
+               return -ENOENT;
+
+       pdev = of_find_device_by_node(np);
+       of_node_put(np);
+       if (!pdev)
+               return -ENOENT;
+
+       mc = platform_get_drvdata(pdev);
+       if (!mc)
+               return -EPROBE_DEFER;
+
+       mc->timings = devm_kcalloc(mc->dev, emc->num_timings, sizeof(*timing),
+                                  GFP_KERNEL);
+       if (!mc->timings)
+               return -ENOMEM;
+
+       for (i = 0; i < emc->num_timings; i++)
+               mc->timings[mc->num_timings++].rate = emc->timings[i].rate;
+
+       return 0;
+}
+
 static int tegra_emc_probe(struct platform_device *pdev)
 {
        struct device_node *np;
@@ -705,6 +740,18 @@ static int tegra_emc_probe(struct platform_device *pdev)
                return err;
        }
 
+       /*
+        * Only Tegra30+ SoCs are having Memory Controller timings initialized
+        * by the MC driver. For Tegra20 we need to populate the MC timings
+        * from here. The MC timings will be used by the Tegra20 devfreq driver.
+        */
+       err = tegra_emc_init_mc_timings(emc);
+       if (err) {
+               dev_err(&pdev->dev, "failed to initialize mc timings: %d\n",
+                       err);
+               return err;
+       }
+
        tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
 
        emc->clk = devm_clk_get(&pdev->dev, "emc");
-- 
2.26.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to