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