blob: 29ecac40a29e5c5c28d5403bcbdd427542e49609 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefano Babic42f151a2010-10-13 12:17:14 +02002/*
3 * Porting to u-boot:
4 *
5 * (C) Copyright 2010
6 * Stefano Babic, DENX Software Engineering, sbabic@denx.de
7 *
8 * MX51 Linux framebuffer:
9 *
10 * (C) Copyright 2004-2010 Freescale Semiconductor, Inc.
Stefano Babic42f151a2010-10-13 12:17:14 +020011 */
12
Stefano Babic42f151a2010-10-13 12:17:14 +020013#include <common.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090014#include <linux/errno.h>
Eric Nelsonc9e2be62014-04-29 14:37:56 -070015#include <asm/global_data.h>
Stefano Babic42f151a2010-10-13 12:17:14 +020016#include <linux/string.h>
17#include <linux/list.h>
18#include <linux/fb.h>
19#include <asm/io.h>
Anatolij Gustschin983e2f22019-03-18 23:29:31 +010020#include <asm/mach-imx/video.h>
Stefano Babic42f151a2010-10-13 12:17:14 +020021#include <malloc.h>
Stefano Babic61852442011-09-28 11:21:15 +020022#include <video_fb.h>
Anatolij Gustschin411e73d2019-03-18 23:29:32 +010023#include "../videomodes.h"
Stefano Babic42f151a2010-10-13 12:17:14 +020024#include "ipu.h"
25#include "mxcfb.h"
Eric Nelson988ad422012-09-23 07:30:54 +000026#include "ipu_regs.h"
Stefano Babic42f151a2010-10-13 12:17:14 +020027
Anatolij Gustschin983e2f22019-03-18 23:29:31 +010028#include <dm.h>
29#include <video.h>
30
Eric Nelsonc9e2be62014-04-29 14:37:56 -070031DECLARE_GLOBAL_DATA_PTR;
32
Stefano Babic42f151a2010-10-13 12:17:14 +020033static int mxcfb_map_video_memory(struct fb_info *fbi);
34static int mxcfb_unmap_video_memory(struct fb_info *fbi);
35
Stefano Babic61852442011-09-28 11:21:15 +020036/* graphics setup */
37static GraphicDevice panel;
Eric Nelson10a6cd12012-10-03 07:27:38 +000038static struct fb_videomode const *gmode;
Marek Vasutff5c108c2011-10-06 00:25:03 +020039static uint8_t gdisp;
40static uint32_t gpixfmt;
Stefano Babic42f151a2010-10-13 12:17:14 +020041
Jeroen Hofsteea175d302014-10-08 22:57:47 +020042static void fb_videomode_to_var(struct fb_var_screeninfo *var,
Stefano Babic42f151a2010-10-13 12:17:14 +020043 const struct fb_videomode *mode)
44{
45 var->xres = mode->xres;
46 var->yres = mode->yres;
47 var->xres_virtual = mode->xres;
48 var->yres_virtual = mode->yres;
49 var->xoffset = 0;
50 var->yoffset = 0;
51 var->pixclock = mode->pixclock;
52 var->left_margin = mode->left_margin;
53 var->right_margin = mode->right_margin;
54 var->upper_margin = mode->upper_margin;
55 var->lower_margin = mode->lower_margin;
56 var->hsync_len = mode->hsync_len;
57 var->vsync_len = mode->vsync_len;
58 var->sync = mode->sync;
59 var->vmode = mode->vmode & FB_VMODE_MASK;
60}
61
62/*
63 * Structure containing the MXC specific framebuffer information.
64 */
65struct mxcfb_info {
66 int blank;
67 ipu_channel_t ipu_ch;
68 int ipu_di;
69 u32 ipu_di_pix_fmt;
70 unsigned char overlay;
71 unsigned char alpha_chan_en;
72 dma_addr_t alpha_phy_addr0;
73 dma_addr_t alpha_phy_addr1;
74 void *alpha_virt_addr0;
75 void *alpha_virt_addr1;
76 uint32_t alpha_mem_len;
77 uint32_t cur_ipu_buf;
78 uint32_t cur_ipu_alpha_buf;
79
80 u32 pseudo_palette[16];
81};
82
83enum {
84 BOTH_ON,
85 SRC_ON,
86 TGT_ON,
87 BOTH_OFF
88};
89
90static unsigned long default_bpp = 16;
91static unsigned char g_dp_in_use;
92static struct fb_info *mxcfb_info[3];
93static int ext_clk_used;
94
95static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
96{
97 uint32_t pixfmt = 0;
98
99 debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
100
101 if (fbi->var.nonstd)
102 return fbi->var.nonstd;
103
104 switch (fbi->var.bits_per_pixel) {
105 case 24:
106 pixfmt = IPU_PIX_FMT_BGR24;
107 break;
108 case 32:
109 pixfmt = IPU_PIX_FMT_BGR32;
110 break;
111 case 16:
112 pixfmt = IPU_PIX_FMT_RGB565;
113 break;
114 }
115 return pixfmt;
116}
117
118/*
119 * Set fixed framebuffer parameters based on variable settings.
120 *
121 * @param info framebuffer information pointer
122 */
123static int mxcfb_set_fix(struct fb_info *info)
124{
125 struct fb_fix_screeninfo *fix = &info->fix;
126 struct fb_var_screeninfo *var = &info->var;
127
128 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
129
130 fix->type = FB_TYPE_PACKED_PIXELS;
131 fix->accel = FB_ACCEL_NONE;
132 fix->visual = FB_VISUAL_TRUECOLOR;
133 fix->xpanstep = 1;
134 fix->ypanstep = 1;
135
136 return 0;
137}
138
139static int setup_disp_channel1(struct fb_info *fbi)
140{
141 ipu_channel_params_t params;
142 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
143
144 memset(&params, 0, sizeof(params));
145 params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
146
147 debug("%s called\n", __func__);
148 /*
149 * Assuming interlaced means yuv output, below setting also
150 * valid for mem_dc_sync. FG should have the same vmode as BG.
151 */
152 if (fbi->var.vmode & FB_VMODE_INTERLACED) {
153 params.mem_dp_bg_sync.interlaced = 1;
154 params.mem_dp_bg_sync.out_pixel_fmt =
155 IPU_PIX_FMT_YUV444;
156 } else {
157 if (mxc_fbi->ipu_di_pix_fmt) {
158 params.mem_dp_bg_sync.out_pixel_fmt =
159 mxc_fbi->ipu_di_pix_fmt;
160 } else {
161 params.mem_dp_bg_sync.out_pixel_fmt =
162 IPU_PIX_FMT_RGB666;
163 }
164 }
165 params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
166 if (mxc_fbi->alpha_chan_en)
167 params.mem_dp_bg_sync.alpha_chan_en = 1;
168
169 ipu_init_channel(mxc_fbi->ipu_ch, &params);
170
171 return 0;
172}
173
174static int setup_disp_channel2(struct fb_info *fbi)
175{
176 int retval = 0;
177 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
178
179 mxc_fbi->cur_ipu_buf = 1;
180 if (mxc_fbi->alpha_chan_en)
181 mxc_fbi->cur_ipu_alpha_buf = 1;
182
183 fbi->var.xoffset = fbi->var.yoffset = 0;
184
185 debug("%s: %x %d %d %d %lx %lx\n",
186 __func__,
187 mxc_fbi->ipu_ch,
188 fbi->var.xres,
189 fbi->var.yres,
190 fbi->fix.line_length,
191 fbi->fix.smem_start,
192 fbi->fix.smem_start +
193 (fbi->fix.line_length * fbi->var.yres));
194
195 retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
196 bpp_to_pixfmt(fbi),
197 fbi->var.xres, fbi->var.yres,
198 fbi->fix.line_length,
199 fbi->fix.smem_start +
200 (fbi->fix.line_length * fbi->var.yres),
201 fbi->fix.smem_start,
202 0, 0);
203 if (retval)
204 printf("ipu_init_channel_buffer error %d\n", retval);
205
206 return retval;
207}
208
209/*
210 * Set framebuffer parameters and change the operating mode.
211 *
212 * @param info framebuffer information pointer
213 */
214static int mxcfb_set_par(struct fb_info *fbi)
215{
216 int retval = 0;
217 u32 mem_len;
218 ipu_di_signal_cfg_t sig_cfg;
219 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
220 uint32_t out_pixel_fmt;
221
222 ipu_disable_channel(mxc_fbi->ipu_ch);
223 ipu_uninit_channel(mxc_fbi->ipu_ch);
224 mxcfb_set_fix(fbi);
225
226 mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
227 if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
228 if (fbi->fix.smem_start)
229 mxcfb_unmap_video_memory(fbi);
230
231 if (mxcfb_map_video_memory(fbi) < 0)
232 return -ENOMEM;
233 }
234
235 setup_disp_channel1(fbi);
236
237 memset(&sig_cfg, 0, sizeof(sig_cfg));
238 if (fbi->var.vmode & FB_VMODE_INTERLACED) {
239 sig_cfg.interlaced = 1;
240 out_pixel_fmt = IPU_PIX_FMT_YUV444;
241 } else {
242 if (mxc_fbi->ipu_di_pix_fmt)
243 out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
244 else
245 out_pixel_fmt = IPU_PIX_FMT_RGB666;
246 }
247 if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
248 sig_cfg.odd_field_first = 1;
249 if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
250 sig_cfg.ext_clk = 1;
251 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
252 sig_cfg.Hsync_pol = 1;
253 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
254 sig_cfg.Vsync_pol = 1;
255 if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
256 sig_cfg.clk_pol = 1;
257 if (fbi->var.sync & FB_SYNC_DATA_INVERT)
258 sig_cfg.data_pol = 1;
259 if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
260 sig_cfg.enable_pol = 1;
261 if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
262 sig_cfg.clkidle_en = 1;
263
Jeroen Hofstee98276212014-10-14 20:37:14 +0200264 debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL);
Stefano Babic42f151a2010-10-13 12:17:14 +0200265
266 if (ipu_init_sync_panel(mxc_fbi->ipu_di,
267 (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
268 fbi->var.xres, fbi->var.yres,
269 out_pixel_fmt,
270 fbi->var.left_margin,
271 fbi->var.hsync_len,
272 fbi->var.right_margin,
273 fbi->var.upper_margin,
274 fbi->var.vsync_len,
275 fbi->var.lower_margin,
276 0, sig_cfg) != 0) {
277 puts("mxcfb: Error initializing panel.\n");
278 return -EINVAL;
279 }
280
281 retval = setup_disp_channel2(fbi);
282 if (retval)
283 return retval;
284
285 if (mxc_fbi->blank == FB_BLANK_UNBLANK)
286 ipu_enable_channel(mxc_fbi->ipu_ch);
287
288 return retval;
289}
290
291/*
292 * Check framebuffer variable parameters and adjust to valid values.
293 *
294 * @param var framebuffer variable parameters
295 *
296 * @param info framebuffer information pointer
297 */
298static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
299{
300 u32 vtotal;
301 u32 htotal;
302
303 if (var->xres_virtual < var->xres)
304 var->xres_virtual = var->xres;
305 if (var->yres_virtual < var->yres)
306 var->yres_virtual = var->yres;
307
308 if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
309 (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
310 var->bits_per_pixel = default_bpp;
311
312 switch (var->bits_per_pixel) {
313 case 8:
314 var->red.length = 3;
315 var->red.offset = 5;
316 var->red.msb_right = 0;
317
318 var->green.length = 3;
319 var->green.offset = 2;
320 var->green.msb_right = 0;
321
322 var->blue.length = 2;
323 var->blue.offset = 0;
324 var->blue.msb_right = 0;
325
326 var->transp.length = 0;
327 var->transp.offset = 0;
328 var->transp.msb_right = 0;
329 break;
330 case 16:
331 var->red.length = 5;
332 var->red.offset = 11;
333 var->red.msb_right = 0;
334
335 var->green.length = 6;
336 var->green.offset = 5;
337 var->green.msb_right = 0;
338
339 var->blue.length = 5;
340 var->blue.offset = 0;
341 var->blue.msb_right = 0;
342
343 var->transp.length = 0;
344 var->transp.offset = 0;
345 var->transp.msb_right = 0;
346 break;
347 case 24:
348 var->red.length = 8;
349 var->red.offset = 16;
350 var->red.msb_right = 0;
351
352 var->green.length = 8;
353 var->green.offset = 8;
354 var->green.msb_right = 0;
355
356 var->blue.length = 8;
357 var->blue.offset = 0;
358 var->blue.msb_right = 0;
359
360 var->transp.length = 0;
361 var->transp.offset = 0;
362 var->transp.msb_right = 0;
363 break;
364 case 32:
365 var->red.length = 8;
366 var->red.offset = 16;
367 var->red.msb_right = 0;
368
369 var->green.length = 8;
370 var->green.offset = 8;
371 var->green.msb_right = 0;
372
373 var->blue.length = 8;
374 var->blue.offset = 0;
375 var->blue.msb_right = 0;
376
377 var->transp.length = 8;
378 var->transp.offset = 24;
379 var->transp.msb_right = 0;
380 break;
381 }
382
383 if (var->pixclock < 1000) {
384 htotal = var->xres + var->right_margin + var->hsync_len +
385 var->left_margin;
386 vtotal = var->yres + var->lower_margin + var->vsync_len +
387 var->upper_margin;
388 var->pixclock = (vtotal * htotal * 6UL) / 100UL;
389 var->pixclock = KHZ2PICOS(var->pixclock);
390 printf("pixclock set for 60Hz refresh = %u ps\n",
391 var->pixclock);
392 }
393
394 var->height = -1;
395 var->width = -1;
396 var->grayscale = 0;
397
398 return 0;
399}
400
401static int mxcfb_map_video_memory(struct fb_info *fbi)
402{
403 if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
404 fbi->fix.smem_len = fbi->var.yres_virtual *
405 fbi->fix.line_length;
406 }
Eric Nelsonfe6296f2013-07-26 17:53:45 -0700407 fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN);
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100408
409#if CONFIG_IS_ENABLED(DM_VIDEO)
410 fbi->screen_base = (char *)gd->video_bottom;
411#else
Eric Nelsonfe6296f2013-07-26 17:53:45 -0700412 fbi->screen_base = (char *)memalign(ARCH_DMA_MINALIGN,
413 fbi->fix.smem_len);
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100414#endif
415
Stefano Babic61852442011-09-28 11:21:15 +0200416 fbi->fix.smem_start = (unsigned long)fbi->screen_base;
Stefano Babic42f151a2010-10-13 12:17:14 +0200417 if (fbi->screen_base == 0) {
418 puts("Unable to allocate framebuffer memory\n");
419 fbi->fix.smem_len = 0;
420 fbi->fix.smem_start = 0;
421 return -EBUSY;
422 }
423
424 debug("allocated fb @ paddr=0x%08X, size=%d.\n",
425 (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
426
427 fbi->screen_size = fbi->fix.smem_len;
428
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100429#if CONFIG_IS_ENABLED(VIDEO)
Eric Nelsonc9e2be62014-04-29 14:37:56 -0700430 gd->fb_base = fbi->fix.smem_start;
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100431#endif
Eric Nelsonc9e2be62014-04-29 14:37:56 -0700432
Stefano Babic42f151a2010-10-13 12:17:14 +0200433 /* Clear the screen */
434 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
435
436 return 0;
437}
438
439static int mxcfb_unmap_video_memory(struct fb_info *fbi)
440{
441 fbi->screen_base = 0;
442 fbi->fix.smem_start = 0;
443 fbi->fix.smem_len = 0;
444 return 0;
445}
446
447/*
448 * Initializes the framebuffer information pointer. After allocating
449 * sufficient memory for the framebuffer structure, the fields are
450 * filled with custom information passed in from the configurable
451 * structures. This includes information such as bits per pixel,
452 * color maps, screen width/height and RGBA offsets.
453 *
454 * @return Framebuffer structure initialized with our information
455 */
456static struct fb_info *mxcfb_init_fbinfo(void)
457{
458#define BYTES_PER_LONG 4
459#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
460 struct fb_info *fbi;
461 struct mxcfb_info *mxcfbi;
462 char *p;
463 int size = sizeof(struct mxcfb_info) + PADDING +
464 sizeof(struct fb_info);
465
466 debug("%s: %d %d %d %d\n",
467 __func__,
468 PADDING,
469 size,
470 sizeof(struct mxcfb_info),
471 sizeof(struct fb_info));
472 /*
473 * Allocate sufficient memory for the fb structure
474 */
475
476 p = malloc(size);
477 if (!p)
478 return NULL;
479
480 memset(p, 0, size);
481
482 fbi = (struct fb_info *)p;
483 fbi->par = p + sizeof(struct fb_info) + PADDING;
484
485 mxcfbi = (struct mxcfb_info *)fbi->par;
486 debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
487 (unsigned int)fbi, (unsigned int)mxcfbi);
488
489 fbi->var.activate = FB_ACTIVATE_NOW;
490
491 fbi->flags = FBINFO_FLAG_DEFAULT;
492 fbi->pseudo_palette = mxcfbi->pseudo_palette;
493
494 return fbi;
495}
496
497/*
498 * Probe routine for the framebuffer driver. It is called during the
Jeroen Hofstee98276212014-10-14 20:37:14 +0200499 * driver binding process. The following functions are performed in
Stefano Babic42f151a2010-10-13 12:17:14 +0200500 * this routine: Framebuffer initialization, Memory allocation and
501 * mapping, Framebuffer registration, IPU initialization.
502 *
503 * @return Appropriate error code to the kernel common code
504 */
Marek Vasutff5c108c2011-10-06 00:25:03 +0200505static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp,
Eric Nelson10a6cd12012-10-03 07:27:38 +0000506 struct fb_videomode const *mode)
Stefano Babic42f151a2010-10-13 12:17:14 +0200507{
508 struct fb_info *fbi;
509 struct mxcfb_info *mxcfbi;
510 int ret = 0;
511
512 /*
513 * Initialize FB structures
514 */
515 fbi = mxcfb_init_fbinfo();
516 if (!fbi) {
517 ret = -ENOMEM;
518 goto err0;
519 }
520 mxcfbi = (struct mxcfb_info *)fbi->par;
521
522 if (!g_dp_in_use) {
523 mxcfbi->ipu_ch = MEM_BG_SYNC;
524 mxcfbi->blank = FB_BLANK_UNBLANK;
525 } else {
526 mxcfbi->ipu_ch = MEM_DC_SYNC;
527 mxcfbi->blank = FB_BLANK_POWERDOWN;
528 }
529
Marek Vasutff5c108c2011-10-06 00:25:03 +0200530 mxcfbi->ipu_di = disp;
Stefano Babic42f151a2010-10-13 12:17:14 +0200531
532 ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
533 ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
534 strcpy(fbi->fix.id, "DISP3 BG");
535
536 g_dp_in_use = 1;
537
538 mxcfb_info[mxcfbi->ipu_di] = fbi;
539
540 /* Need dummy values until real panel is configured */
Stefano Babic42f151a2010-10-13 12:17:14 +0200541
542 mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
543 fb_videomode_to_var(&fbi->var, mode);
Stefano Babic61852442011-09-28 11:21:15 +0200544 fbi->var.bits_per_pixel = 16;
545 fbi->fix.line_length = fbi->var.xres * (fbi->var.bits_per_pixel / 8);
546 fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
Stefano Babic42f151a2010-10-13 12:17:14 +0200547
548 mxcfb_check_var(&fbi->var, fbi);
549
550 /* Default Y virtual size is 2x panel size */
551 fbi->var.yres_virtual = fbi->var.yres * 2;
552
553 mxcfb_set_fix(fbi);
554
Jeroen Hofstee98276212014-10-14 20:37:14 +0200555 /* allocate fb first */
Stefano Babic42f151a2010-10-13 12:17:14 +0200556 if (mxcfb_map_video_memory(fbi) < 0)
557 return -ENOMEM;
558
559 mxcfb_set_par(fbi);
560
Stefano Babic61852442011-09-28 11:21:15 +0200561 panel.winSizeX = mode->xres;
562 panel.winSizeY = mode->yres;
563 panel.plnSizeX = mode->xres;
564 panel.plnSizeY = mode->yres;
Stefano Babic42f151a2010-10-13 12:17:14 +0200565
Stefano Babic61852442011-09-28 11:21:15 +0200566 panel.frameAdrs = (u32)fbi->screen_base;
567 panel.memSize = fbi->screen_size;
Stefano Babic42f151a2010-10-13 12:17:14 +0200568
Stefano Babic61852442011-09-28 11:21:15 +0200569 panel.gdfBytesPP = 2;
570 panel.gdfIndex = GDF_16BIT_565RGB;
Stefano Babic42f151a2010-10-13 12:17:14 +0200571
572 ipu_dump_registers();
573
574 return 0;
575
576err0:
577 return ret;
578}
579
Eric Nelson988ad422012-09-23 07:30:54 +0000580void ipuv3_fb_shutdown(void)
581{
Anatolij Gustschinfa4211c2017-08-25 15:10:43 +0200582 int i;
Tom Rini47dce762017-09-01 16:17:17 -0400583 struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;
Eric Nelson988ad422012-09-23 07:30:54 +0000584
Anatolij Gustschin3e7ad7d2017-09-04 23:33:45 +0200585 if (!ipu_clk_enabled())
586 return;
587
Eric Nelson988ad422012-09-23 07:30:54 +0000588 for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) {
589 struct fb_info *fbi = mxcfb_info[i];
590 if (fbi) {
591 struct mxcfb_info *mxc_fbi = fbi->par;
592 ipu_disable_channel(mxc_fbi->ipu_ch);
593 ipu_uninit_channel(mxc_fbi->ipu_ch);
594 }
595 }
596 for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) {
597 __raw_writel(__raw_readl(&stat->int_stat[i]),
598 &stat->int_stat[i]);
599 }
600}
601
Stefano Babic61852442011-09-28 11:21:15 +0200602void *video_hw_init(void)
Stefano Babic42f151a2010-10-13 12:17:14 +0200603{
604 int ret;
605
606 ret = ipu_probe();
607 if (ret)
608 puts("Error initializing IPU\n");
609
Marek Vasutff5c108c2011-10-06 00:25:03 +0200610 ret = mxcfb_probe(gpixfmt, gdisp, gmode);
Stefano Babic61852442011-09-28 11:21:15 +0200611 debug("Framebuffer at 0x%x\n", (unsigned int)panel.frameAdrs);
Stefano Babic42f151a2010-10-13 12:17:14 +0200612
Stefano Babic61852442011-09-28 11:21:15 +0200613 return (void *)&panel;
614}
Stefano Babic42f151a2010-10-13 12:17:14 +0200615
Eric Nelson10a6cd12012-10-03 07:27:38 +0000616int ipuv3_fb_init(struct fb_videomode const *mode,
617 uint8_t disp,
618 uint32_t pixfmt)
Stefano Babic61852442011-09-28 11:21:15 +0200619{
620 gmode = mode;
Marek Vasutff5c108c2011-10-06 00:25:03 +0200621 gdisp = disp;
622 gpixfmt = pixfmt;
Stefano Babic61852442011-09-28 11:21:15 +0200623
624 return 0;
Stefano Babic42f151a2010-10-13 12:17:14 +0200625}
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100626
627#if CONFIG_IS_ENABLED(DM_VIDEO)
628enum {
629 /* Maximum display size we support */
630 LCD_MAX_WIDTH = 1920,
631 LCD_MAX_HEIGHT = 1080,
632 LCD_MAX_LOG2_BPP = VIDEO_BPP16,
633};
634
635static int ipuv3_video_probe(struct udevice *dev)
636{
637 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
638 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
639 u32 fb_start, fb_end;
640 int ret;
641
642 debug("%s() plat: base 0x%lx, size 0x%x\n",
643 __func__, plat->base, plat->size);
644
645 ret = ipu_probe();
646 if (ret)
647 return ret;
648
649 ret = ipu_displays_init();
650 if (ret < 0)
651 return ret;
652
653 ret = mxcfb_probe(gpixfmt, gdisp, gmode);
654 if (ret < 0)
655 return ret;
656
657 uc_priv->xsize = gmode->xres;
658 uc_priv->ysize = gmode->yres;
659 uc_priv->bpix = LCD_MAX_LOG2_BPP;
660
661 /* Enable dcache for the frame buffer */
662 fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
663 fb_end = plat->base + plat->size;
664 fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
665 mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
666 DCACHE_WRITEBACK);
667 video_set_flush_dcache(dev, true);
668
669 return 0;
670}
671
672struct ipuv3_video_priv {
673 ulong regs;
674};
675
676static int ipuv3_video_bind(struct udevice *dev)
677{
678 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
679
680 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
Marek Vasut28bdd932019-05-06 01:11:32 +0200681 (1 << VIDEO_BPP32) / 8;
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100682
683 return 0;
684}
685
686static const struct udevice_id ipuv3_video_ids[] = {
687 { .compatible = "fsl,imx6q-ipu" },
Steffen Dirkwinkel4e40f1a2019-04-17 13:57:15 +0200688 { .compatible = "fsl,imx53-ipu" },
Anatolij Gustschin983e2f22019-03-18 23:29:31 +0100689 { }
690};
691
692U_BOOT_DRIVER(ipuv3_video) = {
693 .name = "ipuv3_video",
694 .id = UCLASS_VIDEO,
695 .of_match = ipuv3_video_ids,
696 .bind = ipuv3_video_bind,
697 .probe = ipuv3_video_probe,
698 .priv_auto_alloc_size = sizeof(struct ipuv3_video_priv),
699 .flags = DM_FLAG_PRE_RELOC,
700};
701#endif /* CONFIG_DM_VIDEO */