From: Peter De Schrijver <pdeschrijver@nvidia.com>
To: <linux-clk@vger.kernel.org>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
Subject: [RFC 11/14] memory: tegra: parse DT and costruct timing tables
Date: Sat, 15 Sep 2018 00:48:12 +0300 [thread overview]
Message-ID: <1536961695-27809-12-git-send-email-pdeschrijver@nvidia.com> (raw)
In-Reply-To: <1536961695-27809-1-git-send-email-pdeschrijver@nvidia.com>
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
drivers/memory/tegra/tegra210-dt-parse.c | 363 +++++++++++++++++++++++++++++++
1 file changed, 363 insertions(+)
create mode 100644 drivers/memory/tegra/tegra210-dt-parse.c
diff --git a/drivers/memory/tegra/tegra210-dt-parse.c b/drivers/memory/tegra/tegra210-dt-parse.c
new file mode 100644
index 0000000..553663a
--- /dev/null
+++ b/drivers/memory/tegra/tegra210-dt-parse.c
@@ -0,0 +1,363 @@
+/*
+ * drivers/platform/tegra/mc/tegra_emc_dt_parse.c
+ *
+ * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <soc/tegra/fuse.h>
+//#include <soc/tegra/tegra_emc.h>
+
+#include "tegra210-emc-reg.h"
+
+static struct device_node *tegra_emc_ramcode_devnode(
+ struct device_node *np)
+{
+ struct device_node *iter;
+ u32 reg;
+
+ for_each_child_of_node(np, iter) {
+ if (of_property_read_u32(iter, "nvidia,ram-code", ®))
+ continue;
+ if (reg == tegra_read_ram_code())
+ return of_node_get(iter);
+ }
+
+ return NULL;
+}
+
+static void *tegra_emc_dt_parse_pdata_comp(const char *emc_mode,
+ const char *comp,
+ void *pdata,
+ struct device_node *tnp,
+ struct platform_device *pdev,
+ int num_tables, int *table_count)
+{
+#define PNE_U32(node, entry, tbl_entry) \
+ do { \
+ int __ret__; \
+ u32 __tmp__; \
+ \
+ __ret__ = of_property_read_u32((node), (entry), &__tmp__); \
+ if (__ret__) { \
+ dev_err(&pdev->dev, "Failed to parse %s in %s: %d\n", \
+ (entry), (node)->full_name, __ret__); \
+ continue; \
+ } \
+ \
+ tables[i].tbl_entry = __tmp__; \
+ } while (0)
+
+#define PNE_U32_ARRAY(node, entry, tbl_entry, length) \
+ do { \
+ int __ret__; \
+ \
+ __ret__ = of_property_read_u32_array((node), (entry), \
+ (tbl_entry), (length)); \
+ if (__ret__) { \
+ dev_err(&pdev->dev, "Failed to parse %s in %s: %d\n", \
+ (entry), (node)->full_name, __ret__); \
+ continue; \
+ } \
+ } while (0)
+
+ int i = 0, ret = 0;
+ struct device_node *iter;
+ struct emc_timing *tables;
+
+ tables = devm_kzalloc(&pdev->dev,
+ sizeof(*tables) * num_tables, GFP_KERNEL);
+
+ if (!tables) {
+ of_node_put(tnp);
+ return tables;
+ }
+
+ for_each_child_of_node(tnp, iter) {
+ if (of_device_is_compatible(iter, comp)) {
+ const char *source_name;
+ const char *dvfs_ver;
+
+ ret = of_property_read_string(iter,
+ "nvidia,source", &source_name);
+ if (ret) {
+ dev_err(&pdev->dev, "no source name in %s\n",
+ iter->full_name);
+ continue;
+ }
+ strlcpy(tables[i].clock_src, source_name,
+ sizeof(tables[i].clock_src));
+
+ ret = of_property_read_string(iter,
+ "nvidia,dvfs-version", &dvfs_ver);
+ if (ret) {
+ dev_err(&pdev->dev, "no dvfs version in %s\n",
+ iter->full_name);
+ continue;
+ }
+ strlcpy(tables[i].dvfs_ver, dvfs_ver,
+ sizeof(tables[i].dvfs_ver));
+
+ PNE_U32(iter, "nvidia,revision", rev);
+ PNE_U32(iter, "clock-frequency", rate);
+ PNE_U32(iter, "nvidia,emc-min-mv", min_volt);
+ PNE_U32(iter, "nvidia,gk20a-min-mv", gpu_min_volt);
+ PNE_U32(iter, "nvidia,src-sel-reg", clk_src_emc);
+ PNE_U32(iter, "nvidia,burst-regs-num", num_burst);
+ PNE_U32(iter, "nvidia,emc-cfg-2", emc_cfg_2);
+ PNE_U32(iter, "nvidia,emc-sel-dpd-ctrl",
+ emc_sel_dpd_ctrl);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config",
+ emc_auto_cal_config);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config2",
+ emc_auto_cal_config2);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config3",
+ emc_auto_cal_config3);
+ PNE_U32(iter, "nvidia,emc-clock-latency-change",
+ latency);
+ PNE_U32_ARRAY(iter, "nvidia,emc-registers",
+ tables[i].burst_regs,
+ tables[i].num_burst);
+
+ PNE_U32(iter, "nvidia,needs-training", needs_training);
+ PNE_U32(iter, "nvidia,trained", trained);
+ if (tables[i].rev < 0x6)
+ goto skip_periodic_training_params;
+ PNE_U32(iter, "nvidia,periodic_training",
+ periodic_training);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c0d0u0",
+ trained_dram_clktree_c0d0u0);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c0d0u1",
+ trained_dram_clktree_c0d0u1);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c0d1u0",
+ trained_dram_clktree_c0d1u0);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c0d1u1",
+ trained_dram_clktree_c0d1u1);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c1d0u0",
+ trained_dram_clktree_c1d0u0);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c1d0u1",
+ trained_dram_clktree_c1d0u1);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c1d1u0",
+ trained_dram_clktree_c1d1u0);
+ PNE_U32(iter, "nvidia,trained_dram_clktree_c1d1u1",
+ trained_dram_clktree_c1d1u1);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c0d0u0",
+ current_dram_clktree_c0d0u0);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c0d0u1",
+ current_dram_clktree_c0d0u1);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c0d1u0",
+ current_dram_clktree_c0d1u0);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c0d1u1",
+ current_dram_clktree_c0d1u1);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c1d0u0",
+ current_dram_clktree_c1d0u0);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c1d0u1",
+ current_dram_clktree_c1d0u1);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c1d1u0",
+ current_dram_clktree_c1d1u0);
+ PNE_U32(iter, "nvidia,current_dram_clktree_c1d1u1",
+ current_dram_clktree_c1d1u1);
+ PNE_U32(iter, "nvidia,run_clocks", run_clocks);
+ PNE_U32(iter, "nvidia,tree_margin", tree_margin);
+
+skip_periodic_training_params:
+ PNE_U32(iter, "nvidia,burst-regs-per-ch-num",
+ num_burst_per_ch);
+ PNE_U32(iter, "nvidia,trim-regs-num", num_trim);
+ PNE_U32(iter, "nvidia,trim-regs-per-ch-num",
+ num_trim_per_ch);
+ PNE_U32(iter, "nvidia,burst-mc-regs-num",
+ num_mc_regs);
+ PNE_U32(iter, "nvidia,la-scale-regs-num",
+ num_up_down);
+ PNE_U32(iter, "nvidia,vref-regs-num", vref_num);
+ PNE_U32(iter, "nvidia,dram-timing-regs-num",
+ dram_timing_num);
+ PNE_U32(iter, "nvidia,min-mrs-wait", min_mrs_wait);
+ PNE_U32(iter, "nvidia,emc-mrw", emc_mrw);
+ PNE_U32(iter, "nvidia,emc-mrw2", emc_mrw2);
+ PNE_U32(iter, "nvidia,emc-mrw3", emc_mrw3);
+ PNE_U32(iter, "nvidia,emc-mrw4", emc_mrw4);
+ PNE_U32(iter, "nvidia,emc-mrw9", emc_mrw9);
+ PNE_U32(iter, "nvidia,emc-mrs", emc_mrs);
+ PNE_U32(iter, "nvidia,emc-emrs", emc_emrs);
+ PNE_U32(iter, "nvidia,emc-emrs2", emc_emrs2);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config4",
+ emc_auto_cal_config4);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config5",
+ emc_auto_cal_config5);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config6",
+ emc_auto_cal_config6);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config7",
+ emc_auto_cal_config7);
+ PNE_U32(iter, "nvidia,emc-auto-cal-config8",
+ emc_auto_cal_config8);
+ PNE_U32(iter, "nvidia,emc-fdpd-ctrl-cmd-no-ramp",
+ emc_fdpd_ctrl_cmd_no_ramp);
+ PNE_U32(iter, "nvidia,dll-clk-src", dll_clk_src);
+ PNE_U32(iter, "nvidia,clk-out-enb-x-0-clk-enb-emc-dll",
+ clk_out_enb_x_0_clk_enb_emc_dll);
+
+ if (tables[i].rev >= 0x7)
+ PNE_U32_ARRAY(iter, "nvidia,ptfv",
+ tables[i].ptfv_list,
+ sizeof(tables[i].ptfv_list)
+ / sizeof(u32));
+
+ PNE_U32_ARRAY(iter, "nvidia,emc-burst-regs-per-ch",
+ tables[i].burst_reg_per_ch,
+ tables[i].num_burst_per_ch);
+ PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-ca-train",
+ tables[i].shadow_regs_ca_train,
+ tables[i].num_burst);
+ PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-quse-train",
+ tables[i].shadow_regs_quse_train,
+ tables[i].num_burst);
+ PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-rdwr-train",
+ tables[i].shadow_regs_rdwr_train,
+ tables[i].num_burst);
+ PNE_U32_ARRAY(iter, "nvidia,emc-trim-regs",
+ tables[i].trim_regs,
+ tables[i].num_trim);
+ PNE_U32_ARRAY(iter, "nvidia,emc-trim-regs-per-ch",
+ tables[i].trim_perch_regs,
+ tables[i].num_trim_per_ch);
+ PNE_U32_ARRAY(iter, "nvidia,emc-vref-regs",
+ tables[i].vref_perch_regs,
+ tables[i].vref_num);
+ PNE_U32_ARRAY(iter, "nvidia,emc-dram-timing-regs",
+ tables[i].dram_timings,
+ tables[i].dram_timing_num);
+ PNE_U32_ARRAY(iter, "nvidia,emc-burst-mc-regs",
+ tables[i].burst_mc_regs,
+ tables[i].num_mc_regs);
+ PNE_U32_ARRAY(iter, "nvidia,emc-la-scale-regs",
+ tables[i].la_scale_regs,
+ tables[i].num_up_down);
+ i++;
+ }
+ }
+ *table_count = i;
+ return tables;
+}
+
+static const struct of_device_id emc_table_match[] = {
+ {
+ .compatible = "nvidia,tegra210-emc-table",
+ .data = "nvidia,tegra210-emc-table-derated",
+ },
+ {
+ .compatible = "nvidia,tegra21-emc-table",
+ .data = "nvidia,tegra21-emc-table-derated",
+ },
+ { },
+};
+
+int tegra_emc_dt_parse_pdata(struct platform_device *pdev,
+ struct emc_timing **tables,
+ struct emc_timing **derated_tables,
+ int *num_entries)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *tnp, *iter;
+ int num_tables, table_count;
+ u32 tegra_bct_strapping;
+ const char *emc_mode = "nvidia,emc-mode-0";
+ struct tegra21_emc_pdata *pdata = NULL;
+ const char *comp = NULL;
+ const char *comp_derated = NULL;
+ const void *prop;
+
+ if (!np) {
+ dev_err(&pdev->dev,
+ "Unable to find external-memory-controller node\n");
+ return -ENODEV;
+ }
+
+ tegra_bct_strapping = tegra_read_ram_code();
+
+ prop = of_get_property(pdev->dev.of_node,
+ "nvidia,poll_thresh_freq", NULL);
+ if (prop) {
+ unsigned long freq_thresh = (unsigned long)be32_to_cpup(prop);
+
+// tegra210_emc_mr4_set_freq_thresh(freq_thresh);
+ pr_info("tegra: emc: Using MR4 freq threshold: %lu\n",
+ freq_thresh);
+ }
+
+ if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+ tnp = tegra_emc_ramcode_devnode(np);
+
+ if (!tnp) {
+ dev_warn(&pdev->dev,
+ "can't find emc table for ram-code 0x%02x\n",
+ tegra_bct_strapping);
+ return -ENODEV;
+ }
+ } else
+ tnp = of_node_get(np);
+
+ num_tables = 0;
+ for_each_child_of_node(tnp, iter) {
+ if (!comp) {
+ const struct of_device_id *m =
+ of_match_node(emc_table_match, iter);
+ if (m) {
+ comp = m->compatible;
+ comp_derated = m->data;
+ num_tables++;
+ }
+ continue;
+ }
+ if (of_device_is_compatible(iter, comp))
+ num_tables++;
+ }
+
+ if (!num_tables) {
+ *tables = NULL;
+ goto out;
+ }
+
+ *tables = tegra_emc_dt_parse_pdata_comp(emc_mode, comp, pdata, tnp,
+ pdev, num_tables, &table_count);
+ *num_entries = table_count;
+
+ /* populate the derated tables */
+ num_tables = 0;
+ for_each_child_of_node(tnp, iter) {
+ if (of_device_is_compatible(iter, comp_derated))
+ num_tables++;
+ }
+
+ if (!num_tables) {
+ *derated_tables = NULL;
+ goto out;
+ }
+
+ *derated_tables = tegra_emc_dt_parse_pdata_comp(emc_mode,
+ comp_derated, pdata, tnp, pdev, num_tables,
+ &table_count);
+
+out:
+ of_node_put(tnp);
+ return 0;
+}
--
1.9.1
next prev parent reply other threads:[~2018-09-15 6:44 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-14 21:48 [RFC 00/14] Tegra210 EMC scaling Peter De Schrijver
2018-09-14 21:48 ` [RFC 01/14] memory: tegra: mc: Add Tegra210 MC emem registers Peter De Schrijver
2018-09-14 21:48 ` [RFC 02/14] clk: tegra: rename emc timing functions Peter De Schrijver
2018-09-14 21:48 ` [RFC 03/14] clk: tegra: emc: simplify parent matching Peter De Schrijver
2018-09-14 21:48 ` [RFC 04/14] clk: tegra: emc: prepare for Tegra210 parent table Peter De Schrijver
2018-09-14 21:48 ` [RFC 05/14] memory: tegra: mc: Introduce helpers Peter De Schrijver
2018-09-14 21:48 ` [RFC 06/14] memory: tegra: mc: Add support for scaled LA Peter De Schrijver
2018-09-14 21:48 ` [RFC 07/14] memory: tegra: scaled LA register for Tegra210 Peter De Schrijver
2018-09-14 21:48 ` [RFC 08/14] clk: tegra: clock changes for emc scaling Peter De Schrijver
2018-09-14 21:48 ` [RFC 09/14] memory: tegra: Add definitions shared by Tegra210 EMC scaling code Peter De Schrijver
2018-09-14 21:48 ` [RFC 10/14] memory: tegra: Add Tegra210 EMC scaling sequence Peter De Schrijver
2018-09-14 21:48 ` Peter De Schrijver [this message]
2018-09-14 21:48 ` [RFC 12/14] memory: tegra: Tegra210 EMC memory driver Peter De Schrijver
2018-09-14 21:48 ` [RFC 13/14] memory: tegra: enable Tegra210 EMC scaling driver Peter De Schrijver
2018-09-14 21:48 ` [RFC 14/14] dt-bindings: tegra: Add Tegra210 EMC binding Peter De Schrijver
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1536961695-27809-12-git-send-email-pdeschrijver@nvidia.com \
--to=pdeschrijver@nvidia.com \
--cc=linux-clk@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox