1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2016 Nexell Co., Ltd.
4 *
5 * Author: junghyun, kim <jhkim@nexell.co.kr>
6 */
7
8 #include <linux/types.h>
9 #include <linux/io.h>
10
11 #include "s5pxx18_soc_disptop_clk.h"
12 #include "s5pxx18_soc_disptop.h"
13
14 static struct {
15 struct nx_disptop_clkgen_register_set *__g_pregister;
16 } __g_module_variables[NUMBER_OF_DISPTOP_CLKGEN_MODULE] = {
17 { NULL,},
18 };
19
nx_disp_top_clkgen_initialize(void)20 int nx_disp_top_clkgen_initialize(void)
21 {
22 static int binit;
23 u32 i;
24
25 if (binit == 0) {
26 for (i = 0; i < NUMBER_OF_DISPTOP_CLKGEN_MODULE; i++)
27 __g_module_variables[i].__g_pregister = NULL;
28 binit = 1;
29 }
30 return 1;
31 }
32
nx_disp_top_clkgen_get_number_of_module(void)33 u32 nx_disp_top_clkgen_get_number_of_module(void)
34 {
35 return NUMBER_OF_DISPTOP_CLKGEN_MODULE;
36 }
37
nx_disp_top_clkgen_get_physical_address(u32 module_index)38 u32 nx_disp_top_clkgen_get_physical_address(u32 module_index)
39 {
40 static const u32 physical_addr[] =
41 PHY_BASEADDR_DISPTOP_CLKGEN_LIST;
42
43 return (u32)physical_addr[module_index];
44 }
45
nx_disp_top_clkgen_get_size_of_register_set(void)46 u32 nx_disp_top_clkgen_get_size_of_register_set(void)
47 {
48 return sizeof(struct nx_disptop_clkgen_register_set);
49 }
50
nx_disp_top_clkgen_set_base_address(u32 module_index,void * base_address)51 void nx_disp_top_clkgen_set_base_address(u32 module_index, void *base_address)
52 {
53 __g_module_variables[module_index].__g_pregister =
54 (struct nx_disptop_clkgen_register_set *)base_address;
55 }
56
nx_disp_top_clkgen_get_base_address(u32 module_index)57 void *nx_disp_top_clkgen_get_base_address(u32 module_index)
58 {
59 return (void *)__g_module_variables[module_index].__g_pregister;
60 }
61
nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index,enum nx_bclkmode mode)62 void nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index,
63 enum nx_bclkmode mode)
64 {
65 register struct nx_disptop_clkgen_register_set *pregister;
66 register u32 regvalue;
67 u32 clkmode = 0;
68
69 pregister = __g_module_variables[module_index].__g_pregister;
70 switch (mode) {
71 case nx_bclkmode_disable:
72 clkmode = 0;
73 case nx_bclkmode_dynamic:
74 clkmode = 2;
75 break;
76 case nx_bclkmode_always:
77 clkmode = 3;
78 break;
79 default:
80 break;
81 }
82
83 regvalue = pregister->clkenb;
84 regvalue &= ~3ul;
85 regvalue |= (clkmode & 0x03);
86
87 writel(regvalue, &pregister->clkenb);
88 }
89
nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index)90 enum nx_bclkmode nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index)
91 {
92 register struct nx_disptop_clkgen_register_set *pregister;
93 u32 mode = 0;
94
95 pregister = __g_module_variables[module_index].__g_pregister;
96 mode = (pregister->clkenb & 3ul);
97
98 switch (mode) {
99 case 0:
100 return nx_bclkmode_disable;
101 case 2:
102 return nx_bclkmode_dynamic;
103 case 3:
104 return nx_bclkmode_always;
105 default:
106 break;
107 }
108 return nx_bclkmode_disable;
109 }
110
nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index,enum nx_pclkmode mode)111 void nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index,
112 enum nx_pclkmode mode)
113 {
114 register struct nx_disptop_clkgen_register_set *pregister;
115 register u32 regvalue;
116 const u32 pclkmode_pos = 3;
117 u32 clkmode = 0;
118
119 pregister = __g_module_variables[module_index].__g_pregister;
120 switch (mode) {
121 case nx_pclkmode_dynamic:
122 clkmode = 0;
123 break;
124 case nx_pclkmode_always:
125 clkmode = 1;
126 break;
127 default:
128 break;
129 }
130
131 regvalue = pregister->clkenb;
132 regvalue &= ~(1ul << pclkmode_pos);
133 regvalue |= (clkmode & 0x01) << pclkmode_pos;
134
135 writel(regvalue, &pregister->clkenb);
136 }
137
nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index)138 enum nx_pclkmode nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index)
139 {
140 register struct nx_disptop_clkgen_register_set *pregister;
141 const u32 pclkmode_pos = 3;
142
143 pregister = __g_module_variables[module_index].__g_pregister;
144
145 if (pregister->clkenb & (1ul << pclkmode_pos))
146 return nx_pclkmode_always;
147
148 return nx_pclkmode_dynamic;
149 }
150
nx_disp_top_clkgen_set_clock_source(u32 module_index,u32 index,u32 clk_src)151 void nx_disp_top_clkgen_set_clock_source(u32 module_index, u32 index,
152 u32 clk_src)
153 {
154 register struct nx_disptop_clkgen_register_set *pregister;
155 register u32 read_value;
156
157 const u32 clksrcsel_pos = 2;
158 const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
159
160 pregister = __g_module_variables[module_index].__g_pregister;
161
162 read_value = pregister->CLKGEN[index << 1];
163 read_value &= ~clksrcsel_mask;
164 read_value |= clk_src << clksrcsel_pos;
165
166 writel(read_value, &pregister->CLKGEN[index << 1]);
167 }
168
nx_disp_top_clkgen_get_clock_source(u32 module_index,u32 index)169 u32 nx_disp_top_clkgen_get_clock_source(u32 module_index, u32 index)
170 {
171 register struct nx_disptop_clkgen_register_set *pregister;
172 const u32 clksrcsel_pos = 2;
173 const u32 clksrcsel_mask = 0x07 << clksrcsel_pos;
174
175 pregister = __g_module_variables[module_index].__g_pregister;
176
177 return (pregister->CLKGEN[index << 1] &
178 clksrcsel_mask) >> clksrcsel_pos;
179 }
180
nx_disp_top_clkgen_set_clock_divisor(u32 module_index,u32 index,u32 divisor)181 void nx_disp_top_clkgen_set_clock_divisor(u32 module_index, u32 index,
182 u32 divisor)
183 {
184 register struct nx_disptop_clkgen_register_set *pregister;
185 const u32 clkdiv_pos = 5;
186 const u32 clkdiv_mask = 0xff << clkdiv_pos;
187 register u32 read_value;
188
189 pregister = __g_module_variables[module_index].__g_pregister;
190
191 read_value = pregister->CLKGEN[index << 1];
192 read_value &= ~clkdiv_mask;
193 read_value |= (divisor - 1) << clkdiv_pos;
194 writel(read_value, &pregister->CLKGEN[index << 1]);
195 }
196
nx_disp_top_clkgen_get_clock_divisor(u32 module_index,u32 index)197 u32 nx_disp_top_clkgen_get_clock_divisor(u32 module_index, u32 index)
198 {
199 register struct nx_disptop_clkgen_register_set *pregister;
200 const u32 clkdiv_pos = 5;
201 const u32 clkdiv_mask = 0xff << clkdiv_pos;
202
203 pregister = __g_module_variables[module_index].__g_pregister;
204
205 return ((pregister->CLKGEN[index << 1] &
206 clkdiv_mask) >> clkdiv_pos) + 1;
207 }
208
nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index,int enable)209 void nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index, int enable)
210 {
211 register struct nx_disptop_clkgen_register_set *pregister;
212 register u32 read_value;
213 const u32 clkgenenb_pos = 2;
214 const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
215
216 pregister = __g_module_variables[module_index].__g_pregister;
217
218 read_value = pregister->clkenb;
219 read_value &= ~clkgenenb_mask;
220 read_value |= (u32)enable << clkgenenb_pos;
221
222 writel(read_value, &pregister->clkenb);
223 }
224
nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index)225 int nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index)
226 {
227 register struct nx_disptop_clkgen_register_set *pregister;
228 const u32 clkgenenb_pos = 2;
229 const u32 clkgenenb_mask = 1ul << clkgenenb_pos;
230
231 pregister = __g_module_variables[module_index].__g_pregister;
232
233 return (int)((pregister->clkenb &
234 clkgenenb_mask) >> clkgenenb_pos);
235 }
236
nx_disp_top_clkgen_set_clock_out_inv(u32 module_index,u32 index,int out_clk_inv)237 void nx_disp_top_clkgen_set_clock_out_inv(u32 module_index, u32 index,
238 int out_clk_inv)
239 {
240 register struct nx_disptop_clkgen_register_set *pregister;
241 register u32 read_value;
242 const u32 outclkinv_pos = 1;
243 const u32 outclkinv_mask = 1ul << outclkinv_pos;
244
245 pregister = __g_module_variables[module_index].__g_pregister;
246
247 read_value = pregister->CLKGEN[index << 1];
248 read_value &= ~outclkinv_mask;
249 read_value |= out_clk_inv << outclkinv_pos;
250
251 writel(read_value, &pregister->CLKGEN[index << 1]);
252 }
253
nx_disp_top_clkgen_get_clock_out_inv(u32 module_index,u32 index)254 int nx_disp_top_clkgen_get_clock_out_inv(u32 module_index, u32 index)
255 {
256 register struct nx_disptop_clkgen_register_set *pregister;
257 const u32 outclkinv_pos = 1;
258 const u32 outclkinv_mask = 1ul << outclkinv_pos;
259
260 pregister = __g_module_variables[module_index].__g_pregister;
261
262 return (int)((pregister->CLKGEN[index << 1] &
263 outclkinv_mask) >> outclkinv_pos);
264 }
265
nx_disp_top_clkgen_set_input_inv(u32 module_index,u32 index,int in_clk_inv)266 int nx_disp_top_clkgen_set_input_inv(u32 module_index,
267 u32 index, int in_clk_inv)
268 {
269 register struct nx_disptop_clkgen_register_set *pregister;
270 register u32 read_value;
271 const u32 inclkinv_pos = 4 + index;
272 const u32 inclkinv_mask = 1ul << inclkinv_pos;
273
274 pregister = __g_module_variables[module_index].__g_pregister;
275
276 read_value = pregister->clkenb;
277 read_value &= ~inclkinv_mask;
278 read_value |= in_clk_inv << inclkinv_pos;
279
280 writel(read_value, &pregister->clkenb);
281 return true;
282 }
283
nx_disp_top_clkgen_get_input_inv(u32 module_index,u32 index)284 int nx_disp_top_clkgen_get_input_inv(u32 module_index, u32 index)
285 {
286 register struct nx_disptop_clkgen_register_set *pregister;
287 const u32 inclkinv_pos = 4 + index;
288 const u32 inclkinv_mask = 1ul << inclkinv_pos;
289
290 pregister = __g_module_variables[module_index].__g_pregister;
291
292 return (int)((pregister->clkenb &
293 inclkinv_mask) >> inclkinv_pos);
294 }
295
nx_disp_top_clkgen_set_clock_out_select(u32 module_index,u32 index,int bbypass)296 void nx_disp_top_clkgen_set_clock_out_select(u32 module_index, u32 index,
297 int bbypass)
298 {
299 register struct nx_disptop_clkgen_register_set *pregister;
300 register u32 read_value;
301
302 pregister = __g_module_variables[module_index].__g_pregister;
303
304 read_value = pregister->CLKGEN[index << 1];
305 read_value = read_value & (~0x01);
306 read_value = read_value | bbypass;
307
308 writel(read_value, &pregister->CLKGEN[index << 1]);
309 }
310