blob: dc8f2cfd800b11da3d37907645b4818bc818ec3d [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>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass655306c2020-05-10 11:39:58 -060015#include <part.h>
Simon Glass274e0b02020-05-10 11:39:56 -060016#include <asm/cache.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090017#include <linux/errno.h>
Eric Nelsonc9e2be62014-04-29 14:37:56 -070018#include <asm/global_data.h>
Stefano Babic42f151a2010-10-13 12:17:14 +020019#include <linux/string.h>
20#include <linux/list.h>
21#include <linux/fb.h>
22#include <asm/io.h>
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +010023#include <asm/mach-imx/video.h>
Stefano Babic42f151a2010-10-13 12:17:14 +020024#include <malloc.h>
Stefano Babic61852442011-09-28 11:21:15 +020025#include <video_fb.h>
Anatolij Gustschin411e73d2019-03-18 23:29:32 +010026#include "../videomodes.h"
Stefano Babic42f151a2010-10-13 12:17:14 +020027#include "ipu.h"
28#include "mxcfb.h"
Eric Nelson988ad422012-09-23 07:30:54 +000029#include "ipu_regs.h"
Heiko Schocher3c787842019-07-22 06:49:07 +020030#include "display.h"
Heiko Schocher92afc9b2019-07-22 06:49:08 +020031#include <panel.h>
Stefano Babic42f151a2010-10-13 12:17:14 +020032
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +010033#include <dm.h>
34#include <video.h>
35
Eric Nelsonc9e2be62014-04-29 14:37:56 -070036DECLARE_GLOBAL_DATA_PTR;
37
Stefano Babic42f151a2010-10-13 12:17:14 +020038static int mxcfb_map_video_memory(struct fb_info *fbi);
39static int mxcfb_unmap_video_memory(struct fb_info *fbi);
40
Eric Nelson10a6cd12012-10-03 07:27:38 +000041static struct fb_videomode const *gmode;
Marek Vasutff5c108c2011-10-06 00:25:03 +020042static uint8_t gdisp;
43static uint32_t gpixfmt;
Stefano Babic42f151a2010-10-13 12:17:14 +020044
Jeroen Hofsteea175d302014-10-08 22:57:47 +020045static void fb_videomode_to_var(struct fb_var_screeninfo *var,
Stefano Babic42f151a2010-10-13 12:17:14 +020046 const struct fb_videomode *mode)
47{
48 var->xres = mode->xres;
49 var->yres = mode->yres;
50 var->xres_virtual = mode->xres;
51 var->yres_virtual = mode->yres;
52 var->xoffset = 0;
53 var->yoffset = 0;
54 var->pixclock = mode->pixclock;
55 var->left_margin = mode->left_margin;
56 var->right_margin = mode->right_margin;
57 var->upper_margin = mode->upper_margin;
58 var->lower_margin = mode->lower_margin;
59 var->hsync_len = mode->hsync_len;
60 var->vsync_len = mode->vsync_len;
61 var->sync = mode->sync;
62 var->vmode = mode->vmode & FB_VMODE_MASK;
63}
64
65/*
66 * Structure containing the MXC specific framebuffer information.
67 */
68struct mxcfb_info {
Anatolij Gustschin76057ba2020-08-03 15:45:33 +020069 struct udevice *udev;
Stefano Babic42f151a2010-10-13 12:17:14 +020070 int blank;
71 ipu_channel_t ipu_ch;
72 int ipu_di;
73 u32 ipu_di_pix_fmt;
74 unsigned char overlay;
75 unsigned char alpha_chan_en;
76 dma_addr_t alpha_phy_addr0;
77 dma_addr_t alpha_phy_addr1;
78 void *alpha_virt_addr0;
79 void *alpha_virt_addr1;
80 uint32_t alpha_mem_len;
81 uint32_t cur_ipu_buf;
82 uint32_t cur_ipu_alpha_buf;
83
84 u32 pseudo_palette[16];
85};
86
87enum {
88 BOTH_ON,
89 SRC_ON,
90 TGT_ON,
91 BOTH_OFF
92};
93
94static unsigned long default_bpp = 16;
95static unsigned char g_dp_in_use;
96static struct fb_info *mxcfb_info[3];
97static int ext_clk_used;
98
99static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
100{
101 uint32_t pixfmt = 0;
102
103 debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
104
105 if (fbi->var.nonstd)
106 return fbi->var.nonstd;
107
108 switch (fbi->var.bits_per_pixel) {
109 case 24:
110 pixfmt = IPU_PIX_FMT_BGR24;
111 break;
112 case 32:
113 pixfmt = IPU_PIX_FMT_BGR32;
114 break;
115 case 16:
116 pixfmt = IPU_PIX_FMT_RGB565;
117 break;
118 }
119 return pixfmt;
120}
121
Stefano Babic42f151a2010-10-13 12:17:14 +0200122static int setup_disp_channel1(struct fb_info *fbi)
123{
124 ipu_channel_params_t params;
125 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
126
127 memset(&params, 0, sizeof(params));
128 params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
129
130 debug("%s called\n", __func__);
131 /*
132 * Assuming interlaced means yuv output, below setting also
133 * valid for mem_dc_sync. FG should have the same vmode as BG.
134 */
135 if (fbi->var.vmode & FB_VMODE_INTERLACED) {
136 params.mem_dp_bg_sync.interlaced = 1;
137 params.mem_dp_bg_sync.out_pixel_fmt =
138 IPU_PIX_FMT_YUV444;
139 } else {
140 if (mxc_fbi->ipu_di_pix_fmt) {
141 params.mem_dp_bg_sync.out_pixel_fmt =
142 mxc_fbi->ipu_di_pix_fmt;
143 } else {
144 params.mem_dp_bg_sync.out_pixel_fmt =
145 IPU_PIX_FMT_RGB666;
146 }
147 }
148 params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
149 if (mxc_fbi->alpha_chan_en)
150 params.mem_dp_bg_sync.alpha_chan_en = 1;
151
152 ipu_init_channel(mxc_fbi->ipu_ch, &params);
153
154 return 0;
155}
156
157static int setup_disp_channel2(struct fb_info *fbi)
158{
159 int retval = 0;
160 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
161
162 mxc_fbi->cur_ipu_buf = 1;
163 if (mxc_fbi->alpha_chan_en)
164 mxc_fbi->cur_ipu_alpha_buf = 1;
165
166 fbi->var.xoffset = fbi->var.yoffset = 0;
167
168 debug("%s: %x %d %d %d %lx %lx\n",
169 __func__,
170 mxc_fbi->ipu_ch,
171 fbi->var.xres,
172 fbi->var.yres,
173 fbi->fix.line_length,
174 fbi->fix.smem_start,
175 fbi->fix.smem_start +
176 (fbi->fix.line_length * fbi->var.yres));
177
178 retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
179 bpp_to_pixfmt(fbi),
180 fbi->var.xres, fbi->var.yres,
181 fbi->fix.line_length,
182 fbi->fix.smem_start +
183 (fbi->fix.line_length * fbi->var.yres),
184 fbi->fix.smem_start,
185 0, 0);
186 if (retval)
187 printf("ipu_init_channel_buffer error %d\n", retval);
188
189 return retval;
190}
191
192/*
193 * Set framebuffer parameters and change the operating mode.
194 *
195 * @param info framebuffer information pointer
196 */
197static int mxcfb_set_par(struct fb_info *fbi)
198{
199 int retval = 0;
200 u32 mem_len;
201 ipu_di_signal_cfg_t sig_cfg;
202 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
203 uint32_t out_pixel_fmt;
204
205 ipu_disable_channel(mxc_fbi->ipu_ch);
206 ipu_uninit_channel(mxc_fbi->ipu_ch);
Stefano Babic42f151a2010-10-13 12:17:14 +0200207
208 mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
209 if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
210 if (fbi->fix.smem_start)
211 mxcfb_unmap_video_memory(fbi);
212
213 if (mxcfb_map_video_memory(fbi) < 0)
214 return -ENOMEM;
215 }
216
217 setup_disp_channel1(fbi);
218
219 memset(&sig_cfg, 0, sizeof(sig_cfg));
220 if (fbi->var.vmode & FB_VMODE_INTERLACED) {
221 sig_cfg.interlaced = 1;
222 out_pixel_fmt = IPU_PIX_FMT_YUV444;
223 } else {
224 if (mxc_fbi->ipu_di_pix_fmt)
225 out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
226 else
227 out_pixel_fmt = IPU_PIX_FMT_RGB666;
228 }
229 if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
230 sig_cfg.odd_field_first = 1;
231 if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
232 sig_cfg.ext_clk = 1;
233 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
234 sig_cfg.Hsync_pol = 1;
235 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
236 sig_cfg.Vsync_pol = 1;
237 if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
238 sig_cfg.clk_pol = 1;
239 if (fbi->var.sync & FB_SYNC_DATA_INVERT)
240 sig_cfg.data_pol = 1;
241 if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
242 sig_cfg.enable_pol = 1;
243 if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
244 sig_cfg.clkidle_en = 1;
245
Jeroen Hofstee98276212014-10-14 20:37:14 +0200246 debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL);
Stefano Babic42f151a2010-10-13 12:17:14 +0200247
248 if (ipu_init_sync_panel(mxc_fbi->ipu_di,
249 (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
250 fbi->var.xres, fbi->var.yres,
251 out_pixel_fmt,
252 fbi->var.left_margin,
253 fbi->var.hsync_len,
254 fbi->var.right_margin,
255 fbi->var.upper_margin,
256 fbi->var.vsync_len,
257 fbi->var.lower_margin,
258 0, sig_cfg) != 0) {
259 puts("mxcfb: Error initializing panel.\n");
260 return -EINVAL;
261 }
262
263 retval = setup_disp_channel2(fbi);
264 if (retval)
265 return retval;
266
267 if (mxc_fbi->blank == FB_BLANK_UNBLANK)
268 ipu_enable_channel(mxc_fbi->ipu_ch);
269
270 return retval;
271}
272
273/*
274 * Check framebuffer variable parameters and adjust to valid values.
275 *
276 * @param var framebuffer variable parameters
277 *
278 * @param info framebuffer information pointer
279 */
280static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
281{
282 u32 vtotal;
283 u32 htotal;
284
285 if (var->xres_virtual < var->xres)
286 var->xres_virtual = var->xres;
287 if (var->yres_virtual < var->yres)
288 var->yres_virtual = var->yres;
289
290 if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
291 (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
292 var->bits_per_pixel = default_bpp;
293
294 switch (var->bits_per_pixel) {
295 case 8:
296 var->red.length = 3;
297 var->red.offset = 5;
298 var->red.msb_right = 0;
299
300 var->green.length = 3;
301 var->green.offset = 2;
302 var->green.msb_right = 0;
303
304 var->blue.length = 2;
305 var->blue.offset = 0;
306 var->blue.msb_right = 0;
307
308 var->transp.length = 0;
309 var->transp.offset = 0;
310 var->transp.msb_right = 0;
311 break;
312 case 16:
313 var->red.length = 5;
314 var->red.offset = 11;
315 var->red.msb_right = 0;
316
317 var->green.length = 6;
318 var->green.offset = 5;
319 var->green.msb_right = 0;
320
321 var->blue.length = 5;
322 var->blue.offset = 0;
323 var->blue.msb_right = 0;
324
325 var->transp.length = 0;
326 var->transp.offset = 0;
327 var->transp.msb_right = 0;
328 break;
329 case 24:
330 var->red.length = 8;
331 var->red.offset = 16;
332 var->red.msb_right = 0;
333
334 var->green.length = 8;
335 var->green.offset = 8;
336 var->green.msb_right = 0;
337
338 var->blue.length = 8;
339 var->blue.offset = 0;
340 var->blue.msb_right = 0;
341
342 var->transp.length = 0;
343 var->transp.offset = 0;
344 var->transp.msb_right = 0;
345 break;
346 case 32:
347 var->red.length = 8;
348 var->red.offset = 16;
349 var->red.msb_right = 0;
350
351 var->green.length = 8;
352 var->green.offset = 8;
353 var->green.msb_right = 0;
354
355 var->blue.length = 8;
356 var->blue.offset = 0;
357 var->blue.msb_right = 0;
358
359 var->transp.length = 8;
360 var->transp.offset = 24;
361 var->transp.msb_right = 0;
362 break;
363 }
364
365 if (var->pixclock < 1000) {
366 htotal = var->xres + var->right_margin + var->hsync_len +
367 var->left_margin;
368 vtotal = var->yres + var->lower_margin + var->vsync_len +
369 var->upper_margin;
370 var->pixclock = (vtotal * htotal * 6UL) / 100UL;
371 var->pixclock = KHZ2PICOS(var->pixclock);
372 printf("pixclock set for 60Hz refresh = %u ps\n",
373 var->pixclock);
374 }
375
376 var->height = -1;
377 var->width = -1;
378 var->grayscale = 0;
379
380 return 0;
381}
382
383static int mxcfb_map_video_memory(struct fb_info *fbi)
384{
Anatolij Gustschin76057ba2020-08-03 15:45:33 +0200385 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
386 struct video_uc_platdata *plat = dev_get_uclass_platdata(mxc_fbi->udev);
387
Stefano Babic42f151a2010-10-13 12:17:14 +0200388 if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
389 fbi->fix.smem_len = fbi->var.yres_virtual *
390 fbi->fix.line_length;
391 }
Eric Nelsonfe6296f2013-07-26 17:53:45 -0700392 fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN);
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100393
Anatolij Gustschin76057ba2020-08-03 15:45:33 +0200394 fbi->screen_base = (char *)plat->base;
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100395
Stefano Babic61852442011-09-28 11:21:15 +0200396 fbi->fix.smem_start = (unsigned long)fbi->screen_base;
Stefano Babic42f151a2010-10-13 12:17:14 +0200397 if (fbi->screen_base == 0) {
398 puts("Unable to allocate framebuffer memory\n");
399 fbi->fix.smem_len = 0;
400 fbi->fix.smem_start = 0;
401 return -EBUSY;
402 }
403
404 debug("allocated fb @ paddr=0x%08X, size=%d.\n",
405 (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
406
407 fbi->screen_size = fbi->fix.smem_len;
Eric Nelsonc9e2be62014-04-29 14:37:56 -0700408 gd->fb_base = fbi->fix.smem_start;
409
Stefano Babic42f151a2010-10-13 12:17:14 +0200410 /* Clear the screen */
411 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
412
413 return 0;
414}
415
416static int mxcfb_unmap_video_memory(struct fb_info *fbi)
417{
418 fbi->screen_base = 0;
419 fbi->fix.smem_start = 0;
420 fbi->fix.smem_len = 0;
421 return 0;
422}
423
424/*
425 * Initializes the framebuffer information pointer. After allocating
426 * sufficient memory for the framebuffer structure, the fields are
427 * filled with custom information passed in from the configurable
428 * structures. This includes information such as bits per pixel,
429 * color maps, screen width/height and RGBA offsets.
430 *
431 * @return Framebuffer structure initialized with our information
432 */
433static struct fb_info *mxcfb_init_fbinfo(void)
434{
435#define BYTES_PER_LONG 4
436#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
437 struct fb_info *fbi;
438 struct mxcfb_info *mxcfbi;
439 char *p;
440 int size = sizeof(struct mxcfb_info) + PADDING +
441 sizeof(struct fb_info);
442
443 debug("%s: %d %d %d %d\n",
444 __func__,
445 PADDING,
446 size,
447 sizeof(struct mxcfb_info),
448 sizeof(struct fb_info));
449 /*
450 * Allocate sufficient memory for the fb structure
451 */
452
453 p = malloc(size);
454 if (!p)
455 return NULL;
456
457 memset(p, 0, size);
458
459 fbi = (struct fb_info *)p;
460 fbi->par = p + sizeof(struct fb_info) + PADDING;
461
462 mxcfbi = (struct mxcfb_info *)fbi->par;
463 debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
464 (unsigned int)fbi, (unsigned int)mxcfbi);
465
466 fbi->var.activate = FB_ACTIVATE_NOW;
467
468 fbi->flags = FBINFO_FLAG_DEFAULT;
469 fbi->pseudo_palette = mxcfbi->pseudo_palette;
470
471 return fbi;
472}
473
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200474extern struct clk *g_ipu_clk;
475
Stefano Babic42f151a2010-10-13 12:17:14 +0200476/*
477 * Probe routine for the framebuffer driver. It is called during the
Jeroen Hofstee98276212014-10-14 20:37:14 +0200478 * driver binding process. The following functions are performed in
Stefano Babic42f151a2010-10-13 12:17:14 +0200479 * this routine: Framebuffer initialization, Memory allocation and
480 * mapping, Framebuffer registration, IPU initialization.
481 *
482 * @return Appropriate error code to the kernel common code
483 */
Anatolij Gustschin76057ba2020-08-03 15:45:33 +0200484static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt,
485 uint8_t disp, struct fb_videomode const *mode)
Stefano Babic42f151a2010-10-13 12:17:14 +0200486{
487 struct fb_info *fbi;
488 struct mxcfb_info *mxcfbi;
Stefano Babic42f151a2010-10-13 12:17:14 +0200489
490 /*
491 * Initialize FB structures
492 */
493 fbi = mxcfb_init_fbinfo();
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200494 if (!fbi)
495 return -ENOMEM;
496
Stefano Babic42f151a2010-10-13 12:17:14 +0200497 mxcfbi = (struct mxcfb_info *)fbi->par;
498
499 if (!g_dp_in_use) {
500 mxcfbi->ipu_ch = MEM_BG_SYNC;
501 mxcfbi->blank = FB_BLANK_UNBLANK;
502 } else {
503 mxcfbi->ipu_ch = MEM_DC_SYNC;
504 mxcfbi->blank = FB_BLANK_POWERDOWN;
505 }
506
Marek Vasutff5c108c2011-10-06 00:25:03 +0200507 mxcfbi->ipu_di = disp;
Anatolij Gustschin76057ba2020-08-03 15:45:33 +0200508 mxcfbi->udev = dev;
Stefano Babic42f151a2010-10-13 12:17:14 +0200509
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200510 if (!ipu_clk_enabled())
511 clk_enable(g_ipu_clk);
512
Stefano Babic42f151a2010-10-13 12:17:14 +0200513 ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
514 ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
Stefano Babic42f151a2010-10-13 12:17:14 +0200515
516 g_dp_in_use = 1;
517
518 mxcfb_info[mxcfbi->ipu_di] = fbi;
519
520 /* Need dummy values until real panel is configured */
Stefano Babic42f151a2010-10-13 12:17:14 +0200521
522 mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
523 fb_videomode_to_var(&fbi->var, mode);
Stefano Babic61852442011-09-28 11:21:15 +0200524 fbi->var.bits_per_pixel = 16;
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200525 fbi->fix.line_length = fbi->var.xres_virtual *
526 (fbi->var.bits_per_pixel / 8);
Stefano Babic61852442011-09-28 11:21:15 +0200527 fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
Stefano Babic42f151a2010-10-13 12:17:14 +0200528
529 mxcfb_check_var(&fbi->var, fbi);
530
531 /* Default Y virtual size is 2x panel size */
532 fbi->var.yres_virtual = fbi->var.yres * 2;
533
Jeroen Hofstee98276212014-10-14 20:37:14 +0200534 /* allocate fb first */
Stefano Babic42f151a2010-10-13 12:17:14 +0200535 if (mxcfb_map_video_memory(fbi) < 0)
536 return -ENOMEM;
537
538 mxcfb_set_par(fbi);
539
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200540#ifdef DEBUG
Stefano Babic42f151a2010-10-13 12:17:14 +0200541 ipu_dump_registers();
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200542#endif
Stefano Babic42f151a2010-10-13 12:17:14 +0200543
544 return 0;
Stefano Babic42f151a2010-10-13 12:17:14 +0200545}
546
Eric Nelson988ad422012-09-23 07:30:54 +0000547void ipuv3_fb_shutdown(void)
548{
Anatolij Gustschinfa4211c2017-08-25 15:10:43 +0200549 int i;
Tom Rini47dce762017-09-01 16:17:17 -0400550 struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;
Eric Nelson988ad422012-09-23 07:30:54 +0000551
Anatolij Gustschin3e7ad7d2017-09-04 23:33:45 +0200552 if (!ipu_clk_enabled())
553 return;
554
Eric Nelson988ad422012-09-23 07:30:54 +0000555 for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) {
556 struct fb_info *fbi = mxcfb_info[i];
557 if (fbi) {
558 struct mxcfb_info *mxc_fbi = fbi->par;
559 ipu_disable_channel(mxc_fbi->ipu_ch);
560 ipu_uninit_channel(mxc_fbi->ipu_ch);
561 }
562 }
563 for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) {
564 __raw_writel(__raw_readl(&stat->int_stat[i]),
565 &stat->int_stat[i]);
566 }
567}
Stefano Babic42f151a2010-10-13 12:17:14 +0200568
Eric Nelson10a6cd12012-10-03 07:27:38 +0000569int ipuv3_fb_init(struct fb_videomode const *mode,
570 uint8_t disp,
571 uint32_t pixfmt)
Stefano Babic61852442011-09-28 11:21:15 +0200572{
573 gmode = mode;
Marek Vasutff5c108c2011-10-06 00:25:03 +0200574 gdisp = disp;
575 gpixfmt = pixfmt;
Stefano Babic61852442011-09-28 11:21:15 +0200576
577 return 0;
Stefano Babic42f151a2010-10-13 12:17:14 +0200578}
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100579
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100580enum {
581 /* Maximum display size we support */
582 LCD_MAX_WIDTH = 1920,
583 LCD_MAX_HEIGHT = 1080,
584 LCD_MAX_LOG2_BPP = VIDEO_BPP16,
585};
586
587static int ipuv3_video_probe(struct udevice *dev)
588{
589 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
590 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
Heiko Schocher3c787842019-07-22 06:49:07 +0200591#if defined(CONFIG_DISPLAY)
592 struct udevice *disp_dev;
593#endif
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100594 u32 fb_start, fb_end;
595 int ret;
596
597 debug("%s() plat: base 0x%lx, size 0x%x\n",
598 __func__, plat->base, plat->size);
599
600 ret = ipu_probe();
601 if (ret)
602 return ret;
603
604 ret = ipu_displays_init();
605 if (ret < 0)
606 return ret;
607
Anatolij Gustschin76057ba2020-08-03 15:45:33 +0200608 ret = mxcfb_probe(dev, gpixfmt, gdisp, gmode);
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100609 if (ret < 0)
610 return ret;
611
Heiko Schocher3c787842019-07-22 06:49:07 +0200612#if defined(CONFIG_DISPLAY)
613 ret = uclass_first_device(UCLASS_DISPLAY, &disp_dev);
614 if (disp_dev) {
615 ret = display_enable(disp_dev, 16, NULL);
616 if (ret < 0)
617 return ret;
618 }
619#endif
Anatolij Gustschin00878362020-05-26 00:09:22 +0200620 if (CONFIG_IS_ENABLED(PANEL)) {
621 struct udevice *panel_dev;
622
623 ret = uclass_get_device(UCLASS_PANEL, 0, &panel_dev);
624 if (panel_dev)
625 panel_enable_backlight(panel_dev);
626 }
Heiko Schocher3c787842019-07-22 06:49:07 +0200627
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100628 uc_priv->xsize = gmode->xres;
629 uc_priv->ysize = gmode->yres;
630 uc_priv->bpix = LCD_MAX_LOG2_BPP;
631
632 /* Enable dcache for the frame buffer */
633 fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
634 fb_end = plat->base + plat->size;
635 fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
636 mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
637 DCACHE_WRITEBACK);
638 video_set_flush_dcache(dev, true);
Heiko Schocherabb59422019-07-22 06:49:05 +0200639 gd->fb_base = fb_start;
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100640
641 return 0;
642}
643
644struct ipuv3_video_priv {
645 ulong regs;
646};
647
648static int ipuv3_video_bind(struct udevice *dev)
649{
650 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
651
652 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
Marek Vasut28bdd932019-05-06 01:11:32 +0200653 (1 << VIDEO_BPP32) / 8;
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100654
655 return 0;
656}
657
658static const struct udevice_id ipuv3_video_ids[] = {
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200659#ifdef CONFIG_ARCH_MX6
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100660 { .compatible = "fsl,imx6q-ipu" },
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200661#endif
662#ifdef CONFIG_ARCH_MX5
Steffen Dirkwinkel4e40f1a2019-04-17 13:57:15 +0200663 { .compatible = "fsl,imx53-ipu" },
Anatolij Gustschin8329ce32020-05-25 14:34:17 +0200664#endif
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100665 { }
666};
667
Walter Lozano35f61872020-07-29 12:31:20 -0300668U_BOOT_DRIVER(fsl_imx6q_ipu) = {
669 .name = "fsl_imx6q_ipu",
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100670 .id = UCLASS_VIDEO,
671 .of_match = ipuv3_video_ids,
672 .bind = ipuv3_video_bind,
673 .probe = ipuv3_video_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700674 .priv_auto = sizeof(struct ipuv3_video_priv),
Anatolij Gustschin983e2f2a2019-03-18 23:29:31 +0100675 .flags = DM_FLAG_PRE_RELOC,
676};