aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-03-12 15:00:59 -0400
committerLucas Stach <l.stach@pengutronix.de>2017-03-29 09:53:53 -0400
commitbcdfb5e56dc539506f72e8087c993af1f7ff06eb (patch)
treeb01232ce0b4e7a46e2fe60df346b602882c82954
parentfda8fa5b8ab2ceb02cb66ee2fe2ed83aa209bc5b (diff)
drm/etnaviv: add etnaviv cooling device
Each Vivante GPU contains a clock divider which can divide the GPU clock by 2^n, which can lower the power dissipation from the GPU. It has been suggested that the GC600 on Dove is responsible for 20-30% of the power dissipation from the SoC, so lowering the GPU clock rate provides a way to throttle the power dissiptation, and reduce the temperature when the SoC gets hot. This patch hooks the Etnaviv driver into the kernel's thermal management to allow the GPUs to be throttled when necessary, allowing a reduction in GPU clock rate from /1 to /64 in power of 2 steps. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c84
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h2
2 files changed, 71 insertions, 15 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index a81a2e84f6ad..cab4cf546c17 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -18,6 +18,7 @@
18#include <linux/dma-fence.h> 18#include <linux/dma-fence.h>
19#include <linux/moduleparam.h> 19#include <linux/moduleparam.h>
20#include <linux/of_device.h> 20#include <linux/of_device.h>
21#include <linux/thermal.h>
21 22
22#include "etnaviv_cmdbuf.h" 23#include "etnaviv_cmdbuf.h"
23#include "etnaviv_dump.h" 24#include "etnaviv_dump.h"
@@ -409,6 +410,17 @@ static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
409 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); 410 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
410} 411}
411 412
413static void etnaviv_gpu_update_clock(struct etnaviv_gpu *gpu)
414{
415 unsigned int fscale = 1 << (6 - gpu->freq_scale);
416 u32 clock;
417
418 clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
419 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale);
420
421 etnaviv_gpu_load_clock(gpu, clock);
422}
423
412static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) 424static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
413{ 425{
414 u32 control, idle; 426 u32 control, idle;
@@ -426,11 +438,10 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
426 timeout = jiffies + msecs_to_jiffies(1000); 438 timeout = jiffies + msecs_to_jiffies(1000);
427 439
428 while (time_is_after_jiffies(timeout)) { 440 while (time_is_after_jiffies(timeout)) {
429 control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
430 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
431
432 /* enable clock */ 441 /* enable clock */
433 etnaviv_gpu_load_clock(gpu, control); 442 etnaviv_gpu_update_clock(gpu);
443
444 control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
434 445
435 /* Wait for stable clock. Vivante's code waited for 1ms */ 446 /* Wait for stable clock. Vivante's code waited for 1ms */
436 usleep_range(1000, 10000); 447 usleep_range(1000, 10000);
@@ -490,11 +501,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
490 } 501 }
491 502
492 /* We rely on the GPU running, so program the clock */ 503 /* We rely on the GPU running, so program the clock */
493 control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | 504 etnaviv_gpu_update_clock(gpu);
494 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
495
496 /* enable clock */
497 etnaviv_gpu_load_clock(gpu, control);
498 505
499 return 0; 506 return 0;
500} 507}
@@ -1532,17 +1539,13 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
1532#ifdef CONFIG_PM 1539#ifdef CONFIG_PM
1533static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu) 1540static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
1534{ 1541{
1535 u32 clock;
1536 int ret; 1542 int ret;
1537 1543
1538 ret = mutex_lock_killable(&gpu->lock); 1544 ret = mutex_lock_killable(&gpu->lock);
1539 if (ret) 1545 if (ret)
1540 return ret; 1546 return ret;
1541 1547
1542 clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | 1548 etnaviv_gpu_update_clock(gpu);
1543 VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
1544
1545 etnaviv_gpu_load_clock(gpu, clock);
1546 etnaviv_gpu_hw_init(gpu); 1549 etnaviv_gpu_hw_init(gpu);
1547 1550
1548 gpu->switch_context = true; 1551 gpu->switch_context = true;
@@ -1554,6 +1557,47 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
1554} 1557}
1555#endif 1558#endif
1556 1559
1560static int
1561etnaviv_gpu_cooling_get_max_state(struct thermal_cooling_device *cdev,
1562 unsigned long *state)
1563{
1564 *state = 6;
1565
1566 return 0;
1567}
1568
1569static int
1570etnaviv_gpu_cooling_get_cur_state(struct thermal_cooling_device *cdev,
1571 unsigned long *state)
1572{
1573 struct etnaviv_gpu *gpu = cdev->devdata;
1574
1575 *state = gpu->freq_scale;
1576
1577 return 0;
1578}
1579
1580static int
1581etnaviv_gpu_cooling_set_cur_state(struct thermal_cooling_device *cdev,
1582 unsigned long state)
1583{
1584 struct etnaviv_gpu *gpu = cdev->devdata;
1585
1586 mutex_lock(&gpu->lock);
1587 gpu->freq_scale = state;
1588 if (!pm_runtime_suspended(gpu->dev))
1589 etnaviv_gpu_update_clock(gpu);
1590 mutex_unlock(&gpu->lock);
1591
1592 return 0;
1593}
1594
1595static struct thermal_cooling_device_ops cooling_ops = {
1596 .get_max_state = etnaviv_gpu_cooling_get_max_state,
1597 .get_cur_state = etnaviv_gpu_cooling_get_cur_state,
1598 .set_cur_state = etnaviv_gpu_cooling_set_cur_state,
1599};
1600
1557static int etnaviv_gpu_bind(struct device *dev, struct device *master, 1601static int etnaviv_gpu_bind(struct device *dev, struct device *master,
1558 void *data) 1602 void *data)
1559{ 1603{
@@ -1562,13 +1606,20 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
1562 struct etnaviv_gpu *gpu = dev_get_drvdata(dev); 1606 struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
1563 int ret; 1607 int ret;
1564 1608
1609 gpu->cooling = thermal_of_cooling_device_register(dev->of_node,
1610 (char *)dev_name(dev), gpu, &cooling_ops);
1611 if (IS_ERR(gpu->cooling))
1612 return PTR_ERR(gpu->cooling);
1613
1565#ifdef CONFIG_PM 1614#ifdef CONFIG_PM
1566 ret = pm_runtime_get_sync(gpu->dev); 1615 ret = pm_runtime_get_sync(gpu->dev);
1567#else 1616#else
1568 ret = etnaviv_gpu_clk_enable(gpu); 1617 ret = etnaviv_gpu_clk_enable(gpu);
1569#endif 1618#endif
1570 if (ret < 0) 1619 if (ret < 0) {
1620 thermal_cooling_device_unregister(gpu->cooling);
1571 return ret; 1621 return ret;
1622 }
1572 1623
1573 gpu->drm = drm; 1624 gpu->drm = drm;
1574 gpu->fence_context = dma_fence_context_alloc(1); 1625 gpu->fence_context = dma_fence_context_alloc(1);
@@ -1622,6 +1673,9 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
1622 } 1673 }
1623 1674
1624 gpu->drm = NULL; 1675 gpu->drm = NULL;
1676
1677 thermal_cooling_device_unregister(gpu->cooling);
1678 gpu->cooling = NULL;
1625} 1679}
1626 1680
1627static const struct component_ops gpu_ops = { 1681static const struct component_ops gpu_ops = {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 1c0606ea7d5e..6a1e68eec24c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -97,6 +97,7 @@ struct etnaviv_cmdbuf;
97 97
98struct etnaviv_gpu { 98struct etnaviv_gpu {
99 struct drm_device *drm; 99 struct drm_device *drm;
100 struct thermal_cooling_device *cooling;
100 struct device *dev; 101 struct device *dev;
101 struct mutex lock; 102 struct mutex lock;
102 struct etnaviv_chip_identity identity; 103 struct etnaviv_chip_identity identity;
@@ -150,6 +151,7 @@ struct etnaviv_gpu {
150 u32 hangcheck_fence; 151 u32 hangcheck_fence;
151 u32 hangcheck_dma_addr; 152 u32 hangcheck_dma_addr;
152 struct work_struct recover_work; 153 struct work_struct recover_work;
154 unsigned int freq_scale;
153}; 155};
154 156
155static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) 157static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)