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