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