1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
3  * All rights reserved.
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/clk/clk-conf.h>
8 #include <linux/err.h>
9 #include <linux/delay.h>
10 #include <linux/of.h>
11 
12 #include <drm/drm_print.h>
13 
14 #include "dpu_io_util.h"
15 
msm_dss_put_clk(struct dss_clk * clk_arry,int num_clk)16 void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
17 {
18 	int i;
19 
20 	for (i = num_clk - 1; i >= 0; i--) {
21 		if (clk_arry[i].clk)
22 			clk_put(clk_arry[i].clk);
23 		clk_arry[i].clk = NULL;
24 	}
25 }
26 
msm_dss_get_clk(struct device * dev,struct dss_clk * clk_arry,int num_clk)27 int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
28 {
29 	int i, rc = 0;
30 
31 	for (i = 0; i < num_clk; i++) {
32 		clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
33 		rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
34 		if (rc) {
35 			DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
36 				__builtin_return_address(0), __func__,
37 				clk_arry[i].clk_name, rc);
38 			goto error;
39 		}
40 	}
41 
42 	return rc;
43 
44 error:
45 	for (i--; i >= 0; i--) {
46 		if (clk_arry[i].clk)
47 			clk_put(clk_arry[i].clk);
48 		clk_arry[i].clk = NULL;
49 	}
50 
51 	return rc;
52 }
53 
msm_dss_clk_set_rate(struct dss_clk * clk_arry,int num_clk)54 int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
55 {
56 	int i, rc = 0;
57 
58 	for (i = 0; i < num_clk; i++) {
59 		if (clk_arry[i].clk) {
60 			if (clk_arry[i].type != DSS_CLK_AHB) {
61 				DEV_DBG("%pS->%s: '%s' rate %ld\n",
62 					__builtin_return_address(0), __func__,
63 					clk_arry[i].clk_name,
64 					clk_arry[i].rate);
65 				rc = clk_set_rate(clk_arry[i].clk,
66 					clk_arry[i].rate);
67 				if (rc) {
68 					DEV_ERR("%pS->%s: %s failed. rc=%d\n",
69 						__builtin_return_address(0),
70 						__func__,
71 						clk_arry[i].clk_name, rc);
72 					break;
73 				}
74 			}
75 		} else {
76 			DEV_ERR("%pS->%s: '%s' is not available\n",
77 				__builtin_return_address(0), __func__,
78 				clk_arry[i].clk_name);
79 			rc = -EPERM;
80 			break;
81 		}
82 	}
83 
84 	return rc;
85 }
86 
msm_dss_enable_clk(struct dss_clk * clk_arry,int num_clk,int enable)87 int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
88 {
89 	int i, rc = 0;
90 
91 	if (enable) {
92 		for (i = 0; i < num_clk; i++) {
93 			DEV_DBG("%pS->%s: enable '%s'\n",
94 				__builtin_return_address(0), __func__,
95 				clk_arry[i].clk_name);
96 			if (clk_arry[i].clk) {
97 				rc = clk_prepare_enable(clk_arry[i].clk);
98 				if (rc)
99 					DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
100 						__builtin_return_address(0),
101 						__func__,
102 						clk_arry[i].clk_name, rc);
103 			} else {
104 				DEV_ERR("%pS->%s: '%s' is not available\n",
105 					__builtin_return_address(0), __func__,
106 					clk_arry[i].clk_name);
107 				rc = -EPERM;
108 			}
109 
110 			if (rc && i) {
111 				msm_dss_enable_clk(&clk_arry[i - 1],
112 					i - 1, false);
113 				break;
114 			}
115 		}
116 	} else {
117 		for (i = num_clk - 1; i >= 0; i--) {
118 			DEV_DBG("%pS->%s: disable '%s'\n",
119 				__builtin_return_address(0), __func__,
120 				clk_arry[i].clk_name);
121 
122 			if (clk_arry[i].clk)
123 				clk_disable_unprepare(clk_arry[i].clk);
124 			else
125 				DEV_ERR("%pS->%s: '%s' is not available\n",
126 					__builtin_return_address(0), __func__,
127 					clk_arry[i].clk_name);
128 		}
129 	}
130 
131 	return rc;
132 }
133 
msm_dss_parse_clock(struct platform_device * pdev,struct dss_module_power * mp)134 int msm_dss_parse_clock(struct platform_device *pdev,
135 			struct dss_module_power *mp)
136 {
137 	u32 i, rc = 0;
138 	const char *clock_name;
139 	int num_clk = 0;
140 
141 	if (!pdev || !mp)
142 		return -EINVAL;
143 
144 	mp->num_clk = 0;
145 	num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names");
146 	if (num_clk <= 0) {
147 		pr_debug("clocks are not defined\n");
148 		return 0;
149 	}
150 
151 	mp->clk_config = devm_kcalloc(&pdev->dev,
152 				      num_clk, sizeof(struct dss_clk),
153 				      GFP_KERNEL);
154 	if (!mp->clk_config)
155 		return -ENOMEM;
156 
157 	for (i = 0; i < num_clk; i++) {
158 		rc = of_property_read_string_index(pdev->dev.of_node,
159 						   "clock-names", i,
160 						   &clock_name);
161 		if (rc) {
162 			DRM_DEV_ERROR(&pdev->dev, "Failed to get clock name for %d\n",
163 				i);
164 			break;
165 		}
166 		strlcpy(mp->clk_config[i].clk_name, clock_name,
167 			sizeof(mp->clk_config[i].clk_name));
168 
169 		mp->clk_config[i].type = DSS_CLK_AHB;
170 	}
171 
172 	rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, num_clk);
173 	if (rc) {
174 		DRM_DEV_ERROR(&pdev->dev, "Failed to get clock refs %d\n", rc);
175 		goto err;
176 	}
177 
178 	rc = of_clk_set_defaults(pdev->dev.of_node, false);
179 	if (rc) {
180 		DRM_DEV_ERROR(&pdev->dev, "Failed to set clock defaults %d\n", rc);
181 		goto err;
182 	}
183 
184 	for (i = 0; i < num_clk; i++) {
185 		u32 rate = clk_get_rate(mp->clk_config[i].clk);
186 		if (!rate)
187 			continue;
188 		mp->clk_config[i].rate = rate;
189 		mp->clk_config[i].type = DSS_CLK_PCLK;
190 	}
191 
192 	mp->num_clk = num_clk;
193 	return 0;
194 
195 err:
196 	msm_dss_put_clk(mp->clk_config, num_clk);
197 	return rc;
198 }
199