Message ID | 20161115221059.31629-1-d-gerlach@ti.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Hi Dave, [auto build test ERROR on robh/for-next] [also build test ERROR on v4.9-rc5] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Dave-Gerlach/WIP-Test-OPP-multi-regulator-support-with-ti-opp-domain-driver/20161116-084525 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next config: ia64-allmodconfig (attached as .config) compiler: ia64-linux-gcc (GCC) 6.2.0 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=ia64 All error/warnings (new ones prefixed by >>): >> drivers/soc/ti/ti-opp-domain.c:231:49: warning: 'struct dev_pm_set_opp_data' declared inside parameter list will not be visible outside of this definition or declaration int ti_oppdm_set_opp(struct device *dev, struct dev_pm_set_opp_data *data) ^~~~~~~~~~~~~~~~~~~ drivers/soc/ti/ti-opp-domain.c: In function 'ti_oppdm_set_opp': >> drivers/soc/ti/ti-opp-domain.c:233:50: error: dereferencing pointer to incomplete type 'struct dev_pm_set_opp_data' struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0]; ^~ >> drivers/soc/ti/ti-opp-domain.c:244:71: error: dereferencing pointer to incomplete type 'struct dev_pm_opp_supply' vdd_uv = oppdm_get_optimal_vdd_voltage(dev, &opp_data, new_supply_vbb->u_volt); ^~ >> drivers/soc/ti/ti-opp-domain.c:330:1: warning: label 'restore_voltage' defined but not used [-Wunused-label] restore_voltage: ^~~~~~~~~~~~~~~ >> drivers/soc/ti/ti-opp-domain.c:325:1: warning: label 'restore_freq' defined but not used [-Wunused-label] restore_freq: ^~~~~~~~~~~~ >> drivers/soc/ti/ti-opp-domain.c:234:28: warning: unused variable 'old_supply_vbb' [-Wunused-variable] struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1]; ^~~~~~~~~~~~~~ drivers/soc/ti/ti-opp-domain.c: In function 'ti_oppdm_probe': drivers/soc/ti/ti-opp-domain.c:383:8: error: implicit declaration of function 'dev_pm_opp_set_regulators' [-Werror=implicit-function-declaration] ret = dev_pm_opp_set_regulators(cpu_dev, names, ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/soc/ti/ti-opp-domain.c:408:2: error: implicit declaration of function 'dev_pm_opp_register_set_opp_helper' [-Werror=implicit-function-declaration] dev_pm_opp_register_set_opp_helper(cpu_dev, ti_oppdm_set_opp); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/soc/ti/ti-opp-domain.c:378:28: warning: unused variable 'oppdm_dev' [-Wunused-variable] struct pm_opp_domain_dev *oppdm_dev; ^~~~~~~~~ At top level: drivers/soc/ti/ti-opp-domain.c:181:13: warning: 'oppdm_free_optimized_voltages' defined but not used [-Wunused-function] static void oppdm_free_optimized_voltages(struct device *dev, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +233 drivers/soc/ti/ti-opp-domain.c 225 * @dev: opp domain device for which we are doing the transition 226 * @data: information on regulators and new and old opps provided by 227 * opp core to use in transition 228 * 229 * Return: If successful, 0, else appropriate error value. 230 */ > 231 int ti_oppdm_set_opp(struct device *dev, struct dev_pm_set_opp_data *data) 232 { > 233 struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0]; > 234 struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1]; 235 struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0]; 236 struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1]; 237 unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; 238 struct clk *clk = data->clk; 239 struct regulator *vdd_reg = data->regulators[0]; 240 struct regulator *vbb_reg = data->regulators[1]; 241 int vdd_uv; 242 int ret; 243 > 244 vdd_uv = oppdm_get_optimal_vdd_voltage(dev, &opp_data, new_supply_vbb->u_volt); 245 246 /* Scaling up? Scale voltage before frequency */ 247 if (freq > old_freq) { 248 /* Regulator not available for device */ 249 250 dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", 251 new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, 252 new_supply_vbb->u_volt_max); 253 254 ret = regulator_set_voltage_triplet(vbb_reg, 255 new_supply_vbb->u_volt_min, 256 new_supply_vbb->u_volt, 257 new_supply_vbb->u_volt_max); 258 if (ret) { 259 dev_err(dev, "vbb failed for %luuV[min %luuV max %luuV]\n", 260 new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, 261 new_supply_vbb->u_volt_max); 262 return ret; 263 } 264 265 dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, 266 new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, 267 new_supply_vdd->u_volt_max); 268 269 ret = regulator_set_voltage_triplet(vdd_reg, 270 new_supply_vdd->u_volt_min, 271 new_supply_vdd->u_volt, 272 new_supply_vdd->u_volt_max); 273 if (ret) 274 dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", 275 __func__, new_supply_vdd->u_volt_min, 276 new_supply_vdd->u_volt, 277 new_supply_vdd->u_volt_max, ret); 278 } 279 280 /* Change frequency */ 281 dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", 282 __func__, old_freq, freq); 283 284 ret = clk_set_rate(clk, freq); 285 if (ret) { 286 dev_err(dev, "%s: failed to set clock rate: %d\n", __func__, 287 ret); 288 } 289 290 /* Scaling down? Scale voltage after frequency */ 291 if (freq < old_freq) { 292 dev_dbg(dev, "vbb post %luuV[min %luuV max %luuV]\n", 293 new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, 294 new_supply_vbb->u_volt_max); 295 296 ret = regulator_set_voltage_triplet(vbb_reg, 297 new_supply_vbb->u_volt_min, 298 new_supply_vbb->u_volt, 299 new_supply_vbb->u_volt_max); 300 if (ret) { 301 dev_err(dev, "vbb failed for %luuV[min %luuV max %luuV]\n", 302 new_supply_vbb->u_volt, 303 new_supply_vbb->u_volt_min, 304 new_supply_vbb->u_volt_max); 305 return ret; 306 } 307 308 dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, 309 new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, 310 new_supply_vdd->u_volt_max); 311 312 ret = regulator_set_voltage_triplet(vdd_reg, 313 new_supply_vdd->u_volt_min, 314 new_supply_vdd->u_volt, 315 new_supply_vdd->u_volt_max); 316 if (ret) 317 dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", 318 __func__, new_supply_vdd->u_volt_min, 319 new_supply_vdd->u_volt, 320 new_supply_vdd->u_volt_max, ret); 321 } 322 323 return 0; 324 > 325 restore_freq: 326 ret = clk_set_rate(clk, old_freq); 327 if (ret) 328 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", 329 __func__, old_freq); > 330 restore_voltage: 331 /* This shouldn't harm even if the voltages weren't updated earlier */ 332 if (old_supply_vdd->u_volt) { 333 dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, 334 old_supply_vdd->u_volt_min, old_supply_vdd->u_volt, 335 old_supply_vdd->u_volt_max); 336 337 ret = regulator_set_voltage_triplet(vdd_reg, 338 old_supply_vdd->u_volt_min, 339 old_supply_vdd->u_volt, 340 old_supply_vdd->u_volt_max); 341 if (ret) 342 dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", 343 __func__, old_supply_vdd->u_volt_min, 344 old_supply_vdd->u_volt, 345 old_supply_vdd->u_volt_max, ret); 346 } 347 348 return ret; 349 } 350 351 static const struct ti_oppdm_of_data omap_generic_of_data = { 352 }; 353 354 static const struct ti_oppdm_of_data omap_omap5_of_data = { 355 .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE, 356 .efuse_voltage_mask = 0xFFF, 357 .efuse_voltage_uv = false, 358 }; 359 360 static const struct ti_oppdm_of_data omap_omap5core_of_data = { 361 .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE | OPPDM_HAS_NO_ABB, 362 .efuse_voltage_mask = 0xFFF, 363 .efuse_voltage_uv = false, 364 }; 365 366 static const struct of_device_id ti_oppdm_of_match[] = { 367 {.compatible = "ti,omap-oppdm", .data = &omap_generic_of_data}, 368 {.compatible = "ti,omap5-oppdm", .data = &omap_omap5_of_data}, 369 {.compatible = "ti,omap5-core-oppdm", .data = &omap_omap5core_of_data}, 370 {}, 371 }; 372 373 static int ti_oppdm_probe(struct platform_device *pdev) 374 { 375 struct device *dev = &pdev->dev; 376 struct device *cpu_dev = get_cpu_device(0); /* Gross hack */ 377 const struct of_device_id *match; > 378 struct pm_opp_domain_dev *oppdm_dev; 379 int ret = 0; 380 const struct ti_oppdm_of_data *of_data; 381 const char *names[] = {"vdd", "vbb"}; 382 > 383 ret = dev_pm_opp_set_regulators(cpu_dev, names, 384 ARRAY_SIZE(names)); 385 386 if (ret) --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Dave, [auto build test WARNING on robh/for-next] [also build test WARNING on v4.9-rc5 next-20161115] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Dave-Gerlach/WIP-Test-OPP-multi-regulator-support-with-ti-opp-domain-driver/20161116-084525 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next config: m68k-allmodconfig (attached as .config) compiler: m68k-linux-gcc (GCC) 4.9.0 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=m68k All warnings (new ones prefixed by >>): drivers/soc/ti/ti-opp-domain.c:231:49: warning: 'struct dev_pm_set_opp_data' declared inside parameter list int ti_oppdm_set_opp(struct device *dev, struct dev_pm_set_opp_data *data) ^ drivers/soc/ti/ti-opp-domain.c:231:49: warning: its scope is only this definition or declaration, which is probably not what you want drivers/soc/ti/ti-opp-domain.c: In function 'ti_oppdm_set_opp': drivers/soc/ti/ti-opp-domain.c:233:50: error: dereferencing pointer to incomplete type struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0]; ^ drivers/soc/ti/ti-opp-domain.c:234:50: error: dereferencing pointer to incomplete type struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1]; ^ drivers/soc/ti/ti-opp-domain.c:235:50: error: dereferencing pointer to incomplete type struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0]; ^ drivers/soc/ti/ti-opp-domain.c:236:50: error: dereferencing pointer to incomplete type struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1]; ^ drivers/soc/ti/ti-opp-domain.c:237:31: error: dereferencing pointer to incomplete type unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ^ drivers/soc/ti/ti-opp-domain.c:237:58: error: dereferencing pointer to incomplete type unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ^ drivers/soc/ti/ti-opp-domain.c:238:24: error: dereferencing pointer to incomplete type struct clk *clk = data->clk; ^ drivers/soc/ti/ti-opp-domain.c:239:34: error: dereferencing pointer to incomplete type struct regulator *vdd_reg = data->regulators[0]; ^ drivers/soc/ti/ti-opp-domain.c:240:34: error: dereferencing pointer to incomplete type struct regulator *vbb_reg = data->regulators[1]; ^ drivers/soc/ti/ti-opp-domain.c:244:71: error: dereferencing pointer to incomplete type vdd_uv = oppdm_get_optimal_vdd_voltage(dev, &opp_data, new_supply_vbb->u_volt); ^ In file included from include/linux/printk.h:305:0, from include/linux/kernel.h:13, from include/linux/clk.h:16, from drivers/soc/ti/ti-opp-domain.c:14: drivers/soc/ti/ti-opp-domain.c:251:18: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ >> drivers/soc/ti/ti-opp-domain.c:250:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", ^ drivers/soc/ti/ti-opp-domain.c:251:42: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ >> drivers/soc/ti/ti-opp-domain.c:250:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", ^ drivers/soc/ti/ti-opp-domain.c:252:18: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt_max); ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ >> drivers/soc/ti/ti-opp-domain.c:250:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", ^ drivers/soc/ti/ti-opp-domain.c:255:25: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt_min, ^ drivers/soc/ti/ti-opp-domain.c:256:25: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, ^ drivers/soc/ti/ti-opp-domain.c:257:25: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt_max); ^ drivers/soc/ti/ti-opp-domain.c:260:19: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ drivers/soc/ti/ti-opp-domain.c:260:43: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ drivers/soc/ti/ti-opp-domain.c:261:19: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt_max); ^ In file included from include/linux/printk.h:305:0, from include/linux/kernel.h:13, from include/linux/clk.h:16, from drivers/soc/ti/ti-opp-domain.c:14: drivers/soc/ti/ti-opp-domain.c:266:18: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:265:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, ^ drivers/soc/ti/ti-opp-domain.c:266:46: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:265:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, ^ drivers/soc/ti/ti-opp-domain.c:267:18: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_max); ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:265:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, ^ drivers/soc/ti/ti-opp-domain.c:270:25: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_min, ^ drivers/soc/ti/ti-opp-domain.c:271:25: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt, ^ drivers/soc/ti/ti-opp-domain.c:272:25: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_max); ^ drivers/soc/ti/ti-opp-domain.c:275:29: error: dereferencing pointer to incomplete type __func__, new_supply_vdd->u_volt_min, ^ drivers/soc/ti/ti-opp-domain.c:276:19: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt, ^ drivers/soc/ti/ti-opp-domain.c:277:19: error: dereferencing pointer to incomplete type new_supply_vdd->u_volt_max, ret); ^ In file included from include/linux/printk.h:305:0, from include/linux/kernel.h:13, from include/linux/clk.h:16, from drivers/soc/ti/ti-opp-domain.c:14: drivers/soc/ti/ti-opp-domain.c:293:19: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:292:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb post %luuV[min %luuV max %luuV]\n", ^ drivers/soc/ti/ti-opp-domain.c:293:43: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:292:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb post %luuV[min %luuV max %luuV]\n", ^ drivers/soc/ti/ti-opp-domain.c:294:19: error: dereferencing pointer to incomplete type new_supply_vbb->u_volt_max); ^ include/linux/dynamic_debug.h:135:9: note: in definition of macro 'dynamic_dev_dbg' ##__VA_ARGS__); \ ^ drivers/soc/ti/ti-opp-domain.c:292:3: note: in expansion of macro 'dev_dbg' dev_dbg(dev, "vbb post %luuV[min %luuV max %luuV]\n", ^ vim +/dev_dbg +250 drivers/soc/ti/ti-opp-domain.c 234 struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1]; 235 struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0]; 236 struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1]; 237 unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; 238 struct clk *clk = data->clk; 239 struct regulator *vdd_reg = data->regulators[0]; 240 struct regulator *vbb_reg = data->regulators[1]; 241 int vdd_uv; 242 int ret; 243 244 vdd_uv = oppdm_get_optimal_vdd_voltage(dev, &opp_data, new_supply_vbb->u_volt); 245 246 /* Scaling up? Scale voltage before frequency */ 247 if (freq > old_freq) { 248 /* Regulator not available for device */ 249 > 250 dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", 251 new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, 252 new_supply_vbb->u_volt_max); 253 254 ret = regulator_set_voltage_triplet(vbb_reg, 255 new_supply_vbb->u_volt_min, 256 new_supply_vbb->u_volt, 257 new_supply_vbb->u_volt_max); 258 if (ret) { --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Thanks for this Dave :) On 15-11-16, 16:10, Dave Gerlach wrote: > NOT FOR MERGE! > > Introduce a test version of a 'ti-opp-domain' driver that will use new > multiple regulator support introduced to the OPP core by Viresh [1]. > Tested on v4.9-rc1 with that series applied. This is needed on TI > platforms like DRA7/AM57 in order to control both CPU regulator and > Adaptive Body Bias (ABB) regulator as described by Nishanth Menon here > [2]. These regulators must be scaled in sequence during an OPP > transition depending on whether or not the frequency is being scaled up > or down. Based on the new functionality provided by Viresh this driver > does the following: > > * Call dev_pm_opp_set_regulators with the names of the two regulators > that feed the CPU: > * vdd is the 'cpu-supply' commonly used for cpufreq-dt but > renamed so the cpufreq-dt driver doesn't use it directly. > Note that this is supplied in board dts as it's external to > SoC. I think I can fix this somehow.. Lemme check. > * vbb for the ABB regulator. This is provided in SoC dtsi as it > is internal to the SoC. > * Provide a platform set_opp function using > dev_pm_opp_register_set_opp_helper that is called when an OPP > transition is requested. > * Allow cpufreq-dt to probe which will work because no cpu-supply > regulator is found so the driver proceeds and calls > dev_pm_opp_set_rate which through the OPP core invokes the platform > set_opp call we provided > * Platform set_opp call provided by this driver checks to see if we are > scaling frequency up or down and based on this, scales vbb before vdd > for up or the other way around for down. > > In addition to that, this driver implements AVS Class 0 as described in > section 18.4.6.12 of AM572x TRM [3] using the same platform set_rate > hook added to the OPP core. There are registers that define the optimal > voltage for that specific piece of silicon for an OPP so this driver > simply looks up this optimal value and programs that for an OPP instead > of the nominal value. > > Missing from this is a good way to ensure that cpufreq-dt does not just > proceed if no cpu-supply regulator is found but we were intending to > rely on a platform set_opp and multiple regulators. > > [1] https://marc.info/?l=linux-pm&m=147746362402994&w=2 > [2] https://marc.info/?l=linux-pm&m=145684495832764&w=2 > [3] http://www.ti.com/lit/ug/spruhz6g/spruhz6g.pdf > > Signed-off-by: Dave Gerlach <d-gerlach@ti.com> > --- > arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi | 2 +- > arch/arm/boot/dts/dra7.dtsi | 46 ++- > drivers/soc/ti/Makefile | 2 + > drivers/soc/ti/ti-opp-domain.c | 427 ++++++++++++++++++++++++ I would rather ask you to move this to drivers/base/power/opp/
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi index 6df7829a2c15..d92551c15780 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi +++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi @@ -410,7 +410,7 @@ }; &cpu0 { - cpu0-supply = <&smps12_reg>; + vdd-supply = <&smps12_reg>; voltage-tolerance = <1>; }; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index d4fcd68f6349..311166b9e8c4 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -80,11 +80,7 @@ compatible = "arm,cortex-a15"; reg = <0>; - operating-points = < - /* kHz uV */ - 1000000 1060000 - 1176000 1160000 - >; + operating-points-v2 = <&cpu0_opp_table>; clocks = <&dpll_mpu_ck>; clock-names = "cpu"; @@ -95,6 +91,32 @@ cooling-min-level = <0>; cooling-max-level = <2>; #cooling-cells = <2>; /* min followed by max */ + + vbb-supply = <&abb_mpu>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp_nom@1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <1060000 850000 1150000>, + <1060000 850000 1150000>; + opp-suspend; + }; + + opp_od@1176000000 { + opp-hz = /bits/ 64 <1176000000>; + opp-microvolt = <1160000 885000 1160000>, + <1160000 885000 1160000>; + }; + + opp_high@1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1210000 950000 1250000>, + < 1210000 950000 1250000>; }; }; @@ -1966,6 +1988,20 @@ clocks = <&l3_iclk_div>; clock-names = "fck"; }; + + oppdm_mpu: oppdm@4a003b20 { + compatible = "ti,omap5-oppdm"; + #oppdm-cells = <0>; + reg = <0x4a003b20 0xc>; + ti,efuse-settings = < + /* uV offset */ + 1060000 0x0 + 1160000 0x4 + 1210000 0x8 + >; + ti,absolute-max-voltage-uv = <1500000>; + }; + }; thermal_zones: thermal-zones { diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile index 48ff3a79634f..e3595e3f1d6a 100644 --- a/drivers/soc/ti/Makefile +++ b/drivers/soc/ti/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o +obj-y += ti-opp-domain.o +#obj-$(CONFIG_OPP_DOMAIN_TI) += ti-opp-domain.o diff --git a/drivers/soc/ti/ti-opp-domain.c b/drivers/soc/ti/ti-opp-domain.c new file mode 100644 index 000000000000..33683548b326 --- /dev/null +++ b/drivers/soc/ti/ti-opp-domain.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon <nm@ti.com> + * Dave Gerlach <d-gerlach@ti.com> + * + * 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. + * + * TI OPP Domain driver that provides overrides into the regulator control + * for generic opp domains to handle devices with ABB regulator and/or + * SmartReflex Class0. + */ +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +/** + * struct ti_oppdm_optimum_voltage_table - optimized voltage table + * @reference_uv: reference voltage (usually Nominal voltage) + * @optimized_uv: Optimized voltage from efuse + */ +struct ti_oppdm_optimum_voltage_table { + unsigned int reference_uv; + unsigned int optimized_uv; +}; + +/** + * struct ti_oppdm_data - OMAP specific opp domain data + * @vdd_reg: VDD regulator + * @vbb_reg: Body Bias regulator + * @vdd_table: Optimized voltage mapping table + * @num_vdd_table: number of entries in vdd_table + * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the domain + */ +struct ti_oppdm_data { + struct regulator *vdd_reg; + struct regulator *vbb_reg; + struct ti_oppdm_optimum_voltage_table *vdd_table; + u32 num_vdd_table; + u32 vdd_absolute_max_voltage_uv; +}; + +static struct ti_oppdm_data opp_data; +/** + * struct ti_oppdm_of_data - device tree match data + * @desc: opp domain descriptor for opp domain core + * @flags: specific type of opp domain + * @efuse_voltage_mask: mask required for efuse register representing voltage + * @efuse_voltage_uv: Are the efuse entries in micro-volts? if not, assume + * milli-volts. + */ +struct ti_oppdm_of_data { +#define OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE BIT(1) +#define OPPDM_HAS_NO_ABB BIT(2) + const u8 flags; + const u32 efuse_voltage_mask; + const bool efuse_voltage_uv; +}; + +/** + * oppdm_store_optimized_voltages() - store optimized voltages + * @dev: opp domain device for which we need to store info + * @data: data specific to the device + * + * Picks up efuse based optimized voltages for VDD unique per device and + * stores it in internal data structure for use during transition requests. + * + * Return: If successful, 0, else appropriate error value. + */ +static int oppdm_store_optimized_voltages(struct device *dev, + struct ti_oppdm_data *data) +{ + void __iomem *base; + struct property *prop; + struct resource *res; + const __be32 *val; + int proplen, i; + int ret = 0; + struct ti_oppdm_optimum_voltage_table *table; + const struct ti_oppdm_of_data *of_data = dev_get_drvdata(dev); + + /* pick up Efuse based voltages */ + res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Unable to get IO resource\n"); + ret = -ENODEV; + goto out_map; + } + + base = ioremap_nocache(res->start, resource_size(res)); + if (!base) { + dev_err(dev, "Unable to map Efuse registers\n"); + ret = -ENOMEM; + goto out_map; + } + + /* Fetch efuse-settings. */ + prop = of_find_property(dev->of_node, "ti,efuse-settings", NULL); + if (!prop) { + dev_err(dev, "No 'ti,efuse-settings' property found\n"); + ret = -EINVAL; + goto out; + } + + proplen = prop->length / sizeof(int); + data->num_vdd_table = proplen / 2; + /* Verify for corrupted OPP entries in dt */ + if (data->num_vdd_table * 2 * sizeof(int) != prop->length) { + dev_err(dev, "Invalid 'ti,efuse-settings'\n"); + ret = -EINVAL; + goto out; + } + + ret = of_property_read_u32(dev->of_node, "ti,absolute-max-voltage-uv", + &data->vdd_absolute_max_voltage_uv); + if (ret) { + dev_err(dev, "ti,absolute-max-voltage-uv is missing\n"); + ret = -EINVAL; + goto out; + } + + table = kzalloc(sizeof(*data->vdd_table) * + data->num_vdd_table, GFP_KERNEL); + if (!table) { + ret = -ENOMEM; + goto out; + } + data->vdd_table = table; + + val = prop->value; + for (i = 0; i < data->num_vdd_table; i++, table++) { + u32 efuse_offset; + u32 tmp; + + table->reference_uv = be32_to_cpup(val++); + efuse_offset = be32_to_cpup(val++); + + tmp = readl(base + efuse_offset); + tmp &= of_data->efuse_voltage_mask; + tmp >>= __ffs(of_data->efuse_voltage_mask); + + table->optimized_uv = of_data->efuse_voltage_uv ? tmp : + tmp * 1000; + + dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d vset=%d\n", + i, efuse_offset, table->reference_uv, + table->optimized_uv); + + /* + * Some older samples might not have optimized efuse + * Use reference voltage for those - just add debug message + * for them. + */ + if (!table->optimized_uv) { + dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d:vset0\n", + i, efuse_offset, table->reference_uv); + table->optimized_uv = table->reference_uv; + } + } +out: + iounmap(base); +out_map: + return ret; +} + +/** + * oppdm_free_optimized_voltages() - free resources for optimized voltages + * @dev: opp domain device for which we need to free info + * @data: data specific to the device + */ +static void oppdm_free_optimized_voltages(struct device *dev, + struct ti_oppdm_data *data) +{ + kfree(data->vdd_table); + data->vdd_table = NULL; + data->num_vdd_table = 0; +} + +/** + * oppdm_get_optimal_vdd_voltage() - Finds optimal voltage for the domain + * @dev: opp domain device for which we need to find info + * @data: data specific to the device + * @reference_uv: reference voltage (OPP voltage) for which we need value + * + * Return: if a match is found, return optimized voltage, else return + * reference_uv, also return reference_uv if no optimization is needed. + */ +static int oppdm_get_optimal_vdd_voltage(struct device *dev, + struct ti_oppdm_data *data, + int reference_uv) +{ + int i; + struct ti_oppdm_optimum_voltage_table *table; + + if (!data->num_vdd_table) + return reference_uv; + + table = data->vdd_table; + if (!table) + return -EINVAL; + + /* Find a exact match - this list is usually very small */ + for (i = 0; i < data->num_vdd_table; i++, table++) + if (table->reference_uv == reference_uv) + return table->optimized_uv; + + /* IF things are screwed up, we'd make a mess on console.. ratelimit */ + dev_err_ratelimited(dev, "%s: Failed optimized voltage match for %d\n", + __func__, reference_uv); + return reference_uv; +} + +/** + * ti_oppdm_set_opp() - do the opp domain transition + * @dev: opp domain device for which we are doing the transition + * @data: information on regulators and new and old opps provided by + * opp core to use in transition + * + * Return: If successful, 0, else appropriate error value. + */ +int ti_oppdm_set_opp(struct device *dev, struct dev_pm_set_opp_data *data) +{ + struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0]; + struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1]; + struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0]; + struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1]; + unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; + struct clk *clk = data->clk; + struct regulator *vdd_reg = data->regulators[0]; + struct regulator *vbb_reg = data->regulators[1]; + int vdd_uv; + int ret; + + vdd_uv = oppdm_get_optimal_vdd_voltage(dev, &opp_data, new_supply_vbb->u_volt); + + /* Scaling up? Scale voltage before frequency */ + if (freq > old_freq) { + /* Regulator not available for device */ + + dev_dbg(dev, "vbb pre %luuV[min %luuV max %luuV]\n", + new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt_max); + + ret = regulator_set_voltage_triplet(vbb_reg, + new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt, + new_supply_vbb->u_volt_max); + if (ret) { + dev_err(dev, "vbb failed for %luuV[min %luuV max %luuV]\n", + new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt_max); + return ret; + } + + dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, + new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max); + + ret = regulator_set_voltage_triplet(vdd_reg, + new_supply_vdd->u_volt_min, + new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max); + if (ret) + dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", + __func__, new_supply_vdd->u_volt_min, + new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max, ret); + } + + /* Change frequency */ + dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", + __func__, old_freq, freq); + + ret = clk_set_rate(clk, freq); + if (ret) { + dev_err(dev, "%s: failed to set clock rate: %d\n", __func__, + ret); + } + + /* Scaling down? Scale voltage after frequency */ + if (freq < old_freq) { + dev_dbg(dev, "vbb post %luuV[min %luuV max %luuV]\n", + new_supply_vbb->u_volt, new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt_max); + + ret = regulator_set_voltage_triplet(vbb_reg, + new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt, + new_supply_vbb->u_volt_max); + if (ret) { + dev_err(dev, "vbb failed for %luuV[min %luuV max %luuV]\n", + new_supply_vbb->u_volt, + new_supply_vbb->u_volt_min, + new_supply_vbb->u_volt_max); + return ret; + } + + dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, + new_supply_vdd->u_volt_min, new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max); + + ret = regulator_set_voltage_triplet(vdd_reg, + new_supply_vdd->u_volt_min, + new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max); + if (ret) + dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", + __func__, new_supply_vdd->u_volt_min, + new_supply_vdd->u_volt, + new_supply_vdd->u_volt_max, ret); + } + + return 0; + +restore_freq: + ret = clk_set_rate(clk, old_freq); + if (ret) + dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", + __func__, old_freq); +restore_voltage: + /* This shouldn't harm even if the voltages weren't updated earlier */ + if (old_supply_vdd->u_volt) { + dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, + old_supply_vdd->u_volt_min, old_supply_vdd->u_volt, + old_supply_vdd->u_volt_max); + + ret = regulator_set_voltage_triplet(vdd_reg, + old_supply_vdd->u_volt_min, + old_supply_vdd->u_volt, + old_supply_vdd->u_volt_max); + if (ret) + dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n", + __func__, old_supply_vdd->u_volt_min, + old_supply_vdd->u_volt, + old_supply_vdd->u_volt_max, ret); + } + + return ret; +} + +static const struct ti_oppdm_of_data omap_generic_of_data = { +}; + +static const struct ti_oppdm_of_data omap_omap5_of_data = { + .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE, + .efuse_voltage_mask = 0xFFF, + .efuse_voltage_uv = false, +}; + +static const struct ti_oppdm_of_data omap_omap5core_of_data = { + .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE | OPPDM_HAS_NO_ABB, + .efuse_voltage_mask = 0xFFF, + .efuse_voltage_uv = false, +}; + +static const struct of_device_id ti_oppdm_of_match[] = { + {.compatible = "ti,omap-oppdm", .data = &omap_generic_of_data}, + {.compatible = "ti,omap5-oppdm", .data = &omap_omap5_of_data}, + {.compatible = "ti,omap5-core-oppdm", .data = &omap_omap5core_of_data}, + {}, +}; + +static int ti_oppdm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *cpu_dev = get_cpu_device(0); /* Gross hack */ + const struct of_device_id *match; + struct pm_opp_domain_dev *oppdm_dev; + int ret = 0; + const struct ti_oppdm_of_data *of_data; + const char *names[] = {"vdd", "vbb"}; + + ret = dev_pm_opp_set_regulators(cpu_dev, names, + ARRAY_SIZE(names)); + + if (ret) + return ret; + + match = of_match_device(ti_oppdm_of_match, dev); + if (!match) { + /* We do not expect this to happen */ + dev_err(dev, "%s: Unable to match device\n", __func__); + return -ENODEV; + } + if (!match->data) { + /* Again, unlikely.. but mistakes do happen */ + dev_err(dev, "%s: Bad data in match\n", __func__); + return -EINVAL; + } + of_data = match->data; + + dev_set_drvdata(dev, (void *)of_data); + /* If we need optimized voltage */ + if (of_data->flags & OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE) { + ret = oppdm_store_optimized_voltages(dev, &opp_data); + } + + dev_pm_opp_register_set_opp_helper(cpu_dev, ti_oppdm_set_opp); + + return ret; +} + +MODULE_DEVICE_TABLE(of, ti_oppdm_of_match); + +static struct platform_driver ti_oppdm_driver = { + .probe = ti_oppdm_probe, + .driver = { + .name = "ti_oppdm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ti_oppdm_of_match), + }, +}; +module_platform_driver(ti_oppdm_driver); + +MODULE_DESCRIPTION("Texas Instruments OMAP OPP Domain driver"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_LICENSE("GPL v2");
NOT FOR MERGE! Introduce a test version of a 'ti-opp-domain' driver that will use new multiple regulator support introduced to the OPP core by Viresh [1]. Tested on v4.9-rc1 with that series applied. This is needed on TI platforms like DRA7/AM57 in order to control both CPU regulator and Adaptive Body Bias (ABB) regulator as described by Nishanth Menon here [2]. These regulators must be scaled in sequence during an OPP transition depending on whether or not the frequency is being scaled up or down. Based on the new functionality provided by Viresh this driver does the following: * Call dev_pm_opp_set_regulators with the names of the two regulators that feed the CPU: * vdd is the 'cpu-supply' commonly used for cpufreq-dt but renamed so the cpufreq-dt driver doesn't use it directly. Note that this is supplied in board dts as it's external to SoC. * vbb for the ABB regulator. This is provided in SoC dtsi as it is internal to the SoC. * Provide a platform set_opp function using dev_pm_opp_register_set_opp_helper that is called when an OPP transition is requested. * Allow cpufreq-dt to probe which will work because no cpu-supply regulator is found so the driver proceeds and calls dev_pm_opp_set_rate which through the OPP core invokes the platform set_opp call we provided * Platform set_opp call provided by this driver checks to see if we are scaling frequency up or down and based on this, scales vbb before vdd for up or the other way around for down. In addition to that, this driver implements AVS Class 0 as described in section 18.4.6.12 of AM572x TRM [3] using the same platform set_rate hook added to the OPP core. There are registers that define the optimal voltage for that specific piece of silicon for an OPP so this driver simply looks up this optimal value and programs that for an OPP instead of the nominal value. Missing from this is a good way to ensure that cpufreq-dt does not just proceed if no cpu-supply regulator is found but we were intending to rely on a platform set_opp and multiple regulators. [1] https://marc.info/?l=linux-pm&m=147746362402994&w=2 [2] https://marc.info/?l=linux-pm&m=145684495832764&w=2 [3] http://www.ti.com/lit/ug/spruhz6g/spruhz6g.pdf Signed-off-by: Dave Gerlach <d-gerlach@ti.com> --- arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi | 2 +- arch/arm/boot/dts/dra7.dtsi | 46 ++- drivers/soc/ti/Makefile | 2 + drivers/soc/ti/ti-opp-domain.c | 427 ++++++++++++++++++++++++ 4 files changed, 471 insertions(+), 6 deletions(-) create mode 100644 drivers/soc/ti/ti-opp-domain.c