.. | .. |
---|
34 | 34 | #include <linux/dma-mapping.h> |
---|
35 | 35 | #include <linux/pm_runtime.h> |
---|
36 | 36 | #include <linux/delay.h> |
---|
| 37 | +#include <linux/regmap.h> |
---|
| 38 | +#include <linux/mfd/syscon.h> |
---|
37 | 39 | #include <linux/rockchip/cpu.h> |
---|
| 40 | +#include <soc/rockchip/rockchip_ipa.h> |
---|
38 | 41 | #include <soc/rockchip/rockchip_opp_select.h> |
---|
39 | 42 | |
---|
40 | 43 | #include <linux/mali/mali_utgard.h> |
---|
.. | .. |
---|
47 | 50 | |
---|
48 | 51 | /*---------------------------------------------------------------------------*/ |
---|
49 | 52 | |
---|
| 53 | +#define RK3528_GPU_SD_SLP_HAST 0x10024 |
---|
50 | 54 | #define DEFAULT_UTILISATION_PERIOD_IN_MS (100) |
---|
51 | 55 | |
---|
52 | 56 | /* |
---|
.. | .. |
---|
55 | 59 | struct rk_context { |
---|
56 | 60 | /* mali device. */ |
---|
57 | 61 | struct device *dev; |
---|
| 62 | + struct regmap *grf; |
---|
58 | 63 | /* is the GPU powered on? */ |
---|
59 | 64 | bool is_powered; |
---|
60 | 65 | /* debug only, the period in ms to count gpu_utilisation. */ |
---|
.. | .. |
---|
183 | 188 | } |
---|
184 | 189 | |
---|
185 | 190 | platform->dev = dev; |
---|
| 191 | + platform->grf = syscon_regmap_lookup_by_phandle(dev->of_node, |
---|
| 192 | + "rockchip,grf"); |
---|
| 193 | + if (IS_ERR(platform->grf)) |
---|
| 194 | + platform->grf = NULL; |
---|
186 | 195 | platform->is_powered = false; |
---|
187 | 196 | |
---|
188 | 197 | platform->utilisation_period = DEFAULT_UTILISATION_PERIOD_IN_MS; |
---|
.. | .. |
---|
232 | 241 | static u32 static_coefficient; |
---|
233 | 242 | static s32 ts[4]; |
---|
234 | 243 | 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 | | -} |
---|
| 244 | +static struct ipa_power_model_data *model_data; |
---|
302 | 245 | |
---|
303 | 246 | /* Calculate gpu static power example for reference */ |
---|
304 | 247 | static unsigned long rk_model_static_power(struct devfreq *devfreq, |
---|
.. | .. |
---|
360 | 303 | return dynamic_power; |
---|
361 | 304 | } |
---|
362 | 305 | |
---|
363 | | -struct devfreq_cooling_power rk_cooling_ops = { |
---|
| 306 | +static struct devfreq_cooling_power rk_cooling_ops = { |
---|
364 | 307 | .get_static_power = rk_model_static_power, |
---|
365 | 308 | .get_dynamic_power = rk_model_dynamic_power, |
---|
366 | 309 | }; |
---|
| 310 | + |
---|
| 311 | +static unsigned long mali_devfreq_get_static_power(struct devfreq *devfreq, |
---|
| 312 | + unsigned long voltage) |
---|
| 313 | +{ |
---|
| 314 | + return rockchip_ipa_get_static_power(model_data, voltage); |
---|
| 315 | +} |
---|
| 316 | + |
---|
| 317 | +static int power_model_simple_init(struct platform_device *pdev) |
---|
| 318 | +{ |
---|
| 319 | + struct device_node *power_model_node; |
---|
| 320 | + const char *tz_name; |
---|
| 321 | + u32 static_power, dynamic_power; |
---|
| 322 | + u32 voltage, voltage_squared, voltage_cubed, frequency; |
---|
| 323 | + |
---|
| 324 | + if (of_find_compatible_node(pdev->dev.of_node, NULL, "simple-power-model")) { |
---|
| 325 | + of_property_read_u32(pdev->dev.of_node, |
---|
| 326 | + "dynamic-power-coefficient", |
---|
| 327 | + (u32 *)&rk_cooling_ops.dyn_power_coeff); |
---|
| 328 | + model_data = rockchip_ipa_power_model_init(&pdev->dev, |
---|
| 329 | + "gpu_leakage"); |
---|
| 330 | + if (IS_ERR_OR_NULL(model_data)) { |
---|
| 331 | + model_data = NULL; |
---|
| 332 | + dev_err(&pdev->dev, "failed to initialize power model\n"); |
---|
| 333 | + } else if (model_data->dynamic_coefficient) { |
---|
| 334 | + rk_cooling_ops.dyn_power_coeff = |
---|
| 335 | + model_data->dynamic_coefficient; |
---|
| 336 | + rk_cooling_ops.get_dynamic_power = NULL; |
---|
| 337 | + rk_cooling_ops.get_static_power = mali_devfreq_get_static_power; |
---|
| 338 | + } |
---|
| 339 | + if (!rk_cooling_ops.dyn_power_coeff) { |
---|
| 340 | + dev_err(&pdev->dev, "failed to get dynamic-coefficient\n"); |
---|
| 341 | + return -EINVAL; |
---|
| 342 | + } |
---|
| 343 | + |
---|
| 344 | + return 0; |
---|
| 345 | + } |
---|
| 346 | + |
---|
| 347 | + power_model_node = of_get_child_by_name(pdev->dev.of_node, |
---|
| 348 | + "power_model"); |
---|
| 349 | + if (!power_model_node) { |
---|
| 350 | + dev_err(&pdev->dev, "could not find power_model node\n"); |
---|
| 351 | + return -ENODEV; |
---|
| 352 | + } |
---|
| 353 | + if (!of_device_is_compatible(power_model_node, |
---|
| 354 | + "arm,mali-simple-power-model")) { |
---|
| 355 | + dev_err(&pdev->dev, "power_model incompatible with simple power model\n"); |
---|
| 356 | + return -ENODEV; |
---|
| 357 | + } |
---|
| 358 | + |
---|
| 359 | + if (of_property_read_string(power_model_node, "thermal-zone", |
---|
| 360 | + &tz_name)) { |
---|
| 361 | + dev_err(&pdev->dev, "ts in power_model not available\n"); |
---|
| 362 | + return -EINVAL; |
---|
| 363 | + } |
---|
| 364 | + |
---|
| 365 | + gpu_tz = thermal_zone_get_zone_by_name(tz_name); |
---|
| 366 | + if (IS_ERR(gpu_tz)) { |
---|
| 367 | + pr_warn_ratelimited("Error getting gpu thermal zone '%s'(%ld), not yet ready?\n", |
---|
| 368 | + tz_name, |
---|
| 369 | + PTR_ERR(gpu_tz)); |
---|
| 370 | + gpu_tz = NULL; |
---|
| 371 | + } |
---|
| 372 | + |
---|
| 373 | + if (of_property_read_u32(power_model_node, "static-power", |
---|
| 374 | + &static_power)) { |
---|
| 375 | + dev_err(&pdev->dev, "static-power in power_model not available\n"); |
---|
| 376 | + return -EINVAL; |
---|
| 377 | + } |
---|
| 378 | + if (of_property_read_u32(power_model_node, "dynamic-power", |
---|
| 379 | + &dynamic_power)) { |
---|
| 380 | + dev_err(&pdev->dev, "dynamic-power in power_model not available\n"); |
---|
| 381 | + return -EINVAL; |
---|
| 382 | + } |
---|
| 383 | + if (of_property_read_u32(power_model_node, "voltage", |
---|
| 384 | + &voltage)) { |
---|
| 385 | + dev_err(&pdev->dev, "voltage in power_model not available\n"); |
---|
| 386 | + return -EINVAL; |
---|
| 387 | + } |
---|
| 388 | + if (of_property_read_u32(power_model_node, "frequency", |
---|
| 389 | + &frequency)) { |
---|
| 390 | + dev_err(&pdev->dev, "frequency in power_model not available\n"); |
---|
| 391 | + return -EINVAL; |
---|
| 392 | + } |
---|
| 393 | + voltage_squared = (voltage * voltage) / 1000; |
---|
| 394 | + voltage_cubed = voltage * voltage * voltage; |
---|
| 395 | + static_coefficient = (static_power << 20) / (voltage_cubed >> 10); |
---|
| 396 | + dynamic_coefficient = (((dynamic_power * 1000) / voltage_squared) |
---|
| 397 | + * 1000) / frequency; |
---|
| 398 | + |
---|
| 399 | + if (of_property_read_u32_array(power_model_node, "ts", (u32 *)ts, 4)) { |
---|
| 400 | + dev_err(&pdev->dev, "ts in power_model not available\n"); |
---|
| 401 | + return -EINVAL; |
---|
| 402 | + } |
---|
| 403 | + |
---|
| 404 | + return 0; |
---|
| 405 | +} |
---|
| 406 | + |
---|
367 | 407 | #endif |
---|
368 | 408 | |
---|
369 | 409 | /*---------------------------------------------------------------------------*/ |
---|
.. | .. |
---|
376 | 416 | #if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
---|
377 | 417 | struct mali_device *mdev = dev_get_drvdata(dev); |
---|
378 | 418 | |
---|
379 | | - if (mdev->clock) |
---|
380 | | - ret = clk_enable(mdev->clock); |
---|
| 419 | + ret = clk_bulk_enable(mdev->num_clks, mdev->clks); |
---|
381 | 420 | #endif |
---|
382 | 421 | return ret; |
---|
383 | 422 | } |
---|
.. | .. |
---|
387 | 426 | #if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
---|
388 | 427 | struct mali_device *mdev = dev_get_drvdata(dev); |
---|
389 | 428 | |
---|
390 | | - if (mdev->clock) |
---|
391 | | - clk_disable(mdev->clock); |
---|
| 429 | + clk_bulk_disable(mdev->num_clks, mdev->clks); |
---|
392 | 430 | #endif |
---|
393 | 431 | } |
---|
394 | 432 | |
---|
.. | .. |
---|
432 | 470 | goto fail_to_enable_regulator; |
---|
433 | 471 | } |
---|
434 | 472 | |
---|
| 473 | + if (cpu_is_rk3528()) { |
---|
| 474 | +#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
---|
| 475 | + struct mali_device *mdev = dev_get_drvdata(dev); |
---|
| 476 | + |
---|
| 477 | + clk_set_rate(mdev->clock, mdev->current_freq); |
---|
| 478 | +#endif |
---|
| 479 | + if (platform->grf) |
---|
| 480 | + regmap_write(platform->grf, |
---|
| 481 | + RK3528_GPU_SD_SLP_HAST, |
---|
| 482 | + 0xffff0000); |
---|
| 483 | + } |
---|
| 484 | + |
---|
435 | 485 | platform->is_powered = true; |
---|
436 | 486 | } |
---|
437 | 487 | |
---|
.. | .. |
---|
449 | 499 | struct rk_context *platform = s_rk_context; |
---|
450 | 500 | |
---|
451 | 501 | if (platform->is_powered) { |
---|
| 502 | + if (cpu_is_rk3528()) { |
---|
| 503 | +#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_HAVE_CLK) |
---|
| 504 | + struct mali_device *mdev = dev_get_drvdata(dev); |
---|
| 505 | + |
---|
| 506 | + //use normal pll 200M for gpu when suspend |
---|
| 507 | + clk_set_rate(mdev->clock, 200000000); |
---|
| 508 | +#endif |
---|
| 509 | + if (platform->grf) |
---|
| 510 | + regmap_write(platform->grf, |
---|
| 511 | + RK3528_GPU_SD_SLP_HAST, |
---|
| 512 | + 0xfffffffd); |
---|
| 513 | + } |
---|
452 | 514 | rk_platform_disable_clk_gpu(dev); |
---|
453 | 515 | rk_platform_disable_gpu_regulator(dev); |
---|
454 | 516 | |
---|