1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 OR MIT
2*4882a593Smuzhiyun /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/iopoll.h>
5*4882a593Smuzhiyun #include <linux/device.h>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "lima_device.h"
8*4882a593Smuzhiyun #include "lima_pmu.h"
9*4882a593Smuzhiyun #include "lima_regs.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define pmu_write(reg, data) writel(data, ip->iomem + reg)
12*4882a593Smuzhiyun #define pmu_read(reg) readl(ip->iomem + reg)
13*4882a593Smuzhiyun
lima_pmu_wait_cmd(struct lima_ip * ip)14*4882a593Smuzhiyun static int lima_pmu_wait_cmd(struct lima_ip *ip)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun struct lima_device *dev = ip->dev;
17*4882a593Smuzhiyun int err;
18*4882a593Smuzhiyun u32 v;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun err = readl_poll_timeout(ip->iomem + LIMA_PMU_INT_RAWSTAT,
21*4882a593Smuzhiyun v, v & LIMA_PMU_INT_CMD_MASK,
22*4882a593Smuzhiyun 100, 100000);
23*4882a593Smuzhiyun if (err) {
24*4882a593Smuzhiyun dev_err(dev->dev, "timeout wait pmu cmd\n");
25*4882a593Smuzhiyun return err;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
29*4882a593Smuzhiyun return 0;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
lima_pmu_get_ip_mask(struct lima_ip * ip)32*4882a593Smuzhiyun static u32 lima_pmu_get_ip_mask(struct lima_ip *ip)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct lima_device *dev = ip->dev;
35*4882a593Smuzhiyun u32 ret = 0;
36*4882a593Smuzhiyun int i;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun ret |= LIMA_PMU_POWER_GP0_MASK;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (dev->id == lima_gpu_mali400) {
41*4882a593Smuzhiyun ret |= LIMA_PMU_POWER_L2_MASK;
42*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
43*4882a593Smuzhiyun if (dev->ip[lima_ip_pp0 + i].present)
44*4882a593Smuzhiyun ret |= LIMA_PMU_POWER_PP_MASK(i);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun } else {
47*4882a593Smuzhiyun if (dev->ip[lima_ip_pp0].present)
48*4882a593Smuzhiyun ret |= LIMA450_PMU_POWER_PP0_MASK;
49*4882a593Smuzhiyun for (i = lima_ip_pp1; i <= lima_ip_pp3; i++) {
50*4882a593Smuzhiyun if (dev->ip[i].present) {
51*4882a593Smuzhiyun ret |= LIMA450_PMU_POWER_PP13_MASK;
52*4882a593Smuzhiyun break;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) {
56*4882a593Smuzhiyun if (dev->ip[i].present) {
57*4882a593Smuzhiyun ret |= LIMA450_PMU_POWER_PP47_MASK;
58*4882a593Smuzhiyun break;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun return ret;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
lima_pmu_hw_init(struct lima_ip * ip)66*4882a593Smuzhiyun static int lima_pmu_hw_init(struct lima_ip *ip)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun int err;
69*4882a593Smuzhiyun u32 stat;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun pmu_write(LIMA_PMU_INT_MASK, 0);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* If this value is too low, when in high GPU clk freq,
74*4882a593Smuzhiyun * GPU will be in unstable state.
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun pmu_write(LIMA_PMU_SW_DELAY, 0xffff);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* status reg 1=off 0=on */
79*4882a593Smuzhiyun stat = pmu_read(LIMA_PMU_STATUS);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /* power up all ip */
82*4882a593Smuzhiyun if (stat) {
83*4882a593Smuzhiyun pmu_write(LIMA_PMU_POWER_UP, stat);
84*4882a593Smuzhiyun err = lima_pmu_wait_cmd(ip);
85*4882a593Smuzhiyun if (err)
86*4882a593Smuzhiyun return err;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
lima_pmu_hw_fini(struct lima_ip * ip)91*4882a593Smuzhiyun static void lima_pmu_hw_fini(struct lima_ip *ip)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun u32 stat;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (!ip->data.mask)
96*4882a593Smuzhiyun ip->data.mask = lima_pmu_get_ip_mask(ip);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun stat = ~pmu_read(LIMA_PMU_STATUS) & ip->data.mask;
99*4882a593Smuzhiyun if (stat) {
100*4882a593Smuzhiyun pmu_write(LIMA_PMU_POWER_DOWN, stat);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* Don't wait for interrupt on Mali400 if all domains are
103*4882a593Smuzhiyun * powered off because the HW won't generate an interrupt
104*4882a593Smuzhiyun * in this case.
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun if (ip->dev->id == lima_gpu_mali400)
107*4882a593Smuzhiyun pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
108*4882a593Smuzhiyun else
109*4882a593Smuzhiyun lima_pmu_wait_cmd(ip);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
lima_pmu_resume(struct lima_ip * ip)113*4882a593Smuzhiyun int lima_pmu_resume(struct lima_ip *ip)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun return lima_pmu_hw_init(ip);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
lima_pmu_suspend(struct lima_ip * ip)118*4882a593Smuzhiyun void lima_pmu_suspend(struct lima_ip *ip)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun lima_pmu_hw_fini(ip);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
lima_pmu_init(struct lima_ip * ip)123*4882a593Smuzhiyun int lima_pmu_init(struct lima_ip *ip)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun return lima_pmu_hw_init(ip);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
lima_pmu_fini(struct lima_ip * ip)128*4882a593Smuzhiyun void lima_pmu_fini(struct lima_ip *ip)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun lima_pmu_hw_fini(ip);
131*4882a593Smuzhiyun }
132