1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 #include "de_clock.h"
12
13 static void *de_base;
14 #if defined(CONFIG_ARCH_SUN50IW10)
15 static void *de1_base;
16 #endif
17
18 static struct de_clk_para de_clk_tbl[] = {
19 {
20 .clk_no = DE_CLK_CORE0,
21 .div = 1,
22 .ahb_gate_adr = 0x04,
23 .ahb_gate_shift = 0,
24 .ahb_reset_adr = 0x08,
25 .ahb_reset_shift = 0,
26 .dram_gate_adr = 0x00,
27 .dram_gate_shift = 32,
28 .mod_adr = 0x00,
29 .mod_enable_shift = 0,
30 .mod_div_adr = 0x0c,
31 .mod_div_shift = 0,
32 .mod_div_width = 4,
33 },
34 {
35 .clk_no = DE_CLK_CORE1,
36 .div = 1,
37 .ahb_gate_adr = 0x04,
38 .ahb_gate_shift = 1,
39 .ahb_reset_adr = 0x08,
40 #if defined(DE_WB_RESET_SHARE)
41 .ahb_reset_shift = 2,
42 #else
43 .ahb_reset_shift = 1,
44 #endif
45 .dram_gate_adr = 0x00,
46 .dram_gate_shift = 32,
47 .mod_adr = 0x00,
48 .mod_enable_shift = 1,
49 .mod_div_adr = 0x0c,
50 .mod_div_shift = 4,
51 .mod_div_width = 4,
52 },
53 {
54 .clk_no = DE_CLK_WB,
55 .div = 1,
56 .ahb_gate_adr = 0x04,
57 .ahb_gate_shift = 2,
58 .ahb_reset_adr = 0x08,
59 .ahb_reset_shift = 2,
60 .dram_gate_adr = 0x00,
61 .dram_gate_shift = 32,
62 .mod_adr = 0x00,
63 .mod_enable_shift = 2,
64 .mod_div_adr = 0x0c,
65 .mod_div_shift = 8,
66 .mod_div_width = 4,
67 },
68 };
69
de_clk_set_div(u32 clk_no,u32 div)70 static s32 de_clk_set_div(u32 clk_no, u32 div)
71 {
72 u32 i = 0;
73 u32 reg_val;
74 u32 len = sizeof(de_clk_tbl) / sizeof(struct de_clk_para);
75
76 #if defined(CONFIG_ARCH_SUN50IW10)
77 for (i = 0; i < len; i++) {
78 if (de_clk_tbl[i].clk_no == clk_no) {
79 reg_val = readl(de_clk_tbl[i].mod_div_adr + de1_base);
80 reg_val =
81 SET_BITS(de_clk_tbl[i].mod_div_shift,
82 de_clk_tbl[i].mod_div_width, reg_val,
83 (div - 1));
84 writel(reg_val, de_clk_tbl[i].mod_div_adr + de1_base);
85
86 break;
87 }
88 }
89 #endif
90 for (i = 0; i < len; i++) {
91 if (de_clk_tbl[i].clk_no == clk_no) {
92 reg_val = readl(de_clk_tbl[i].mod_div_adr + de_base);
93 reg_val =
94 SET_BITS(de_clk_tbl[i].mod_div_shift,
95 de_clk_tbl[i].mod_div_width, reg_val,
96 (div - 1));
97 writel(reg_val, de_clk_tbl[i].mod_div_adr + de_base);
98
99 return 0;
100 }
101 }
102
103 DE_WRN("clk %d not foundis not initializd\n", clk_no);
104
105 return -1;
106 }
107
__de_clk_enable(u32 clk_no)108 static s32 __de_clk_enable(u32 clk_no)
109 {
110 u32 i;
111 u32 reg_val;
112 u32 len = sizeof(de_clk_tbl) / sizeof(struct de_clk_para);
113
114 for (i = 0; i < len; i++) {
115 if (de_clk_tbl[i].clk_no == clk_no) {
116 /* set clk div */
117 de_clk_set_div(clk_no, de_clk_tbl[i].div);
118
119 if (de_clk_tbl[i].ahb_reset_shift < 32) {
120 reg_val = readl(de_clk_tbl[i].ahb_reset_adr
121 + de_base);
122 reg_val =
123 SET_BITS(de_clk_tbl[i].ahb_reset_shift, 1,
124 reg_val, 1);
125 writel(reg_val,
126 de_clk_tbl[i].ahb_reset_adr + de_base);
127 DE_INF("clk %d reset enable\n", clk_no);
128 }
129
130 if (de_clk_tbl[i].ahb_gate_shift < 32) {
131 reg_val =
132 readl(de_clk_tbl[i].ahb_gate_adr + de_base);
133 reg_val =
134 SET_BITS(de_clk_tbl[i].ahb_gate_shift, 1,
135 reg_val, 1);
136 writel(reg_val,
137 de_clk_tbl[i].ahb_gate_adr + de_base);
138 DE_INF("clk %d gate enable\n", clk_no);
139 }
140
141 if (de_clk_tbl[i].mod_enable_shift < 32) {
142 reg_val =
143 readl(de_clk_tbl[i].mod_adr + de_base);
144 reg_val =
145 SET_BITS(de_clk_tbl[i].mod_enable_shift, 1,
146 reg_val, 1);
147 writel(reg_val,
148 de_clk_tbl[i].mod_adr + de_base);
149 DE_INF("clk %d mod enable\n", clk_no);
150 }
151
152 if (de_clk_tbl[i].dram_gate_shift < 32) {
153 reg_val =
154 readl(de_clk_tbl[i].dram_gate_adr
155 + de_base);
156 reg_val =
157 SET_BITS(de_clk_tbl[i].dram_gate_shift, 1,
158 reg_val, 1);
159 writel(reg_val,
160 de_clk_tbl[i].dram_gate_adr + de_base);
161 DE_INF("clk %d dram enable\n", clk_no);
162 }
163 }
164 }
165
166 return 0;
167 }
168
__de_clk_disable(u32 clk_no)169 static s32 __de_clk_disable(u32 clk_no)
170 {
171 u32 i;
172 u32 reg_val;
173 u32 len = sizeof(de_clk_tbl) / sizeof(struct de_clk_para);
174
175 for (i = 0; i < len; i++) {
176 if (de_clk_tbl[i].clk_no != clk_no)
177 continue;
178
179 if (de_clk_tbl[i].dram_gate_shift < 32) {
180 reg_val =
181 readl(de_clk_tbl[i].dram_gate_adr
182 + de_base);
183 reg_val =
184 SET_BITS(de_clk_tbl[i].dram_gate_shift, 1,
185 reg_val, 0);
186 writel(reg_val,
187 de_clk_tbl[i].dram_gate_adr + de_base);
188 DE_INF("clk %d dram disable\n", clk_no);
189 }
190
191 if (de_clk_tbl[i].mod_enable_shift < 32) {
192 reg_val =
193 readl(de_clk_tbl[i].mod_adr + de_base);
194 reg_val =
195 SET_BITS(de_clk_tbl[i].mod_enable_shift, 1,
196 reg_val, 0);
197 writel(reg_val,
198 de_clk_tbl[i].mod_adr + de_base);
199 DE_INF("clk %d mod disable\n", clk_no);
200 }
201
202 if (de_clk_tbl[i].ahb_gate_shift < 32) {
203 reg_val =
204 readl(de_clk_tbl[i].ahb_gate_adr + de_base);
205 reg_val =
206 SET_BITS(de_clk_tbl[i].ahb_gate_shift, 1,
207 reg_val, 0);
208 writel(reg_val,
209 de_clk_tbl[i].ahb_gate_adr + de_base);
210 DE_INF("clk %d gate disable\n", clk_no);
211 }
212
213 if (de_clk_tbl[i].ahb_reset_shift < 32) {
214 #if defined(DE_WB_RESET_SHARE)
215 if ((clk_no == DE_CLK_CORE1)
216 || (clk_no == DE_CLK_WB))
217 continue;
218 #endif
219 reg_val = readl(de_clk_tbl[i].ahb_reset_adr
220 + de_base);
221 reg_val = SET_BITS(de_clk_tbl[i].ahb_reset_shift, 1,
222 reg_val, 0);
223 writel(reg_val, de_clk_tbl[i].ahb_reset_adr + de_base);
224 DE_INF("clk %d reset disable\n", clk_no);
225 }
226 }
227
228 return 0;
229 }
230
de_clk_enable(u32 clk_no)231 s32 de_clk_enable(u32 clk_no)
232 {
233 #if defined(CONFIG_ARCH_SUN50IW10)
234 void *tmp = de_base;
235 de_base = de1_base;
236 __de_clk_enable(clk_no);
237 de_base = tmp;
238 #endif
239 return __de_clk_enable(clk_no);
240 }
241
de_clk_disable(u32 clk_no)242 s32 de_clk_disable(u32 clk_no)
243 {
244 #if defined(CONFIG_ARCH_SUN50IW10)
245 void *tmp = de_base;
246 de_base = de1_base;
247 __de_clk_disable(clk_no);
248 de_base = tmp;
249 #endif
250 return __de_clk_disable(clk_no);
251 }
252
de_clk_set_reg_base(uintptr_t reg_base)253 s32 de_clk_set_reg_base(uintptr_t reg_base)
254 {
255 de_base = (void *)reg_base;
256
257 return 0;
258 }
259
260 #if defined(CONFIG_ARCH_SUN50IW10)
de1_clk_set_reg_base(uintptr_t reg_base)261 s32 de1_clk_set_reg_base(uintptr_t reg_base)
262 {
263 de1_base = (void *)reg_base;
264
265 return 0;
266 }
267 #endif
268