All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
@ 2025-04-30 17:52 ` Aaron Kling via B4 Relay
  0 siblings, 0 replies; 7+ messages in thread
From: Aaron Kling @ 2025-04-30 17:52 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter
  Cc: linux-kernel, linux-tegra, Aaron Kling

These are generated by the Tegra210 Android bootloader. This is similar
to the Tegra124 handling, so the support is based on that and modified
to match Tegra210 by referencing the downstream Nvidia 4.9 kernel.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
---
 drivers/memory/tegra/tegra210-emc-core.c | 246 +++++++++++++++++++++++++++++--
 1 file changed, 236 insertions(+), 10 deletions(-)

diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index e63f6269057106ded054dea94d92d96cb9c13c06..0b8c7cd09679dc64b3fb04acf2bb5963dd7544fc 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -1783,6 +1783,226 @@ static void tegra210_emc_detect(struct tegra210_emc *emc)
 		emc->num_channels = 1;
 }
 
+static struct device_node *
+tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
+{
+	struct device_node *np;
+	int err;
+
+	for_each_child_of_node(node, np) {
+		u32 value;
+
+		err = of_property_read_u32(np, "nvidia,ram-code", &value);
+		if (err || (value != ram_code))
+			continue;
+
+		return np;
+	}
+
+	return NULL;
+}
+
+static int load_one_timing_from_dt(struct tegra210_emc *emc,
+				   struct tegra210_emc_timing *timing,
+				   struct device_node *node)
+{
+	int err;
+
+#define EMC_READ_PROP(prop, dtprop) { \
+	err = of_property_read_u32(node, dtprop, &timing->prop); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+#define EMC_READ_PROP_STRING(prop, dtprop) { \
+	err = of_property_read_string(node, dtprop, (const char **)&timing->prop); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+#define EMC_READ_PROP_ARRAY(prop, dtprop, length) { \
+	err = of_property_read_u32_array(node, dtprop, timing->prop, length); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+	EMC_READ_PROP_STRING(clock_src, "nvidia,source")
+	EMC_READ_PROP_STRING(dvfs_ver, "nvidia,dvfs-version")
+
+	EMC_READ_PROP(revision, "nvidia,revision")
+	EMC_READ_PROP(rate, "clock-frequency")
+	EMC_READ_PROP(min_volt, "nvidia,emc-min-mv")
+	EMC_READ_PROP(gpu_min_volt, "nvidia,gk20a-min-mv")
+	EMC_READ_PROP(clk_src_emc, "nvidia,src-sel-reg")
+	EMC_READ_PROP(num_burst, "nvidia,burst-regs-num")
+	EMC_READ_PROP(emc_cfg_2, "nvidia,emc-cfg-2")
+	EMC_READ_PROP(emc_sel_dpd_ctrl, "nvidia,emc-sel-dpd-ctrl")
+	EMC_READ_PROP(emc_auto_cal_config, "nvidia,emc-auto-cal-config")
+	EMC_READ_PROP(emc_auto_cal_config2, "nvidia,emc-auto-cal-config2")
+	EMC_READ_PROP(emc_auto_cal_config3, "nvidia,emc-auto-cal-config3")
+	EMC_READ_PROP(latency, "nvidia,emc-clock-latency-change")
+	EMC_READ_PROP_ARRAY(burst_regs, "nvidia,emc-registers", timing->num_burst)
+	EMC_READ_PROP(needs_training, "nvidia,needs-training")
+	EMC_READ_PROP(trained, "nvidia,trained")
+
+	if (timing->revision >= 0x6) {
+		EMC_READ_PROP(periodic_training, "nvidia,periodic_training")
+		EMC_READ_PROP(trained_dram_clktree[C0D0U0], "nvidia,trained_dram_clktree_c0d0u0")
+		EMC_READ_PROP(trained_dram_clktree[C0D0U1], "nvidia,trained_dram_clktree_c0d0u1")
+		EMC_READ_PROP(trained_dram_clktree[C0D1U0], "nvidia,trained_dram_clktree_c0d1u0")
+		EMC_READ_PROP(trained_dram_clktree[C0D1U1], "nvidia,trained_dram_clktree_c0d1u1")
+		EMC_READ_PROP(trained_dram_clktree[C1D0U0], "nvidia,trained_dram_clktree_c1d0u0")
+		EMC_READ_PROP(trained_dram_clktree[C1D0U1], "nvidia,trained_dram_clktree_c1d0u1")
+		EMC_READ_PROP(trained_dram_clktree[C1D1U0], "nvidia,trained_dram_clktree_c1d1u0")
+		EMC_READ_PROP(trained_dram_clktree[C1D1U1], "nvidia,trained_dram_clktree_c1d1u1")
+		EMC_READ_PROP(current_dram_clktree[C0D0U0], "nvidia,current_dram_clktree_c0d0u0")
+		EMC_READ_PROP(current_dram_clktree[C0D0U1], "nvidia,current_dram_clktree_c0d0u1")
+		EMC_READ_PROP(current_dram_clktree[C0D1U0], "nvidia,current_dram_clktree_c0d1u0")
+		EMC_READ_PROP(current_dram_clktree[C0D1U1], "nvidia,current_dram_clktree_c0d1u1")
+		EMC_READ_PROP(current_dram_clktree[C1D0U0], "nvidia,current_dram_clktree_c1d0u0")
+		EMC_READ_PROP(current_dram_clktree[C1D0U1], "nvidia,current_dram_clktree_c1d0u1")
+		EMC_READ_PROP(current_dram_clktree[C1D1U0], "nvidia,current_dram_clktree_c1d1u0")
+		EMC_READ_PROP(current_dram_clktree[C1D1U1], "nvidia,current_dram_clktree_c1d1u1")
+		EMC_READ_PROP(run_clocks, "nvidia,run_clocks")
+		EMC_READ_PROP(tree_margin, "nvidia,tree_margin")
+	}
+
+	EMC_READ_PROP(num_burst_per_ch, "nvidia,burst-regs-per-ch-num")
+	EMC_READ_PROP(num_trim, "nvidia,trim-regs-num")
+	EMC_READ_PROP(num_trim_per_ch, "nvidia,trim-regs-per-ch-num")
+	EMC_READ_PROP(num_mc_regs, "nvidia,burst-mc-regs-num")
+	EMC_READ_PROP(num_up_down, "nvidia,la-scale-regs-num")
+	EMC_READ_PROP(vref_num, "nvidia,vref-regs-num")
+	EMC_READ_PROP(dram_timing_num, "nvidia,dram-timing-regs-num")
+	EMC_READ_PROP(min_mrs_wait, "nvidia,min-mrs-wait")
+	EMC_READ_PROP(emc_mrw, "nvidia,emc-mrw")
+	EMC_READ_PROP(emc_mrw2, "nvidia,emc-mrw2")
+	EMC_READ_PROP(emc_mrw3, "nvidia,emc-mrw3")
+	EMC_READ_PROP(emc_mrw4, "nvidia,emc-mrw4")
+	EMC_READ_PROP(emc_mrw9, "nvidia,emc-mrw9")
+	EMC_READ_PROP(emc_mrs, "nvidia,emc-mrs")
+	EMC_READ_PROP(emc_emrs, "nvidia,emc-emrs")
+	EMC_READ_PROP(emc_emrs2, "nvidia,emc-emrs2")
+	EMC_READ_PROP(emc_auto_cal_config4, "nvidia,emc-auto-cal-config4")
+	EMC_READ_PROP(emc_auto_cal_config5, "nvidia,emc-auto-cal-config5")
+	EMC_READ_PROP(emc_auto_cal_config6, "nvidia,emc-auto-cal-config6")
+	EMC_READ_PROP(emc_auto_cal_config7, "nvidia,emc-auto-cal-config7")
+	EMC_READ_PROP(emc_auto_cal_config8, "nvidia,emc-auto-cal-config8")
+	EMC_READ_PROP(emc_fdpd_ctrl_cmd_no_ramp, "nvidia,emc-fdpd-ctrl-cmd-no-ramp")
+	EMC_READ_PROP(dll_clk_src, "nvidia,dll-clk-src")
+	EMC_READ_PROP(clk_out_enb_x_0_clk_enb_emc_dll, "nvidia,clk-out-enb-x-0-clk-enb-emc-dll")
+
+	if (timing->revision >= 0x7)
+		EMC_READ_PROP_ARRAY(ptfv_list, "nvidia,ptfv", ARRAY_SIZE(timing->ptfv_list))
+
+	EMC_READ_PROP_ARRAY(burst_reg_per_ch, "nvidia,emc-burst-regs-per-ch",
+			timing->num_burst_per_ch)
+	EMC_READ_PROP_ARRAY(shadow_regs_ca_train, "nvidia,emc-shadow-regs-ca-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(shadow_regs_quse_train, "nvidia,emc-shadow-regs-quse-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(shadow_regs_rdwr_train, "nvidia,emc-shadow-regs-rdwr-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(trim_regs, "nvidia,emc-trim-regs", timing->num_trim)
+	EMC_READ_PROP_ARRAY(trim_perch_regs, "nvidia,emc-trim-regs-per-ch", timing->num_trim_per_ch)
+	EMC_READ_PROP_ARRAY(vref_perch_regs, "nvidia,emc-vref-regs", timing->vref_num)
+	EMC_READ_PROP_ARRAY(dram_timings, "nvidia,emc-dram-timing-regs", timing->dram_timing_num)
+	EMC_READ_PROP_ARRAY(burst_mc_regs, "nvidia,emc-burst-mc-regs", timing->num_mc_regs)
+	EMC_READ_PROP_ARRAY(la_scale_regs, "nvidia,emc-la-scale-regs", timing->num_up_down)
+
+#undef EMC_READ_PROP
+#undef EMC_READ_STRING
+#undef EMC_READ_PROP_ARRAY
+
+	return 0;
+}
+
+#define NOMINAL_COMPATIBLE "nvidia,tegra21-emc-table"
+#define DERATED_COMPATIBLE "nvidia,tegra21-emc-table-derated"
+static int tegra210_emc_load_timings_from_dt(struct tegra210_emc *emc,
+					     struct device_node *node)
+{
+	struct tegra210_emc_timing *timing;
+	unsigned int num_nominal = 0, num_derated = 0;
+	int err;
+
+	emc->num_timings = 0;
+	for_each_child_of_node_scoped(node, child) {
+		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
+			emc->num_timings++;
+		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
+			num_derated++;
+	}
+
+	if (!emc->num_timings || (num_derated && (emc->num_timings != num_derated)))
+		return -EINVAL;
+
+	emc->nominal = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
+				    GFP_KERNEL);
+	if (!emc->nominal)
+		return -ENOMEM;
+
+	if (num_derated) {
+		num_derated = 0;
+		emc->derated = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
+					    GFP_KERNEL);
+		if (!emc->derated)
+			return -ENOMEM;
+	}
+
+	for_each_child_of_node_scoped(node, child) {
+		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
+			timing = &emc->nominal[num_nominal++];
+		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
+			timing = &emc->derated[num_derated++];
+		else
+			continue;
+
+		err = load_one_timing_from_dt(emc, timing, child);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
+{
+	struct device_node *node, *np = emc->dev->of_node;
+	int ram_code, ret = 0;
+
+	if (!np) {
+		dev_err(emc->dev, "Unable to find emc node\n");
+		return -ENODEV;
+	}
+
+	if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+		ram_code = tegra_read_ram_code();
+		node = tegra_emc_find_node_by_ram_code(np, ram_code);
+
+		if (!node) {
+			dev_warn(emc->dev, "can't find emc table for ram-code\n");
+			return -ENODEV;
+		}
+
+		ret = tegra210_emc_load_timings_from_dt(emc, node);
+		of_node_put(node);
+	} else {
+		ret = tegra210_emc_load_timings_from_dt(emc, np);
+	}
+
+	return ret;
+}
+
 static int tegra210_emc_validate_timings(struct tegra210_emc *emc,
 					 struct tegra210_emc_timing *timings,
 					 unsigned int num_timings)
@@ -1815,6 +2035,7 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	struct device_node *np;
 	unsigned int i;
 	int err;
+	bool have_dt_tables = false;
 
 	emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
 	if (!emc)
@@ -1847,16 +2068,20 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	np = pdev->dev.of_node;
 
 	/* attach to the nominal and (optional) derated tables */
-	err = of_reserved_mem_device_init_by_name(emc->dev, np, "nominal");
-	if (err < 0) {
-		dev_err(emc->dev, "failed to get nominal EMC table: %d\n", err);
-		return err;
-	}
+	if (of_reserved_mem_device_init_by_name(emc->dev, np, "nominal") >= 0) {
+		err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
+		if (err < 0 && err != -ENODEV) {
+			dev_err(emc->dev, "failed to get derated EMC table: %d\n", err);
+			goto release;
+		}
+	} else {
+		err = tegra210_emc_parse_dt(emc);
+		if (err < 0) {
+			dev_err(emc->dev, "failed to get EMC tables: %d\n", err);
+			return err;
+		}
 
-	err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
-	if (err < 0 && err != -ENODEV) {
-		dev_err(emc->dev, "failed to get derated EMC table: %d\n", err);
-		goto release;
+		have_dt_tables = true;
 	}
 
 	/* validate the tables */
@@ -1980,7 +2205,8 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	debugfs_remove_recursive(emc->debugfs.root);
 	tegra210_clk_emc_detach(emc->clk);
 release:
-	of_reserved_mem_device_release(emc->dev);
+	if (!have_dt_tables)
+		of_reserved_mem_device_release(emc->dev);
 
 	return err;
 }

---
base-commit: 8bac8898fe398ffa3e09075ecea2be511725fb0b
change-id: 20250429-tegra210-emc-dt-97dce690ad4e

Best regards,
-- 
Aaron Kling <webgeek1234@gmail.com>


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
@ 2025-04-30 17:52 ` Aaron Kling via B4 Relay
  0 siblings, 0 replies; 7+ messages in thread
From: Aaron Kling via B4 Relay @ 2025-04-30 17:52 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter
  Cc: linux-kernel, linux-tegra, Aaron Kling

From: Aaron Kling <webgeek1234@gmail.com>

These are generated by the Tegra210 Android bootloader. This is similar
to the Tegra124 handling, so the support is based on that and modified
to match Tegra210 by referencing the downstream Nvidia 4.9 kernel.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
---
 drivers/memory/tegra/tegra210-emc-core.c | 246 +++++++++++++++++++++++++++++--
 1 file changed, 236 insertions(+), 10 deletions(-)

diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index e63f6269057106ded054dea94d92d96cb9c13c06..0b8c7cd09679dc64b3fb04acf2bb5963dd7544fc 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -1783,6 +1783,226 @@ static void tegra210_emc_detect(struct tegra210_emc *emc)
 		emc->num_channels = 1;
 }
 
+static struct device_node *
+tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
+{
+	struct device_node *np;
+	int err;
+
+	for_each_child_of_node(node, np) {
+		u32 value;
+
+		err = of_property_read_u32(np, "nvidia,ram-code", &value);
+		if (err || (value != ram_code))
+			continue;
+
+		return np;
+	}
+
+	return NULL;
+}
+
+static int load_one_timing_from_dt(struct tegra210_emc *emc,
+				   struct tegra210_emc_timing *timing,
+				   struct device_node *node)
+{
+	int err;
+
+#define EMC_READ_PROP(prop, dtprop) { \
+	err = of_property_read_u32(node, dtprop, &timing->prop); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+#define EMC_READ_PROP_STRING(prop, dtprop) { \
+	err = of_property_read_string(node, dtprop, (const char **)&timing->prop); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+#define EMC_READ_PROP_ARRAY(prop, dtprop, length) { \
+	err = of_property_read_u32_array(node, dtprop, timing->prop, length); \
+	if (err) { \
+		dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \
+			node, err); \
+		return err; \
+	} \
+}
+
+	EMC_READ_PROP_STRING(clock_src, "nvidia,source")
+	EMC_READ_PROP_STRING(dvfs_ver, "nvidia,dvfs-version")
+
+	EMC_READ_PROP(revision, "nvidia,revision")
+	EMC_READ_PROP(rate, "clock-frequency")
+	EMC_READ_PROP(min_volt, "nvidia,emc-min-mv")
+	EMC_READ_PROP(gpu_min_volt, "nvidia,gk20a-min-mv")
+	EMC_READ_PROP(clk_src_emc, "nvidia,src-sel-reg")
+	EMC_READ_PROP(num_burst, "nvidia,burst-regs-num")
+	EMC_READ_PROP(emc_cfg_2, "nvidia,emc-cfg-2")
+	EMC_READ_PROP(emc_sel_dpd_ctrl, "nvidia,emc-sel-dpd-ctrl")
+	EMC_READ_PROP(emc_auto_cal_config, "nvidia,emc-auto-cal-config")
+	EMC_READ_PROP(emc_auto_cal_config2, "nvidia,emc-auto-cal-config2")
+	EMC_READ_PROP(emc_auto_cal_config3, "nvidia,emc-auto-cal-config3")
+	EMC_READ_PROP(latency, "nvidia,emc-clock-latency-change")
+	EMC_READ_PROP_ARRAY(burst_regs, "nvidia,emc-registers", timing->num_burst)
+	EMC_READ_PROP(needs_training, "nvidia,needs-training")
+	EMC_READ_PROP(trained, "nvidia,trained")
+
+	if (timing->revision >= 0x6) {
+		EMC_READ_PROP(periodic_training, "nvidia,periodic_training")
+		EMC_READ_PROP(trained_dram_clktree[C0D0U0], "nvidia,trained_dram_clktree_c0d0u0")
+		EMC_READ_PROP(trained_dram_clktree[C0D0U1], "nvidia,trained_dram_clktree_c0d0u1")
+		EMC_READ_PROP(trained_dram_clktree[C0D1U0], "nvidia,trained_dram_clktree_c0d1u0")
+		EMC_READ_PROP(trained_dram_clktree[C0D1U1], "nvidia,trained_dram_clktree_c0d1u1")
+		EMC_READ_PROP(trained_dram_clktree[C1D0U0], "nvidia,trained_dram_clktree_c1d0u0")
+		EMC_READ_PROP(trained_dram_clktree[C1D0U1], "nvidia,trained_dram_clktree_c1d0u1")
+		EMC_READ_PROP(trained_dram_clktree[C1D1U0], "nvidia,trained_dram_clktree_c1d1u0")
+		EMC_READ_PROP(trained_dram_clktree[C1D1U1], "nvidia,trained_dram_clktree_c1d1u1")
+		EMC_READ_PROP(current_dram_clktree[C0D0U0], "nvidia,current_dram_clktree_c0d0u0")
+		EMC_READ_PROP(current_dram_clktree[C0D0U1], "nvidia,current_dram_clktree_c0d0u1")
+		EMC_READ_PROP(current_dram_clktree[C0D1U0], "nvidia,current_dram_clktree_c0d1u0")
+		EMC_READ_PROP(current_dram_clktree[C0D1U1], "nvidia,current_dram_clktree_c0d1u1")
+		EMC_READ_PROP(current_dram_clktree[C1D0U0], "nvidia,current_dram_clktree_c1d0u0")
+		EMC_READ_PROP(current_dram_clktree[C1D0U1], "nvidia,current_dram_clktree_c1d0u1")
+		EMC_READ_PROP(current_dram_clktree[C1D1U0], "nvidia,current_dram_clktree_c1d1u0")
+		EMC_READ_PROP(current_dram_clktree[C1D1U1], "nvidia,current_dram_clktree_c1d1u1")
+		EMC_READ_PROP(run_clocks, "nvidia,run_clocks")
+		EMC_READ_PROP(tree_margin, "nvidia,tree_margin")
+	}
+
+	EMC_READ_PROP(num_burst_per_ch, "nvidia,burst-regs-per-ch-num")
+	EMC_READ_PROP(num_trim, "nvidia,trim-regs-num")
+	EMC_READ_PROP(num_trim_per_ch, "nvidia,trim-regs-per-ch-num")
+	EMC_READ_PROP(num_mc_regs, "nvidia,burst-mc-regs-num")
+	EMC_READ_PROP(num_up_down, "nvidia,la-scale-regs-num")
+	EMC_READ_PROP(vref_num, "nvidia,vref-regs-num")
+	EMC_READ_PROP(dram_timing_num, "nvidia,dram-timing-regs-num")
+	EMC_READ_PROP(min_mrs_wait, "nvidia,min-mrs-wait")
+	EMC_READ_PROP(emc_mrw, "nvidia,emc-mrw")
+	EMC_READ_PROP(emc_mrw2, "nvidia,emc-mrw2")
+	EMC_READ_PROP(emc_mrw3, "nvidia,emc-mrw3")
+	EMC_READ_PROP(emc_mrw4, "nvidia,emc-mrw4")
+	EMC_READ_PROP(emc_mrw9, "nvidia,emc-mrw9")
+	EMC_READ_PROP(emc_mrs, "nvidia,emc-mrs")
+	EMC_READ_PROP(emc_emrs, "nvidia,emc-emrs")
+	EMC_READ_PROP(emc_emrs2, "nvidia,emc-emrs2")
+	EMC_READ_PROP(emc_auto_cal_config4, "nvidia,emc-auto-cal-config4")
+	EMC_READ_PROP(emc_auto_cal_config5, "nvidia,emc-auto-cal-config5")
+	EMC_READ_PROP(emc_auto_cal_config6, "nvidia,emc-auto-cal-config6")
+	EMC_READ_PROP(emc_auto_cal_config7, "nvidia,emc-auto-cal-config7")
+	EMC_READ_PROP(emc_auto_cal_config8, "nvidia,emc-auto-cal-config8")
+	EMC_READ_PROP(emc_fdpd_ctrl_cmd_no_ramp, "nvidia,emc-fdpd-ctrl-cmd-no-ramp")
+	EMC_READ_PROP(dll_clk_src, "nvidia,dll-clk-src")
+	EMC_READ_PROP(clk_out_enb_x_0_clk_enb_emc_dll, "nvidia,clk-out-enb-x-0-clk-enb-emc-dll")
+
+	if (timing->revision >= 0x7)
+		EMC_READ_PROP_ARRAY(ptfv_list, "nvidia,ptfv", ARRAY_SIZE(timing->ptfv_list))
+
+	EMC_READ_PROP_ARRAY(burst_reg_per_ch, "nvidia,emc-burst-regs-per-ch",
+			timing->num_burst_per_ch)
+	EMC_READ_PROP_ARRAY(shadow_regs_ca_train, "nvidia,emc-shadow-regs-ca-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(shadow_regs_quse_train, "nvidia,emc-shadow-regs-quse-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(shadow_regs_rdwr_train, "nvidia,emc-shadow-regs-rdwr-train",
+			timing->num_burst)
+	EMC_READ_PROP_ARRAY(trim_regs, "nvidia,emc-trim-regs", timing->num_trim)
+	EMC_READ_PROP_ARRAY(trim_perch_regs, "nvidia,emc-trim-regs-per-ch", timing->num_trim_per_ch)
+	EMC_READ_PROP_ARRAY(vref_perch_regs, "nvidia,emc-vref-regs", timing->vref_num)
+	EMC_READ_PROP_ARRAY(dram_timings, "nvidia,emc-dram-timing-regs", timing->dram_timing_num)
+	EMC_READ_PROP_ARRAY(burst_mc_regs, "nvidia,emc-burst-mc-regs", timing->num_mc_regs)
+	EMC_READ_PROP_ARRAY(la_scale_regs, "nvidia,emc-la-scale-regs", timing->num_up_down)
+
+#undef EMC_READ_PROP
+#undef EMC_READ_STRING
+#undef EMC_READ_PROP_ARRAY
+
+	return 0;
+}
+
+#define NOMINAL_COMPATIBLE "nvidia,tegra21-emc-table"
+#define DERATED_COMPATIBLE "nvidia,tegra21-emc-table-derated"
+static int tegra210_emc_load_timings_from_dt(struct tegra210_emc *emc,
+					     struct device_node *node)
+{
+	struct tegra210_emc_timing *timing;
+	unsigned int num_nominal = 0, num_derated = 0;
+	int err;
+
+	emc->num_timings = 0;
+	for_each_child_of_node_scoped(node, child) {
+		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
+			emc->num_timings++;
+		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
+			num_derated++;
+	}
+
+	if (!emc->num_timings || (num_derated && (emc->num_timings != num_derated)))
+		return -EINVAL;
+
+	emc->nominal = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
+				    GFP_KERNEL);
+	if (!emc->nominal)
+		return -ENOMEM;
+
+	if (num_derated) {
+		num_derated = 0;
+		emc->derated = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
+					    GFP_KERNEL);
+		if (!emc->derated)
+			return -ENOMEM;
+	}
+
+	for_each_child_of_node_scoped(node, child) {
+		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
+			timing = &emc->nominal[num_nominal++];
+		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
+			timing = &emc->derated[num_derated++];
+		else
+			continue;
+
+		err = load_one_timing_from_dt(emc, timing, child);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
+{
+	struct device_node *node, *np = emc->dev->of_node;
+	int ram_code, ret = 0;
+
+	if (!np) {
+		dev_err(emc->dev, "Unable to find emc node\n");
+		return -ENODEV;
+	}
+
+	if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+		ram_code = tegra_read_ram_code();
+		node = tegra_emc_find_node_by_ram_code(np, ram_code);
+
+		if (!node) {
+			dev_warn(emc->dev, "can't find emc table for ram-code\n");
+			return -ENODEV;
+		}
+
+		ret = tegra210_emc_load_timings_from_dt(emc, node);
+		of_node_put(node);
+	} else {
+		ret = tegra210_emc_load_timings_from_dt(emc, np);
+	}
+
+	return ret;
+}
+
 static int tegra210_emc_validate_timings(struct tegra210_emc *emc,
 					 struct tegra210_emc_timing *timings,
 					 unsigned int num_timings)
@@ -1815,6 +2035,7 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	struct device_node *np;
 	unsigned int i;
 	int err;
+	bool have_dt_tables = false;
 
 	emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
 	if (!emc)
@@ -1847,16 +2068,20 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	np = pdev->dev.of_node;
 
 	/* attach to the nominal and (optional) derated tables */
-	err = of_reserved_mem_device_init_by_name(emc->dev, np, "nominal");
-	if (err < 0) {
-		dev_err(emc->dev, "failed to get nominal EMC table: %d\n", err);
-		return err;
-	}
+	if (of_reserved_mem_device_init_by_name(emc->dev, np, "nominal") >= 0) {
+		err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
+		if (err < 0 && err != -ENODEV) {
+			dev_err(emc->dev, "failed to get derated EMC table: %d\n", err);
+			goto release;
+		}
+	} else {
+		err = tegra210_emc_parse_dt(emc);
+		if (err < 0) {
+			dev_err(emc->dev, "failed to get EMC tables: %d\n", err);
+			return err;
+		}
 
-	err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
-	if (err < 0 && err != -ENODEV) {
-		dev_err(emc->dev, "failed to get derated EMC table: %d\n", err);
-		goto release;
+		have_dt_tables = true;
 	}
 
 	/* validate the tables */
@@ -1980,7 +2205,8 @@ static int tegra210_emc_probe(struct platform_device *pdev)
 	debugfs_remove_recursive(emc->debugfs.root);
 	tegra210_clk_emc_detach(emc->clk);
 release:
-	of_reserved_mem_device_release(emc->dev);
+	if (!have_dt_tables)
+		of_reserved_mem_device_release(emc->dev);
 
 	return err;
 }

---
base-commit: 8bac8898fe398ffa3e09075ecea2be511725fb0b
change-id: 20250429-tegra210-emc-dt-97dce690ad4e

Best regards,
-- 
Aaron Kling <webgeek1234@gmail.com>



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
  2025-04-30 17:52 ` Aaron Kling via B4 Relay
  (?)
@ 2025-05-04 13:37 ` Krzysztof Kozlowski
  2025-05-04 15:58   ` Aaron Kling
  -1 siblings, 1 reply; 7+ messages in thread
From: Krzysztof Kozlowski @ 2025-05-04 13:37 UTC (permalink / raw)
  To: webgeek1234, Thierry Reding, Jonathan Hunter; +Cc: linux-kernel, linux-tegra

On 30/04/2025 19:52, Aaron Kling via B4 Relay wrote:
> +#undef EMC_READ_PROP
> +#undef EMC_READ_STRING
> +#undef EMC_READ_PROP_ARRAY
> +
> +	return 0;
> +}
> +
> +#define NOMINAL_COMPATIBLE "nvidia,tegra21-emc-table"
> +#define DERATED_COMPATIBLE "nvidia,tegra21-emc-table-derated"

No, you cannot add undocumented compatibles. Missing bindings.

> +static int tegra210_emc_load_timings_from_dt(struct tegra210_emc *emc,
> +					     struct device_node *node)
> +{
> +	struct tegra210_emc_timing *timing;
> +	unsigned int num_nominal = 0, num_derated = 0;
> +	int err;
> +
> +	emc->num_timings = 0;
> +	for_each_child_of_node_scoped(node, child) {
> +		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
> +			emc->num_timings++;
> +		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
> +			num_derated++;
> +	}
> +
> +	if (!emc->num_timings || (num_derated && (emc->num_timings != num_derated)))
> +		return -EINVAL;
> +
> +	emc->nominal = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
> +				    GFP_KERNEL);
> +	if (!emc->nominal)
> +		return -ENOMEM;
> +
> +	if (num_derated) {
> +		num_derated = 0;
> +		emc->derated = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
> +					    GFP_KERNEL);
> +		if (!emc->derated)
> +			return -ENOMEM;
> +	}
> +
> +	for_each_child_of_node_scoped(node, child) {
> +		if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
> +			timing = &emc->nominal[num_nominal++];
> +		else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
> +			timing = &emc->derated[num_derated++];
> +		else
> +			continue;
> +
> +		err = load_one_timing_from_dt(emc, timing, child);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
> +{
> +	struct device_node *node, *np = emc->dev->of_node;
> +	int ram_code, ret = 0;
> +
> +	if (!np) {
> +		dev_err(emc->dev, "Unable to find emc node\n");
> +		return -ENODEV;
> +	}
> +
> +	if (of_find_property(np, "nvidia,use-ram-code", NULL)) {

I cannot find the bindings for this. Where is your DTS? Was it tested?

It seems nothing here is documented.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
  2025-05-04 13:37 ` Krzysztof Kozlowski
@ 2025-05-04 15:58   ` Aaron Kling
  2025-05-04 16:13     ` Krzysztof Kozlowski
  0 siblings, 1 reply; 7+ messages in thread
From: Aaron Kling @ 2025-05-04 15:58 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Thierry Reding, Jonathan Hunter, linux-kernel, linux-tegra

On Sun, May 4, 2025 at 8:38 AM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On 30/04/2025 19:52, Aaron Kling via B4 Relay wrote:
> > +#undef EMC_READ_PROP
> > +#undef EMC_READ_STRING
> > +#undef EMC_READ_PROP_ARRAY
> > +
> > +     return 0;
> > +}
> > +
> > +#define NOMINAL_COMPATIBLE "nvidia,tegra21-emc-table"
> > +#define DERATED_COMPATIBLE "nvidia,tegra21-emc-table-derated"
>
> No, you cannot add undocumented compatibles. Missing bindings.
>
> > +static int tegra210_emc_load_timings_from_dt(struct tegra210_emc *emc,
> > +                                          struct device_node *node)
> > +{
> > +     struct tegra210_emc_timing *timing;
> > +     unsigned int num_nominal = 0, num_derated = 0;
> > +     int err;
> > +
> > +     emc->num_timings = 0;
> > +     for_each_child_of_node_scoped(node, child) {
> > +             if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
> > +                     emc->num_timings++;
> > +             else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
> > +                     num_derated++;
> > +     }
> > +
> > +     if (!emc->num_timings || (num_derated && (emc->num_timings != num_derated)))
> > +             return -EINVAL;
> > +
> > +     emc->nominal = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
> > +                                 GFP_KERNEL);
> > +     if (!emc->nominal)
> > +             return -ENOMEM;
> > +
> > +     if (num_derated) {
> > +             num_derated = 0;
> > +             emc->derated = devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing),
> > +                                         GFP_KERNEL);
> > +             if (!emc->derated)
> > +                     return -ENOMEM;
> > +     }
> > +
> > +     for_each_child_of_node_scoped(node, child) {
> > +             if (of_device_is_compatible(child, NOMINAL_COMPATIBLE))
> > +                     timing = &emc->nominal[num_nominal++];
> > +             else if (of_device_is_compatible(child, DERATED_COMPATIBLE))
> > +                     timing = &emc->derated[num_derated++];
> > +             else
> > +                     continue;
> > +
> > +             err = load_one_timing_from_dt(emc, timing, child);
> > +             if (err)
> > +                     return err;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
> > +{
> > +     struct device_node *node, *np = emc->dev->of_node;
> > +     int ram_code, ret = 0;
> > +
> > +     if (!np) {
> > +             dev_err(emc->dev, "Unable to find emc node\n");
> > +             return -ENODEV;
> > +     }
> > +
> > +     if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
>
> I cannot find the bindings for this. Where is your DTS? Was it tested?
>
> It seems nothing here is documented.

The relevant nodes are filled in by the bootloader. I had hoped that
the early stage bootloader would be able to copy that into the
mainline dt without needing to prime said mainline dt, but that's not
working as hoped. I'll send a v2 with dt bindings and the first usage
of it in p2371-2180.

Sincerely,
Aaron

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
  2025-05-04 15:58   ` Aaron Kling
@ 2025-05-04 16:13     ` Krzysztof Kozlowski
  2025-05-04 17:18       ` Aaron Kling
  0 siblings, 1 reply; 7+ messages in thread
From: Krzysztof Kozlowski @ 2025-05-04 16:13 UTC (permalink / raw)
  To: Aaron Kling; +Cc: Thierry Reding, Jonathan Hunter, linux-kernel, linux-tegra

On 04/05/2025 17:58, Aaron Kling wrote:
>>> +static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
>>> +{
>>> +     struct device_node *node, *np = emc->dev->of_node;
>>> +     int ram_code, ret = 0;
>>> +
>>> +     if (!np) {
>>> +             dev_err(emc->dev, "Unable to find emc node\n");
>>> +             return -ENODEV;
>>> +     }
>>> +
>>> +     if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
>>
>> I cannot find the bindings for this. Where is your DTS? Was it tested?
>>
>> It seems nothing here is documented.
> 
> The relevant nodes are filled in by the bootloader. I had hoped that
> the early stage bootloader would be able to copy that into the

It does not matter. You cannot have compatibles and ABI here without
documenting that ABI.



Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
  2025-05-04 16:13     ` Krzysztof Kozlowski
@ 2025-05-04 17:18       ` Aaron Kling
  0 siblings, 0 replies; 7+ messages in thread
From: Aaron Kling @ 2025-05-04 17:18 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Thierry Reding, Jonathan Hunter, linux-kernel, linux-tegra

On Sun, May 4, 2025 at 11:13 AM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On 04/05/2025 17:58, Aaron Kling wrote:
> >>> +static int tegra210_emc_parse_dt(struct tegra210_emc *emc)
> >>> +{
> >>> +     struct device_node *node, *np = emc->dev->of_node;
> >>> +     int ram_code, ret = 0;
> >>> +
> >>> +     if (!np) {
> >>> +             dev_err(emc->dev, "Unable to find emc node\n");
> >>> +             return -ENODEV;
> >>> +     }
> >>> +
> >>> +     if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
> >>
> >> I cannot find the bindings for this. Where is your DTS? Was it tested?
> >>
> >> It seems nothing here is documented.
> >
> > The relevant nodes are filled in by the bootloader. I had hoped that
> > the early stage bootloader would be able to copy that into the
>
> It does not matter. You cannot have compatibles and ABI here without
> documenting that ABI.

Understood, I will keep that in mind should the situation arise again.
And it will be rectified for this patch in v2.

Sincerely,
Aaron

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
@ 2025-05-09  2:11 kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2025-05-09  2:11 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp, Dan Carpenter

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20250430-tegra210-emc-dt-v1-1-99896fa69341@gmail.com>
References: <20250430-tegra210-emc-dt-v1-1-99896fa69341@gmail.com>
TO: Aaron Kling via B4 Relay <devnull+webgeek1234.gmail.com@kernel.org>
TO: Krzysztof Kozlowski <krzk@kernel.org>
TO: Thierry Reding <thierry.reding@gmail.com>
TO: Jonathan Hunter <jonathanh@nvidia.com>
CC: linux-kernel@vger.kernel.org
CC: linux-tegra@vger.kernel.org
CC: Aaron Kling <webgeek1234@gmail.com>

Hi Aaron,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 8bac8898fe398ffa3e09075ecea2be511725fb0b]

url:    https://github.com/intel-lab-lkp/linux/commits/Aaron-Kling-via-B4-Relay/memory-tegra210-emc-Support-Device-Tree-EMC-Tables/20250501-020252
base:   8bac8898fe398ffa3e09075ecea2be511725fb0b
patch link:    https://lore.kernel.org/r/20250430-tegra210-emc-dt-v1-1-99896fa69341%40gmail.com
patch subject: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables
:::::: branch date: 8 days ago
:::::: commit date: 8 days ago
config: loongarch-randconfig-r071-20250502 (https://download.01.org/0day-ci/archive/20250509/202505090927.326G2S8V-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Closes: https://lore.kernel.org/r/202505090927.326G2S8V-lkp@intel.com/

smatch warnings:
drivers/memory/tegra/tegra210-emc-core.c:2081 tegra210_emc_probe() warn: missing unwind goto?

vim +2081 drivers/memory/tegra/tegra210-emc-core.c

10de21148f7d28 Joseph Lo       2019-05-29  2029  
10de21148f7d28 Joseph Lo       2019-05-29  2030  static int tegra210_emc_probe(struct platform_device *pdev)
10de21148f7d28 Joseph Lo       2019-05-29  2031  {
0553d7b204ef48 Thierry Reding  2020-04-03  2032  	struct thermal_cooling_device *cd;
10de21148f7d28 Joseph Lo       2019-05-29  2033  	unsigned long current_rate;
10de21148f7d28 Joseph Lo       2019-05-29  2034  	struct tegra210_emc *emc;
10de21148f7d28 Joseph Lo       2019-05-29  2035  	struct device_node *np;
10de21148f7d28 Joseph Lo       2019-05-29  2036  	unsigned int i;
10de21148f7d28 Joseph Lo       2019-05-29  2037  	int err;
48e6cf9a684da2 Aaron Kling     2025-04-30  2038  	bool have_dt_tables = false;
10de21148f7d28 Joseph Lo       2019-05-29  2039  
10de21148f7d28 Joseph Lo       2019-05-29  2040  	emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
10de21148f7d28 Joseph Lo       2019-05-29  2041  	if (!emc)
10de21148f7d28 Joseph Lo       2019-05-29  2042  		return -ENOMEM;
10de21148f7d28 Joseph Lo       2019-05-29  2043  
10de21148f7d28 Joseph Lo       2019-05-29  2044  	emc->clk = devm_clk_get(&pdev->dev, "emc");
10de21148f7d28 Joseph Lo       2019-05-29  2045  	if (IS_ERR(emc->clk))
10de21148f7d28 Joseph Lo       2019-05-29  2046  		return PTR_ERR(emc->clk);
10de21148f7d28 Joseph Lo       2019-05-29  2047  
10de21148f7d28 Joseph Lo       2019-05-29  2048  	platform_set_drvdata(pdev, emc);
10de21148f7d28 Joseph Lo       2019-05-29  2049  	spin_lock_init(&emc->lock);
10de21148f7d28 Joseph Lo       2019-05-29  2050  	emc->dev = &pdev->dev;
10de21148f7d28 Joseph Lo       2019-05-29  2051  
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2052  	emc->mc = devm_tegra_memory_controller_get(&pdev->dev);
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2053  	if (IS_ERR(emc->mc))
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2054  		return PTR_ERR(emc->mc);
10de21148f7d28 Joseph Lo       2019-05-29  2055  
10de21148f7d28 Joseph Lo       2019-05-29  2056  	emc->regs = devm_platform_ioremap_resource(pdev, 0);
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2057  	if (IS_ERR(emc->regs))
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2058  		return PTR_ERR(emc->regs);
10de21148f7d28 Joseph Lo       2019-05-29  2059  
10de21148f7d28 Joseph Lo       2019-05-29  2060  	for (i = 0; i < 2; i++) {
10de21148f7d28 Joseph Lo       2019-05-29  2061  		emc->channel[i] = devm_platform_ioremap_resource(pdev, 1 + i);
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2062  		if (IS_ERR(emc->channel[i]))
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2063  			return PTR_ERR(emc->channel[i]);
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2064  
10de21148f7d28 Joseph Lo       2019-05-29  2065  	}
10de21148f7d28 Joseph Lo       2019-05-29  2066  
10de21148f7d28 Joseph Lo       2019-05-29  2067  	tegra210_emc_detect(emc);
10de21148f7d28 Joseph Lo       2019-05-29  2068  	np = pdev->dev.of_node;
10de21148f7d28 Joseph Lo       2019-05-29  2069  
0553d7b204ef48 Thierry Reding  2020-04-03  2070  	/* attach to the nominal and (optional) derated tables */
48e6cf9a684da2 Aaron Kling     2025-04-30  2071  	if (of_reserved_mem_device_init_by_name(emc->dev, np, "nominal") >= 0) {
0553d7b204ef48 Thierry Reding  2020-04-03  2072  		err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
0553d7b204ef48 Thierry Reding  2020-04-03  2073  		if (err < 0 && err != -ENODEV) {
0553d7b204ef48 Thierry Reding  2020-04-03  2074  			dev_err(emc->dev, "failed to get derated EMC table: %d\n", err);
0553d7b204ef48 Thierry Reding  2020-04-03  2075  			goto release;
0553d7b204ef48 Thierry Reding  2020-04-03  2076  		}
48e6cf9a684da2 Aaron Kling     2025-04-30  2077  	} else {
48e6cf9a684da2 Aaron Kling     2025-04-30  2078  		err = tegra210_emc_parse_dt(emc);
48e6cf9a684da2 Aaron Kling     2025-04-30  2079  		if (err < 0) {
48e6cf9a684da2 Aaron Kling     2025-04-30  2080  			dev_err(emc->dev, "failed to get EMC tables: %d\n", err);
48e6cf9a684da2 Aaron Kling     2025-04-30 @2081  			return err;
48e6cf9a684da2 Aaron Kling     2025-04-30  2082  		}
48e6cf9a684da2 Aaron Kling     2025-04-30  2083  
48e6cf9a684da2 Aaron Kling     2025-04-30  2084  		have_dt_tables = true;
48e6cf9a684da2 Aaron Kling     2025-04-30  2085  	}
0553d7b204ef48 Thierry Reding  2020-04-03  2086  
10de21148f7d28 Joseph Lo       2019-05-29  2087  	/* validate the tables */
0553d7b204ef48 Thierry Reding  2020-04-03  2088  	if (emc->nominal) {
0553d7b204ef48 Thierry Reding  2020-04-03  2089  		err = tegra210_emc_validate_timings(emc, emc->nominal,
10de21148f7d28 Joseph Lo       2019-05-29  2090  						    emc->num_timings);
10de21148f7d28 Joseph Lo       2019-05-29  2091  		if (err < 0)
10de21148f7d28 Joseph Lo       2019-05-29  2092  			goto release;
0553d7b204ef48 Thierry Reding  2020-04-03  2093  	}
0553d7b204ef48 Thierry Reding  2020-04-03  2094  
0553d7b204ef48 Thierry Reding  2020-04-03  2095  	if (emc->derated) {
0553d7b204ef48 Thierry Reding  2020-04-03  2096  		err = tegra210_emc_validate_timings(emc, emc->derated,
0553d7b204ef48 Thierry Reding  2020-04-03  2097  						    emc->num_timings);
0553d7b204ef48 Thierry Reding  2020-04-03  2098  		if (err < 0)
0553d7b204ef48 Thierry Reding  2020-04-03  2099  			goto release;
0553d7b204ef48 Thierry Reding  2020-04-03  2100  	}
0553d7b204ef48 Thierry Reding  2020-04-03  2101  
0553d7b204ef48 Thierry Reding  2020-04-03  2102  	/* default to the nominal table */
0553d7b204ef48 Thierry Reding  2020-04-03  2103  	emc->timings = emc->nominal;
10de21148f7d28 Joseph Lo       2019-05-29  2104  
10de21148f7d28 Joseph Lo       2019-05-29  2105  	/* pick the current timing based on the current EMC clock rate */
10de21148f7d28 Joseph Lo       2019-05-29  2106  	current_rate = clk_get_rate(emc->clk) / 1000;
10de21148f7d28 Joseph Lo       2019-05-29  2107  
10de21148f7d28 Joseph Lo       2019-05-29  2108  	for (i = 0; i < emc->num_timings; i++) {
10de21148f7d28 Joseph Lo       2019-05-29  2109  		if (emc->timings[i].rate == current_rate) {
10de21148f7d28 Joseph Lo       2019-05-29  2110  			emc->last = &emc->timings[i];
10de21148f7d28 Joseph Lo       2019-05-29  2111  			break;
10de21148f7d28 Joseph Lo       2019-05-29  2112  		}
10de21148f7d28 Joseph Lo       2019-05-29  2113  	}
10de21148f7d28 Joseph Lo       2019-05-29  2114  
10de21148f7d28 Joseph Lo       2019-05-29  2115  	if (i == emc->num_timings) {
10de21148f7d28 Joseph Lo       2019-05-29  2116  		dev_err(emc->dev, "no EMC table entry found for %lu kHz\n",
10de21148f7d28 Joseph Lo       2019-05-29  2117  			current_rate);
10de21148f7d28 Joseph Lo       2019-05-29  2118  		err = -ENOENT;
10de21148f7d28 Joseph Lo       2019-05-29  2119  		goto release;
10de21148f7d28 Joseph Lo       2019-05-29  2120  	}
10de21148f7d28 Joseph Lo       2019-05-29  2121  
10de21148f7d28 Joseph Lo       2019-05-29  2122  	/* pick a compatible clock change sequence for the EMC table */
10de21148f7d28 Joseph Lo       2019-05-29  2123  	for (i = 0; i < ARRAY_SIZE(tegra210_emc_sequences); i++) {
10de21148f7d28 Joseph Lo       2019-05-29  2124  		const struct tegra210_emc_sequence *sequence =
10de21148f7d28 Joseph Lo       2019-05-29  2125  				tegra210_emc_sequences[i];
10de21148f7d28 Joseph Lo       2019-05-29  2126  
10de21148f7d28 Joseph Lo       2019-05-29  2127  		if (emc->timings[0].revision == sequence->revision) {
10de21148f7d28 Joseph Lo       2019-05-29  2128  			emc->sequence = sequence;
10de21148f7d28 Joseph Lo       2019-05-29  2129  			break;
10de21148f7d28 Joseph Lo       2019-05-29  2130  		}
10de21148f7d28 Joseph Lo       2019-05-29  2131  	}
10de21148f7d28 Joseph Lo       2019-05-29  2132  
10de21148f7d28 Joseph Lo       2019-05-29  2133  	if (!emc->sequence) {
10de21148f7d28 Joseph Lo       2019-05-29  2134  		dev_err(&pdev->dev, "sequence %u not supported\n",
10de21148f7d28 Joseph Lo       2019-05-29  2135  			emc->timings[0].revision);
10de21148f7d28 Joseph Lo       2019-05-29  2136  		err = -ENOTSUPP;
10de21148f7d28 Joseph Lo       2019-05-29  2137  		goto release;
10de21148f7d28 Joseph Lo       2019-05-29  2138  	}
10de21148f7d28 Joseph Lo       2019-05-29  2139  
10de21148f7d28 Joseph Lo       2019-05-29  2140  	emc->offsets = &tegra210_emc_table_register_offsets;
0553d7b204ef48 Thierry Reding  2020-04-03  2141  	emc->refresh = TEGRA210_EMC_REFRESH_NOMINAL;
10de21148f7d28 Joseph Lo       2019-05-29  2142  
10de21148f7d28 Joseph Lo       2019-05-29  2143  	emc->provider.owner = THIS_MODULE;
10de21148f7d28 Joseph Lo       2019-05-29  2144  	emc->provider.dev = &pdev->dev;
10de21148f7d28 Joseph Lo       2019-05-29  2145  	emc->provider.set_rate = tegra210_emc_set_rate;
10de21148f7d28 Joseph Lo       2019-05-29  2146  
10de21148f7d28 Joseph Lo       2019-05-29  2147  	emc->provider.configs = devm_kcalloc(&pdev->dev, emc->num_timings,
10de21148f7d28 Joseph Lo       2019-05-29  2148  					     sizeof(*emc->provider.configs),
10de21148f7d28 Joseph Lo       2019-05-29  2149  					     GFP_KERNEL);
10de21148f7d28 Joseph Lo       2019-05-29  2150  	if (!emc->provider.configs) {
10de21148f7d28 Joseph Lo       2019-05-29  2151  		err = -ENOMEM;
10de21148f7d28 Joseph Lo       2019-05-29  2152  		goto release;
10de21148f7d28 Joseph Lo       2019-05-29  2153  	}
10de21148f7d28 Joseph Lo       2019-05-29  2154  
10de21148f7d28 Joseph Lo       2019-05-29  2155  	emc->provider.num_configs = emc->num_timings;
10de21148f7d28 Joseph Lo       2019-05-29  2156  
10de21148f7d28 Joseph Lo       2019-05-29  2157  	for (i = 0; i < emc->provider.num_configs; i++) {
10de21148f7d28 Joseph Lo       2019-05-29  2158  		struct tegra210_emc_timing *timing = &emc->timings[i];
10de21148f7d28 Joseph Lo       2019-05-29  2159  		struct tegra210_clk_emc_config *config =
10de21148f7d28 Joseph Lo       2019-05-29  2160  				&emc->provider.configs[i];
10de21148f7d28 Joseph Lo       2019-05-29  2161  		u32 value;
10de21148f7d28 Joseph Lo       2019-05-29  2162  
10de21148f7d28 Joseph Lo       2019-05-29  2163  		config->rate = timing->rate * 1000UL;
10de21148f7d28 Joseph Lo       2019-05-29  2164  		config->value = timing->clk_src_emc;
10de21148f7d28 Joseph Lo       2019-05-29  2165  
10de21148f7d28 Joseph Lo       2019-05-29  2166  		value = timing->burst_mc_regs[MC_EMEM_ARB_MISC0_INDEX];
10de21148f7d28 Joseph Lo       2019-05-29  2167  
10de21148f7d28 Joseph Lo       2019-05-29  2168  		if ((value & MC_EMEM_ARB_MISC0_EMC_SAME_FREQ) == 0)
10de21148f7d28 Joseph Lo       2019-05-29  2169  			config->same_freq = false;
10de21148f7d28 Joseph Lo       2019-05-29  2170  		else
10de21148f7d28 Joseph Lo       2019-05-29  2171  			config->same_freq = true;
10de21148f7d28 Joseph Lo       2019-05-29  2172  	}
10de21148f7d28 Joseph Lo       2019-05-29  2173  
10de21148f7d28 Joseph Lo       2019-05-29  2174  	err = tegra210_clk_emc_attach(emc->clk, &emc->provider);
10de21148f7d28 Joseph Lo       2019-05-29  2175  	if (err < 0) {
10de21148f7d28 Joseph Lo       2019-05-29  2176  		dev_err(&pdev->dev, "failed to attach to EMC clock: %d\n", err);
10de21148f7d28 Joseph Lo       2019-05-29  2177  		goto release;
10de21148f7d28 Joseph Lo       2019-05-29  2178  	}
10de21148f7d28 Joseph Lo       2019-05-29  2179  
10de21148f7d28 Joseph Lo       2019-05-29  2180  	emc->clkchange_delay = 100;
10de21148f7d28 Joseph Lo       2019-05-29  2181  	emc->training_interval = 100;
10de21148f7d28 Joseph Lo       2019-05-29  2182  	dev_set_drvdata(emc->dev, emc);
10de21148f7d28 Joseph Lo       2019-05-29  2183  
0553d7b204ef48 Thierry Reding  2020-04-03  2184  	timer_setup(&emc->refresh_timer, tegra210_emc_poll_refresh,
0553d7b204ef48 Thierry Reding  2020-04-03  2185  		    TIMER_DEFERRABLE);
0553d7b204ef48 Thierry Reding  2020-04-03  2186  	atomic_set(&emc->refresh_poll, 0);
0553d7b204ef48 Thierry Reding  2020-04-03  2187  	emc->refresh_poll_interval = 1000;
0553d7b204ef48 Thierry Reding  2020-04-03  2188  
10de21148f7d28 Joseph Lo       2019-05-29  2189  	timer_setup(&emc->training, tegra210_emc_train, 0);
10de21148f7d28 Joseph Lo       2019-05-29  2190  
10de21148f7d28 Joseph Lo       2019-05-29  2191  	tegra210_emc_debugfs_init(emc);
10de21148f7d28 Joseph Lo       2019-05-29  2192  
0553d7b204ef48 Thierry Reding  2020-04-03  2193  	cd = devm_thermal_of_cooling_device_register(emc->dev, np, "emc", emc,
0553d7b204ef48 Thierry Reding  2020-04-03  2194  						     &tegra210_emc_cd_ops);
0553d7b204ef48 Thierry Reding  2020-04-03  2195  	if (IS_ERR(cd)) {
0553d7b204ef48 Thierry Reding  2020-04-03  2196  		err = PTR_ERR(cd);
0553d7b204ef48 Thierry Reding  2020-04-03  2197  		dev_err(emc->dev, "failed to register cooling device: %d\n",
0553d7b204ef48 Thierry Reding  2020-04-03  2198  			err);
0553d7b204ef48 Thierry Reding  2020-04-03  2199  		goto detach;
0553d7b204ef48 Thierry Reding  2020-04-03  2200  	}
0553d7b204ef48 Thierry Reding  2020-04-03  2201  
10de21148f7d28 Joseph Lo       2019-05-29  2202  	return 0;
10de21148f7d28 Joseph Lo       2019-05-29  2203  
0553d7b204ef48 Thierry Reding  2020-04-03  2204  detach:
0553d7b204ef48 Thierry Reding  2020-04-03  2205  	debugfs_remove_recursive(emc->debugfs.root);
0553d7b204ef48 Thierry Reding  2020-04-03  2206  	tegra210_clk_emc_detach(emc->clk);
10de21148f7d28 Joseph Lo       2019-05-29  2207  release:
48e6cf9a684da2 Aaron Kling     2025-04-30  2208  	if (!have_dt_tables)
10de21148f7d28 Joseph Lo       2019-05-29  2209  		of_reserved_mem_device_release(emc->dev);
6c6bd2075f01f8 Dmitry Osipenko 2020-11-04  2210  
10de21148f7d28 Joseph Lo       2019-05-29  2211  	return err;
10de21148f7d28 Joseph Lo       2019-05-29  2212  }
10de21148f7d28 Joseph Lo       2019-05-29  2213  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-05-09  2:11 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-30 17:52 [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables Aaron Kling
2025-04-30 17:52 ` Aaron Kling via B4 Relay
2025-05-04 13:37 ` Krzysztof Kozlowski
2025-05-04 15:58   ` Aaron Kling
2025-05-04 16:13     ` Krzysztof Kozlowski
2025-05-04 17:18       ` Aaron Kling
  -- strict thread matches above, loose matches on Subject: below --
2025-05-09  2:11 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.