Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved
0004  */
0005 
0006 #include <linux/cpufreq.h>
0007 #include <linux/dma-mapping.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/platform_device.h>
0011 
0012 #include <soc/tegra/bpmp.h>
0013 #include <soc/tegra/bpmp-abi.h>
0014 
0015 #define TEGRA186_NUM_CLUSTERS       2
0016 #define EDVD_OFFSET_A57(core)       ((SZ_64K * 6) + (0x20 + (core) * 0x4))
0017 #define EDVD_OFFSET_DENVER(core)    ((SZ_64K * 7) + (0x20 + (core) * 0x4))
0018 #define EDVD_CORE_VOLT_FREQ_F_SHIFT 0
0019 #define EDVD_CORE_VOLT_FREQ_F_MASK  0xffff
0020 #define EDVD_CORE_VOLT_FREQ_V_SHIFT 16
0021 
0022 struct tegra186_cpufreq_cpu {
0023     unsigned int bpmp_cluster_id;
0024     unsigned int edvd_offset;
0025 };
0026 
0027 static const struct tegra186_cpufreq_cpu tegra186_cpus[] = {
0028     /* CPU0 - A57 Cluster */
0029     {
0030         .bpmp_cluster_id = 1,
0031         .edvd_offset = EDVD_OFFSET_A57(0)
0032     },
0033     /* CPU1 - Denver Cluster */
0034     {
0035         .bpmp_cluster_id = 0,
0036         .edvd_offset = EDVD_OFFSET_DENVER(0)
0037     },
0038     /* CPU2 - Denver Cluster */
0039     {
0040         .bpmp_cluster_id = 0,
0041         .edvd_offset = EDVD_OFFSET_DENVER(1)
0042     },
0043     /* CPU3 - A57 Cluster */
0044     {
0045         .bpmp_cluster_id = 1,
0046         .edvd_offset = EDVD_OFFSET_A57(1)
0047     },
0048     /* CPU4 - A57 Cluster */
0049     {
0050         .bpmp_cluster_id = 1,
0051         .edvd_offset = EDVD_OFFSET_A57(2)
0052     },
0053     /* CPU5 - A57 Cluster */
0054     {
0055         .bpmp_cluster_id = 1,
0056         .edvd_offset = EDVD_OFFSET_A57(3)
0057     },
0058 };
0059 
0060 struct tegra186_cpufreq_cluster {
0061     struct cpufreq_frequency_table *table;
0062     u32 ref_clk_khz;
0063     u32 div;
0064 };
0065 
0066 struct tegra186_cpufreq_data {
0067     void __iomem *regs;
0068     struct tegra186_cpufreq_cluster *clusters;
0069     const struct tegra186_cpufreq_cpu *cpus;
0070 };
0071 
0072 static int tegra186_cpufreq_init(struct cpufreq_policy *policy)
0073 {
0074     struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
0075     unsigned int cluster = data->cpus[policy->cpu].bpmp_cluster_id;
0076 
0077     policy->freq_table = data->clusters[cluster].table;
0078     policy->cpuinfo.transition_latency = 300 * 1000;
0079     policy->driver_data = NULL;
0080 
0081     return 0;
0082 }
0083 
0084 static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
0085                        unsigned int index)
0086 {
0087     struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
0088     struct cpufreq_frequency_table *tbl = policy->freq_table + index;
0089     unsigned int edvd_offset = data->cpus[policy->cpu].edvd_offset;
0090     u32 edvd_val = tbl->driver_data;
0091 
0092     writel(edvd_val, data->regs + edvd_offset);
0093 
0094     return 0;
0095 }
0096 
0097 static unsigned int tegra186_cpufreq_get(unsigned int cpu)
0098 {
0099     struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
0100     struct tegra186_cpufreq_cluster *cluster;
0101     struct cpufreq_policy *policy;
0102     unsigned int edvd_offset, cluster_id;
0103     u32 ndiv;
0104 
0105     policy = cpufreq_cpu_get(cpu);
0106     if (!policy)
0107         return 0;
0108 
0109     edvd_offset = data->cpus[policy->cpu].edvd_offset;
0110     ndiv = readl(data->regs + edvd_offset) & EDVD_CORE_VOLT_FREQ_F_MASK;
0111     cluster_id = data->cpus[policy->cpu].bpmp_cluster_id;
0112     cluster = &data->clusters[cluster_id];
0113     cpufreq_cpu_put(policy);
0114 
0115     return (cluster->ref_clk_khz * ndiv) / cluster->div;
0116 }
0117 
0118 static struct cpufreq_driver tegra186_cpufreq_driver = {
0119     .name = "tegra186",
0120     .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
0121             CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0122     .get = tegra186_cpufreq_get,
0123     .verify = cpufreq_generic_frequency_table_verify,
0124     .target_index = tegra186_cpufreq_set_target,
0125     .init = tegra186_cpufreq_init,
0126     .attr = cpufreq_generic_attr,
0127 };
0128 
0129 static struct cpufreq_frequency_table *init_vhint_table(
0130     struct platform_device *pdev, struct tegra_bpmp *bpmp,
0131     struct tegra186_cpufreq_cluster *cluster, unsigned int cluster_id)
0132 {
0133     struct cpufreq_frequency_table *table;
0134     struct mrq_cpu_vhint_request req;
0135     struct tegra_bpmp_message msg;
0136     struct cpu_vhint_data *data;
0137     int err, i, j, num_rates = 0;
0138     dma_addr_t phys;
0139     void *virt;
0140 
0141     virt = dma_alloc_coherent(bpmp->dev, sizeof(*data), &phys,
0142                   GFP_KERNEL);
0143     if (!virt)
0144         return ERR_PTR(-ENOMEM);
0145 
0146     data = (struct cpu_vhint_data *)virt;
0147 
0148     memset(&req, 0, sizeof(req));
0149     req.addr = phys;
0150     req.cluster_id = cluster_id;
0151 
0152     memset(&msg, 0, sizeof(msg));
0153     msg.mrq = MRQ_CPU_VHINT;
0154     msg.tx.data = &req;
0155     msg.tx.size = sizeof(req);
0156 
0157     err = tegra_bpmp_transfer(bpmp, &msg);
0158     if (err) {
0159         table = ERR_PTR(err);
0160         goto free;
0161     }
0162     if (msg.rx.ret) {
0163         table = ERR_PTR(-EINVAL);
0164         goto free;
0165     }
0166 
0167     for (i = data->vfloor; i <= data->vceil; i++) {
0168         u16 ndiv = data->ndiv[i];
0169 
0170         if (ndiv < data->ndiv_min || ndiv > data->ndiv_max)
0171             continue;
0172 
0173         /* Only store lowest voltage index for each rate */
0174         if (i > 0 && ndiv == data->ndiv[i - 1])
0175             continue;
0176 
0177         num_rates++;
0178     }
0179 
0180     table = devm_kcalloc(&pdev->dev, num_rates + 1, sizeof(*table),
0181                  GFP_KERNEL);
0182     if (!table) {
0183         table = ERR_PTR(-ENOMEM);
0184         goto free;
0185     }
0186 
0187     cluster->ref_clk_khz = data->ref_clk_hz / 1000;
0188     cluster->div = data->pdiv * data->mdiv;
0189 
0190     for (i = data->vfloor, j = 0; i <= data->vceil; i++) {
0191         struct cpufreq_frequency_table *point;
0192         u16 ndiv = data->ndiv[i];
0193         u32 edvd_val = 0;
0194 
0195         if (ndiv < data->ndiv_min || ndiv > data->ndiv_max)
0196             continue;
0197 
0198         /* Only store lowest voltage index for each rate */
0199         if (i > 0 && ndiv == data->ndiv[i - 1])
0200             continue;
0201 
0202         edvd_val |= i << EDVD_CORE_VOLT_FREQ_V_SHIFT;
0203         edvd_val |= ndiv << EDVD_CORE_VOLT_FREQ_F_SHIFT;
0204 
0205         point = &table[j++];
0206         point->driver_data = edvd_val;
0207         point->frequency = (cluster->ref_clk_khz * ndiv) / cluster->div;
0208     }
0209 
0210     table[j].frequency = CPUFREQ_TABLE_END;
0211 
0212 free:
0213     dma_free_coherent(bpmp->dev, sizeof(*data), virt, phys);
0214 
0215     return table;
0216 }
0217 
0218 static int tegra186_cpufreq_probe(struct platform_device *pdev)
0219 {
0220     struct tegra186_cpufreq_data *data;
0221     struct tegra_bpmp *bpmp;
0222     unsigned int i = 0, err;
0223 
0224     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0225     if (!data)
0226         return -ENOMEM;
0227 
0228     data->clusters = devm_kcalloc(&pdev->dev, TEGRA186_NUM_CLUSTERS,
0229                       sizeof(*data->clusters), GFP_KERNEL);
0230     if (!data->clusters)
0231         return -ENOMEM;
0232 
0233     data->cpus = tegra186_cpus;
0234 
0235     bpmp = tegra_bpmp_get(&pdev->dev);
0236     if (IS_ERR(bpmp))
0237         return PTR_ERR(bpmp);
0238 
0239     data->regs = devm_platform_ioremap_resource(pdev, 0);
0240     if (IS_ERR(data->regs)) {
0241         err = PTR_ERR(data->regs);
0242         goto put_bpmp;
0243     }
0244 
0245     for (i = 0; i < TEGRA186_NUM_CLUSTERS; i++) {
0246         struct tegra186_cpufreq_cluster *cluster = &data->clusters[i];
0247 
0248         cluster->table = init_vhint_table(pdev, bpmp, cluster, i);
0249         if (IS_ERR(cluster->table)) {
0250             err = PTR_ERR(cluster->table);
0251             goto put_bpmp;
0252         }
0253     }
0254 
0255     tegra186_cpufreq_driver.driver_data = data;
0256 
0257     err = cpufreq_register_driver(&tegra186_cpufreq_driver);
0258 
0259 put_bpmp:
0260     tegra_bpmp_put(bpmp);
0261 
0262     return err;
0263 }
0264 
0265 static int tegra186_cpufreq_remove(struct platform_device *pdev)
0266 {
0267     cpufreq_unregister_driver(&tegra186_cpufreq_driver);
0268 
0269     return 0;
0270 }
0271 
0272 static const struct of_device_id tegra186_cpufreq_of_match[] = {
0273     { .compatible = "nvidia,tegra186-ccplex-cluster", },
0274     { }
0275 };
0276 MODULE_DEVICE_TABLE(of, tegra186_cpufreq_of_match);
0277 
0278 static struct platform_driver tegra186_cpufreq_platform_driver = {
0279     .driver = {
0280         .name = "tegra186-cpufreq",
0281         .of_match_table = tegra186_cpufreq_of_match,
0282     },
0283     .probe = tegra186_cpufreq_probe,
0284     .remove = tegra186_cpufreq_remove,
0285 };
0286 module_platform_driver(tegra186_cpufreq_platform_driver);
0287 
0288 MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
0289 MODULE_DESCRIPTION("NVIDIA Tegra186 cpufreq driver");
0290 MODULE_LICENSE("GPL v2");