From patchwork Fri Sep 14 21:48:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter De Schrijver X-Patchwork-Id: 10601345 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D87AA13AD for ; Sat, 15 Sep 2018 01:27:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C40CC2B89B for ; Sat, 15 Sep 2018 01:27:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B86D62B89C; Sat, 15 Sep 2018 01:27:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8DE442B8D4 for ; Sat, 15 Sep 2018 01:27:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726181AbeIOGoK (ORCPT ); Sat, 15 Sep 2018 02:44:10 -0400 Received: from hqemgate15.nvidia.com ([216.228.121.64]:11291 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725907AbeIOGoK (ORCPT ); Sat, 15 Sep 2018 02:44:10 -0400 Received: from hqpgpgate102.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Fri, 14 Sep 2018 18:26:37 -0700 Received: from HQMAIL101.nvidia.com ([172.20.161.6]) by hqpgpgate102.nvidia.com (PGP Universal service); Fri, 14 Sep 2018 18:27:12 -0700 X-PGP-Universal: processed; by hqpgpgate102.nvidia.com on Fri, 14 Sep 2018 18:27:12 -0700 Received: from tbergstrom-lnx.Nvidia.com (10.124.1.5) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 15 Sep 2018 01:27:12 +0000 Received: from tbergstrom-lnx.nvidia.com (localhost [127.0.0.1]) by tbergstrom-lnx.Nvidia.com (Postfix) with ESMTP id 3CB1EF8376B; Sat, 15 Sep 2018 00:48:18 +0300 (EEST) From: Peter De Schrijver To: CC: Peter De Schrijver Subject: [RFC 11/14] memory: tegra: parse DT and costruct timing tables Date: Sat, 15 Sep 2018 00:48:12 +0300 Message-ID: <1536961695-27809-12-git-send-email-pdeschrijver@nvidia.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1536961695-27809-1-git-send-email-pdeschrijver@nvidia.com> References: <1536961695-27809-1-git-send-email-pdeschrijver@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [10.124.1.5] X-ClientProxiedBy: HQMAIL105.nvidia.com (172.20.187.12) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1536974797; bh=R32n2OhuPvdmzPj/EPy/RpY8DGRVVjmhH2Jj7Pi5s4k=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: Content-Type:X-Originating-IP:X-ClientProxiedBy; b=OyGiAn+JLvsNTSJsssTvVesR73dvK52D3kSQvx3wFJ51jNjiO8gbwMC/g1ZThQD5W KzUq8HGTaLmDB6psXffVWDF2K+GbCVgS2wkqzscjt6Y9rxDQjh6WEOrnyUq6bzeg5X F45d0OZ2WE+n+x5tPjx7l+ldqhBuEC0/DqpOPfvcZUMYkgJiJGgotyEGbTfQzQ+ICp s9OY6cOnxc+FYLGw3tOWCM3SJqmCSSnEptkkrq92t7KkDu/T/S/3ZngXJdoQRanT/7 RyD5VLvjxDYmgwOuT0Wjv/Su5AEm6Wg30FLfFfVAMup2zQqk+sGGiMylJb+bHMmx88 iyFCLuruNCcpw== Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Peter De Schrijver --- drivers/memory/tegra/tegra210-dt-parse.c | 363 +++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 drivers/memory/tegra/tegra210-dt-parse.c diff --git a/drivers/memory/tegra/tegra210-dt-parse.c b/drivers/memory/tegra/tegra210-dt-parse.c new file mode 100644 index 0000000..553663a --- /dev/null +++ b/drivers/memory/tegra/tegra210-dt-parse.c @@ -0,0 +1,363 @@ +/* + * drivers/platform/tegra/mc/tegra_emc_dt_parse.c + * + * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +//#include + +#include "tegra210-emc-reg.h" + +static struct device_node *tegra_emc_ramcode_devnode( + struct device_node *np) +{ + struct device_node *iter; + u32 reg; + + for_each_child_of_node(np, iter) { + if (of_property_read_u32(iter, "nvidia,ram-code", ®)) + continue; + if (reg == tegra_read_ram_code()) + return of_node_get(iter); + } + + return NULL; +} + +static void *tegra_emc_dt_parse_pdata_comp(const char *emc_mode, + const char *comp, + void *pdata, + struct device_node *tnp, + struct platform_device *pdev, + int num_tables, int *table_count) +{ +#define PNE_U32(node, entry, tbl_entry) \ + do { \ + int __ret__; \ + u32 __tmp__; \ + \ + __ret__ = of_property_read_u32((node), (entry), &__tmp__); \ + if (__ret__) { \ + dev_err(&pdev->dev, "Failed to parse %s in %s: %d\n", \ + (entry), (node)->full_name, __ret__); \ + continue; \ + } \ + \ + tables[i].tbl_entry = __tmp__; \ + } while (0) + +#define PNE_U32_ARRAY(node, entry, tbl_entry, length) \ + do { \ + int __ret__; \ + \ + __ret__ = of_property_read_u32_array((node), (entry), \ + (tbl_entry), (length)); \ + if (__ret__) { \ + dev_err(&pdev->dev, "Failed to parse %s in %s: %d\n", \ + (entry), (node)->full_name, __ret__); \ + continue; \ + } \ + } while (0) + + int i = 0, ret = 0; + struct device_node *iter; + struct emc_timing *tables; + + tables = devm_kzalloc(&pdev->dev, + sizeof(*tables) * num_tables, GFP_KERNEL); + + if (!tables) { + of_node_put(tnp); + return tables; + } + + for_each_child_of_node(tnp, iter) { + if (of_device_is_compatible(iter, comp)) { + const char *source_name; + const char *dvfs_ver; + + ret = of_property_read_string(iter, + "nvidia,source", &source_name); + if (ret) { + dev_err(&pdev->dev, "no source name in %s\n", + iter->full_name); + continue; + } + strlcpy(tables[i].clock_src, source_name, + sizeof(tables[i].clock_src)); + + ret = of_property_read_string(iter, + "nvidia,dvfs-version", &dvfs_ver); + if (ret) { + dev_err(&pdev->dev, "no dvfs version in %s\n", + iter->full_name); + continue; + } + strlcpy(tables[i].dvfs_ver, dvfs_ver, + sizeof(tables[i].dvfs_ver)); + + PNE_U32(iter, "nvidia,revision", rev); + PNE_U32(iter, "clock-frequency", rate); + PNE_U32(iter, "nvidia,emc-min-mv", min_volt); + PNE_U32(iter, "nvidia,gk20a-min-mv", gpu_min_volt); + PNE_U32(iter, "nvidia,src-sel-reg", clk_src_emc); + PNE_U32(iter, "nvidia,burst-regs-num", num_burst); + PNE_U32(iter, "nvidia,emc-cfg-2", emc_cfg_2); + PNE_U32(iter, "nvidia,emc-sel-dpd-ctrl", + emc_sel_dpd_ctrl); + PNE_U32(iter, "nvidia,emc-auto-cal-config", + emc_auto_cal_config); + PNE_U32(iter, "nvidia,emc-auto-cal-config2", + emc_auto_cal_config2); + PNE_U32(iter, "nvidia,emc-auto-cal-config3", + emc_auto_cal_config3); + PNE_U32(iter, "nvidia,emc-clock-latency-change", + latency); + PNE_U32_ARRAY(iter, "nvidia,emc-registers", + tables[i].burst_regs, + tables[i].num_burst); + + PNE_U32(iter, "nvidia,needs-training", needs_training); + PNE_U32(iter, "nvidia,trained", trained); + if (tables[i].rev < 0x6) + goto skip_periodic_training_params; + PNE_U32(iter, "nvidia,periodic_training", + periodic_training); + PNE_U32(iter, "nvidia,trained_dram_clktree_c0d0u0", + trained_dram_clktree_c0d0u0); + PNE_U32(iter, "nvidia,trained_dram_clktree_c0d0u1", + trained_dram_clktree_c0d0u1); + PNE_U32(iter, "nvidia,trained_dram_clktree_c0d1u0", + trained_dram_clktree_c0d1u0); + PNE_U32(iter, "nvidia,trained_dram_clktree_c0d1u1", + trained_dram_clktree_c0d1u1); + PNE_U32(iter, "nvidia,trained_dram_clktree_c1d0u0", + trained_dram_clktree_c1d0u0); + PNE_U32(iter, "nvidia,trained_dram_clktree_c1d0u1", + trained_dram_clktree_c1d0u1); + PNE_U32(iter, "nvidia,trained_dram_clktree_c1d1u0", + trained_dram_clktree_c1d1u0); + PNE_U32(iter, "nvidia,trained_dram_clktree_c1d1u1", + trained_dram_clktree_c1d1u1); + PNE_U32(iter, "nvidia,current_dram_clktree_c0d0u0", + current_dram_clktree_c0d0u0); + PNE_U32(iter, "nvidia,current_dram_clktree_c0d0u1", + current_dram_clktree_c0d0u1); + PNE_U32(iter, "nvidia,current_dram_clktree_c0d1u0", + current_dram_clktree_c0d1u0); + PNE_U32(iter, "nvidia,current_dram_clktree_c0d1u1", + current_dram_clktree_c0d1u1); + PNE_U32(iter, "nvidia,current_dram_clktree_c1d0u0", + current_dram_clktree_c1d0u0); + PNE_U32(iter, "nvidia,current_dram_clktree_c1d0u1", + current_dram_clktree_c1d0u1); + PNE_U32(iter, "nvidia,current_dram_clktree_c1d1u0", + current_dram_clktree_c1d1u0); + PNE_U32(iter, "nvidia,current_dram_clktree_c1d1u1", + current_dram_clktree_c1d1u1); + PNE_U32(iter, "nvidia,run_clocks", run_clocks); + PNE_U32(iter, "nvidia,tree_margin", tree_margin); + +skip_periodic_training_params: + PNE_U32(iter, "nvidia,burst-regs-per-ch-num", + num_burst_per_ch); + PNE_U32(iter, "nvidia,trim-regs-num", num_trim); + PNE_U32(iter, "nvidia,trim-regs-per-ch-num", + num_trim_per_ch); + PNE_U32(iter, "nvidia,burst-mc-regs-num", + num_mc_regs); + PNE_U32(iter, "nvidia,la-scale-regs-num", + num_up_down); + PNE_U32(iter, "nvidia,vref-regs-num", vref_num); + PNE_U32(iter, "nvidia,dram-timing-regs-num", + dram_timing_num); + PNE_U32(iter, "nvidia,min-mrs-wait", min_mrs_wait); + PNE_U32(iter, "nvidia,emc-mrw", emc_mrw); + PNE_U32(iter, "nvidia,emc-mrw2", emc_mrw2); + PNE_U32(iter, "nvidia,emc-mrw3", emc_mrw3); + PNE_U32(iter, "nvidia,emc-mrw4", emc_mrw4); + PNE_U32(iter, "nvidia,emc-mrw9", emc_mrw9); + PNE_U32(iter, "nvidia,emc-mrs", emc_mrs); + PNE_U32(iter, "nvidia,emc-emrs", emc_emrs); + PNE_U32(iter, "nvidia,emc-emrs2", emc_emrs2); + PNE_U32(iter, "nvidia,emc-auto-cal-config4", + emc_auto_cal_config4); + PNE_U32(iter, "nvidia,emc-auto-cal-config5", + emc_auto_cal_config5); + PNE_U32(iter, "nvidia,emc-auto-cal-config6", + emc_auto_cal_config6); + PNE_U32(iter, "nvidia,emc-auto-cal-config7", + emc_auto_cal_config7); + PNE_U32(iter, "nvidia,emc-auto-cal-config8", + emc_auto_cal_config8); + PNE_U32(iter, "nvidia,emc-fdpd-ctrl-cmd-no-ramp", + emc_fdpd_ctrl_cmd_no_ramp); + PNE_U32(iter, "nvidia,dll-clk-src", dll_clk_src); + PNE_U32(iter, "nvidia,clk-out-enb-x-0-clk-enb-emc-dll", + clk_out_enb_x_0_clk_enb_emc_dll); + + if (tables[i].rev >= 0x7) + PNE_U32_ARRAY(iter, "nvidia,ptfv", + tables[i].ptfv_list, + sizeof(tables[i].ptfv_list) + / sizeof(u32)); + + PNE_U32_ARRAY(iter, "nvidia,emc-burst-regs-per-ch", + tables[i].burst_reg_per_ch, + tables[i].num_burst_per_ch); + PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-ca-train", + tables[i].shadow_regs_ca_train, + tables[i].num_burst); + PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-quse-train", + tables[i].shadow_regs_quse_train, + tables[i].num_burst); + PNE_U32_ARRAY(iter, "nvidia,emc-shadow-regs-rdwr-train", + tables[i].shadow_regs_rdwr_train, + tables[i].num_burst); + PNE_U32_ARRAY(iter, "nvidia,emc-trim-regs", + tables[i].trim_regs, + tables[i].num_trim); + PNE_U32_ARRAY(iter, "nvidia,emc-trim-regs-per-ch", + tables[i].trim_perch_regs, + tables[i].num_trim_per_ch); + PNE_U32_ARRAY(iter, "nvidia,emc-vref-regs", + tables[i].vref_perch_regs, + tables[i].vref_num); + PNE_U32_ARRAY(iter, "nvidia,emc-dram-timing-regs", + tables[i].dram_timings, + tables[i].dram_timing_num); + PNE_U32_ARRAY(iter, "nvidia,emc-burst-mc-regs", + tables[i].burst_mc_regs, + tables[i].num_mc_regs); + PNE_U32_ARRAY(iter, "nvidia,emc-la-scale-regs", + tables[i].la_scale_regs, + tables[i].num_up_down); + i++; + } + } + *table_count = i; + return tables; +} + +static const struct of_device_id emc_table_match[] = { + { + .compatible = "nvidia,tegra210-emc-table", + .data = "nvidia,tegra210-emc-table-derated", + }, + { + .compatible = "nvidia,tegra21-emc-table", + .data = "nvidia,tegra21-emc-table-derated", + }, + { }, +}; + +int tegra_emc_dt_parse_pdata(struct platform_device *pdev, + struct emc_timing **tables, + struct emc_timing **derated_tables, + int *num_entries) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *tnp, *iter; + int num_tables, table_count; + u32 tegra_bct_strapping; + const char *emc_mode = "nvidia,emc-mode-0"; + struct tegra21_emc_pdata *pdata = NULL; + const char *comp = NULL; + const char *comp_derated = NULL; + const void *prop; + + if (!np) { + dev_err(&pdev->dev, + "Unable to find external-memory-controller node\n"); + return -ENODEV; + } + + tegra_bct_strapping = tegra_read_ram_code(); + + prop = of_get_property(pdev->dev.of_node, + "nvidia,poll_thresh_freq", NULL); + if (prop) { + unsigned long freq_thresh = (unsigned long)be32_to_cpup(prop); + +// tegra210_emc_mr4_set_freq_thresh(freq_thresh); + pr_info("tegra: emc: Using MR4 freq threshold: %lu\n", + freq_thresh); + } + + if (of_find_property(np, "nvidia,use-ram-code", NULL)) { + tnp = tegra_emc_ramcode_devnode(np); + + if (!tnp) { + dev_warn(&pdev->dev, + "can't find emc table for ram-code 0x%02x\n", + tegra_bct_strapping); + return -ENODEV; + } + } else + tnp = of_node_get(np); + + num_tables = 0; + for_each_child_of_node(tnp, iter) { + if (!comp) { + const struct of_device_id *m = + of_match_node(emc_table_match, iter); + if (m) { + comp = m->compatible; + comp_derated = m->data; + num_tables++; + } + continue; + } + if (of_device_is_compatible(iter, comp)) + num_tables++; + } + + if (!num_tables) { + *tables = NULL; + goto out; + } + + *tables = tegra_emc_dt_parse_pdata_comp(emc_mode, comp, pdata, tnp, + pdev, num_tables, &table_count); + *num_entries = table_count; + + /* populate the derated tables */ + num_tables = 0; + for_each_child_of_node(tnp, iter) { + if (of_device_is_compatible(iter, comp_derated)) + num_tables++; + } + + if (!num_tables) { + *derated_tables = NULL; + goto out; + } + + *derated_tables = tegra_emc_dt_parse_pdata_comp(emc_mode, + comp_derated, pdata, tnp, pdev, num_tables, + &table_count); + +out: + of_node_put(tnp); + return 0; +}