~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/drivers/video/exynos_fimd.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 unsigned long *lcd_base_addr;
 
25
static vidinfo_t *pvid;
 
26
static struct exynos_fb *fimd_ctrl;
 
27
 
 
28
void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size,
 
29
                u_long palette_size)
 
30
{
 
31
        lcd_base_addr = (unsigned long *)screen_base;
 
32
}
 
33
 
 
34
static void exynos_fimd_set_dualrgb(unsigned int enabled)
 
35
{
 
36
        unsigned int cfg = 0;
 
37
 
 
38
        if (enabled) {
 
39
                cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
 
40
                        EXYNOS_DUALRGB_VDEN_EN_ENABLE;
 
41
 
 
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);
 
45
        }
 
46
 
 
47
        writel(cfg, &fimd_ctrl->dualrgb);
 
48
}
 
49
 
 
50
static void exynos_fimd_set_dp_clkcon(unsigned int enabled)
 
51
{
 
52
        unsigned int cfg = 0;
 
53
 
 
54
        if (enabled)
 
55
                cfg = EXYNOS_DP_CLK_ENABLE;
 
56
 
 
57
        writel(cfg, &fimd_ctrl->dp_mie_clkcon);
 
58
}
 
59
 
 
60
static void exynos_fimd_set_par(unsigned int win_id)
 
61
{
 
62
        unsigned int cfg = 0;
 
63
 
 
64
        /* set window control */
 
65
        cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
 
66
                        EXYNOS_WINCON(win_id));
 
67
 
 
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);
 
72
 
 
73
        /* DATAPATH is DMA */
 
74
        cfg |= EXYNOS_WINCON_DATAPATH_DMA;
 
75
 
 
76
        cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
 
77
 
 
78
        /* dma burst is 16 */
 
79
        cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
 
80
 
 
81
        switch (pvid->vl_bpix) {
 
82
        case 4:
 
83
                cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
 
84
                break;
 
85
        default:
 
86
                cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
 
87
                break;
 
88
        }
 
89
 
 
90
        writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
 
91
                        EXYNOS_WINCON(win_id));
 
92
 
 
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));
 
97
 
 
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);
 
102
 
 
103
        writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b +
 
104
                        EXYNOS_VIDOSD(win_id));
 
105
 
 
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));
 
110
}
 
111
 
 
112
static void exynos_fimd_set_buffer_address(unsigned int win_id)
 
113
{
 
114
        unsigned long start_addr, end_addr;
 
115
 
 
116
        start_addr = (unsigned long)lcd_base_addr;
 
117
        end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) *
 
118
                                pvid->vl_row);
 
119
 
 
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));
 
124
}
 
125
 
 
126
static void exynos_fimd_set_clock(vidinfo_t *pvid)
 
127
{
 
128
        unsigned int cfg = 0, div = 0, remainder, remainder_div;
 
129
        unsigned long pixel_clock;
 
130
        unsigned long long src_clock;
 
131
 
 
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);
 
143
        } else {
 
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);
 
149
        }
 
150
 
 
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);
 
157
 
 
158
        src_clock = (unsigned long long) get_lcd_clk();
 
159
 
 
160
        /* get quotient and remainder. */
 
161
        remainder = do_div(src_clock, pixel_clock);
 
162
        div = src_clock;
 
163
 
 
164
        remainder *= 10;
 
165
        remainder_div = remainder / pixel_clock;
 
166
 
 
167
        /* round about one places of decimals. */
 
168
        if (remainder_div >= 5)
 
169
                div++;
 
170
 
 
171
        /* in case of dual lcd mode. */
 
172
        if (pvid->dual_lcd_enabled)
 
173
                div--;
 
174
 
 
175
        cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
 
176
        writel(cfg, &fimd_ctrl->vidcon0);
 
177
}
 
178
 
 
179
void exynos_set_trigger(void)
 
180
{
 
181
        unsigned int cfg = 0;
 
182
 
 
183
        cfg = readl(&fimd_ctrl->trigcon);
 
184
 
 
185
        cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
 
186
 
 
187
        writel(cfg, &fimd_ctrl->trigcon);
 
188
}
 
189
 
 
190
int exynos_is_i80_frame_done(void)
 
191
{
 
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(void)
 
205
{
 
206
        unsigned int cfg = 0;
 
207
 
 
208
        /* display on */
 
209
        cfg = readl(&fimd_ctrl->vidcon0);
 
210
        cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
 
211
        writel(cfg, &fimd_ctrl->vidcon0);
 
212
}
 
213
 
 
214
static void exynos_fimd_window_on(unsigned int win_id)
 
215
{
 
216
        unsigned int cfg = 0;
 
217
 
 
218
        /* enable window */
 
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));
 
224
 
 
225
        cfg = readl(&fimd_ctrl->winshmap);
 
226
        cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
 
227
        writel(cfg, &fimd_ctrl->winshmap);
 
228
}
 
229
 
 
230
void exynos_fimd_lcd_off(void)
 
231
{
 
232
        unsigned int cfg = 0;
 
233
 
 
234
        cfg = readl(&fimd_ctrl->vidcon0);
 
235
        cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
 
236
        writel(cfg, &fimd_ctrl->vidcon0);
 
237
}
 
238
 
 
239
void exynos_fimd_window_off(unsigned int win_id)
 
240
{
 
241
        unsigned int cfg = 0;
 
242
 
 
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));
 
248
 
 
249
        cfg = readl(&fimd_ctrl->winshmap);
 
250
        cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
 
251
        writel(cfg, &fimd_ctrl->winshmap);
 
252
}
 
253
 
 
254
 
 
255
void exynos_fimd_lcd_init(vidinfo_t *vid)
 
256
{
 
257
        unsigned int cfg = 0, rgb_mode;
 
258
        unsigned int offset;
 
259
#ifdef CONFIG_OF_CONTROL
 
260
        unsigned int node;
 
261
 
 
262
        node = fdtdec_next_compatible(gd->fdt_blob,
 
263
                                        0, COMPAT_SAMSUNG_EXYNOS_FIMD);
 
264
        if (node <= 0)
 
265
                debug("exynos_fb: Can't get device node for fimd\n");
 
266
 
 
267
        fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob,
 
268
                                                                node, "reg");
 
269
        if (fimd_ctrl == NULL)
 
270
                debug("Can't get the FIMD base address\n");
 
271
#else
 
272
        fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd();
 
273
#endif
 
274
 
 
275
        offset = exynos_fimd_get_base_offset();
 
276
 
 
277
        /* store panel info to global variable */
 
278
        pvid = vid;
 
279
 
 
280
        rgb_mode = vid->rgb_mode;
 
281
 
 
282
        if (vid->interface_mode == FIMD_RGB_INTERFACE) {
 
283
                cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
 
284
                writel(cfg, &fimd_ctrl->vidcon0);
 
285
 
 
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);
 
292
 
 
293
                /* set polarity */
 
294
                cfg = 0;
 
295
                if (!pvid->vl_clkp)
 
296
                        cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
 
297
                if (!pvid->vl_hsp)
 
298
                        cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
 
299
                if (!pvid->vl_vsp)
 
300
                        cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
 
301
                if (!pvid->vl_dp)
 
302
                        cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
 
303
 
 
304
                writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset);
 
305
 
 
306
                /* set timing */
 
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);
 
311
 
 
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);
 
315
 
 
316
                writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset);
 
317
 
 
318
                /* set lcd size */
 
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);
 
323
 
 
324
                writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset);
 
325
        }
 
326
 
 
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);
 
332
 
 
333
        /* set par */
 
334
        exynos_fimd_set_par(pvid->win_id);
 
335
 
 
336
        /* set memory address */
 
337
        exynos_fimd_set_buffer_address(pvid->win_id);
 
338
 
 
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);
 
344
 
 
345
        writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 +
 
346
                                        EXYNOS_BUFFER_SIZE(pvid->win_id));
 
347
 
 
348
        /* set clock */
 
349
        exynos_fimd_set_clock(pvid);
 
350
 
 
351
        /* set rgb mode to dual lcd. */
 
352
        exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled);
 
353
 
 
354
        /* display on */
 
355
        exynos_fimd_lcd_on();
 
356
 
 
357
        /* window on */
 
358
        exynos_fimd_window_on(pvid->win_id);
 
359
 
 
360
        exynos_fimd_set_dp_clkcon(pvid->dp_enabled);
 
361
}
 
362
 
 
363
unsigned long exynos_fimd_calc_fbsize(void)
 
364
{
 
365
        return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8);
 
366
}