uboot/drivers/video/sunxi/sunxi_display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Display driver for Allwinner SoCs.
   4 *
   5 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
   6 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
   7 */
   8
   9#include <common.h>
  10#include <display.h>
  11#include <dm.h>
  12#include <cpu_func.h>
  13#include <efi_loader.h>
  14#include <init.h>
  15#include <time.h>
  16#include <linux/delay.h>
  17
  18#include <asm/arch/clock.h>
  19#include <asm/arch/display.h>
  20#include <asm/arch/lcdc.h>
  21#include <asm/arch/pwm.h>
  22#include <asm/arch/tve.h>
  23#include <asm/global_data.h>
  24#include <asm/gpio.h>
  25#include <asm/io.h>
  26#include <axp_pmic.h>
  27#include <errno.h>
  28#include <fdtdec.h>
  29#include <fdt_support.h>
  30#include <i2c.h>
  31#include <malloc.h>
  32#include <video.h>
  33#include <dm/uclass-internal.h>
  34#include "../videomodes.h"
  35#include "../anx9804.h"
  36#include "../hitachi_tx18d42vm_lcd.h"
  37#include "../ssd2828.h"
  38#include "simplefb_common.h"
  39
  40#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
  41#define PWM_ON 0
  42#define PWM_OFF 1
  43#else
  44#define PWM_ON 1
  45#define PWM_OFF 0
  46#endif
  47
  48DECLARE_GLOBAL_DATA_PTR;
  49
  50/* Maximum LCD size we support */
  51#define LCD_MAX_WIDTH           3840
  52#define LCD_MAX_HEIGHT          2160
  53#define LCD_MAX_LOG2_BPP        VIDEO_BPP32
  54
  55enum sunxi_monitor {
  56        sunxi_monitor_none,
  57        sunxi_monitor_dvi,
  58        sunxi_monitor_hdmi,
  59        sunxi_monitor_lcd,
  60        sunxi_monitor_vga,
  61        sunxi_monitor_composite_pal,
  62        sunxi_monitor_composite_ntsc,
  63        sunxi_monitor_composite_pal_m,
  64        sunxi_monitor_composite_pal_nc,
  65};
  66#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
  67
  68struct sunxi_display_priv {
  69        enum sunxi_monitor monitor;
  70        unsigned int depth;
  71        unsigned int fb_addr;
  72        unsigned int fb_size;
  73};
  74
  75const struct ctfb_res_modes composite_video_modes[2] = {
  76        /*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
  77        { 720,  576, 50, 37037,  27000, 137,   5, 20, 27,   2, 2, 0, FB_VMODE_INTERLACED },
  78        { 720,  480, 60, 37037,  27000, 116,  20, 16, 27,   2, 2, 0, FB_VMODE_INTERLACED },
  79};
  80
  81#ifdef CONFIG_VIDEO_HDMI
  82
  83/*
  84 * Wait up to 200ms for value to be set in given part of reg.
  85 */
  86static int await_completion(u32 *reg, u32 mask, u32 val)
  87{
  88        unsigned long tmo = timer_get_us() + 200000;
  89
  90        while ((readl(reg) & mask) != val) {
  91                if (timer_get_us() > tmo) {
  92                        printf("DDC: timeout reading EDID\n");
  93                        return -ETIME;
  94                }
  95        }
  96        return 0;
  97}
  98
  99static int sunxi_hdmi_hpd_detect(int hpd_delay)
 100{
 101        struct sunxi_ccm_reg * const ccm =
 102                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 103        struct sunxi_hdmi_reg * const hdmi =
 104                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 105        unsigned long tmo = timer_get_us() + hpd_delay * 1000;
 106
 107        /* Set pll3 to 300MHz */
 108        clock_set_pll3(300000000);
 109
 110        /* Set hdmi parent to pll3 */
 111        clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
 112                        CCM_HDMI_CTRL_PLL3);
 113
 114        /* Set ahb gating to pass */
 115#ifdef CONFIG_SUNXI_GEN_SUN6I
 116        setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
 117#endif
 118        setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
 119
 120        /* Clock on */
 121        setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
 122
 123        writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
 124        writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
 125
 126        /* Enable PLLs for eventual DDC */
 127        writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
 128               &hdmi->pad_ctrl1);
 129        writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
 130               &hdmi->pll_ctrl);
 131        writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
 132
 133        while (timer_get_us() < tmo) {
 134                if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
 135                        return 1;
 136        }
 137
 138        return 0;
 139}
 140
 141static void sunxi_hdmi_shutdown(void)
 142{
 143        struct sunxi_ccm_reg * const ccm =
 144                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 145        struct sunxi_hdmi_reg * const hdmi =
 146                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 147
 148        clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
 149        clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
 150        clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
 151#ifdef CONFIG_SUNXI_GEN_SUN6I
 152        clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
 153#endif
 154        clock_set_pll3(0);
 155}
 156
 157static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
 158{
 159        struct sunxi_hdmi_reg * const hdmi =
 160                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 161
 162        setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
 163        writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
 164               SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
 165               SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
 166               SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
 167#ifndef CONFIG_MACH_SUN6I
 168        writel(n, &hdmi->ddc_byte_count);
 169        writel(cmnd, &hdmi->ddc_cmnd);
 170#else
 171        writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
 172#endif
 173        setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
 174
 175        return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
 176}
 177
 178static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
 179{
 180        struct sunxi_hdmi_reg * const hdmi =
 181                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 182        int i, n;
 183
 184        while (count > 0) {
 185                if (count > 16)
 186                        n = 16;
 187                else
 188                        n = count;
 189
 190                if (sunxi_hdmi_ddc_do_command(
 191                                SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
 192                                offset, n))
 193                        return -ETIME;
 194
 195                for (i = 0; i < n; i++)
 196                        *buf++ = readb(&hdmi->ddc_fifo_data);
 197
 198                offset += n;
 199                count -= n;
 200        }
 201
 202        return 0;
 203}
 204
 205static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
 206{
 207        int r, retries = 2;
 208
 209        do {
 210                r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
 211                if (r)
 212                        continue;
 213                r = edid_check_checksum(buf);
 214                if (r) {
 215                        printf("EDID block %d: checksum error%s\n",
 216                               block, retries ? ", retrying" : "");
 217                }
 218        } while (r && retries--);
 219
 220        return r;
 221}
 222
 223static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
 224                                    struct ctfb_res_modes *mode,
 225                                    bool verbose_mode)
 226{
 227        struct edid1_info edid1;
 228        struct edid_cea861_info cea681[4];
 229        struct edid_detailed_timing *t =
 230                (struct edid_detailed_timing *)edid1.monitor_details.timing;
 231        struct sunxi_hdmi_reg * const hdmi =
 232                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 233        struct sunxi_ccm_reg * const ccm =
 234                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 235        int i, r, ext_blocks = 0;
 236
 237        /* Reset i2c controller */
 238        setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
 239        writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
 240               SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
 241               SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
 242               SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
 243        if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
 244                return -EIO;
 245
 246        writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
 247#ifndef CONFIG_MACH_SUN6I
 248        writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
 249               SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
 250#endif
 251
 252        r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
 253        if (r == 0) {
 254                r = edid_check_info(&edid1);
 255                if (r) {
 256                        if (verbose_mode)
 257                                printf("EDID: invalid EDID data\n");
 258                        r = -EINVAL;
 259                }
 260        }
 261        if (r == 0) {
 262                ext_blocks = edid1.extension_flag;
 263                if (ext_blocks > 4)
 264                        ext_blocks = 4;
 265                for (i = 0; i < ext_blocks; i++) {
 266                        if (sunxi_hdmi_edid_get_block(1 + i,
 267                                                (u8 *)&cea681[i]) != 0) {
 268                                ext_blocks = i;
 269                                break;
 270                        }
 271                }
 272        }
 273
 274        /* Disable DDC engine, no longer needed */
 275        clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
 276        clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
 277
 278        if (r)
 279                return r;
 280
 281        /* We want version 1.3 or 1.2 with detailed timing info */
 282        if (edid1.version != 1 || (edid1.revision < 3 &&
 283                        !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
 284                printf("EDID: unsupported version %d.%d\n",
 285                       edid1.version, edid1.revision);
 286                return -EINVAL;
 287        }
 288
 289        /* Take the first usable detailed timing */
 290        for (i = 0; i < 4; i++, t++) {
 291                r = video_edid_dtd_to_ctfb_res_modes(t, mode);
 292                if (r == 0)
 293                        break;
 294        }
 295        if (i == 4) {
 296                printf("EDID: no usable detailed timing found\n");
 297                return -ENOENT;
 298        }
 299
 300        /* Check for basic audio support, if found enable hdmi output */
 301        sunxi_display->monitor = sunxi_monitor_dvi;
 302        for (i = 0; i < ext_blocks; i++) {
 303                if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
 304                    cea681[i].revision < 2)
 305                        continue;
 306
 307                if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
 308                        sunxi_display->monitor = sunxi_monitor_hdmi;
 309        }
 310
 311        return 0;
 312}
 313
 314#endif /* CONFIG_VIDEO_HDMI */
 315
 316#ifdef CONFIG_MACH_SUN4I
 317/*
 318 * Testing has shown that on sun4i the display backend engine does not have
 319 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
 320 * fifo underruns. So on sun4i we use the display frontend engine to do the
 321 * dma from memory, as the frontend does have deep enough fifo-s.
 322 */
 323
 324static const u32 sun4i_vert_coef[32] = {
 325        0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
 326        0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
 327        0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
 328        0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
 329        0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
 330        0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
 331        0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
 332        0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
 333};
 334
 335static const u32 sun4i_horz_coef[64] = {
 336        0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
 337        0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
 338        0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
 339        0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
 340        0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
 341        0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
 342        0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
 343        0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
 344        0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
 345        0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
 346        0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
 347        0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
 348        0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
 349        0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
 350        0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
 351        0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
 352};
 353
 354static void sunxi_frontend_init(void)
 355{
 356        struct sunxi_ccm_reg * const ccm =
 357                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 358        struct sunxi_de_fe_reg * const de_fe =
 359                (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
 360        int i;
 361
 362        /* Clocks on */
 363        setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
 364        setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
 365        clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
 366
 367        setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
 368
 369        for (i = 0; i < 32; i++) {
 370                writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
 371                writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
 372                writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
 373                writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
 374                writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
 375                writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
 376        }
 377
 378        setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
 379}
 380
 381static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
 382                                    unsigned int address)
 383{
 384        struct sunxi_de_fe_reg * const de_fe =
 385                (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
 386
 387        setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
 388        writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
 389        writel(mode->xres * 4, &de_fe->ch0_stride);
 390        writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
 391        writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
 392
 393        writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
 394               &de_fe->ch0_insize);
 395        writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
 396               &de_fe->ch0_outsize);
 397        writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
 398        writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
 399
 400        writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
 401               &de_fe->ch1_insize);
 402        writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
 403               &de_fe->ch1_outsize);
 404        writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
 405        writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
 406
 407        setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
 408}
 409
 410static void sunxi_frontend_enable(void)
 411{
 412        struct sunxi_de_fe_reg * const de_fe =
 413                (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
 414
 415        setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
 416}
 417#else
 418static void sunxi_frontend_init(void) {}
 419static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
 420                                    unsigned int address) {}
 421static void sunxi_frontend_enable(void) {}
 422#endif
 423
 424static bool sunxi_is_composite(enum sunxi_monitor monitor)
 425{
 426        switch (monitor) {
 427        case sunxi_monitor_none:
 428        case sunxi_monitor_dvi:
 429        case sunxi_monitor_hdmi:
 430        case sunxi_monitor_lcd:
 431        case sunxi_monitor_vga:
 432                return false;
 433        case sunxi_monitor_composite_pal:
 434        case sunxi_monitor_composite_ntsc:
 435        case sunxi_monitor_composite_pal_m:
 436        case sunxi_monitor_composite_pal_nc:
 437                return true;
 438        }
 439
 440        return false; /* Never reached */
 441}
 442
 443/*
 444 * This is the entity that mixes and matches the different layers and inputs.
 445 * Allwinner calls it the back-end, but i like composer better.
 446 */
 447static void sunxi_composer_init(void)
 448{
 449        struct sunxi_ccm_reg * const ccm =
 450                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 451        struct sunxi_de_be_reg * const de_be =
 452                (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
 453        int i;
 454
 455        sunxi_frontend_init();
 456
 457#ifdef CONFIG_SUNXI_GEN_SUN6I
 458        /* Reset off */
 459        setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
 460#endif
 461
 462        /* Clocks on */
 463        setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
 464#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
 465        setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
 466#endif
 467        clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
 468
 469        /* Engine bug, clear registers after reset */
 470        for (i = 0x0800; i < 0x1000; i += 4)
 471                writel(0, SUNXI_DE_BE0_BASE + i);
 472
 473        setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
 474}
 475
 476static const u32 sunxi_rgb2yuv_coef[12] = {
 477        0x00000107, 0x00000204, 0x00000064, 0x00000108,
 478        0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
 479        0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
 480};
 481
 482static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
 483                                    unsigned int address,
 484                                    enum sunxi_monitor monitor)
 485{
 486        struct sunxi_de_be_reg * const de_be =
 487                (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
 488        int i;
 489
 490        sunxi_frontend_mode_set(mode, address);
 491
 492        writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
 493               &de_be->disp_size);
 494        writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
 495               &de_be->layer0_size);
 496#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
 497        writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
 498        writel(address << 3, &de_be->layer0_addr_low32b);
 499        writel(address >> 29, &de_be->layer0_addr_high4b);
 500#else
 501        writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
 502#endif
 503        writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
 504
 505        setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
 506        if (mode->vmode == FB_VMODE_INTERLACED)
 507                setbits_le32(&de_be->mode,
 508#ifndef CONFIG_MACH_SUN5I
 509                             SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
 510#endif
 511                             SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
 512
 513        if (sunxi_is_composite(monitor)) {
 514                writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
 515                       &de_be->output_color_ctrl);
 516                for (i = 0; i < 12; i++)
 517                        writel(sunxi_rgb2yuv_coef[i],
 518                               &de_be->output_color_coef[i]);
 519        }
 520}
 521
 522static void sunxi_composer_enable(void)
 523{
 524        struct sunxi_de_be_reg * const de_be =
 525                (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
 526
 527        sunxi_frontend_enable();
 528
 529        setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
 530        setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
 531}
 532
 533static void sunxi_lcdc_init(void)
 534{
 535        struct sunxi_ccm_reg * const ccm =
 536                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 537        struct sunxi_lcdc_reg * const lcdc =
 538                (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 539
 540        /* Reset off */
 541#ifdef CONFIG_SUNXI_GEN_SUN6I
 542        setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
 543#else
 544        setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
 545#endif
 546
 547        /* Clock on */
 548        setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
 549#ifdef CONFIG_VIDEO_LCD_IF_LVDS
 550#ifdef CONFIG_SUNXI_GEN_SUN6I
 551        setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
 552#else
 553        setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
 554#endif
 555#endif
 556
 557        lcdc_init(lcdc);
 558}
 559
 560static void sunxi_lcdc_panel_enable(void)
 561{
 562        int pin, reset_pin;
 563
 564        /*
 565         * Start with backlight disabled to avoid the screen flashing to
 566         * white while the lcd inits.
 567         */
 568        pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
 569        if (pin >= 0) {
 570                gpio_request(pin, "lcd_backlight_enable");
 571                gpio_direction_output(pin, 0);
 572        }
 573
 574        pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
 575        if (pin >= 0) {
 576                gpio_request(pin, "lcd_backlight_pwm");
 577                gpio_direction_output(pin, PWM_OFF);
 578        }
 579
 580        reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
 581        if (reset_pin >= 0) {
 582                gpio_request(reset_pin, "lcd_reset");
 583                gpio_direction_output(reset_pin, 0); /* Assert reset */
 584        }
 585
 586        /* Give the backlight some time to turn off and power up the panel. */
 587        mdelay(40);
 588        pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
 589        if (pin >= 0) {
 590                gpio_request(pin, "lcd_power");
 591                gpio_direction_output(pin, 1);
 592        }
 593
 594        if (reset_pin >= 0)
 595                gpio_direction_output(reset_pin, 1); /* De-assert reset */
 596}
 597
 598static void sunxi_lcdc_backlight_enable(void)
 599{
 600        int pin;
 601
 602        /*
 603         * We want to have scanned out at least one frame before enabling the
 604         * backlight to avoid the screen flashing to white when we enable it.
 605         */
 606        mdelay(40);
 607
 608        pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
 609        if (pin >= 0)
 610                gpio_direction_output(pin, 1);
 611
 612        pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
 613#ifdef SUNXI_PWM_PIN0
 614        if (pin == SUNXI_PWM_PIN0) {
 615                writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
 616                       SUNXI_PWM_CTRL_ENABLE0 |
 617                       SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
 618                writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
 619                sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
 620                return;
 621        }
 622#endif
 623        if (pin >= 0)
 624                gpio_direction_output(pin, PWM_ON);
 625}
 626
 627static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
 628                                      const struct ctfb_res_modes *mode,
 629                                      bool for_ext_vga_dac)
 630{
 631        struct sunxi_lcdc_reg * const lcdc =
 632                (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 633        struct sunxi_ccm_reg * const ccm =
 634                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 635        int clk_div, clk_double, pin;
 636        struct display_timing timing;
 637
 638#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
 639        for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
 640#else
 641        for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
 642#endif
 643#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
 644                sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
 645#endif
 646#ifdef CONFIG_VIDEO_LCD_IF_LVDS
 647                sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
 648#endif
 649#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
 650                sunxi_gpio_set_drv(pin, 3);
 651#endif
 652        }
 653
 654        lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
 655                     sunxi_is_composite(sunxi_display->monitor));
 656
 657        video_ctfb_mode_to_display_timing(mode, &timing);
 658        lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
 659                            sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
 660}
 661
 662#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 663static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 664                                      int *clk_div, int *clk_double,
 665                                      bool use_portd_hvsync,
 666                                      enum sunxi_monitor monitor)
 667{
 668        struct sunxi_lcdc_reg * const lcdc =
 669                (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 670        struct sunxi_ccm_reg * const ccm =
 671                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 672        struct display_timing timing;
 673
 674        video_ctfb_mode_to_display_timing(mode, &timing);
 675        lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
 676                            sunxi_is_composite(monitor));
 677
 678        if (use_portd_hvsync) {
 679                sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
 680                sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
 681        }
 682
 683        lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
 684                     sunxi_is_composite(monitor));
 685}
 686#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
 687
 688#ifdef CONFIG_VIDEO_HDMI
 689
 690static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
 691{
 692        struct sunxi_hdmi_reg * const hdmi =
 693                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 694        u8 checksum = 0;
 695        u8 avi_info_frame[17] = {
 696                0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
 697                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 698                0x00
 699        };
 700        u8 vendor_info_frame[19] = {
 701                0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
 702                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 703                0x00, 0x00, 0x00
 704        };
 705        int i;
 706
 707        if (mode->pixclock_khz <= 27000)
 708                avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
 709        else
 710                avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
 711
 712        if (mode->xres * 100 / mode->yres < 156)
 713                avi_info_frame[5] |= 0x18; /* 4 : 3 */
 714        else
 715                avi_info_frame[5] |= 0x28; /* 16 : 9 */
 716
 717        for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
 718                checksum += avi_info_frame[i];
 719
 720        avi_info_frame[3] = 0x100 - checksum;
 721
 722        for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
 723                writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
 724
 725        writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
 726        writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
 727
 728        for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
 729                writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
 730
 731        writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
 732        writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
 733
 734        setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
 735}
 736
 737static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
 738                                int clk_div, int clk_double,
 739                                enum sunxi_monitor monitor)
 740{
 741        struct sunxi_hdmi_reg * const hdmi =
 742                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 743        int x, y;
 744
 745        /* Write clear interrupt status bits */
 746        writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
 747
 748        if (monitor == sunxi_monitor_hdmi)
 749                sunxi_hdmi_setup_info_frames(mode);
 750
 751        /* Set input sync enable */
 752        writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
 753
 754        /* Init various registers, select pll3 as clock source */
 755        writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
 756        writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
 757        writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
 758        writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
 759        writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
 760
 761        /* Setup clk div and doubler */
 762        clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
 763                        SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
 764        if (!clk_double)
 765                setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
 766
 767        /* Setup timing registers */
 768        writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
 769               &hdmi->video_size);
 770
 771        x = mode->hsync_len + mode->left_margin;
 772        y = mode->vsync_len + mode->upper_margin;
 773        writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
 774
 775        x = mode->right_margin;
 776        y = mode->lower_margin;
 777        writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
 778
 779        x = mode->hsync_len;
 780        y = mode->vsync_len;
 781        writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
 782
 783        if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
 784                setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
 785
 786        if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
 787                setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
 788}
 789
 790static void sunxi_hdmi_enable(void)
 791{
 792        struct sunxi_hdmi_reg * const hdmi =
 793                (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
 794
 795        udelay(100);
 796        setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
 797}
 798
 799#endif /* CONFIG_VIDEO_HDMI */
 800
 801#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 802
 803static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
 804{
 805        struct sunxi_ccm_reg * const ccm =
 806                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 807        struct sunxi_tve_reg * const tve =
 808                (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
 809
 810        /* Reset off */
 811        setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
 812        /* Clock on */
 813        setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
 814
 815        switch (monitor) {
 816        case sunxi_monitor_vga:
 817                tvencoder_mode_set(tve, tve_mode_vga);
 818                break;
 819        case sunxi_monitor_composite_pal_nc:
 820                tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
 821                break;
 822        case sunxi_monitor_composite_pal:
 823                tvencoder_mode_set(tve, tve_mode_composite_pal);
 824                break;
 825        case sunxi_monitor_composite_pal_m:
 826                tvencoder_mode_set(tve, tve_mode_composite_pal_m);
 827                break;
 828        case sunxi_monitor_composite_ntsc:
 829                tvencoder_mode_set(tve, tve_mode_composite_ntsc);
 830                break;
 831        case sunxi_monitor_none:
 832        case sunxi_monitor_dvi:
 833        case sunxi_monitor_hdmi:
 834        case sunxi_monitor_lcd:
 835                break;
 836        }
 837}
 838
 839#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
 840
 841static void sunxi_drc_init(void)
 842{
 843#ifdef CONFIG_SUNXI_GEN_SUN6I
 844        struct sunxi_ccm_reg * const ccm =
 845                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 846
 847        /* On sun6i the drc must be clocked even when in pass-through mode */
 848#ifdef CONFIG_MACH_SUN8I_A33
 849        setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
 850#endif
 851        setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
 852        clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
 853#endif
 854}
 855
 856#ifdef CONFIG_VIDEO_VGA_VIA_LCD
 857static void sunxi_vga_external_dac_enable(void)
 858{
 859        int pin;
 860
 861        pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
 862        if (pin >= 0) {
 863                gpio_request(pin, "vga_enable");
 864                gpio_direction_output(pin, 1);
 865        }
 866}
 867#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
 868
 869#ifdef CONFIG_VIDEO_LCD_SSD2828
 870static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
 871{
 872        struct ssd2828_config cfg = {
 873                .csx_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
 874                .sck_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
 875                .sdi_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
 876                .sdo_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
 877                .reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
 878                .ssd2828_tx_clk_khz  = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
 879                .ssd2828_color_depth = 24,
 880#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
 881                .mipi_dsi_number_of_data_lanes           = 4,
 882                .mipi_dsi_bitrate_per_data_lane_mbps     = 513,
 883                .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
 884                .mipi_dsi_delay_after_set_display_on_ms  = 200
 885#else
 886#error MIPI LCD panel needs configuration parameters
 887#endif
 888        };
 889
 890        if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
 891                printf("SSD2828: SPI pins are not properly configured\n");
 892                return 1;
 893        }
 894        if (cfg.reset_pin == -1) {
 895                printf("SSD2828: Reset pin is not properly configured\n");
 896                return 1;
 897        }
 898
 899        return ssd2828_init(&cfg, mode);
 900}
 901#endif /* CONFIG_VIDEO_LCD_SSD2828 */
 902
 903#ifdef CONFIG_VIDEO_LCD_PANEL_I2C
 904static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display)
 905{
 906        const char *name = CONFIG_VIDEO_LCD_PANEL_I2C_NAME;
 907        struct udevice *i2c_bus;
 908        int ret;
 909
 910        ret = uclass_get_device_by_name(UCLASS_I2C, name, &i2c_bus);
 911        if (ret)
 912                return;
 913
 914        if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
 915                /*
 916                 * The anx9804 needs 1.8V from eldo3, we do this here
 917                 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
 918                 * to avoid turning this on when using hdmi output.
 919                 */
 920                axp_set_eldo(3, 1800);
 921                anx9804_init(i2c_bus, 4,
 922                             ANX9804_DATA_RATE_1620M,
 923                             sunxi_display->depth);
 924        }
 925        if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
 926                struct udevice *chip;
 927
 928                ret = i2c_get_chip(i2c_bus, 0x5c, 1, &chip);
 929                if (ret)
 930                        return;
 931
 932                dm_i2c_reg_write(chip, 0x04, 0x42); /* Turn on the LCD */
 933        }
 934}
 935#else
 936static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display) {}
 937#endif
 938
 939static void sunxi_engines_init(void)
 940{
 941        sunxi_composer_init();
 942        sunxi_lcdc_init();
 943        sunxi_drc_init();
 944}
 945
 946static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
 947                           const struct ctfb_res_modes *mode,
 948                           unsigned int address)
 949{
 950        enum sunxi_monitor monitor = sunxi_display->monitor;
 951        int __maybe_unused clk_div, clk_double;
 952        struct sunxi_lcdc_reg * const lcdc =
 953                (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 954        struct sunxi_tve_reg * __maybe_unused const tve =
 955                (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
 956
 957        switch (sunxi_display->monitor) {
 958        case sunxi_monitor_none:
 959                break;
 960        case sunxi_monitor_dvi:
 961        case sunxi_monitor_hdmi:
 962#ifdef CONFIG_VIDEO_HDMI
 963                sunxi_composer_mode_set(mode, address, monitor);
 964                sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
 965                sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
 966                sunxi_composer_enable();
 967                lcdc_enable(lcdc, sunxi_display->depth);
 968                sunxi_hdmi_enable();
 969#endif
 970                break;
 971        case sunxi_monitor_lcd:
 972                sunxi_lcdc_panel_enable();
 973                if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
 974                        mdelay(50); /* Wait for lcd controller power on */
 975                        hitachi_tx18d42vm_init();
 976                }
 977                if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_I2C))
 978                        sunxi_panel_i2c_init(sunxi_display);
 979                sunxi_composer_mode_set(mode, address, monitor);
 980                sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
 981                sunxi_composer_enable();
 982                lcdc_enable(lcdc, sunxi_display->depth);
 983#ifdef CONFIG_VIDEO_LCD_SSD2828
 984                sunxi_ssd2828_init(mode);
 985#endif
 986                sunxi_lcdc_backlight_enable();
 987                break;
 988        case sunxi_monitor_vga:
 989#ifdef CONFIG_VIDEO_VGA
 990                sunxi_composer_mode_set(mode, address, monitor);
 991                sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
 992                sunxi_tvencoder_mode_set(monitor);
 993                sunxi_composer_enable();
 994                lcdc_enable(lcdc, sunxi_display->depth);
 995                tvencoder_enable(tve);
 996#elif defined CONFIG_VIDEO_VGA_VIA_LCD
 997                sunxi_composer_mode_set(mode, address, monitor);
 998                sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
 999                sunxi_composer_enable();
1000                lcdc_enable(lcdc, sunxi_display->depth);
1001                sunxi_vga_external_dac_enable();
1002#endif
1003                break;
1004        case sunxi_monitor_composite_pal:
1005        case sunxi_monitor_composite_ntsc:
1006        case sunxi_monitor_composite_pal_m:
1007        case sunxi_monitor_composite_pal_nc:
1008#ifdef CONFIG_VIDEO_COMPOSITE
1009                sunxi_composer_mode_set(mode, address, monitor);
1010                sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
1011                sunxi_tvencoder_mode_set(monitor);
1012                sunxi_composer_enable();
1013                lcdc_enable(lcdc, sunxi_display->depth);
1014                tvencoder_enable(tve);
1015#endif
1016                break;
1017        }
1018}
1019
1020static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1021{
1022        switch (monitor) {
1023        case sunxi_monitor_dvi:                 return "dvi";
1024        case sunxi_monitor_hdmi:                return "hdmi";
1025        case sunxi_monitor_lcd:                 return "lcd";
1026        case sunxi_monitor_vga:                 return "vga";
1027        case sunxi_monitor_composite_pal:       return "composite-pal";
1028        case sunxi_monitor_composite_ntsc:      return "composite-ntsc";
1029        case sunxi_monitor_composite_pal_m:     return "composite-pal-m";
1030        case sunxi_monitor_composite_pal_nc:    return "composite-pal-nc";
1031        case sunxi_monitor_none:                /* fall through */
1032        default:                                return "none";
1033        }
1034}
1035
1036static bool sunxi_has_hdmi(void)
1037{
1038#ifdef CONFIG_VIDEO_HDMI
1039        return true;
1040#else
1041        return false;
1042#endif
1043}
1044
1045static bool sunxi_has_lcd(void)
1046{
1047        char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1048
1049        return lcd_mode[0] != 0;
1050}
1051
1052static bool sunxi_has_vga(void)
1053{
1054#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1055        return true;
1056#else
1057        return false;
1058#endif
1059}
1060
1061static bool sunxi_has_composite(void)
1062{
1063#ifdef CONFIG_VIDEO_COMPOSITE
1064        return true;
1065#else
1066        return false;
1067#endif
1068}
1069
1070static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1071{
1072        if (allow_hdmi && sunxi_has_hdmi())
1073                return sunxi_monitor_dvi;
1074        else if (sunxi_has_lcd())
1075                return sunxi_monitor_lcd;
1076        else if (sunxi_has_vga())
1077                return sunxi_monitor_vga;
1078        else if (sunxi_has_composite())
1079                return sunxi_monitor_composite_pal;
1080        else
1081                return sunxi_monitor_none;
1082}
1083
1084static int sunxi_de_probe(struct udevice *dev)
1085{
1086        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1087        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1088        struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
1089        const struct ctfb_res_modes *mode;
1090        struct ctfb_res_modes custom;
1091        const char *options;
1092#ifdef CONFIG_VIDEO_HDMI
1093        int hpd, hpd_delay, edid;
1094        bool hdmi_present;
1095#endif
1096        int i, overscan_offset, overscan_x, overscan_y;
1097        unsigned int fb_dma_addr;
1098        char mon[16];
1099        char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1100
1101        video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1102                                 &sunxi_display->depth, &options);
1103#ifdef CONFIG_VIDEO_HDMI
1104        hpd = video_get_option_int(options, "hpd", 1);
1105        hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1106        edid = video_get_option_int(options, "edid", 1);
1107#endif
1108        overscan_x = video_get_option_int(options, "overscan_x", -1);
1109        overscan_y = video_get_option_int(options, "overscan_y", -1);
1110        sunxi_display->monitor = sunxi_get_default_mon(true);
1111        video_get_option_string(options, "monitor", mon, sizeof(mon),
1112                                sunxi_get_mon_desc(sunxi_display->monitor));
1113        for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1114                if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1115                        sunxi_display->monitor = i;
1116                        break;
1117                }
1118        }
1119        if (i > SUNXI_MONITOR_LAST)
1120                printf("Unknown monitor: '%s', falling back to '%s'\n",
1121                       mon, sunxi_get_mon_desc(sunxi_display->monitor));
1122
1123#ifdef CONFIG_VIDEO_HDMI
1124        /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1125        if (sunxi_display->monitor == sunxi_monitor_dvi ||
1126            sunxi_display->monitor == sunxi_monitor_hdmi) {
1127                /* Always call hdp_detect, as it also enables clocks, etc. */
1128                hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1129                if (hdmi_present && edid) {
1130                        printf("HDMI connected: ");
1131                        if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
1132                                mode = &custom;
1133                        else
1134                                hdmi_present = false;
1135                }
1136                /* Fall back to EDID in case HPD failed */
1137                if (edid && !hdmi_present) {
1138                        if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
1139                                mode = &custom;
1140                                hdmi_present = true;
1141                        }
1142                }
1143                /* Shut down when display was not found */
1144                if ((hpd || edid) && !hdmi_present) {
1145                        sunxi_hdmi_shutdown();
1146                        sunxi_display->monitor = sunxi_get_default_mon(false);
1147                } /* else continue with hdmi/dvi without a cable connected */
1148        }
1149#endif
1150
1151        switch (sunxi_display->monitor) {
1152        case sunxi_monitor_none:
1153                printf("Unknown monitor\n");
1154                return -EINVAL;
1155        case sunxi_monitor_dvi:
1156        case sunxi_monitor_hdmi:
1157                if (!sunxi_has_hdmi()) {
1158                        printf("HDMI/DVI not supported on this board\n");
1159                        sunxi_display->monitor = sunxi_monitor_none;
1160                        return -EINVAL;
1161                }
1162                break;
1163        case sunxi_monitor_lcd:
1164                if (!sunxi_has_lcd()) {
1165                        printf("LCD not supported on this board\n");
1166                        sunxi_display->monitor = sunxi_monitor_none;
1167                        return -EINVAL;
1168                }
1169                sunxi_display->depth = video_get_params(&custom, lcd_mode);
1170                mode = &custom;
1171                break;
1172        case sunxi_monitor_vga:
1173                if (!sunxi_has_vga()) {
1174                        printf("VGA not supported on this board\n");
1175                        sunxi_display->monitor = sunxi_monitor_none;
1176                        return -EINVAL;
1177                }
1178                sunxi_display->depth = 18;
1179                break;
1180        case sunxi_monitor_composite_pal:
1181        case sunxi_monitor_composite_ntsc:
1182        case sunxi_monitor_composite_pal_m:
1183        case sunxi_monitor_composite_pal_nc:
1184                if (!sunxi_has_composite()) {
1185                        printf("Composite video not supported on this board\n");
1186                        sunxi_display->monitor = sunxi_monitor_none;
1187                        return -EINVAL;
1188                }
1189                if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
1190                    sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
1191                        mode = &composite_video_modes[0];
1192                else
1193                        mode = &composite_video_modes[1];
1194                sunxi_display->depth = 24;
1195                break;
1196        }
1197
1198        /* Yes these defaults are quite high, overscan on composite sucks... */
1199        if (overscan_x == -1)
1200                overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
1201        if (overscan_y == -1)
1202                overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
1203
1204        sunxi_display->fb_size = plat->size;
1205        overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1206        /* We want to keep the fb_base for simplefb page aligned, where as
1207         * the sunxi dma engines will happily accept an unaligned address. */
1208        if (overscan_offset)
1209                sunxi_display->fb_size += 0x1000;
1210
1211        printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1212               mode->xres, mode->yres,
1213               (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1214               sunxi_get_mon_desc(sunxi_display->monitor),
1215               overscan_x, overscan_y);
1216
1217        sunxi_display->fb_addr = plat->base;
1218        sunxi_engines_init();
1219
1220#ifdef CONFIG_EFI_LOADER
1221        efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
1222                           EFI_RESERVED_MEMORY_TYPE);
1223#endif
1224
1225        fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
1226        if (overscan_offset) {
1227                fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1228                sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
1229                memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
1230                flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
1231        }
1232        sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
1233
1234        /* The members of struct video_priv to be set by the driver. */
1235        uc_priv->bpix = VIDEO_BPP32;
1236        uc_priv->xsize = mode->xres;
1237        uc_priv->ysize = mode->yres;
1238
1239        video_set_flush_dcache(dev, true);
1240
1241        return 0;
1242}
1243
1244static int sunxi_de_bind(struct udevice *dev)
1245{
1246        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1247
1248        plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
1249
1250        return 0;
1251}
1252
1253static const struct video_ops sunxi_de_ops = {
1254};
1255
1256U_BOOT_DRIVER(sunxi_de) = {
1257        .name   = "sunxi_de",
1258        .id     = UCLASS_VIDEO,
1259        .ops    = &sunxi_de_ops,
1260        .bind   = sunxi_de_bind,
1261        .probe  = sunxi_de_probe,
1262        .priv_auto = sizeof(struct sunxi_display_priv),
1263        .flags  = DM_FLAG_PRE_RELOC,
1264};
1265
1266U_BOOT_DRVINFO(sunxi_de) = {
1267        .name = "sunxi_de"
1268};
1269
1270/*
1271 * Simplefb support.
1272 */
1273#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1274int sunxi_simplefb_setup(void *blob)
1275{
1276        struct sunxi_display_priv *sunxi_display;
1277        struct video_priv *uc_priv;
1278        struct udevice *de;
1279        int offset, ret;
1280        u64 start, size;
1281        const char *pipeline = NULL;
1282
1283#ifdef CONFIG_MACH_SUN4I
1284#define PIPELINE_PREFIX "de_fe0-"
1285#else
1286#define PIPELINE_PREFIX
1287#endif
1288
1289        ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
1290        if (ret) {
1291                printf("DE not present\n");
1292                return 0;
1293        } else if (!device_active(de)) {
1294                printf("DE is present but not probed\n");
1295                return 0;
1296        }
1297
1298        uc_priv = dev_get_uclass_priv(de);
1299        sunxi_display = dev_get_priv(de);
1300
1301        switch (sunxi_display->monitor) {
1302        case sunxi_monitor_none:
1303                return 0;
1304        case sunxi_monitor_dvi:
1305        case sunxi_monitor_hdmi:
1306                pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1307                break;
1308        case sunxi_monitor_lcd:
1309                pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1310                break;
1311        case sunxi_monitor_vga:
1312#ifdef CONFIG_VIDEO_VGA
1313                pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1314#elif defined CONFIG_VIDEO_VGA_VIA_LCD
1315                pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1316#endif
1317                break;
1318        case sunxi_monitor_composite_pal:
1319        case sunxi_monitor_composite_ntsc:
1320        case sunxi_monitor_composite_pal_m:
1321        case sunxi_monitor_composite_pal_nc:
1322                pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1323                break;
1324        }
1325
1326        offset = sunxi_simplefb_fdt_match(blob, pipeline);
1327        if (offset < 0) {
1328                eprintf("Cannot setup simplefb: node not found\n");
1329                return 0; /* Keep older kernels working */
1330        }
1331
1332        /*
1333         * Do not report the framebuffer as free RAM to the OS, note we cannot
1334         * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1335         * and e.g. Linux refuses to iomap RAM on ARM, see:
1336         * linux/arch/arm/mm/ioremap.c around line 301.
1337         */
1338        start = gd->bd->bi_dram[0].start;
1339        size = sunxi_display->fb_addr - start;
1340        ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1341        if (ret) {
1342                eprintf("Cannot setup simplefb: Error reserving memory\n");
1343                return ret;
1344        }
1345
1346        ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
1347                                      uc_priv->xsize, uc_priv->ysize,
1348                                      VNBYTES(uc_priv->bpix) * uc_priv->xsize,
1349                                      "x8r8g8b8");
1350        if (ret)
1351                eprintf("Cannot setup simplefb: Error setting properties\n");
1352
1353        return ret;
1354}
1355#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
1356