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