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