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
14static struct {
15	struct nx_disptop_clkgen_register_set *__g_pregister;
16} __g_module_variables[NUMBER_OF_DISPTOP_CLKGEN_MODULE] = {
17	{ NULL,},
18};
19
20int 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
33u32 nx_disp_top_clkgen_get_number_of_module(void)
34{
35	return NUMBER_OF_DISPTOP_CLKGEN_MODULE;
36}
37
38u32 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
46u32 nx_disp_top_clkgen_get_size_of_register_set(void)
47{
48	return sizeof(struct nx_disptop_clkgen_register_set);
49}
50
51void 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
57void *nx_disp_top_clkgen_get_base_address(u32 module_index)
58{
59	return (void *)__g_module_variables[module_index].__g_pregister;
60}
61
62void 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
90enum 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
111void 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
138enum 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
151void 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
169u32 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
181void 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
197u32 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
209void 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
225int 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
237void 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
254int 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
266int 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
284int 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
296void 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