uboot/drivers/video/imx/mxc_ipuv3_fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   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.
  11 */
  12
  13#include <common.h>
  14#include <log.h>
  15#include <part.h>
  16#include <asm/cache.h>
  17#include <linux/errno.h>
  18#include <asm/global_data.h>
  19#include <linux/string.h>
  20#include <linux/list.h>
  21#include <linux/fb.h>
  22#include <asm/io.h>
  23#include <asm/mach-imx/video.h>
  24#include <malloc.h>
  25#include <video_fb.h>
  26#include "../videomodes.h"
  27#include "ipu.h"
  28#include "mxcfb.h"
  29#include "ipu_regs.h"
  30#include "display.h"
  31#include <panel.h>
  32
  33#include <dm.h>
  34#include <video.h>
  35
  36DECLARE_GLOBAL_DATA_PTR;
  37
  38static int mxcfb_map_video_memory(struct fb_info *fbi);
  39static int mxcfb_unmap_video_memory(struct fb_info *fbi);
  40
  41static struct fb_videomode const *gmode;
  42static uint8_t gdisp;
  43static uint32_t gpixfmt;
  44
  45static void fb_videomode_to_var(struct fb_var_screeninfo *var,
  46                         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 {
  69        struct udevice *udev;
  70        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
 122static 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);
 207
 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
 246        debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL);
 247
 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{
 385        struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
 386        struct video_uc_plat *plat = dev_get_uclass_plat(mxc_fbi->udev);
 387
 388        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        }
 392        fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN);
 393
 394        fbi->screen_base = (char *)plat->base;
 395
 396        fbi->fix.smem_start = (unsigned long)fbi->screen_base;
 397        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;
 408        gd->fb_base = fbi->fix.smem_start;
 409
 410        /* 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
 474extern struct clk *g_ipu_clk;
 475
 476/*
 477 * Probe routine for the framebuffer driver. It is called during the
 478 * driver binding process. The following functions are performed in
 479 * 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 */
 484static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt,
 485                       uint8_t disp, struct fb_videomode const *mode)
 486{
 487        struct fb_info *fbi;
 488        struct mxcfb_info *mxcfbi;
 489
 490        /*
 491         * Initialize FB structures
 492         */
 493        fbi = mxcfb_init_fbinfo();
 494        if (!fbi)
 495                return -ENOMEM;
 496
 497        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
 507        mxcfbi->ipu_di = disp;
 508        mxcfbi->udev = dev;
 509
 510        if (!ipu_clk_enabled())
 511                clk_enable(g_ipu_clk);
 512
 513        ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
 514        ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
 515
 516        g_dp_in_use = 1;
 517
 518        mxcfb_info[mxcfbi->ipu_di] = fbi;
 519
 520        /* Need dummy values until real panel is configured */
 521
 522        mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
 523        fb_videomode_to_var(&fbi->var, mode);
 524        fbi->var.bits_per_pixel = 16;
 525        fbi->fix.line_length = fbi->var.xres_virtual *
 526                               (fbi->var.bits_per_pixel / 8);
 527        fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
 528
 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
 534        /* allocate fb first */
 535        if (mxcfb_map_video_memory(fbi) < 0)
 536                return -ENOMEM;
 537
 538        mxcfb_set_par(fbi);
 539
 540#ifdef DEBUG
 541        ipu_dump_registers();
 542#endif
 543
 544        return 0;
 545}
 546
 547void ipuv3_fb_shutdown(void)
 548{
 549        int i;
 550        struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;
 551
 552        if (!ipu_clk_enabled())
 553                return;
 554
 555        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}
 568
 569int ipuv3_fb_init(struct fb_videomode const *mode,
 570                  uint8_t disp,
 571                  uint32_t pixfmt)
 572{
 573        gmode = mode;
 574        gdisp = disp;
 575        gpixfmt = pixfmt;
 576
 577        return 0;
 578}
 579
 580enum {
 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_plat *plat = dev_get_uclass_plat(dev);
 590        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 591#if defined(CONFIG_DISPLAY)
 592        struct udevice *disp_dev;
 593#endif
 594        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
 608        ret = mxcfb_probe(dev, gpixfmt, gdisp, gmode);
 609        if (ret < 0)
 610                return ret;
 611
 612#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
 620        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        }
 627
 628        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);
 639        gd->fb_base = fb_start;
 640
 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_plat *plat = dev_get_uclass_plat(dev);
 651
 652        plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
 653                     (1 << VIDEO_BPP32) / 8;
 654
 655        return 0;
 656}
 657
 658static const struct udevice_id ipuv3_video_ids[] = {
 659#ifdef CONFIG_ARCH_MX6
 660        { .compatible = "fsl,imx6q-ipu" },
 661#endif
 662#ifdef CONFIG_ARCH_MX5
 663        { .compatible = "fsl,imx53-ipu" },
 664#endif
 665        { }
 666};
 667
 668U_BOOT_DRIVER(fsl_imx6q_ipu) = {
 669        .name   = "fsl_imx6q_ipu",
 670        .id     = UCLASS_VIDEO,
 671        .of_match = ipuv3_video_ids,
 672        .bind   = ipuv3_video_bind,
 673        .probe  = ipuv3_video_probe,
 674        .priv_auto      = sizeof(struct ipuv3_video_priv),
 675        .flags  = DM_FLAG_PRE_RELOC,
 676};
 677