From nobody Sun Feb 8 20:17:38 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 120612983F4; Wed, 30 Apr 2025 17:52:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746035537; cv=none; b=Do3tuV7Iop+NlQ9VwPBE3dNOSRtLLx9GYigIyaP0LMOxa/Xc/u3FPpbNFfLZvtkt8ydfY6ulv+alPJ/cwd18yDl1O0fIM38bK7SDqSzngv9e22xUyb4iR3mhDv4wZJi8Al8DDuTvhPRWR1mjO0qt5jevfke4oYTkCyZ92DVQ0Lw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746035537; c=relaxed/simple; bh=3IQls6LanaHFfB+tJv6QGqpwwG+ALsyhTOMes6xZWPY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=WkSdwrzXTIcxIPBHnQa7It6Bhry7ttafFy+n4GAl06d1dxDIXaKIGUS/F8ToeYDXJ23RzgPIbQdcryFQ6EQSvL16qdQxa3FAlughxSgx2ONf9EwquyJpruFjXzy6lf7Qr3bo7uIIL9Od+dFY8+drgURxCi+uXGwKYEJjWvvPwUA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RimY1o+5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RimY1o+5" Received: by smtp.kernel.org (Postfix) with ESMTPS id 52222C32782; Wed, 30 Apr 2025 17:52:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1746035535; bh=3IQls6LanaHFfB+tJv6QGqpwwG+ALsyhTOMes6xZWPY=; h=From:Date:Subject:To:Cc:Reply-To:From; b=RimY1o+54Xo2+N5HDxBoVmlO+1gJ0j7Z1+pzm8HLffj0PUt6h6DJ3dmXotUNotr0T fohs8VWG7YBtGpB2y8E3g0wdLbryzATB3ug56eEpBvlfoDLTWMkxa+CG8tdm3NFdUo wcP+71iqOcd3J6sXF4FjWycbsdTZAXSxMY1AqtU0mXFMlgmiyW4flJqD75xXy8shdO /o3hLASffLMi3ZGT1O67YwhLukyb6Wva+TCxGJh035XWUs3cnwoc2YHTwo8dJzcqvy 3SbirMplKJ7yQhHzIuCuPBJ3thTMAZ5MoO83AwsM4gH6TW2jQkojyFQ7u5Dj/4+C3l Bsj2bT3bz0Bxg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D014FC3ABA9; Wed, 30 Apr 2025 17:52:14 +0000 (UTC) From: Aaron Kling via B4 Relay Date: Wed, 30 Apr 2025 12:52:01 -0500 Subject: [PATCH] memory: tegra210-emc: Support Device Tree EMC Tables Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250430-tegra210-emc-dt-v1-1-99896fa69341@gmail.com> X-B4-Tracking: v=1; b=H4sIAEBjEmgC/x3MSwqAIBRG4a3EHXfBpAe2lWgg+ld3kIVGBNLek 4bf4JxMCVGQaKwyRdyS5AgFTV2R22xYweKLSSvdqVYbvrBGqxvF2B37i83gHXqjrG9BpTojFnn +4zS/7wfGrSDaYQAAAA== X-Change-ID: 20250429-tegra210-emc-dt-97dce690ad4e To: Krzysztof Kozlowski , Thierry Reding , Jonathan Hunter Cc: linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org, Aaron Kling X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1746035534; l=11318; i=webgeek1234@gmail.com; s=20250217; h=from:subject:message-id; bh=oK0pr0GREoOZzHrbUEhRzpd0qBn9cGUQIAd6Mb/CAcg=; b=EqKw3T3C+p76GZFOR7E9cQJZ/nd9kzvp+ywCCbBSpfQSz2/MvBpngA1Tqc7KdyLx2f49GpZao e3LTTGH3V8zDWvwetocL7Jly8ji2bPqNlf+53J4tFjvOue+0r4FtXzu X-Developer-Key: i=webgeek1234@gmail.com; a=ed25519; pk=TQwd6q26txw7bkK7B8qtI/kcAohZc7bHHGSD7domdrU= X-Endpoint-Received: by B4 Relay for webgeek1234@gmail.com/20250217 with auth_id=342 X-Original-From: Aaron Kling Reply-To: webgeek1234@gmail.com From: 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 --- 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/tegr= a/tegra210-emc-core.c index e63f6269057106ded054dea94d92d96cb9c13c06..0b8c7cd09679dc64b3fb04acf2b= b5963dd7544fc 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 =3D 1; } =20 +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 =3D of_property_read_u32(np, "nvidia,ram-code", &value); + if (err || (value !=3D 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 =3D 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 =3D of_property_read_string(node, dtprop, (const char **)&timing->pro= p); \ + 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 =3D 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 >=3D 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-ram= p") + 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-cl= k-enb-emc-dll") + + if (timing->revision >=3D 0x7) + EMC_READ_PROP_ARRAY(ptfv_list, "nvidia,ptfv", ARRAY_SIZE(timing->ptfv_li= st)) + + 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-trai= n", + 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", timin= g->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->nu= m_mc_regs) + EMC_READ_PROP_ARRAY(la_scale_regs, "nvidia,emc-la-scale-regs", timing->nu= m_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 =3D 0, num_derated =3D 0; + int err; + + emc->num_timings =3D 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 !=3D num_derat= ed))) + return -EINVAL; + + emc->nominal =3D devm_kcalloc(emc->dev, emc->num_timings, sizeof(*timing), + GFP_KERNEL); + if (!emc->nominal) + return -ENOMEM; + + if (num_derated) { + num_derated =3D 0; + emc->derated =3D 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 =3D &emc->nominal[num_nominal++]; + else if (of_device_is_compatible(child, DERATED_COMPATIBLE)) + timing =3D &emc->derated[num_derated++]; + else + continue; + + err =3D 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 =3D emc->dev->of_node; + int ram_code, ret =3D 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 =3D tegra_read_ram_code(); + node =3D 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 =3D tegra210_emc_load_timings_from_dt(emc, node); + of_node_put(node); + } else { + ret =3D 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 =3D false; =20 emc =3D devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); if (!emc) @@ -1847,16 +2068,20 @@ static int tegra210_emc_probe(struct platform_devic= e *pdev) np =3D pdev->dev.of_node; =20 /* attach to the nominal and (optional) derated tables */ - err =3D 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") >=3D 0) { + err =3D of_reserved_mem_device_init_by_name(emc->dev, np, "derated"); + if (err < 0 && err !=3D -ENODEV) { + dev_err(emc->dev, "failed to get derated EMC table: %d\n", err); + goto release; + } + } else { + err =3D tegra210_emc_parse_dt(emc); + if (err < 0) { + dev_err(emc->dev, "failed to get EMC tables: %d\n", err); + return err; + } =20 - err =3D of_reserved_mem_device_init_by_name(emc->dev, np, "derated"); - if (err < 0 && err !=3D -ENODEV) { - dev_err(emc->dev, "failed to get derated EMC table: %d\n", err); - goto release; + have_dt_tables =3D true; } =20 /* 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); =20 return err; } --- base-commit: 8bac8898fe398ffa3e09075ecea2be511725fb0b change-id: 20250429-tegra210-emc-dt-97dce690ad4e Best regards, --=20 Aaron Kling