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