1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #include <linux/clk.h>
7 #include <linux/interconnect.h>
8 #include <linux/pm_domain.h>
9 #include <linux/pm_opp.h>
10 #include <linux/pm_runtime.h>
11 #include <linux/reset.h>
12
13 #include "iris_core.h"
14 #include "iris_resources.h"
15
16 #define BW_THRESHOLD 50000
17
iris_set_icc_bw(struct iris_core * core,unsigned long icc_bw)18 int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw)
19 {
20 unsigned long bw_kbps = 0, bw_prev = 0;
21 const struct icc_info *icc_tbl;
22 int ret = 0, i;
23
24 icc_tbl = core->iris_platform_data->icc_tbl;
25
26 for (i = 0; i < core->icc_count; i++) {
27 if (!strcmp(core->icc_tbl[i].name, "video-mem")) {
28 bw_kbps = icc_bw;
29 bw_prev = core->power.icc_bw;
30
31 bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps,
32 icc_tbl[i].bw_min_kbps, icc_tbl[i].bw_max_kbps);
33
34 if (abs(bw_kbps - bw_prev) < BW_THRESHOLD && bw_prev)
35 return ret;
36
37 core->icc_tbl[i].avg_bw = bw_kbps;
38
39 core->power.icc_bw = bw_kbps;
40 break;
41 }
42 }
43
44 return icc_bulk_set_bw(core->icc_count, core->icc_tbl);
45 }
46
iris_unset_icc_bw(struct iris_core * core)47 int iris_unset_icc_bw(struct iris_core *core)
48 {
49 u32 i;
50
51 core->power.icc_bw = 0;
52
53 for (i = 0; i < core->icc_count; i++) {
54 core->icc_tbl[i].avg_bw = 0;
55 core->icc_tbl[i].peak_bw = 0;
56 }
57
58 return icc_bulk_set_bw(core->icc_count, core->icc_tbl);
59 }
60
iris_enable_power_domains(struct iris_core * core,struct device * pd_dev)61 int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev)
62 {
63 int ret;
64
65 ret = dev_pm_opp_set_rate(core->dev, ULONG_MAX);
66 if (ret)
67 return ret;
68
69 ret = pm_runtime_get_sync(pd_dev);
70 if (ret < 0)
71 return ret;
72
73 return ret;
74 }
75
iris_disable_power_domains(struct iris_core * core,struct device * pd_dev)76 int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev)
77 {
78 int ret;
79
80 ret = dev_pm_opp_set_rate(core->dev, 0);
81 if (ret)
82 return ret;
83
84 pm_runtime_put_sync(pd_dev);
85
86 return 0;
87 }
88
iris_get_clk_by_type(struct iris_core * core,enum platform_clk_type clk_type)89 static struct clk *iris_get_clk_by_type(struct iris_core *core, enum platform_clk_type clk_type)
90 {
91 const struct platform_clk_data *clk_tbl;
92 u32 clk_cnt, i, j;
93
94 clk_tbl = core->iris_platform_data->clk_tbl;
95 clk_cnt = core->iris_platform_data->clk_tbl_size;
96
97 for (i = 0; i < clk_cnt; i++) {
98 if (clk_tbl[i].clk_type == clk_type) {
99 for (j = 0; core->clock_tbl && j < core->clk_count; j++) {
100 if (!strcmp(core->clock_tbl[j].id, clk_tbl[i].clk_name))
101 return core->clock_tbl[j].clk;
102 }
103 }
104 }
105
106 return NULL;
107 }
108
iris_prepare_enable_clock(struct iris_core * core,enum platform_clk_type clk_type)109 int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_type clk_type)
110 {
111 struct clk *clock;
112
113 clock = iris_get_clk_by_type(core, clk_type);
114 if (!clock)
115 return -EINVAL;
116
117 return clk_prepare_enable(clock);
118 }
119
iris_disable_unprepare_clock(struct iris_core * core,enum platform_clk_type clk_type)120 int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk_type clk_type)
121 {
122 struct clk *clock;
123
124 clock = iris_get_clk_by_type(core, clk_type);
125 if (!clock)
126 return -EINVAL;
127
128 clk_disable_unprepare(clock);
129
130 return 0;
131 }
132