| .. | .. |
|---|
| 35 | 35 | #include <linux/pm_runtime.h> |
|---|
| 36 | 36 | #include <linux/delay.h> |
|---|
| 37 | 37 | #include <linux/rockchip/cpu.h> |
|---|
| 38 | +#include <soc/rockchip/rockchip_ipa.h> |
|---|
| 38 | 39 | #include <soc/rockchip/rockchip_opp_select.h> |
|---|
| 39 | 40 | |
|---|
| 40 | 41 | #include <linux/mali/mali_utgard.h> |
|---|
| .. | .. |
|---|
| 232 | 233 | static u32 static_coefficient; |
|---|
| 233 | 234 | static s32 ts[4]; |
|---|
| 234 | 235 | static struct thermal_zone_device *gpu_tz; |
|---|
| 235 | | - |
|---|
| 236 | | -static int power_model_simple_init(struct platform_device *pdev) |
|---|
| 237 | | -{ |
|---|
| 238 | | - struct device_node *power_model_node; |
|---|
| 239 | | - const char *tz_name; |
|---|
| 240 | | - u32 static_power, dynamic_power; |
|---|
| 241 | | - u32 voltage, voltage_squared, voltage_cubed, frequency; |
|---|
| 242 | | - |
|---|
| 243 | | - power_model_node = of_get_child_by_name(pdev->dev.of_node, |
|---|
| 244 | | - "power_model"); |
|---|
| 245 | | - if (!power_model_node) { |
|---|
| 246 | | - dev_err(&pdev->dev, "could not find power_model node\n"); |
|---|
| 247 | | - return -ENODEV; |
|---|
| 248 | | - } |
|---|
| 249 | | - if (!of_device_is_compatible(power_model_node, |
|---|
| 250 | | - "arm,mali-simple-power-model")) { |
|---|
| 251 | | - dev_err(&pdev->dev, "power_model incompatible with simple power model\n"); |
|---|
| 252 | | - return -ENODEV; |
|---|
| 253 | | - } |
|---|
| 254 | | - |
|---|
| 255 | | - if (of_property_read_string(power_model_node, "thermal-zone", |
|---|
| 256 | | - &tz_name)) { |
|---|
| 257 | | - dev_err(&pdev->dev, "ts in power_model not available\n"); |
|---|
| 258 | | - return -EINVAL; |
|---|
| 259 | | - } |
|---|
| 260 | | - |
|---|
| 261 | | - gpu_tz = thermal_zone_get_zone_by_name(tz_name); |
|---|
| 262 | | - if (IS_ERR(gpu_tz)) { |
|---|
| 263 | | - pr_warn_ratelimited("Error getting gpu thermal zone '%s'(%ld), not yet ready?\n", |
|---|
| 264 | | - tz_name, |
|---|
| 265 | | - PTR_ERR(gpu_tz)); |
|---|
| 266 | | - gpu_tz = NULL; |
|---|
| 267 | | - } |
|---|
| 268 | | - |
|---|
| 269 | | - if (of_property_read_u32(power_model_node, "static-power", |
|---|
| 270 | | - &static_power)) { |
|---|
| 271 | | - dev_err(&pdev->dev, "static-power in power_model not available\n"); |
|---|
| 272 | | - return -EINVAL; |
|---|
| 273 | | - } |
|---|
| 274 | | - if (of_property_read_u32(power_model_node, "dynamic-power", |
|---|
| 275 | | - &dynamic_power)) { |
|---|
| 276 | | - dev_err(&pdev->dev, "dynamic-power in power_model not available\n"); |
|---|
| 277 | | - return -EINVAL; |
|---|
| 278 | | - } |
|---|
| 279 | | - if (of_property_read_u32(power_model_node, "voltage", |
|---|
| 280 | | - &voltage)) { |
|---|
| 281 | | - dev_err(&pdev->dev, "voltage in power_model not available\n"); |
|---|
| 282 | | - return -EINVAL; |
|---|
| 283 | | - } |
|---|
| 284 | | - if (of_property_read_u32(power_model_node, "frequency", |
|---|
| 285 | | - &frequency)) { |
|---|
| 286 | | - dev_err(&pdev->dev, "frequency in power_model not available\n"); |
|---|
| 287 | | - return -EINVAL; |
|---|
| 288 | | - } |
|---|
| 289 | | - voltage_squared = (voltage * voltage) / 1000; |
|---|
| 290 | | - voltage_cubed = voltage * voltage * voltage; |
|---|
| 291 | | - static_coefficient = (static_power << 20) / (voltage_cubed >> 10); |
|---|
| 292 | | - dynamic_coefficient = (((dynamic_power * 1000) / voltage_squared) |
|---|
| 293 | | - * 1000) / frequency; |
|---|
| 294 | | - |
|---|
| 295 | | - if (of_property_read_u32_array(power_model_node, "ts", (u32 *)ts, 4)) { |
|---|
| 296 | | - dev_err(&pdev->dev, "ts in power_model not available\n"); |
|---|
| 297 | | - return -EINVAL; |
|---|
| 298 | | - } |
|---|
| 299 | | - |
|---|
| 300 | | - return 0; |
|---|
| 301 | | -} |
|---|
| 236 | +static struct ipa_power_model_data *model_data; |
|---|
| 302 | 237 | |
|---|
| 303 | 238 | /* Calculate gpu static power example for reference */ |
|---|
| 304 | 239 | static unsigned long rk_model_static_power(struct devfreq *devfreq, |
|---|
| .. | .. |
|---|
| 360 | 295 | return dynamic_power; |
|---|
| 361 | 296 | } |
|---|
| 362 | 297 | |
|---|
| 363 | | -struct devfreq_cooling_power rk_cooling_ops = { |
|---|
| 298 | +static struct devfreq_cooling_power rk_cooling_ops = { |
|---|
| 364 | 299 | .get_static_power = rk_model_static_power, |
|---|
| 365 | 300 | .get_dynamic_power = rk_model_dynamic_power, |
|---|
| 366 | 301 | }; |
|---|
| 302 | + |
|---|
| 303 | +static unsigned long mali_devfreq_get_static_power(struct devfreq *devfreq, |
|---|
| 304 | + unsigned long voltage) |
|---|
| 305 | +{ |
|---|
| 306 | + return rockchip_ipa_get_static_power(model_data, voltage); |
|---|
| 307 | +} |
|---|
| 308 | + |
|---|
| 309 | +static int power_model_simple_init(struct platform_device *pdev) |
|---|
| 310 | +{ |
|---|
| 311 | + struct device_node *power_model_node; |
|---|
| 312 | + const char *tz_name; |
|---|
| 313 | + u32 static_power, dynamic_power; |
|---|
| 314 | + u32 voltage, voltage_squared, voltage_cubed, frequency; |
|---|
| 315 | + |
|---|
| 316 | + if (of_find_compatible_node(pdev->dev.of_node, NULL, "simple-power-model")) { |
|---|
| 317 | + of_property_read_u32(pdev->dev.of_node, |
|---|
| 318 | + "dynamic-power-coefficient", |
|---|
| 319 | + (u32 *)&rk_cooling_ops.dyn_power_coeff); |
|---|
| 320 | + model_data = rockchip_ipa_power_model_init(&pdev->dev, |
|---|
| 321 | + "gpu_leakage"); |
|---|
| 322 | + if (IS_ERR_OR_NULL(model_data)) { |
|---|
| 323 | + model_data = NULL; |
|---|
| 324 | + dev_err(&pdev->dev, "failed to initialize power model\n"); |
|---|
| 325 | + } else if (model_data->dynamic_coefficient) { |
|---|
| 326 | + rk_cooling_ops.dyn_power_coeff = |
|---|
| 327 | + model_data->dynamic_coefficient; |
|---|
| 328 | + rk_cooling_ops.get_dynamic_power = NULL; |
|---|
| 329 | + rk_cooling_ops.get_static_power = mali_devfreq_get_static_power; |
|---|
| 330 | + } |
|---|
| 331 | + if (!rk_cooling_ops.dyn_power_coeff) { |
|---|
| 332 | + dev_err(&pdev->dev, "failed to get dynamic-coefficient\n"); |
|---|
| 333 | + return -EINVAL; |
|---|
| 334 | + } |
|---|
| 335 | + |
|---|
| 336 | + return 0; |
|---|
| 337 | + } |
|---|
| 338 | + |
|---|
| 339 | + power_model_node = of_get_child_by_name(pdev->dev.of_node, |
|---|
| 340 | + "power_model"); |
|---|
| 341 | + if (!power_model_node) { |
|---|
| 342 | + dev_err(&pdev->dev, "could not find power_model node\n"); |
|---|
| 343 | + return -ENODEV; |
|---|
| 344 | + } |
|---|
| 345 | + if (!of_device_is_compatible(power_model_node, |
|---|
| 346 | + "arm,mali-simple-power-model")) { |
|---|
| 347 | + dev_err(&pdev->dev, "power_model incompatible with simple power model\n"); |
|---|
| 348 | + return -ENODEV; |
|---|
| 349 | + } |
|---|
| 350 | + |
|---|
| 351 | + if (of_property_read_string(power_model_node, "thermal-zone", |
|---|
| 352 | + &tz_name)) { |
|---|
| 353 | + dev_err(&pdev->dev, "ts in power_model not available\n"); |
|---|
| 354 | + return -EINVAL; |
|---|
| 355 | + } |
|---|
| 356 | + |
|---|
| 357 | + gpu_tz = thermal_zone_get_zone_by_name(tz_name); |
|---|
| 358 | + if (IS_ERR(gpu_tz)) { |
|---|
| 359 | + pr_warn_ratelimited("Error getting gpu thermal zone '%s'(%ld), not yet ready?\n", |
|---|
| 360 | + tz_name, |
|---|
| 361 | + PTR_ERR(gpu_tz)); |
|---|
| 362 | + gpu_tz = NULL; |
|---|
| 363 | + } |
|---|
| 364 | + |
|---|
| 365 | + if (of_property_read_u32(power_model_node, "static-power", |
|---|
| 366 | + &static_power)) { |
|---|
| 367 | + dev_err(&pdev->dev, "static-power in power_model not available\n"); |
|---|
| 368 | + return -EINVAL; |
|---|
| 369 | + } |
|---|
| 370 | + if (of_property_read_u32(power_model_node, "dynamic-power", |
|---|
| 371 | + &dynamic_power)) { |
|---|
| 372 | + dev_err(&pdev->dev, "dynamic-power in power_model not available\n"); |
|---|
| 373 | + return -EINVAL; |
|---|
| 374 | + } |
|---|
| 375 | + if (of_property_read_u32(power_model_node, "voltage", |
|---|
| 376 | + &voltage)) { |
|---|
| 377 | + dev_err(&pdev->dev, "voltage in power_model not available\n"); |
|---|
| 378 | + return -EINVAL; |
|---|
| 379 | + } |
|---|
| 380 | + if (of_property_read_u32(power_model_node, "frequency", |
|---|
| 381 | + &frequency)) { |
|---|
| 382 | + dev_err(&pdev->dev, "frequency in power_model not available\n"); |
|---|
| 383 | + return -EINVAL; |
|---|
| 384 | + } |
|---|
| 385 | + voltage_squared = (voltage * voltage) / 1000; |
|---|
| 386 | + voltage_cubed = voltage * voltage * voltage; |
|---|
| 387 | + static_coefficient = (static_power << 20) / (voltage_cubed >> 10); |
|---|
| 388 | + dynamic_coefficient = (((dynamic_power * 1000) / voltage_squared) |
|---|
| 389 | + * 1000) / frequency; |
|---|
| 390 | + |
|---|
| 391 | + if (of_property_read_u32_array(power_model_node, "ts", (u32 *)ts, 4)) { |
|---|
| 392 | + dev_err(&pdev->dev, "ts in power_model not available\n"); |
|---|
| 393 | + return -EINVAL; |
|---|
| 394 | + } |
|---|
| 395 | + |
|---|
| 396 | + return 0; |
|---|
| 397 | +} |
|---|
| 398 | + |
|---|
| 367 | 399 | #endif |
|---|
| 368 | 400 | |
|---|
| 369 | 401 | /*---------------------------------------------------------------------------*/ |
|---|
| .. | .. |
|---|
| 376 | 408 | #if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
|---|
| 377 | 409 | struct mali_device *mdev = dev_get_drvdata(dev); |
|---|
| 378 | 410 | |
|---|
| 379 | | - if (mdev->clock) |
|---|
| 380 | | - ret = clk_enable(mdev->clock); |
|---|
| 411 | + ret = clk_bulk_enable(mdev->num_clks, mdev->clks); |
|---|
| 381 | 412 | #endif |
|---|
| 382 | 413 | return ret; |
|---|
| 383 | 414 | } |
|---|
| .. | .. |
|---|
| 387 | 418 | #if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
|---|
| 388 | 419 | struct mali_device *mdev = dev_get_drvdata(dev); |
|---|
| 389 | 420 | |
|---|
| 390 | | - if (mdev->clock) |
|---|
| 391 | | - clk_disable(mdev->clock); |
|---|
| 421 | + clk_bulk_disable(mdev->num_clks, mdev->clks); |
|---|
| 392 | 422 | #endif |
|---|
| 393 | 423 | } |
|---|
| 394 | 424 | |
|---|
| .. | .. |
|---|
| 432 | 462 | goto fail_to_enable_regulator; |
|---|
| 433 | 463 | } |
|---|
| 434 | 464 | |
|---|
| 465 | + if (cpu_is_rk3528()) { |
|---|
| 466 | +#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
|---|
| 467 | + struct mali_device *mdev = dev_get_drvdata(dev); |
|---|
| 468 | + |
|---|
| 469 | + clk_set_rate(mdev->clock, mdev->current_freq); |
|---|
| 470 | +#endif |
|---|
| 471 | + } |
|---|
| 435 | 472 | platform->is_powered = true; |
|---|
| 436 | 473 | } |
|---|
| 437 | 474 | |
|---|
| .. | .. |
|---|
| 449 | 486 | struct rk_context *platform = s_rk_context; |
|---|
| 450 | 487 | |
|---|
| 451 | 488 | if (platform->is_powered) { |
|---|
| 489 | + if (cpu_is_rk3528()) { |
|---|
| 490 | +#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
|---|
| 491 | + struct mali_device *mdev = dev_get_drvdata(dev); |
|---|
| 492 | + |
|---|
| 493 | + //use normal pll 200M for gpu when suspend |
|---|
| 494 | + clk_set_rate(mdev->clock, 200000000); |
|---|
| 495 | +#endif |
|---|
| 496 | + } |
|---|
| 452 | 497 | rk_platform_disable_clk_gpu(dev); |
|---|
| 453 | 498 | rk_platform_disable_gpu_regulator(dev); |
|---|
| 454 | 499 | |
|---|