| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Author: |
|---|
| 5 | 6 | * Mikko Perttunen <mperttunen@nvidia.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This software is licensed under the terms of the GNU General Public |
|---|
| 8 | | - * License version 2, as published by the Free Software Foundation, and |
|---|
| 9 | | - * may be copied, distributed, and modified under those terms. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | 7 | */ |
|---|
| 17 | 8 | |
|---|
| 18 | 9 | #include <linux/clk-provider.h> |
|---|
| .. | .. |
|---|
| 20 | 11 | #include <linux/clkdev.h> |
|---|
| 21 | 12 | #include <linux/debugfs.h> |
|---|
| 22 | 13 | #include <linux/delay.h> |
|---|
| 14 | +#include <linux/io.h> |
|---|
| 23 | 15 | #include <linux/of_address.h> |
|---|
| 24 | 16 | #include <linux/of_platform.h> |
|---|
| 25 | 17 | #include <linux/platform_device.h> |
|---|
| .. | .. |
|---|
| 273 | 265 | #define EMC_PUTERM_ADJ 0x574 |
|---|
| 274 | 266 | |
|---|
| 275 | 267 | #define DRAM_DEV_SEL_ALL 0 |
|---|
| 276 | | -#define DRAM_DEV_SEL_0 (2 << 30) |
|---|
| 277 | | -#define DRAM_DEV_SEL_1 (1 << 30) |
|---|
| 268 | +#define DRAM_DEV_SEL_0 BIT(31) |
|---|
| 269 | +#define DRAM_DEV_SEL_1 BIT(30) |
|---|
| 278 | 270 | |
|---|
| 279 | 271 | #define EMC_CFG_POWER_FEATURES_MASK \ |
|---|
| 280 | 272 | (EMC_CFG_DYN_SREF | EMC_CFG_DRAM_ACPD | EMC_CFG_DRAM_CLKSTOP_SR | \ |
|---|
| .. | .. |
|---|
| 475 | 467 | |
|---|
| 476 | 468 | void __iomem *regs; |
|---|
| 477 | 469 | |
|---|
| 470 | + struct clk *clk; |
|---|
| 471 | + |
|---|
| 478 | 472 | enum emc_dram_type dram_type; |
|---|
| 479 | 473 | unsigned int dram_num; |
|---|
| 480 | 474 | |
|---|
| 481 | 475 | struct emc_timing last_timing; |
|---|
| 482 | 476 | struct emc_timing *timings; |
|---|
| 483 | 477 | unsigned int num_timings; |
|---|
| 478 | + |
|---|
| 479 | + struct { |
|---|
| 480 | + struct dentry *root; |
|---|
| 481 | + unsigned long min_rate; |
|---|
| 482 | + unsigned long max_rate; |
|---|
| 483 | + } debugfs; |
|---|
| 484 | 484 | }; |
|---|
| 485 | 485 | |
|---|
| 486 | 486 | /* Timing change sequence functions */ |
|---|
| .. | .. |
|---|
| 888 | 888 | |
|---|
| 889 | 889 | err = of_property_read_u32(node, "clock-frequency", &value); |
|---|
| 890 | 890 | if (err) { |
|---|
| 891 | | - dev_err(emc->dev, "timing %s: failed to read rate: %d\n", |
|---|
| 892 | | - node->name, err); |
|---|
| 891 | + dev_err(emc->dev, "timing %pOFn: failed to read rate: %d\n", |
|---|
| 892 | + node, err); |
|---|
| 893 | 893 | return err; |
|---|
| 894 | 894 | } |
|---|
| 895 | 895 | |
|---|
| .. | .. |
|---|
| 900 | 900 | ARRAY_SIZE(timing->emc_burst_data)); |
|---|
| 901 | 901 | if (err) { |
|---|
| 902 | 902 | dev_err(emc->dev, |
|---|
| 903 | | - "timing %s: failed to read emc burst data: %d\n", |
|---|
| 904 | | - node->name, err); |
|---|
| 903 | + "timing %pOFn: failed to read emc burst data: %d\n", |
|---|
| 904 | + node, err); |
|---|
| 905 | 905 | return err; |
|---|
| 906 | 906 | } |
|---|
| 907 | 907 | |
|---|
| 908 | 908 | #define EMC_READ_PROP(prop, dtprop) { \ |
|---|
| 909 | 909 | err = of_property_read_u32(node, dtprop, &timing->prop); \ |
|---|
| 910 | 910 | if (err) { \ |
|---|
| 911 | | - dev_err(emc->dev, "timing %s: failed to read " #prop ": %d\n", \ |
|---|
| 912 | | - node->name, err); \ |
|---|
| 911 | + dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \ |
|---|
| 912 | + node, err); \ |
|---|
| 913 | 913 | return err; \ |
|---|
| 914 | 914 | } \ |
|---|
| 915 | 915 | } |
|---|
| .. | .. |
|---|
| 984 | 984 | |
|---|
| 985 | 985 | static const struct of_device_id tegra_emc_of_match[] = { |
|---|
| 986 | 986 | { .compatible = "nvidia,tegra124-emc" }, |
|---|
| 987 | + { .compatible = "nvidia,tegra132-emc" }, |
|---|
| 987 | 988 | {} |
|---|
| 988 | 989 | }; |
|---|
| 989 | 990 | |
|---|
| .. | .. |
|---|
| 1006 | 1007 | return NULL; |
|---|
| 1007 | 1008 | } |
|---|
| 1008 | 1009 | |
|---|
| 1009 | | -/* Debugfs entry */ |
|---|
| 1010 | +/* |
|---|
| 1011 | + * debugfs interface |
|---|
| 1012 | + * |
|---|
| 1013 | + * The memory controller driver exposes some files in debugfs that can be used |
|---|
| 1014 | + * to control the EMC frequency. The top-level directory can be found here: |
|---|
| 1015 | + * |
|---|
| 1016 | + * /sys/kernel/debug/emc |
|---|
| 1017 | + * |
|---|
| 1018 | + * It contains the following files: |
|---|
| 1019 | + * |
|---|
| 1020 | + * - available_rates: This file contains a list of valid, space-separated |
|---|
| 1021 | + * EMC frequencies. |
|---|
| 1022 | + * |
|---|
| 1023 | + * - min_rate: Writing a value to this file sets the given frequency as the |
|---|
| 1024 | + * floor of the permitted range. If this is higher than the currently |
|---|
| 1025 | + * configured EMC frequency, this will cause the frequency to be |
|---|
| 1026 | + * increased so that it stays within the valid range. |
|---|
| 1027 | + * |
|---|
| 1028 | + * - max_rate: Similarily to the min_rate file, writing a value to this file |
|---|
| 1029 | + * sets the given frequency as the ceiling of the permitted range. If |
|---|
| 1030 | + * the value is lower than the currently configured EMC frequency, this |
|---|
| 1031 | + * will cause the frequency to be decreased so that it stays within the |
|---|
| 1032 | + * valid range. |
|---|
| 1033 | + */ |
|---|
| 1010 | 1034 | |
|---|
| 1011 | | -static int emc_debug_rate_get(void *data, u64 *rate) |
|---|
| 1035 | +static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) |
|---|
| 1012 | 1036 | { |
|---|
| 1013 | | - struct clk *c = data; |
|---|
| 1037 | + unsigned int i; |
|---|
| 1014 | 1038 | |
|---|
| 1015 | | - *rate = clk_get_rate(c); |
|---|
| 1039 | + for (i = 0; i < emc->num_timings; i++) |
|---|
| 1040 | + if (rate == emc->timings[i].rate) |
|---|
| 1041 | + return true; |
|---|
| 1016 | 1042 | |
|---|
| 1017 | | - return 0; |
|---|
| 1043 | + return false; |
|---|
| 1018 | 1044 | } |
|---|
| 1019 | 1045 | |
|---|
| 1020 | | -static int emc_debug_rate_set(void *data, u64 rate) |
|---|
| 1021 | | -{ |
|---|
| 1022 | | - struct clk *c = data; |
|---|
| 1023 | | - |
|---|
| 1024 | | - return clk_set_rate(c, rate); |
|---|
| 1025 | | -} |
|---|
| 1026 | | - |
|---|
| 1027 | | -DEFINE_SIMPLE_ATTRIBUTE(emc_debug_rate_fops, emc_debug_rate_get, |
|---|
| 1028 | | - emc_debug_rate_set, "%lld\n"); |
|---|
| 1029 | | - |
|---|
| 1030 | | -static int emc_debug_supported_rates_show(struct seq_file *s, void *data) |
|---|
| 1046 | +static int tegra_emc_debug_available_rates_show(struct seq_file *s, |
|---|
| 1047 | + void *data) |
|---|
| 1031 | 1048 | { |
|---|
| 1032 | 1049 | struct tegra_emc *emc = s->private; |
|---|
| 1033 | 1050 | const char *prefix = ""; |
|---|
| 1034 | 1051 | unsigned int i; |
|---|
| 1035 | 1052 | |
|---|
| 1036 | 1053 | for (i = 0; i < emc->num_timings; i++) { |
|---|
| 1037 | | - struct emc_timing *timing = &emc->timings[i]; |
|---|
| 1038 | | - |
|---|
| 1039 | | - seq_printf(s, "%s%lu", prefix, timing->rate); |
|---|
| 1040 | | - |
|---|
| 1054 | + seq_printf(s, "%s%lu", prefix, emc->timings[i].rate); |
|---|
| 1041 | 1055 | prefix = " "; |
|---|
| 1042 | 1056 | } |
|---|
| 1043 | 1057 | |
|---|
| .. | .. |
|---|
| 1046 | 1060 | return 0; |
|---|
| 1047 | 1061 | } |
|---|
| 1048 | 1062 | |
|---|
| 1049 | | -static int emc_debug_supported_rates_open(struct inode *inode, |
|---|
| 1050 | | - struct file *file) |
|---|
| 1063 | +DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates); |
|---|
| 1064 | + |
|---|
| 1065 | +static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) |
|---|
| 1051 | 1066 | { |
|---|
| 1052 | | - return single_open(file, emc_debug_supported_rates_show, |
|---|
| 1053 | | - inode->i_private); |
|---|
| 1067 | + struct tegra_emc *emc = data; |
|---|
| 1068 | + |
|---|
| 1069 | + *rate = emc->debugfs.min_rate; |
|---|
| 1070 | + |
|---|
| 1071 | + return 0; |
|---|
| 1054 | 1072 | } |
|---|
| 1055 | 1073 | |
|---|
| 1056 | | -static const struct file_operations emc_debug_supported_rates_fops = { |
|---|
| 1057 | | - .open = emc_debug_supported_rates_open, |
|---|
| 1058 | | - .read = seq_read, |
|---|
| 1059 | | - .llseek = seq_lseek, |
|---|
| 1060 | | - .release = single_release, |
|---|
| 1061 | | -}; |
|---|
| 1074 | +static int tegra_emc_debug_min_rate_set(void *data, u64 rate) |
|---|
| 1075 | +{ |
|---|
| 1076 | + struct tegra_emc *emc = data; |
|---|
| 1077 | + int err; |
|---|
| 1078 | + |
|---|
| 1079 | + if (!tegra_emc_validate_rate(emc, rate)) |
|---|
| 1080 | + return -EINVAL; |
|---|
| 1081 | + |
|---|
| 1082 | + err = clk_set_min_rate(emc->clk, rate); |
|---|
| 1083 | + if (err < 0) |
|---|
| 1084 | + return err; |
|---|
| 1085 | + |
|---|
| 1086 | + emc->debugfs.min_rate = rate; |
|---|
| 1087 | + |
|---|
| 1088 | + return 0; |
|---|
| 1089 | +} |
|---|
| 1090 | + |
|---|
| 1091 | +DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_min_rate_fops, |
|---|
| 1092 | + tegra_emc_debug_min_rate_get, |
|---|
| 1093 | + tegra_emc_debug_min_rate_set, "%llu\n"); |
|---|
| 1094 | + |
|---|
| 1095 | +static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) |
|---|
| 1096 | +{ |
|---|
| 1097 | + struct tegra_emc *emc = data; |
|---|
| 1098 | + |
|---|
| 1099 | + *rate = emc->debugfs.max_rate; |
|---|
| 1100 | + |
|---|
| 1101 | + return 0; |
|---|
| 1102 | +} |
|---|
| 1103 | + |
|---|
| 1104 | +static int tegra_emc_debug_max_rate_set(void *data, u64 rate) |
|---|
| 1105 | +{ |
|---|
| 1106 | + struct tegra_emc *emc = data; |
|---|
| 1107 | + int err; |
|---|
| 1108 | + |
|---|
| 1109 | + if (!tegra_emc_validate_rate(emc, rate)) |
|---|
| 1110 | + return -EINVAL; |
|---|
| 1111 | + |
|---|
| 1112 | + err = clk_set_max_rate(emc->clk, rate); |
|---|
| 1113 | + if (err < 0) |
|---|
| 1114 | + return err; |
|---|
| 1115 | + |
|---|
| 1116 | + emc->debugfs.max_rate = rate; |
|---|
| 1117 | + |
|---|
| 1118 | + return 0; |
|---|
| 1119 | +} |
|---|
| 1120 | + |
|---|
| 1121 | +DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_max_rate_fops, |
|---|
| 1122 | + tegra_emc_debug_max_rate_get, |
|---|
| 1123 | + tegra_emc_debug_max_rate_set, "%llu\n"); |
|---|
| 1062 | 1124 | |
|---|
| 1063 | 1125 | static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) |
|---|
| 1064 | 1126 | { |
|---|
| 1065 | | - struct dentry *root, *file; |
|---|
| 1066 | | - struct clk *clk; |
|---|
| 1127 | + unsigned int i; |
|---|
| 1128 | + int err; |
|---|
| 1067 | 1129 | |
|---|
| 1068 | | - root = debugfs_create_dir("emc", NULL); |
|---|
| 1069 | | - if (!root) { |
|---|
| 1130 | + emc->clk = devm_clk_get(dev, "emc"); |
|---|
| 1131 | + if (IS_ERR(emc->clk)) { |
|---|
| 1132 | + if (PTR_ERR(emc->clk) != -ENODEV) { |
|---|
| 1133 | + dev_err(dev, "failed to get EMC clock: %ld\n", |
|---|
| 1134 | + PTR_ERR(emc->clk)); |
|---|
| 1135 | + return; |
|---|
| 1136 | + } |
|---|
| 1137 | + } |
|---|
| 1138 | + |
|---|
| 1139 | + emc->debugfs.min_rate = ULONG_MAX; |
|---|
| 1140 | + emc->debugfs.max_rate = 0; |
|---|
| 1141 | + |
|---|
| 1142 | + for (i = 0; i < emc->num_timings; i++) { |
|---|
| 1143 | + if (emc->timings[i].rate < emc->debugfs.min_rate) |
|---|
| 1144 | + emc->debugfs.min_rate = emc->timings[i].rate; |
|---|
| 1145 | + |
|---|
| 1146 | + if (emc->timings[i].rate > emc->debugfs.max_rate) |
|---|
| 1147 | + emc->debugfs.max_rate = emc->timings[i].rate; |
|---|
| 1148 | + } |
|---|
| 1149 | + |
|---|
| 1150 | + if (!emc->num_timings) { |
|---|
| 1151 | + emc->debugfs.min_rate = clk_get_rate(emc->clk); |
|---|
| 1152 | + emc->debugfs.max_rate = emc->debugfs.min_rate; |
|---|
| 1153 | + } |
|---|
| 1154 | + |
|---|
| 1155 | + err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, |
|---|
| 1156 | + emc->debugfs.max_rate); |
|---|
| 1157 | + if (err < 0) { |
|---|
| 1158 | + dev_err(dev, "failed to set rate range [%lu-%lu] for %pC\n", |
|---|
| 1159 | + emc->debugfs.min_rate, emc->debugfs.max_rate, |
|---|
| 1160 | + emc->clk); |
|---|
| 1161 | + return; |
|---|
| 1162 | + } |
|---|
| 1163 | + |
|---|
| 1164 | + emc->debugfs.root = debugfs_create_dir("emc", NULL); |
|---|
| 1165 | + if (!emc->debugfs.root) { |
|---|
| 1070 | 1166 | dev_err(dev, "failed to create debugfs directory\n"); |
|---|
| 1071 | 1167 | return; |
|---|
| 1072 | 1168 | } |
|---|
| 1073 | 1169 | |
|---|
| 1074 | | - clk = clk_get_sys("tegra-clk-debug", "emc"); |
|---|
| 1075 | | - if (IS_ERR(clk)) { |
|---|
| 1076 | | - dev_err(dev, "failed to get debug clock: %ld\n", PTR_ERR(clk)); |
|---|
| 1077 | | - return; |
|---|
| 1078 | | - } |
|---|
| 1079 | | - |
|---|
| 1080 | | - file = debugfs_create_file("rate", S_IRUGO | S_IWUSR, root, clk, |
|---|
| 1081 | | - &emc_debug_rate_fops); |
|---|
| 1082 | | - if (!file) |
|---|
| 1083 | | - dev_err(dev, "failed to create debugfs entry\n"); |
|---|
| 1084 | | - |
|---|
| 1085 | | - file = debugfs_create_file("supported_rates", S_IRUGO, root, emc, |
|---|
| 1086 | | - &emc_debug_supported_rates_fops); |
|---|
| 1087 | | - if (!file) |
|---|
| 1088 | | - dev_err(dev, "failed to create debugfs entry\n"); |
|---|
| 1170 | + debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, |
|---|
| 1171 | + &tegra_emc_debug_available_rates_fops); |
|---|
| 1172 | + debugfs_create_file("min_rate", 0644, emc->debugfs.root, |
|---|
| 1173 | + emc, &tegra_emc_debug_min_rate_fops); |
|---|
| 1174 | + debugfs_create_file("max_rate", 0644, emc->debugfs.root, |
|---|
| 1175 | + emc, &tegra_emc_debug_max_rate_fops); |
|---|
| 1089 | 1176 | } |
|---|
| 1090 | 1177 | |
|---|
| 1091 | 1178 | static int tegra_emc_probe(struct platform_device *pdev) |
|---|