0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/cpu.h>
0010 #include <linux/io.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/module.h>
0013 #include <linux/init.h>
0014 #include <linux/of.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/pm_opp.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019
0020 #define REVISION_MASK 0xF
0021 #define REVISION_SHIFT 28
0022
0023 #define AM33XX_800M_ARM_MPU_MAX_FREQ 0x1E2F
0024 #define AM43XX_600M_ARM_MPU_MAX_FREQ 0xFFA
0025
0026 #define DRA7_EFUSE_HAS_OD_MPU_OPP 11
0027 #define DRA7_EFUSE_HAS_HIGH_MPU_OPP 15
0028 #define DRA76_EFUSE_HAS_PLUS_MPU_OPP 18
0029 #define DRA7_EFUSE_HAS_ALL_MPU_OPP 23
0030 #define DRA76_EFUSE_HAS_ALL_MPU_OPP 24
0031
0032 #define DRA7_EFUSE_NOM_MPU_OPP BIT(0)
0033 #define DRA7_EFUSE_OD_MPU_OPP BIT(1)
0034 #define DRA7_EFUSE_HIGH_MPU_OPP BIT(2)
0035 #define DRA76_EFUSE_PLUS_MPU_OPP BIT(3)
0036
0037 #define OMAP3_CONTROL_DEVICE_STATUS 0x4800244C
0038 #define OMAP3_CONTROL_IDCODE 0x4830A204
0039 #define OMAP34xx_ProdID_SKUID 0x4830A20C
0040 #define OMAP3_SYSCON_BASE (0x48000000 + 0x2000 + 0x270)
0041
0042 #define VERSION_COUNT 2
0043
0044 struct ti_cpufreq_data;
0045
0046 struct ti_cpufreq_soc_data {
0047 const char * const *reg_names;
0048 unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data,
0049 unsigned long efuse);
0050 unsigned long efuse_fallback;
0051 unsigned long efuse_offset;
0052 unsigned long efuse_mask;
0053 unsigned long efuse_shift;
0054 unsigned long rev_offset;
0055 bool multi_regulator;
0056 };
0057
0058 struct ti_cpufreq_data {
0059 struct device *cpu_dev;
0060 struct device_node *opp_node;
0061 struct regmap *syscon;
0062 const struct ti_cpufreq_soc_data *soc_data;
0063 };
0064
0065 static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
0066 unsigned long efuse)
0067 {
0068 if (!efuse)
0069 efuse = opp_data->soc_data->efuse_fallback;
0070
0071 return ~efuse;
0072 }
0073
0074 static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
0075 unsigned long efuse)
0076 {
0077 unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP;
0078
0079
0080
0081
0082
0083
0084 switch (efuse) {
0085 case DRA76_EFUSE_HAS_PLUS_MPU_OPP:
0086 case DRA76_EFUSE_HAS_ALL_MPU_OPP:
0087 calculated_efuse |= DRA76_EFUSE_PLUS_MPU_OPP;
0088 fallthrough;
0089 case DRA7_EFUSE_HAS_ALL_MPU_OPP:
0090 case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
0091 calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
0092 fallthrough;
0093 case DRA7_EFUSE_HAS_OD_MPU_OPP:
0094 calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP;
0095 }
0096
0097 return calculated_efuse;
0098 }
0099
0100 static unsigned long omap3_efuse_xlate(struct ti_cpufreq_data *opp_data,
0101 unsigned long efuse)
0102 {
0103
0104 return BIT(efuse);
0105 }
0106
0107 static struct ti_cpufreq_soc_data am3x_soc_data = {
0108 .efuse_xlate = amx3_efuse_xlate,
0109 .efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ,
0110 .efuse_offset = 0x07fc,
0111 .efuse_mask = 0x1fff,
0112 .rev_offset = 0x600,
0113 .multi_regulator = false,
0114 };
0115
0116 static struct ti_cpufreq_soc_data am4x_soc_data = {
0117 .efuse_xlate = amx3_efuse_xlate,
0118 .efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ,
0119 .efuse_offset = 0x0610,
0120 .efuse_mask = 0x3f,
0121 .rev_offset = 0x600,
0122 .multi_regulator = false,
0123 };
0124
0125 static struct ti_cpufreq_soc_data dra7_soc_data = {
0126 .efuse_xlate = dra7_efuse_xlate,
0127 .efuse_offset = 0x020c,
0128 .efuse_mask = 0xf80000,
0129 .efuse_shift = 19,
0130 .rev_offset = 0x204,
0131 .multi_regulator = true,
0132 };
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 static struct ti_cpufreq_soc_data omap34xx_soc_data = {
0152 .efuse_xlate = omap3_efuse_xlate,
0153 .efuse_offset = OMAP34xx_ProdID_SKUID - OMAP3_SYSCON_BASE,
0154 .efuse_shift = 3,
0155 .efuse_mask = BIT(3),
0156 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
0157 .multi_regulator = false,
0158 };
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL};
0176
0177 static struct ti_cpufreq_soc_data omap36xx_soc_data = {
0178 .reg_names = omap3_reg_names,
0179 .efuse_xlate = omap3_efuse_xlate,
0180 .efuse_offset = OMAP3_CONTROL_DEVICE_STATUS - OMAP3_SYSCON_BASE,
0181 .efuse_shift = 9,
0182 .efuse_mask = BIT(9),
0183 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
0184 .multi_regulator = true,
0185 };
0186
0187
0188
0189
0190
0191
0192 static struct ti_cpufreq_soc_data am3517_soc_data = {
0193 .efuse_xlate = omap3_efuse_xlate,
0194 .efuse_offset = OMAP3_CONTROL_DEVICE_STATUS - OMAP3_SYSCON_BASE,
0195 .efuse_shift = 0,
0196 .efuse_mask = 0,
0197 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
0198 .multi_regulator = false,
0199 };
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data,
0210 u32 *efuse_value)
0211 {
0212 struct device *dev = opp_data->cpu_dev;
0213 u32 efuse;
0214 int ret;
0215
0216 ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset,
0217 &efuse);
0218 if (ret == -EIO) {
0219
0220 void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
0221 opp_data->soc_data->efuse_offset, 4);
0222
0223 if (!regs)
0224 return -ENOMEM;
0225 efuse = readl(regs);
0226 iounmap(regs);
0227 }
0228 else if (ret) {
0229 dev_err(dev,
0230 "Failed to read the efuse value from syscon: %d\n",
0231 ret);
0232 return ret;
0233 }
0234
0235 efuse = (efuse & opp_data->soc_data->efuse_mask);
0236 efuse >>= opp_data->soc_data->efuse_shift;
0237
0238 *efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse);
0239
0240 return 0;
0241 }
0242
0243
0244
0245
0246
0247
0248
0249
0250 static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
0251 u32 *revision_value)
0252 {
0253 struct device *dev = opp_data->cpu_dev;
0254 u32 revision;
0255 int ret;
0256
0257 ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset,
0258 &revision);
0259 if (ret == -EIO) {
0260
0261 void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
0262 opp_data->soc_data->rev_offset, 4);
0263
0264 if (!regs)
0265 return -ENOMEM;
0266 revision = readl(regs);
0267 iounmap(regs);
0268 }
0269 else if (ret) {
0270 dev_err(dev,
0271 "Failed to read the revision number from syscon: %d\n",
0272 ret);
0273 return ret;
0274 }
0275
0276 *revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
0277
0278 return 0;
0279 }
0280
0281 static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data)
0282 {
0283 struct device *dev = opp_data->cpu_dev;
0284 struct device_node *np = opp_data->opp_node;
0285
0286 opp_data->syscon = syscon_regmap_lookup_by_phandle(np,
0287 "syscon");
0288 if (IS_ERR(opp_data->syscon)) {
0289 dev_err(dev,
0290 "\"syscon\" is missing, cannot use OPPv2 table.\n");
0291 return PTR_ERR(opp_data->syscon);
0292 }
0293
0294 return 0;
0295 }
0296
0297 static const struct of_device_id ti_cpufreq_of_match[] = {
0298 { .compatible = "ti,am33xx", .data = &am3x_soc_data, },
0299 { .compatible = "ti,am3517", .data = &am3517_soc_data, },
0300 { .compatible = "ti,am43", .data = &am4x_soc_data, },
0301 { .compatible = "ti,dra7", .data = &dra7_soc_data },
0302 { .compatible = "ti,omap34xx", .data = &omap34xx_soc_data, },
0303 { .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, },
0304
0305 { .compatible = "ti,omap3430", .data = &omap34xx_soc_data, },
0306 { .compatible = "ti,omap3630", .data = &omap36xx_soc_data, },
0307 {},
0308 };
0309
0310 static const struct of_device_id *ti_cpufreq_match_node(void)
0311 {
0312 struct device_node *np;
0313 const struct of_device_id *match;
0314
0315 np = of_find_node_by_path("/");
0316 match = of_match_node(ti_cpufreq_of_match, np);
0317 of_node_put(np);
0318
0319 return match;
0320 }
0321
0322 static int ti_cpufreq_probe(struct platform_device *pdev)
0323 {
0324 u32 version[VERSION_COUNT];
0325 const struct of_device_id *match;
0326 struct ti_cpufreq_data *opp_data;
0327 const char * const default_reg_names[] = {"vdd", "vbb", NULL};
0328 int ret;
0329 struct dev_pm_opp_config config = {
0330 .supported_hw = version,
0331 .supported_hw_count = ARRAY_SIZE(version),
0332 };
0333
0334 match = dev_get_platdata(&pdev->dev);
0335 if (!match)
0336 return -ENODEV;
0337
0338 opp_data = devm_kzalloc(&pdev->dev, sizeof(*opp_data), GFP_KERNEL);
0339 if (!opp_data)
0340 return -ENOMEM;
0341
0342 opp_data->soc_data = match->data;
0343
0344 opp_data->cpu_dev = get_cpu_device(0);
0345 if (!opp_data->cpu_dev) {
0346 pr_err("%s: Failed to get device for CPU0\n", __func__);
0347 return -ENODEV;
0348 }
0349
0350 opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
0351 if (!opp_data->opp_node) {
0352 dev_info(opp_data->cpu_dev,
0353 "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n");
0354 goto register_cpufreq_dt;
0355 }
0356
0357 ret = ti_cpufreq_setup_syscon_register(opp_data);
0358 if (ret)
0359 goto fail_put_node;
0360
0361
0362
0363
0364
0365
0366
0367 ret = ti_cpufreq_get_rev(opp_data, &version[0]);
0368 if (ret)
0369 goto fail_put_node;
0370
0371 ret = ti_cpufreq_get_efuse(opp_data, &version[1]);
0372 if (ret)
0373 goto fail_put_node;
0374
0375 if (opp_data->soc_data->multi_regulator) {
0376 if (opp_data->soc_data->reg_names)
0377 config.regulator_names = opp_data->soc_data->reg_names;
0378 else
0379 config.regulator_names = default_reg_names;
0380 }
0381
0382 ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config);
0383 if (ret < 0) {
0384 dev_err(opp_data->cpu_dev, "Failed to set OPP config\n");
0385 goto fail_put_node;
0386 }
0387
0388 of_node_put(opp_data->opp_node);
0389
0390 register_cpufreq_dt:
0391 platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
0392
0393 return 0;
0394
0395 fail_put_node:
0396 of_node_put(opp_data->opp_node);
0397
0398 return ret;
0399 }
0400
0401 static int ti_cpufreq_init(void)
0402 {
0403 const struct of_device_id *match;
0404
0405
0406 match = ti_cpufreq_match_node();
0407 if (match)
0408 platform_device_register_data(NULL, "ti-cpufreq", -1, match,
0409 sizeof(*match));
0410
0411 return 0;
0412 }
0413 module_init(ti_cpufreq_init);
0414
0415 static struct platform_driver ti_cpufreq_driver = {
0416 .probe = ti_cpufreq_probe,
0417 .driver = {
0418 .name = "ti-cpufreq",
0419 },
0420 };
0421 builtin_platform_driver(ti_cpufreq_driver);
0422
0423 MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver");
0424 MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
0425 MODULE_LICENSE("GPL v2");