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