exynos: video: Drop static variables in exynos_dp_lowlevel.c
[oweals/u-boot.git] / drivers / video / exynos / exynos_fimd.c
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  *
4  * Author: InKi Dae <inki.dae@samsung.com>
5  * Author: Donghwa Lee <dh09.lee@samsung.com>
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <config.h>
11 #include <common.h>
12 #include <asm/io.h>
13 #include <lcd.h>
14 #include <div64.h>
15 #include <fdtdec.h>
16 #include <libfdt.h>
17 #include <asm/arch/clk.h>
18 #include <asm/arch/clock.h>
19 #include <asm/arch/cpu.h>
20 #include "exynos_fb.h"
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled)
25 {
26         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
27         unsigned int cfg = 0;
28
29         if (enabled) {
30                 cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
31                         EXYNOS_DUALRGB_VDEN_EN_ENABLE;
32
33                 /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
34                 cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) |
35                         EXYNOS_DUALRGB_MAIN_CNT(0);
36         }
37
38         writel(cfg, &fimd_ctrl->dualrgb);
39 }
40
41 static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid,
42                                       unsigned int enabled)
43 {
44         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
45         unsigned int cfg = 0;
46
47         if (enabled)
48                 cfg = EXYNOS_DP_CLK_ENABLE;
49
50         writel(cfg, &fimd_ctrl->dp_mie_clkcon);
51 }
52
53 static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id)
54 {
55         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
56         unsigned int cfg = 0;
57
58         /* set window control */
59         cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
60                         EXYNOS_WINCON(win_id));
61
62         cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
63                 EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
64                 EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
65                 EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
66
67         /* DATAPATH is DMA */
68         cfg |= EXYNOS_WINCON_DATAPATH_DMA;
69
70         cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
71
72         /* dma burst is 16 */
73         cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
74
75         switch (pvid->vl_bpix) {
76         case 4:
77                 cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
78                 break;
79         default:
80                 cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
81                 break;
82         }
83
84         writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
85                         EXYNOS_WINCON(win_id));
86
87         /* set window position to x=0, y=0*/
88         cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
89         writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a +
90                         EXYNOS_VIDOSD(win_id));
91
92         cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) |
93                 EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) |
94                 EXYNOS_VIDOSD_RIGHT_X_E(1) |
95                 EXYNOS_VIDOSD_BOTTOM_Y_E(0);
96
97         writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b +
98                         EXYNOS_VIDOSD(win_id));
99
100         /* set window size for window0*/
101         cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row);
102         writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c +
103                         EXYNOS_VIDOSD(win_id));
104 }
105
106 static void exynos_fimd_set_buffer_address(struct vidinfo *pvid,
107                                            unsigned int win_id,
108                                            ulong lcd_base_addr)
109 {
110         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
111         unsigned long start_addr, end_addr;
112
113         start_addr = lcd_base_addr;
114         end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) *
115                                 pvid->vl_row);
116
117         writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 +
118                         EXYNOS_BUFFER_OFFSET(win_id));
119         writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 +
120                         EXYNOS_BUFFER_OFFSET(win_id));
121 }
122
123 static void exynos_fimd_set_clock(struct vidinfo *pvid)
124 {
125         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
126         unsigned int cfg = 0, div = 0, remainder, remainder_div;
127         unsigned long pixel_clock;
128         unsigned long long src_clock;
129
130         if (pvid->dual_lcd_enabled) {
131                 pixel_clock = pvid->vl_freq *
132                                 (pvid->vl_hspw + pvid->vl_hfpd +
133                                  pvid->vl_hbpd + pvid->vl_col / 2) *
134                                 (pvid->vl_vspw + pvid->vl_vfpd +
135                                  pvid->vl_vbpd + pvid->vl_row);
136         } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) {
137                 pixel_clock = pvid->vl_freq *
138                                 pvid->vl_width * pvid->vl_height *
139                                 (pvid->cs_setup + pvid->wr_setup +
140                                  pvid->wr_act + pvid->wr_hold + 1);
141         } else {
142                 pixel_clock = pvid->vl_freq *
143                                 (pvid->vl_hspw + pvid->vl_hfpd +
144                                  pvid->vl_hbpd + pvid->vl_col) *
145                                 (pvid->vl_vspw + pvid->vl_vfpd +
146                                  pvid->vl_vbpd + pvid->vl_row);
147         }
148
149         cfg = readl(&fimd_ctrl->vidcon0);
150         cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
151                 EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
152                 EXYNOS_VIDCON0_CLKDIR_MASK);
153         cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
154                 EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
155
156         src_clock = (unsigned long long) get_lcd_clk();
157
158         /* get quotient and remainder. */
159         remainder = do_div(src_clock, pixel_clock);
160         div = src_clock;
161
162         remainder *= 10;
163         remainder_div = remainder / pixel_clock;
164
165         /* round about one places of decimals. */
166         if (remainder_div >= 5)
167                 div++;
168
169         /* in case of dual lcd mode. */
170         if (pvid->dual_lcd_enabled)
171                 div--;
172
173         cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
174         writel(cfg, &fimd_ctrl->vidcon0);
175 }
176
177 void exynos_set_trigger(struct vidinfo *pvid)
178 {
179         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
180         unsigned int cfg = 0;
181
182         cfg = readl(&fimd_ctrl->trigcon);
183
184         cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
185
186         writel(cfg, &fimd_ctrl->trigcon);
187 }
188
189 int exynos_is_i80_frame_done(struct vidinfo *pvid)
190 {
191         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
192         unsigned int cfg = 0;
193         int status;
194
195         cfg = readl(&fimd_ctrl->trigcon);
196
197         /* frame done func is valid only when TRIMODE[0] is set to 1. */
198         status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
199                         EXYNOS_I80STATUS_TRIG_DONE;
200
201         return status;
202 }
203
204 static void exynos_fimd_lcd_on(struct vidinfo *pvid)
205 {
206         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
207         unsigned int cfg = 0;
208
209         /* display on */
210         cfg = readl(&fimd_ctrl->vidcon0);
211         cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
212         writel(cfg, &fimd_ctrl->vidcon0);
213 }
214
215 static void exynos_fimd_window_on(struct vidinfo *pvid, unsigned int win_id)
216 {
217         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
218         unsigned int cfg = 0;
219
220         /* enable window */
221         cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
222                         EXYNOS_WINCON(win_id));
223         cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
224         writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
225                         EXYNOS_WINCON(win_id));
226
227         cfg = readl(&fimd_ctrl->winshmap);
228         cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
229         writel(cfg, &fimd_ctrl->winshmap);
230 }
231
232 void exynos_fimd_lcd_off(struct vidinfo *pvid)
233 {
234         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
235         unsigned int cfg = 0;
236
237         cfg = readl(&fimd_ctrl->vidcon0);
238         cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
239         writel(cfg, &fimd_ctrl->vidcon0);
240 }
241
242 void exynos_fimd_window_off(struct vidinfo *pvid, unsigned int win_id)
243 {
244         struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl;
245         unsigned int cfg = 0;
246
247         cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
248                         EXYNOS_WINCON(win_id));
249         cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
250         writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
251                         EXYNOS_WINCON(win_id));
252
253         cfg = readl(&fimd_ctrl->winshmap);
254         cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
255         writel(cfg, &fimd_ctrl->winshmap);
256 }
257
258 /*
259 * The reset value for FIMD SYSMMU register MMU_CTRL is 3
260 * on Exynos5420 and newer versions.
261 * This means FIMD SYSMMU is on by default on Exynos5420
262 * and newer versions.
263 * Since in u-boot we don't use SYSMMU, we should disable
264 * those FIMD SYSMMU.
265 * Note that there are 2 SYSMMU for FIMD: m0 and m1.
266 * m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3.
267 * We disable both of them here.
268 */
269 void exynos_fimd_disable_sysmmu(void)
270 {
271         u32 *sysmmufimd;
272         unsigned int node;
273         int node_list[2];
274         int count;
275         int i;
276
277         count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd",
278                                 COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2);
279         for (i = 0; i < count; i++) {
280                 node = node_list[i];
281                 if (node <= 0) {
282                         debug("Can't get device node for fimd sysmmu\n");
283                         return;
284                 }
285
286                 sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg");
287                 if (!sysmmufimd) {
288                         debug("Can't get base address for sysmmu fimdm0");
289                         return;
290                 }
291
292                 writel(0x0, sysmmufimd);
293         }
294 }
295
296 void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address)
297 {
298         struct exynos_fb *fimd_ctrl;
299         unsigned int cfg = 0, rgb_mode;
300         unsigned int offset;
301         unsigned int node;
302
303         node = fdtdec_next_compatible(gd->fdt_blob,
304                                         0, COMPAT_SAMSUNG_EXYNOS_FIMD);
305         if (node <= 0)
306                 debug("exynos_fb: Can't get device node for fimd\n");
307
308         fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node,
309                                                         "reg");
310         if (fimd_ctrl == NULL)
311                 debug("Can't get the FIMD base address\n");
312         pvid->fimd_ctrl = fimd_ctrl;
313
314         if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu"))
315                 exynos_fimd_disable_sysmmu();
316
317         offset = exynos_fimd_get_base_offset();
318
319         rgb_mode = pvid->rgb_mode;
320
321         if (pvid->interface_mode == FIMD_RGB_INTERFACE) {
322                 cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
323                 writel(cfg, &fimd_ctrl->vidcon0);
324
325                 cfg = readl(&fimd_ctrl->vidcon2);
326                 cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
327                         EXYNOS_VIDCON2_TVFORMATSEL_MASK |
328                         EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
329                 cfg |= EXYNOS_VIDCON2_WB_DISABLE;
330                 writel(cfg, &fimd_ctrl->vidcon2);
331
332                 /* set polarity */
333                 cfg = 0;
334                 if (!pvid->vl_clkp)
335                         cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
336                 if (!pvid->vl_hsp)
337                         cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
338                 if (!pvid->vl_vsp)
339                         cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
340                 if (!pvid->vl_dp)
341                         cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
342
343                 writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset);
344
345                 /* set timing */
346                 cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1);
347                 cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1);
348                 cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1);
349                 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset);
350
351                 cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1);
352                 cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1);
353                 cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1);
354
355                 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset);
356
357                 /* set lcd size */
358                 cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) |
359                         EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) |
360                         EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) |
361                         EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1);
362
363                 writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset);
364         }
365
366         /* set display mode */
367         cfg = readl(&fimd_ctrl->vidcon0);
368         cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
369         cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
370         writel(cfg, &fimd_ctrl->vidcon0);
371
372         /* set par */
373         exynos_fimd_set_par(pvid, pvid->win_id);
374
375         /* set memory address */
376         exynos_fimd_set_buffer_address(pvid, pvid->win_id, lcd_base_address);
377
378         /* set buffer size */
379         cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
380                 EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
381                 EXYNOS_VIDADDR_OFFSIZE(0) |
382                 EXYNOS_VIDADDR_OFFSIZE_E(0);
383
384         writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 +
385                                         EXYNOS_BUFFER_SIZE(pvid->win_id));
386
387         /* set clock */
388         exynos_fimd_set_clock(pvid);
389
390         /* set rgb mode to dual lcd. */
391         exynos_fimd_set_dualrgb(pvid, pvid->dual_lcd_enabled);
392
393         /* display on */
394         exynos_fimd_lcd_on(pvid);
395
396         /* window on */
397         exynos_fimd_window_on(pvid, pvid->win_id);
398
399         exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled);
400 }
401
402 unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid)
403 {
404         return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8);
405 }