1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved 4 */ 5 6 #include <linux/cpufreq.h> 7 #include <linux/dma-mapping.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 12 #include <soc/tegra/bpmp.h> 13 #include <soc/tegra/bpmp-abi.h> 14 15 #define EDVD_CORE_VOLT_FREQ(core) (0x20 + (core) * 0x4) 16 #define EDVD_CORE_VOLT_FREQ_F_SHIFT 0 17 #define EDVD_CORE_VOLT_FREQ_F_MASK 0xffff 18 #define EDVD_CORE_VOLT_FREQ_V_SHIFT 16 19 20 struct tegra186_cpufreq_cluster_info { 21 unsigned long offset; 22 int cpus[4]; 23 unsigned int bpmp_cluster_id; 24 }; 25 26 #define NO_CPU -1 27 static const struct tegra186_cpufreq_cluster_info tegra186_clusters[] = { 28 /* Denver cluster */ 29 { 30 .offset = SZ_64K * 7, 31 .cpus = { 1, 2, NO_CPU, NO_CPU }, 32 .bpmp_cluster_id = 0, 33 }, 34 /* A57 cluster */ 35 { 36 .offset = SZ_64K * 6, 37 .cpus = { 0, 3, 4, 5 }, 38 .bpmp_cluster_id = 1, 39 }, 40 }; 41 42 struct tegra186_cpufreq_cluster { 43 const struct tegra186_cpufreq_cluster_info *info; 44 struct cpufreq_frequency_table *table; 45 u32 ref_clk_khz; 46 u32 div; 47 }; 48 49 struct tegra186_cpufreq_data { 50 void __iomem *regs; 51 52 size_t num_clusters; 53 struct tegra186_cpufreq_cluster *clusters; 54 }; 55 56 static int tegra186_cpufreq_init(struct cpufreq_policy *policy) 57 { 58 struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); 59 unsigned int i; 60 61 for (i = 0; i < data->num_clusters; i++) { 62 struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; 63 const struct tegra186_cpufreq_cluster_info *info = 64 cluster->info; 65 int core; 66 67 for (core = 0; core < ARRAY_SIZE(info->cpus); core++) { 68 if (info->cpus[core] == policy->cpu) 69 break; 70 } 71 if (core == ARRAY_SIZE(info->cpus)) 72 continue; 73 74 policy->driver_data = 75 data->regs + info->offset + EDVD_CORE_VOLT_FREQ(core); 76 policy->freq_table = cluster->table; 77 break; 78 } 79 80 policy->cpuinfo.transition_latency = 300 * 1000; 81 82 return 0; 83 } 84 85 static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy, 86 unsigned int index) 87 { 88 struct cpufreq_frequency_table *tbl = policy->freq_table + index; 89 void __iomem *edvd_reg = policy->driver_data; 90 u32 edvd_val = tbl->driver_data; 91 92 writel(edvd_val, edvd_reg); 93 94 return 0; 95 } 96 97 static unsigned int tegra186_cpufreq_get(unsigned int cpu) 98 { 99 struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); 100 struct cpufreq_policy *policy; 101 void __iomem *edvd_reg; 102 unsigned int i, freq = 0; 103 u32 ndiv; 104 105 policy = cpufreq_cpu_get(cpu); 106 if (!policy) 107 return 0; 108 109 edvd_reg = policy->driver_data; 110 ndiv = readl(edvd_reg) & EDVD_CORE_VOLT_FREQ_F_MASK; 111 112 for (i = 0; i < data->num_clusters; i++) { 113 struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; 114 int core; 115 116 for (core = 0; core < ARRAY_SIZE(cluster->info->cpus); core++) { 117 if (cluster->info->cpus[core] != policy->cpu) 118 continue; 119 120 freq = (cluster->ref_clk_khz * ndiv) / cluster->div; 121 goto out; 122 } 123 } 124 125 out: 126 cpufreq_cpu_put(policy); 127 128 return freq; 129 } 130 131 static struct cpufreq_driver tegra186_cpufreq_driver = { 132 .name = "tegra186", 133 .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | 134 CPUFREQ_NEED_INITIAL_FREQ_CHECK, 135 .get = tegra186_cpufreq_get, 136 .verify = cpufreq_generic_frequency_table_verify, 137 .target_index = tegra186_cpufreq_set_target, 138 .init = tegra186_cpufreq_init, 139 .attr = cpufreq_generic_attr, 140 }; 141 142 static struct cpufreq_frequency_table *init_vhint_table( 143 struct platform_device *pdev, struct tegra_bpmp *bpmp, 144 struct tegra186_cpufreq_cluster *cluster) 145 { 146 struct cpufreq_frequency_table *table; 147 struct mrq_cpu_vhint_request req; 148 struct tegra_bpmp_message msg; 149 struct cpu_vhint_data *data; 150 int err, i, j, num_rates = 0; 151 dma_addr_t phys; 152 void *virt; 153 154 virt = dma_alloc_coherent(bpmp->dev, sizeof(*data), &phys, 155 GFP_KERNEL); 156 if (!virt) 157 return ERR_PTR(-ENOMEM); 158 159 data = (struct cpu_vhint_data *)virt; 160 161 memset(&req, 0, sizeof(req)); 162 req.addr = phys; 163 req.cluster_id = cluster->info->bpmp_cluster_id; 164 165 memset(&msg, 0, sizeof(msg)); 166 msg.mrq = MRQ_CPU_VHINT; 167 msg.tx.data = &req; 168 msg.tx.size = sizeof(req); 169 170 err = tegra_bpmp_transfer(bpmp, &msg); 171 if (err) { 172 table = ERR_PTR(err); 173 goto free; 174 } 175 176 for (i = data->vfloor; i <= data->vceil; i++) { 177 u16 ndiv = data->ndiv[i]; 178 179 if (ndiv < data->ndiv_min || ndiv > data->ndiv_max) 180 continue; 181 182 /* Only store lowest voltage index for each rate */ 183 if (i > 0 && ndiv == data->ndiv[i - 1]) 184 continue; 185 186 num_rates++; 187 } 188 189 table = devm_kcalloc(&pdev->dev, num_rates + 1, sizeof(*table), 190 GFP_KERNEL); 191 if (!table) { 192 table = ERR_PTR(-ENOMEM); 193 goto free; 194 } 195 196 cluster->ref_clk_khz = data->ref_clk_hz / 1000; 197 cluster->div = data->pdiv * data->mdiv; 198 199 for (i = data->vfloor, j = 0; i <= data->vceil; i++) { 200 struct cpufreq_frequency_table *point; 201 u16 ndiv = data->ndiv[i]; 202 u32 edvd_val = 0; 203 204 if (ndiv < data->ndiv_min || ndiv > data->ndiv_max) 205 continue; 206 207 /* Only store lowest voltage index for each rate */ 208 if (i > 0 && ndiv == data->ndiv[i - 1]) 209 continue; 210 211 edvd_val |= i << EDVD_CORE_VOLT_FREQ_V_SHIFT; 212 edvd_val |= ndiv << EDVD_CORE_VOLT_FREQ_F_SHIFT; 213 214 point = &table[j++]; 215 point->driver_data = edvd_val; 216 point->frequency = (cluster->ref_clk_khz * ndiv) / cluster->div; 217 } 218 219 table[j].frequency = CPUFREQ_TABLE_END; 220 221 free: 222 dma_free_coherent(bpmp->dev, sizeof(*data), virt, phys); 223 224 return table; 225 } 226 227 static int tegra186_cpufreq_probe(struct platform_device *pdev) 228 { 229 struct tegra186_cpufreq_data *data; 230 struct tegra_bpmp *bpmp; 231 unsigned int i = 0, err; 232 233 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 234 if (!data) 235 return -ENOMEM; 236 237 data->clusters = devm_kcalloc(&pdev->dev, ARRAY_SIZE(tegra186_clusters), 238 sizeof(*data->clusters), GFP_KERNEL); 239 if (!data->clusters) 240 return -ENOMEM; 241 242 data->num_clusters = ARRAY_SIZE(tegra186_clusters); 243 244 bpmp = tegra_bpmp_get(&pdev->dev); 245 if (IS_ERR(bpmp)) 246 return PTR_ERR(bpmp); 247 248 data->regs = devm_platform_ioremap_resource(pdev, 0); 249 if (IS_ERR(data->regs)) { 250 err = PTR_ERR(data->regs); 251 goto put_bpmp; 252 } 253 254 for (i = 0; i < data->num_clusters; i++) { 255 struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; 256 257 cluster->info = &tegra186_clusters[i]; 258 cluster->table = init_vhint_table(pdev, bpmp, cluster); 259 if (IS_ERR(cluster->table)) { 260 err = PTR_ERR(cluster->table); 261 goto put_bpmp; 262 } 263 } 264 265 tegra186_cpufreq_driver.driver_data = data; 266 267 err = cpufreq_register_driver(&tegra186_cpufreq_driver); 268 269 put_bpmp: 270 tegra_bpmp_put(bpmp); 271 272 return err; 273 } 274 275 static int tegra186_cpufreq_remove(struct platform_device *pdev) 276 { 277 cpufreq_unregister_driver(&tegra186_cpufreq_driver); 278 279 return 0; 280 } 281 282 static const struct of_device_id tegra186_cpufreq_of_match[] = { 283 { .compatible = "nvidia,tegra186-ccplex-cluster", }, 284 { } 285 }; 286 MODULE_DEVICE_TABLE(of, tegra186_cpufreq_of_match); 287 288 static struct platform_driver tegra186_cpufreq_platform_driver = { 289 .driver = { 290 .name = "tegra186-cpufreq", 291 .of_match_table = tegra186_cpufreq_of_match, 292 }, 293 .probe = tegra186_cpufreq_probe, 294 .remove = tegra186_cpufreq_remove, 295 }; 296 module_platform_driver(tegra186_cpufreq_platform_driver); 297 298 MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); 299 MODULE_DESCRIPTION("NVIDIA Tegra186 cpufreq driver"); 300 MODULE_LICENSE("GPL v2"); 301