2
* Copyright (C) 2012 Samsung Electronics
4
* Author: InKi Dae <inki.dae@samsung.com>
5
* Author: Donghwa Lee <dh09.lee@samsung.com>
7
* SPDX-License-Identifier: GPL-2.0+
17
#include <asm/arch/clk.h>
18
#include <asm/arch/clock.h>
19
#include <asm/arch/cpu.h>
20
#include "exynos_fb.h"
22
DECLARE_GLOBAL_DATA_PTR;
24
static unsigned long *lcd_base_addr;
25
static vidinfo_t *pvid;
26
static struct exynos_fb *fimd_ctrl;
28
void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size,
31
lcd_base_addr = (unsigned long *)screen_base;
34
static void exynos_fimd_set_dualrgb(unsigned int enabled)
39
cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
40
EXYNOS_DUALRGB_VDEN_EN_ENABLE;
42
/* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
43
cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) |
44
EXYNOS_DUALRGB_MAIN_CNT(0);
47
writel(cfg, &fimd_ctrl->dualrgb);
50
static void exynos_fimd_set_dp_clkcon(unsigned int enabled)
55
cfg = EXYNOS_DP_CLK_ENABLE;
57
writel(cfg, &fimd_ctrl->dp_mie_clkcon);
60
static void exynos_fimd_set_par(unsigned int win_id)
64
/* set window control */
65
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
66
EXYNOS_WINCON(win_id));
68
cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
69
EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
70
EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
71
EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
74
cfg |= EXYNOS_WINCON_DATAPATH_DMA;
76
cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
79
cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
81
switch (pvid->vl_bpix) {
83
cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
86
cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
90
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
91
EXYNOS_WINCON(win_id));
93
/* set window position to x=0, y=0*/
94
cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
95
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a +
96
EXYNOS_VIDOSD(win_id));
98
cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) |
99
EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) |
100
EXYNOS_VIDOSD_RIGHT_X_E(1) |
101
EXYNOS_VIDOSD_BOTTOM_Y_E(0);
103
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b +
104
EXYNOS_VIDOSD(win_id));
106
/* set window size for window0*/
107
cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row);
108
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c +
109
EXYNOS_VIDOSD(win_id));
112
static void exynos_fimd_set_buffer_address(unsigned int win_id)
114
unsigned long start_addr, end_addr;
116
start_addr = (unsigned long)lcd_base_addr;
117
end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) *
120
writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 +
121
EXYNOS_BUFFER_OFFSET(win_id));
122
writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 +
123
EXYNOS_BUFFER_OFFSET(win_id));
126
static void exynos_fimd_set_clock(vidinfo_t *pvid)
128
unsigned int cfg = 0, div = 0, remainder, remainder_div;
129
unsigned long pixel_clock;
130
unsigned long long src_clock;
132
if (pvid->dual_lcd_enabled) {
133
pixel_clock = pvid->vl_freq *
134
(pvid->vl_hspw + pvid->vl_hfpd +
135
pvid->vl_hbpd + pvid->vl_col / 2) *
136
(pvid->vl_vspw + pvid->vl_vfpd +
137
pvid->vl_vbpd + pvid->vl_row);
138
} else if (pvid->interface_mode == FIMD_CPU_INTERFACE) {
139
pixel_clock = pvid->vl_freq *
140
pvid->vl_width * pvid->vl_height *
141
(pvid->cs_setup + pvid->wr_setup +
142
pvid->wr_act + pvid->wr_hold + 1);
144
pixel_clock = pvid->vl_freq *
145
(pvid->vl_hspw + pvid->vl_hfpd +
146
pvid->vl_hbpd + pvid->vl_col) *
147
(pvid->vl_vspw + pvid->vl_vfpd +
148
pvid->vl_vbpd + pvid->vl_row);
151
cfg = readl(&fimd_ctrl->vidcon0);
152
cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
153
EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
154
EXYNOS_VIDCON0_CLKDIR_MASK);
155
cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
156
EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
158
src_clock = (unsigned long long) get_lcd_clk();
160
/* get quotient and remainder. */
161
remainder = do_div(src_clock, pixel_clock);
165
remainder_div = remainder / pixel_clock;
167
/* round about one places of decimals. */
168
if (remainder_div >= 5)
171
/* in case of dual lcd mode. */
172
if (pvid->dual_lcd_enabled)
175
cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
176
writel(cfg, &fimd_ctrl->vidcon0);
179
void exynos_set_trigger(void)
181
unsigned int cfg = 0;
183
cfg = readl(&fimd_ctrl->trigcon);
185
cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
187
writel(cfg, &fimd_ctrl->trigcon);
190
int exynos_is_i80_frame_done(void)
192
unsigned int cfg = 0;
195
cfg = readl(&fimd_ctrl->trigcon);
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;
204
static void exynos_fimd_lcd_on(void)
206
unsigned int cfg = 0;
209
cfg = readl(&fimd_ctrl->vidcon0);
210
cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
211
writel(cfg, &fimd_ctrl->vidcon0);
214
static void exynos_fimd_window_on(unsigned int win_id)
216
unsigned int cfg = 0;
219
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
220
EXYNOS_WINCON(win_id));
221
cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
222
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
223
EXYNOS_WINCON(win_id));
225
cfg = readl(&fimd_ctrl->winshmap);
226
cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
227
writel(cfg, &fimd_ctrl->winshmap);
230
void exynos_fimd_lcd_off(void)
232
unsigned int cfg = 0;
234
cfg = readl(&fimd_ctrl->vidcon0);
235
cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
236
writel(cfg, &fimd_ctrl->vidcon0);
239
void exynos_fimd_window_off(unsigned int win_id)
241
unsigned int cfg = 0;
243
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
244
EXYNOS_WINCON(win_id));
245
cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
246
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
247
EXYNOS_WINCON(win_id));
249
cfg = readl(&fimd_ctrl->winshmap);
250
cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
251
writel(cfg, &fimd_ctrl->winshmap);
255
void exynos_fimd_lcd_init(vidinfo_t *vid)
257
unsigned int cfg = 0, rgb_mode;
259
#ifdef CONFIG_OF_CONTROL
262
node = fdtdec_next_compatible(gd->fdt_blob,
263
0, COMPAT_SAMSUNG_EXYNOS_FIMD);
265
debug("exynos_fb: Can't get device node for fimd\n");
267
fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob,
269
if (fimd_ctrl == NULL)
270
debug("Can't get the FIMD base address\n");
272
fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd();
275
offset = exynos_fimd_get_base_offset();
277
/* store panel info to global variable */
280
rgb_mode = vid->rgb_mode;
282
if (vid->interface_mode == FIMD_RGB_INTERFACE) {
283
cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
284
writel(cfg, &fimd_ctrl->vidcon0);
286
cfg = readl(&fimd_ctrl->vidcon2);
287
cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
288
EXYNOS_VIDCON2_TVFORMATSEL_MASK |
289
EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
290
cfg |= EXYNOS_VIDCON2_WB_DISABLE;
291
writel(cfg, &fimd_ctrl->vidcon2);
296
cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
298
cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
300
cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
302
cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
304
writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset);
307
cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1);
308
cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1);
309
cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1);
310
writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset);
312
cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1);
313
cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1);
314
cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1);
316
writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset);
319
cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) |
320
EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) |
321
EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) |
322
EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1);
324
writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset);
327
/* set display mode */
328
cfg = readl(&fimd_ctrl->vidcon0);
329
cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
330
cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
331
writel(cfg, &fimd_ctrl->vidcon0);
334
exynos_fimd_set_par(pvid->win_id);
336
/* set memory address */
337
exynos_fimd_set_buffer_address(pvid->win_id);
339
/* set buffer size */
340
cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
341
EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) |
342
EXYNOS_VIDADDR_OFFSIZE(0) |
343
EXYNOS_VIDADDR_OFFSIZE_E(0);
345
writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 +
346
EXYNOS_BUFFER_SIZE(pvid->win_id));
349
exynos_fimd_set_clock(pvid);
351
/* set rgb mode to dual lcd. */
352
exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled);
355
exynos_fimd_lcd_on();
358
exynos_fimd_window_on(pvid->win_id);
360
exynos_fimd_set_dp_clkcon(pvid->dp_enabled);
363
unsigned long exynos_fimd_calc_fbsize(void)
365
return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8);