* [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.