[U-Boot] [PATCH v3 08/18] tegra: Add SOC support for display/lcd

Adam Jiang chaoj at nvidia.com
Thu Jul 19 10:03:04 CEST 2012


On Thu, Jul 12, 2012 at 11:25:08PM +0800, Simon Glass wrote:
> From: Wei Ni <wni at nvidia.com>
> 
> Add support for the LCD peripheral at the Tegra2 SOC level. A separate
> LCD driver will use this functionality to configure the display.
> 
> Mayuresh Kulkarni:
> - changes to remove bitfields and clean up for submission
> 
> Simon Glass:
> - simplify code, move clock control into here, clean-up
> 
> Signed-off-by: Mayuresh Kulkarni <mkulkarni at nvidia.com>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> Changes in v3:
> - Add probe function to read in fdt parameters in display driver
> - Separate display driver and LCD driver more in fdt
> 
>  arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
>  arch/arm/cpu/armv7/tegra2/display.c        |  389 ++++++++++++++++++++
>  arch/arm/include/asm/arch-tegra2/dc.h      |  544 ++++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-tegra2/display.h |  152 ++++++++
>  include/fdtdec.h                           |    1 +
>  lib/fdtdec.c                               |    1 +
>  6 files changed, 1088 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/cpu/armv7/tegra2/display.c
>  create mode 100644 arch/arm/include/asm/arch-tegra2/dc.h
>  create mode 100644 arch/arm/include/asm/arch-tegra2/display.h
> 
> diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile
> index 5d271c4..79e1319 100644
> --- a/arch/arm/cpu/armv7/tegra2/Makefile
> +++ b/arch/arm/cpu/armv7/tegra2/Makefile
> @@ -40,7 +40,7 @@ COBJS-$(CONFIG_TEGRA_PMU) += pmu.o
>  COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
>  COBJS-$(CONFIG_TEGRA2_LP0) += crypto.o warmboot.o warmboot_avp.o
>  COBJS-$(CONFIG_CMD_ENTERRCM) += cmd_enterrcm.o
> -COBJS-$(CONFIG_VIDEO_TEGRA) += pwm.o
> +COBJS-$(CONFIG_VIDEO_TEGRA) += display.o pwm.o
> 
>  COBJS  := $(COBJS-y)
>  SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
> diff --git a/arch/arm/cpu/armv7/tegra2/display.c b/arch/arm/cpu/armv7/tegra2/display.c
> new file mode 100644
> index 0000000..267e89e
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/tegra2/display.c
> @@ -0,0 +1,389 @@
> +/*
> + *  (C) Copyright 2010
> + *  NVIDIA Corporation <www.nvidia.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/arch/clk_rst.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/timer.h>
> +#include <asm/arch/tegra2.h>
> +#include <asm/arch/display.h>
> +#include <asm/arch/dc.h>
> +
> +static struct fdt_disp_config config;
> +
> +static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
> +{
> +       unsigned h_dda, v_dda;
> +       unsigned long val;
> +
> +       val = readl(&dc->cmd.disp_win_header);
> +       val |= WINDOW_A_SELECT;
> +       writel(val, &dc->cmd.disp_win_header);
> +
> +       writel(win->fmt, &dc->win.color_depth);
> +
> +       val = readl(&dc->win.byte_swap);
> +       val |= BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT;
> +       writel(val, &dc->win.byte_swap);
> +
> +       val = win->out_x << H_POSITION_SHIFT;
> +       val |= win->out_y << V_POSITION_SHIFT;
> +       writel(val, &dc->win.pos);
> +
> +       val = win->out_w << H_SIZE_SHIFT;
> +       val |= win->out_h << V_SIZE_SHIFT;
> +       writel(val, &dc->win.size);
> +
> +       val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT;
> +       val |= win->h << V_PRESCALED_SIZE_SHIFT;
> +       writel(val, &dc->win.prescaled_size);
> +
> +       writel(0, &dc->win.h_initial_dda);
> +       writel(0, &dc->win.v_initial_dda);
> +
> +       h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1);
> +       v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1);
> +
> +       val = h_dda << H_DDA_INC_SHIFT;
> +       val |= v_dda << V_DDA_INC_SHIFT;
> +       writel(val, &dc->win.dda_increment);
> +
> +       writel(win->stride, &dc->win.line_stride);
> +       writel(0, &dc->win.buf_stride);
> +
> +       val = WIN_ENABLE;
> +       if (win->bpp < 24)
> +               val |= COLOR_EXPAND;
> +       writel(val, &dc->win.win_opt);
> +
> +       writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr);
> +       writel(win->x, &dc->winbuf.addr_h_offset);
> +       writel(win->y, &dc->winbuf.addr_v_offset);
> +
> +       writel(0xff00, &dc->win.blend_nokey);
> +       writel(0xff00, &dc->win.blend_1win);
> +
> +       val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
> +       val |= GENERAL_UPDATE | WIN_A_UPDATE;
> +       writel(val, &dc->cmd.state_ctrl);
> +}
> +
> +static void write_pair(struct fdt_disp_config *config, int item, u32 *reg)
> +{
> +       writel(config->horiz_timing[item] |
> +                       (config->vert_timing[item] << 16), reg);
> +}
> +
> +static int update_display_mode(struct dc_disp_reg *disp,
> +               struct fdt_disp_config *config)
> +{
> +       unsigned long val;
> +       unsigned long rate;
> +       unsigned long div;
> +
> +       writel(0x0, &disp->disp_timing_opt);
> +       write_pair(config, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync);
> +       write_pair(config, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width);
> +       write_pair(config, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch);
> +       write_pair(config, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch);
> +
> +       writel(config->width | (config->height << 16), &disp->disp_active);
> +
> +       val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
> +       val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
> +       writel(val, &disp->data_enable_opt);
> +
> +       val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT;
> +       val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
> +       val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
> +       writel(val, &disp->disp_interface_ctrl);
> +
> +       /*
> +        * The pixel clock divider is in 7.1 format (where the bottom bit
> +        * represents 0.5). Here we calculate the divider needed to get from
> +        * the display clock (typically 600MHz) to the pixel clock. We round
> +        * up or down as requried.
> +        */
> +       rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL);
> +       div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2;
> +       debug("Display clock %lu, divider %lu\n", rate, div);
> +
> +       writel(0x00010001, &disp->shift_clk_opt);
> +
> +       val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
> +       val |= div << SHIFT_CLK_DIVIDER_SHIFT;
> +       writel(val, &disp->disp_clk_ctrl);
> +
> +       return 0;
> +}
> +
> +/* Start up the display and turn on power to PWMs */
> +static void basic_init(struct dc_cmd_reg *cmd)
> +{
> +       u32 val;
> +
> +       writel(0x00000100, &cmd->gen_incr_syncpt_ctrl);
> +       writel(0x0000011a, &cmd->cont_syncpt_vsync);
> +       writel(0x00000000, &cmd->int_type);
> +       writel(0x00000000, &cmd->int_polarity);
> +       writel(0x00000000, &cmd->int_mask);
> +       writel(0x00000000, &cmd->int_enb);
> +
> +       val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE;
> +       val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE;
> +       val |= PM1_ENABLE;
> +       writel(val, &cmd->disp_pow_ctrl);
> +
> +       val = readl(&cmd->disp_cmd);
> +       val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT;
> +       writel(val, &cmd->disp_cmd);
> +}
> +
> +static void basic_init_timer(struct dc_disp_reg *disp)
> +{
> +       writel(0x00000020, &disp->mem_high_pri);
> +       writel(0x00000001, &disp->mem_high_pri_timer);
> +}
> +
> +static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +};
> +
> +static const u32 rgb_polarity_tab[PIN_REG_COUNT] = {
> +       0x00000000,
> +       0x01000000,
> +       0x00000000,
> +       0x00000000,
> +};
> +
> +static const u32 rgb_data_tab[PIN_REG_COUNT] = {
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +};
> +
> +static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = {
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +       0x00000000,
> +       0x00210222,
> +       0x00002200,
> +       0x00020000,
> +};
> +
> +static void rgb_enable(struct dc_com_reg *com)
> +{
> +       int i;
> +
> +       for (i = 0; i < PIN_REG_COUNT; i++) {
> +               writel(rgb_enb_tab[i], &com->pin_output_enb[i]);
> +               writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]);
> +               writel(rgb_data_tab[i], &com->pin_output_data[i]);
> +       }
> +
> +       for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
> +               writel(rgb_sel_tab[i], &com->pin_output_sel[i]);
> +}
> +
> +int setup_window(struct disp_ctl_win *win, struct fdt_disp_config *config)
> +{
> +       win->x = 0;
> +       win->y = 0;
> +       win->w = config->width;
> +       win->h = config->height;
> +       win->out_x = 0;
> +       win->out_y = 0;
> +       win->out_w = config->width;
> +       win->out_h = config->height;
> +       win->phys_addr = config->frame_buffer;
> +       win->stride = config->width * (1 << config->log2_bpp) / 8;
> +       debug("%s: depth = %d\n", __func__, config->log2_bpp);
> +       switch (config->log2_bpp) {
> +       case 5:
> +       case 24:
> +               win->fmt = COLOR_DEPTH_R8G8B8A8;
> +               win->bpp = 32;
> +               break;
> +       case 4:
> +               win->fmt = COLOR_DEPTH_B5G6R5;
> +               win->bpp = 16;
> +               break;
> +
> +       default:
> +               debug("Unsupported LCD bit depth");
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +struct fdt_disp_config *tegra_display_get_config(void)
> +{
> +       return config.valid ? &config : NULL;
> +}
> +
> +static void debug_timing(const char *name, unsigned int timing[])
> +{
> +#ifdef DEBUG
> +       int i;
> +
> +       debug("%s timing: ", name);
> +       for (i = 0; i < FDT_LCD_TIMING_COUNT; i++)
> +               debug("%d ", timing[i]);
> +       debug("\n");
> +#endif
> +}
> +
> +/**
> + * Decode the display controller information from the fdt.
> + *
> + * @param blob         fdt blob
> + * @param config       structure to store fdt config into
> + * @return 0 if ok, -ve on error
> + */
> +static int tegra_display_decode_config(const void *blob,
> +                                      struct fdt_disp_config *config)
> +{
> +       int front, back, ref;
> +       int node, rgb;
> +       int bpp, bit;
> +
> +       node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_DC);
> +       if (node < 0) {
> +               debug("%s: Cannot find display controller node in fdt\n",
> +                     __func__);
> +               return node;
> +       }
> +       config->disp = (struct disp_ctlr *)fdtdec_get_addr(blob, node, "reg");
> +       if (!config->disp) {
> +               debug("%s: No display controller address\n", __func__);
> +               return -1;
> +       }
> +
> +       rgb = fdt_subnode_offset(blob, node, "rgb");
> +
> +       config->frame_buffer = fdtdec_get_addr(blob, rgb,
> +                                              "nvidia,frame-buffer");
> +       config->width = fdtdec_get_int(blob, rgb, "xres", -1);
> +       config->height = fdtdec_get_int(blob, rgb, "yres", -1);
> +       bpp = fdtdec_get_int(blob, rgb, "nvidia,bits-per-pixel", -1);
> +       bit = ffs(bpp) - 1;
> +       if (bpp == (1 << bit))
> +               config->log2_bpp = bit;
> +       else
> +               config->log2_bpp = bpp;
> +       config->bpp = bpp;
> +       config->pixel_clock = fdtdec_get_int(blob, rgb, "clock", 0);
> +       if (!config->pixel_clock || bpp == -1 ||
> +                       config->width == -1 || config->height == -1) {
> +               debug("%s: Pixel parameters missing\n", __func__);
> +               return -FDT_ERR_NOTFOUND;
> +       }
> +
> +       /* Use a ref-to-sync of 1 always, and take this from the front porch */

ref-to-sync is supposed to be 1 here.

> +       back = fdtdec_get_int(blob, rgb, "left-margin", -1);
> +       front = fdtdec_get_int(blob, rgb, "right-margin", -1);
> +       ref = fdtdec_get_int(blob, rgb, "hsync-len", -1);
> +       if ((back | front | ref) == -1) {
> +               debug("%s: Horizontal parameters missing\n", __func__);
> +               return -FDT_ERR_NOTFOUND;
> +       }
> +       config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 11;

It is assigned to 11.

/Adam

> +       config->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
> +       config->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
> +       config->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
> +               config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC];
> +       debug_timing("horiz", config->horiz_timing);
> +
> +       back = fdtdec_get_int(blob, rgb, "upper-margin", -1);
> +       front = fdtdec_get_int(blob, rgb, "lower-margin", -1);
> +       ref = fdtdec_get_int(blob, rgb, "vsync-len", -1);
> +       if ((back | front | ref) == -1) {
> +               debug("%s: Vertical parameters missing\n", __func__);
> +               return -FDT_ERR_NOTFOUND;
> +       }
> +       config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
> +       config->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
> +       config->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
> +       config->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
> +               config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC];
> +       debug_timing("vert", config->horiz_timing);
> +
> +       config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
> +
> +       config->valid = 1;      /* we have a valid configuration */
> +
> +       return 0;
> +}
> +
> +int tegra_display_probe(const void *blob, void *default_lcd_base)
> +{
> +       struct disp_ctl_win window;
> +       struct dc_ctlr *dc;
> +
> +       if (tegra_display_decode_config(blob, &config))
> +               return -1;
> +
> +       /*
> +        * The framebuffer address should be specified in the device tree.
> +        * This FDT value should be the same as the one defined in Linux kernel;
> +        * otherwise, it causes screen flicker. The FDT value overrides the
> +        * framebuffer allocated at the top of memory by board_init_f().
> +        *
> +        * If the framebuffer address is not defined in the FDT, falls back to
> +        * use the address allocated by board_init_f().
> +        */
> +       if (config.frame_buffer == FDT_ADDR_T_NONE)
> +               config.frame_buffer = (u32)default_lcd_base;
> +
> +       dc = (struct dc_ctlr *)config.disp;
> +
> +       /*
> +        * A header file for clock constants was NAKed upstream.
> +        * TODO: Put this into the FDT and fdt_lcd struct when we have clock
> +        * support there
> +        */
> +       clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH,
> +                              144 * 1000000);
> +       clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL,
> +                              600 * 1000000);
> +       basic_init(&dc->cmd);
> +       basic_init_timer(&dc->disp);
> +       rgb_enable(&dc->com);
> +
> +       if (config.pixel_clock)
> +               update_display_mode(&dc->disp, &config);
> +
> +       if (setup_window(&window, &config))
> +               return -1;
> +
> +       update_window(dc, &window);
> +
> +       return 0;
> +}
> diff --git a/arch/arm/include/asm/arch-tegra2/dc.h b/arch/arm/include/asm/arch-tegra2/dc.h
> new file mode 100644
> index 0000000..46c4137
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-tegra2/dc.h
> @@ -0,0 +1,544 @@
> +/*
> + *  (C) Copyright 2010
> + *  NVIDIA Corporation <www.nvidia.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __ASM_ARCH_TEGRA_DC_H
> +#define __ASM_ARCH_TEGRA_DC_H
> +
> +/* Register definitions for the Tegra display controller */
> +
> +/* CMD register 0x000 ~ 0x43 */
> +struct dc_cmd_reg {
> +       /* Address 0x000 ~ 0x002 */
> +       uint gen_incr_syncpt;           /* _CMD_GENERAL_INCR_SYNCPT_0 */
> +       uint gen_incr_syncpt_ctrl;      /* _CMD_GENERAL_INCR_SYNCPT_CNTRL_0 */
> +       uint gen_incr_syncpt_err;       /* _CMD_GENERAL_INCR_SYNCPT_ERROR_0 */
> +
> +       uint reserved0[5];              /* reserved_0[5] */
> +
> +       /* Address 0x008 ~ 0x00a */
> +       uint win_a_incr_syncpt;         /* _CMD_WIN_A_INCR_SYNCPT_0 */
> +       uint win_a_incr_syncpt_ctrl;    /* _CMD_WIN_A_INCR_SYNCPT_CNTRL_0 */
> +       uint win_a_incr_syncpt_err;     /* _CMD_WIN_A_INCR_SYNCPT_ERROR_0 */
> +
> +       uint reserved1[5];              /* reserved_1[5] */
> +
> +       /* Address 0x010 ~ 0x012 */
> +       uint win_b_incr_syncpt;         /* _CMD_WIN_B_INCR_SYNCPT_0 */
> +       uint win_b_incr_syncpt_ctrl;    /* _CMD_WIN_B_INCR_SYNCPT_CNTRL_0 */
> +       uint win_b_incr_syncpt_err;     /* _CMD_WIN_B_INCR_SYNCPT_ERROR_0 */
> +
> +       uint reserved2[5];              /* reserved_2[5] */
> +
> +       /* Address 0x018 ~ 0x01a */
> +       uint win_c_incr_syncpt;         /* _CMD_WIN_C_INCR_SYNCPT_0 */
> +       uint win_c_incr_syncpt_ctrl;    /* _CMD_WIN_C_INCR_SYNCPT_CNTRL_0 */
> +       uint win_c_incr_syncpt_err;     /* _CMD_WIN_C_INCR_SYNCPT_ERROR_0 */
> +
> +       uint reserved3[13];             /* reserved_3[13] */
> +
> +       /* Address 0x028 */
> +       uint cont_syncpt_vsync;         /* _CMD_CONT_SYNCPT_VSYNC_0 */
> +
> +       uint reserved4[7];              /* reserved_4[7] */
> +
> +       /* Address 0x030 ~ 0x033 */
> +       uint ctxsw;                     /* _CMD_CTXSW_0 */
> +       uint disp_cmd_opt0;             /* _CMD_DISPLAY_COMMAND_OPTION0_0 */
> +       uint disp_cmd;                  /* _CMD_DISPLAY_COMMAND_0 */
> +       uint sig_raise;                 /* _CMD_SIGNAL_RAISE_0 */
> +
> +       uint reserved5[2];              /* reserved_0[2] */
> +
> +       /* Address 0x036 ~ 0x03e */
> +       uint disp_pow_ctrl;             /* _CMD_DISPLAY_POWER_CONTROL_0 */
> +       uint int_stat;                  /* _CMD_INT_STATUS_0 */
> +       uint int_mask;                  /* _CMD_INT_MASK_0 */
> +       uint int_enb;                   /* _CMD_INT_ENABLE_0 */
> +       uint int_type;                  /* _CMD_INT_TYPE_0 */
> +       uint int_polarity;              /* _CMD_INT_POLARITY_0 */
> +       uint sig_raise1;                /* _CMD_SIGNAL_RAISE1_0 */
> +       uint sig_raise2;                /* _CMD_SIGNAL_RAISE2_0 */
> +       uint sig_raise3;                /* _CMD_SIGNAL_RAISE3_0 */
> +
> +       uint reserved6;                 /* reserved_6 */
> +
> +       /* Address 0x040 ~ 0x043 */
> +       uint state_access;              /* _CMD_STATE_ACCESS_0 */
> +       uint state_ctrl;                /* _CMD_STATE_CONTROL_0 */
> +       uint disp_win_header;           /* _CMD_DISPLAY_WINDOW_HEADER_0 */
> +       uint reg_act_ctrl;              /* _CMD_REG_ACT_CONTROL_0 */
> +};
> +
> +enum {
> +       PIN_REG_COUNT           = 4,
> +       PIN_OUTPUT_SEL_COUNT    = 7,
> +};
> +
> +/* COM register 0x300 ~ 0x329 */
> +struct dc_com_reg {
> +       /* Address 0x300 ~ 0x301 */
> +       uint crc_ctrl;                  /* _COM_CRC_CONTROL_0 */
> +       uint crc_checksum;              /* _COM_CRC_CHECKSUM_0 */
> +
> +       /* _COM_PIN_OUTPUT_ENABLE0/1/2/3_0: Address 0x302 ~ 0x305 */
> +       uint pin_output_enb[PIN_REG_COUNT];
> +
> +       /* _COM_PIN_OUTPUT_POLARITY0/1/2/3_0: Address 0x306 ~ 0x309 */
> +       uint pin_output_polarity[PIN_REG_COUNT];
> +
> +       /* _COM_PIN_OUTPUT_DATA0/1/2/3_0: Address 0x30a ~ 0x30d */
> +       uint pin_output_data[PIN_REG_COUNT];
> +
> +       /* _COM_PIN_INPUT_ENABLE0_0: Address 0x30e ~ 0x311 */
> +       uint pin_input_enb[PIN_REG_COUNT];
> +
> +       /* Address 0x312 ~ 0x313 */
> +       uint pin_input_data0;           /* _COM_PIN_INPUT_DATA0_0 */
> +       uint pin_input_data1;           /* _COM_PIN_INPUT_DATA1_0 */
> +
> +       /* _COM_PIN_OUTPUT_SELECT0/1/2/3/4/5/6_0: Address 0x314 ~ 0x31a */
> +       uint pin_output_sel[PIN_OUTPUT_SEL_COUNT];
> +
> +       /* Address 0x31b ~ 0x329 */
> +       uint pin_misc_ctrl;             /* _COM_PIN_MISC_CONTROL_0 */
> +       uint pm0_ctrl;                  /* _COM_PM0_CONTROL_0 */
> +       uint pm0_duty_cycle;            /* _COM_PM0_DUTY_CYCLE_0 */
> +       uint pm1_ctrl;                  /* _COM_PM1_CONTROL_0 */
> +       uint pm1_duty_cycle;            /* _COM_PM1_DUTY_CYCLE_0 */
> +       uint spi_ctrl;                  /* _COM_SPI_CONTROL_0 */
> +       uint spi_start_byte;            /* _COM_SPI_START_BYTE_0 */
> +       uint hspi_wr_data_ab;           /* _COM_HSPI_WRITE_DATA_AB_0 */
> +       uint hspi_wr_data_cd;           /* _COM_HSPI_WRITE_DATA_CD */
> +       uint hspi_cs_dc;                /* _COM_HSPI_CS_DC_0 */
> +       uint scratch_reg_a;             /* _COM_SCRATCH_REGISTER_A_0 */
> +       uint scratch_reg_b;             /* _COM_SCRATCH_REGISTER_B_0 */
> +       uint gpio_ctrl;                 /* _COM_GPIO_CTRL_0 */
> +       uint gpio_debounce_cnt;         /* _COM_GPIO_DEBOUNCE_COUNTER_0 */
> +       uint crc_checksum_latched;      /* _COM_CRC_CHECKSUM_LATCHED_0 */
> +};
> +
> +enum dc_disp_h_pulse_pos {
> +       H_PULSE0_POSITION_A,
> +       H_PULSE0_POSITION_B,
> +       H_PULSE0_POSITION_C,
> +       H_PULSE0_POSITION_D,
> +       H_PULSE0_POSITION_COUNT,
> +};
> +
> +struct _disp_h_pulse {
> +       /* _DISP_H_PULSE0/1/2_CONTROL_0 */
> +       uint h_pulse_ctrl;
> +       /* _DISP_H_PULSE0/1/2_POSITION_A/B/C/D_0 */
> +       uint h_pulse_pos[H_PULSE0_POSITION_COUNT];
> +};
> +
> +enum dc_disp_v_pulse_pos {
> +       V_PULSE0_POSITION_A,
> +       V_PULSE0_POSITION_B,
> +       V_PULSE0_POSITION_C,
> +       V_PULSE0_POSITION_COUNT,
> +};
> +
> +struct _disp_v_pulse0 {
> +       /* _DISP_H_PULSE0/1_CONTROL_0 */
> +       uint v_pulse_ctrl;
> +       /* _DISP_H_PULSE0/1_POSITION_A/B/C_0 */
> +       uint v_pulse_pos[V_PULSE0_POSITION_COUNT];
> +};
> +
> +struct _disp_v_pulse2 {
> +       /* _DISP_H_PULSE2/3_CONTROL_0 */
> +       uint v_pulse_ctrl;
> +       /* _DISP_H_PULSE2/3_POSITION_A_0 */
> +       uint v_pulse_pos_a;
> +};
> +
> +enum dc_disp_h_pulse_reg {
> +       H_PULSE0,
> +       H_PULSE1,
> +       H_PULSE2,
> +       H_PULSE_COUNT,
> +};
> +
> +enum dc_disp_pp_select {
> +       PP_SELECT_A,
> +       PP_SELECT_B,
> +       PP_SELECT_C,
> +       PP_SELECT_D,
> +       PP_SELECT_COUNT,
> +};
> +
> +/* DISP register 0x400 ~ 0x4c1 */
> +struct dc_disp_reg {
> +       /* Address 0x400 ~ 0x40a */
> +       uint disp_signal_opt0;          /* _DISP_DISP_SIGNAL_OPTIONS0_0 */
> +       uint disp_signal_opt1;          /* _DISP_DISP_SIGNAL_OPTIONS1_0 */
> +       uint disp_win_opt;              /* _DISP_DISP_WIN_OPTIONS_0 */
> +       uint mem_high_pri;              /* _DISP_MEM_HIGH_PRIORITY_0 */
> +       uint mem_high_pri_timer;        /* _DISP_MEM_HIGH_PRIORITY_TIMER_0 */
> +       uint disp_timing_opt;           /* _DISP_DISP_TIMING_OPTIONS_0 */
> +       uint ref_to_sync;               /* _DISP_REF_TO_SYNC_0 */
> +       uint sync_width;                /* _DISP_SYNC_WIDTH_0 */
> +       uint back_porch;                /* _DISP_BACK_PORCH_0 */
> +       uint disp_active;               /* _DISP_DISP_ACTIVE_0 */
> +       uint front_porch;               /* _DISP_FRONT_PORCH_0 */
> +
> +       /* Address 0x40b ~ 0x419: _DISP_H_PULSE0/1/2_  */
> +       struct _disp_h_pulse h_pulse[H_PULSE_COUNT];
> +
> +       /* Address 0x41a ~ 0x421 */
> +       struct _disp_v_pulse0 v_pulse0; /* _DISP_V_PULSE0_ */
> +       struct _disp_v_pulse0 v_pulse1; /* _DISP_V_PULSE1_ */
> +
> +       /* Address 0x422 ~ 0x425 */
> +       struct _disp_v_pulse2 v_pulse3; /* _DISP_V_PULSE2_ */
> +       struct _disp_v_pulse2 v_pulse4; /* _DISP_V_PULSE3_ */
> +
> +       /* Address 0x426 ~ 0x429 */
> +       uint m0_ctrl;                   /* _DISP_M0_CONTROL_0 */
> +       uint m1_ctrl;                   /* _DISP_M1_CONTROL_0 */
> +       uint di_ctrl;                   /* _DISP_DI_CONTROL_0 */
> +       uint pp_ctrl;                   /* _DISP_PP_CONTROL_0 */
> +
> +       /* Address 0x42a ~ 0x42d: _DISP_PP_SELECT_A/B/C/D_0 */
> +       uint pp_select[PP_SELECT_COUNT];
> +
> +       /* Address 0x42e ~ 0x435 */
> +       uint disp_clk_ctrl;             /* _DISP_DISP_CLOCK_CONTROL_0 */
> +       uint disp_interface_ctrl;       /* _DISP_DISP_INTERFACE_CONTROL_0 */
> +       uint disp_color_ctrl;           /* _DISP_DISP_COLOR_CONTROL_0 */
> +       uint shift_clk_opt;             /* _DISP_SHIFT_CLOCK_OPTIONS_0 */
> +       uint data_enable_opt;           /* _DISP_DATA_ENABLE_OPTIONS_0 */
> +       uint serial_interface_opt;      /* _DISP_SERIAL_INTERFACE_OPTIONS_0 */
> +       uint lcd_spi_opt;               /* _DISP_LCD_SPI_OPTIONS_0 */
> +       uint border_color;              /* _DISP_BORDER_COLOR_0 */
> +
> +       /* Address 0x436 ~ 0x439 */
> +       uint color_key0_lower;          /* _DISP_COLOR_KEY0_LOWER_0 */
> +       uint color_key0_upper;          /* _DISP_COLOR_KEY0_UPPER_0 */
> +       uint color_key1_lower;          /* _DISP_COLOR_KEY1_LOWER_0 */
> +       uint color_key1_upper;          /* _DISP_COLOR_KEY1_UPPER_0 */
> +
> +       uint reserved0[2];              /* reserved_0[2] */
> +
> +       /* Address 0x43c ~ 0x442 */
> +       uint cursor_foreground;         /* _DISP_CURSOR_FOREGROUND_0 */
> +       uint cursor_background;         /* _DISP_CURSOR_BACKGROUND_0 */
> +       uint cursor_start_addr;         /* _DISP_CURSOR_START_ADDR_0 */
> +       uint cursor_start_addr_ns;      /* _DISP_CURSOR_START_ADDR_NS_0 */
> +       uint cursor_pos;                /* _DISP_CURSOR_POSITION_0 */
> +       uint cursor_pos_ns;             /* _DISP_CURSOR_POSITION_NS_0 */
> +       uint seq_ctrl;                  /* _DISP_INIT_SEQ_CONTROL_0 */
> +
> +       /* Address 0x442 ~ 0x446 */
> +       uint spi_init_seq_data_a;       /* _DISP_SPI_INIT_SEQ_DATA_A_0 */
> +       uint spi_init_seq_data_b;       /* _DISP_SPI_INIT_SEQ_DATA_B_0 */
> +       uint spi_init_seq_data_c;       /* _DISP_SPI_INIT_SEQ_DATA_C_0 */
> +       uint spi_init_seq_data_d;       /* _DISP_SPI_INIT_SEQ_DATA_D_0 */
> +
> +       uint reserved1[0x39];           /* reserved1[0x39], */
> +
> +       /* Address 0x480 ~ 0x484 */
> +       uint dc_mccif_fifoctrl;         /* _DISP_DC_MCCIF_FIFOCTRL_0 */
> +       uint mccif_disp0a_hyst;         /* _DISP_MCCIF_DISPLAY0A_HYST_0 */
> +       uint mccif_disp0b_hyst;         /* _DISP_MCCIF_DISPLAY0B_HYST_0 */
> +       uint mccif_disp0c_hyst;         /* _DISP_MCCIF_DISPLAY0C_HYST_0 */
> +       uint mccif_disp1b_hyst;         /* _DISP_MCCIF_DISPLAY1B_HYST_0 */
> +
> +       uint reserved2[0x3b];           /* reserved2[0x3b] */
> +
> +       /* Address 0x4c0 ~ 0x4c1 */
> +       uint dac_crt_ctrl;              /* _DISP_DAC_CRT_CTRL_0 */
> +       uint disp_misc_ctrl;            /* _DISP_DISP_MISC_CONTROL_0 */
> +};
> +
> +enum dc_winc_filter_p {
> +       WINC_FILTER_COUNT       = 0x10,
> +};
> +
> +/* Window A/B/C register 0x500 ~ 0x628 */
> +struct dc_winc_reg {
> +
> +       /* Address 0x500 */
> +       uint color_palette;             /* _WINC_COLOR_PALETTE_0 */
> +
> +       uint reserved0[0xff];           /* reserved_0[0xff] */
> +
> +       /* Address 0x600 */
> +       uint palette_color_ext;         /* _WINC_PALETTE_COLOR_EXT_0 */
> +
> +       /* _WINC_H_FILTER_P00~0F_0 */
> +       /* Address 0x601 ~ 0x610 */
> +       uint h_filter_p[WINC_FILTER_COUNT];
> +
> +       /* Address 0x611 ~ 0x618 */
> +       uint csc_yof;                   /* _WINC_CSC_YOF_0 */
> +       uint csc_kyrgb;                 /* _WINC_CSC_KYRGB_0 */
> +       uint csc_kur;                   /* _WINC_CSC_KUR_0 */
> +       uint csc_kvr;                   /* _WINC_CSC_KVR_0 */
> +       uint csc_kug;                   /* _WINC_CSC_KUG_0 */
> +       uint csc_kvg;                   /* _WINC_CSC_KVG_0 */
> +       uint csc_kub;                   /* _WINC_CSC_KUB_0 */
> +       uint csc_kvb;                   /* _WINC_CSC_KVB_0 */
> +
> +       /* Address 0x619 ~ 0x628: _WINC_V_FILTER_P00~0F_0 */
> +       uint v_filter_p[WINC_FILTER_COUNT];
> +};
> +
> +/* WIN A/B/C Register 0x700 ~ 0x714*/
> +struct dc_win_reg {
> +       /* Address 0x700 ~ 0x714 */
> +       uint win_opt;                   /* _WIN_WIN_OPTIONS_0 */
> +       uint byte_swap;                 /* _WIN_BYTE_SWAP_0 */
> +       uint buffer_ctrl;               /* _WIN_BUFFER_CONTROL_0 */
> +       uint color_depth;               /* _WIN_COLOR_DEPTH_0 */
> +       uint pos;                       /* _WIN_POSITION_0 */
> +       uint size;                      /* _WIN_SIZE_0 */
> +       uint prescaled_size;            /* _WIN_PRESCALED_SIZE_0 */
> +       uint h_initial_dda;             /* _WIN_H_INITIAL_DDA_0 */
> +       uint v_initial_dda;             /* _WIN_V_INITIAL_DDA_0 */
> +       uint dda_increment;             /* _WIN_DDA_INCREMENT_0 */
> +       uint line_stride;               /* _WIN_LINE_STRIDE_0 */
> +       uint buf_stride;                /* _WIN_BUF_STRIDE_0 */
> +       uint uv_buf_stride;             /* _WIN_UV_BUF_STRIDE_0 */
> +       uint buffer_addr_mode;          /* _WIN_BUFFER_ADDR_MODE_0 */
> +       uint dv_ctrl;                   /* _WIN_DV_CONTROL_0 */
> +       uint blend_nokey;               /* _WIN_BLEND_NOKEY_0 */
> +       uint blend_1win;                /* _WIN_BLEND_1WIN_0 */
> +       uint blend_2win_x;              /* _WIN_BLEND_2WIN_X_0 */
> +       uint blend_2win_y;              /* _WIN_BLEND_2WIN_Y_0 */
> +       uint blend_3win_xy;             /* _WIN_BLEND_3WIN_XY_0 */
> +       uint hp_fetch_ctrl;             /* _WIN_HP_FETCH_CONTROL_0 */
> +};
> +
> +/* WINBUF A/B/C Register 0x800 ~ 0x80a */
> +struct dc_winbuf_reg {
> +       /* Address 0x800 ~ 0x80a */
> +       uint start_addr;                /* _WINBUF_START_ADDR_0 */
> +       uint start_addr_ns;             /* _WINBUF_START_ADDR_NS_0 */
> +       uint start_addr_u;              /* _WINBUF_START_ADDR_U_0 */
> +       uint start_addr_u_ns;           /* _WINBUF_START_ADDR_U_NS_0 */
> +       uint start_addr_v;              /* _WINBUF_START_ADDR_V_0 */
> +       uint start_addr_v_ns;           /* _WINBUF_START_ADDR_V_NS_0 */
> +       uint addr_h_offset;             /* _WINBUF_ADDR_H_OFFSET_0 */
> +       uint addr_h_offset_ns;          /* _WINBUF_ADDR_H_OFFSET_NS_0 */
> +       uint addr_v_offset;             /* _WINBUF_ADDR_V_OFFSET_0 */
> +       uint addr_v_offset_ns;          /* _WINBUF_ADDR_V_OFFSET_NS_0 */
> +       uint uflow_status;              /* _WINBUF_UFLOW_STATUS_0 */
> +};
> +
> +/* Display Controller (DC_) regs */
> +struct dc_ctlr {
> +       struct dc_cmd_reg cmd;          /* CMD register 0x000 ~ 0x43 */
> +       uint reserved0[0x2bc];
> +
> +       struct dc_com_reg com;          /* COM register 0x300 ~ 0x329 */
> +       uint reserved1[0xd6];
> +
> +       struct dc_disp_reg disp;        /* DISP register 0x400 ~ 0x4c1 */
> +       uint reserved2[0x3e];
> +
> +       struct dc_winc_reg winc;        /* Window A/B/C 0x500 ~ 0x628 */
> +       uint reserved3[0xd7];
> +
> +       struct dc_win_reg win;          /* WIN A/B/C 0x700 ~ 0x714*/
> +       uint reserved4[0xeb];
> +
> +       struct dc_winbuf_reg winbuf;    /* WINBUF A/B/C 0x800 ~ 0x80a */
> +};
> +
> +#define BIT(pos)       (1U << pos)
> +
> +/* DC_CMD_DISPLAY_COMMAND 0x032 */
> +#define CTRL_MODE_SHIFT                5
> +#define CTRL_MODE_MASK         (0x3 << CTRL_MODE_SHIFT)
> +enum {
> +       CTRL_MODE_STOP,
> +       CTRL_MODE_C_DISPLAY,
> +       CTRL_MODE_NC_DISPLAY,
> +};
> +
> +/* _WIN_COLOR_DEPTH_0 */
> +enum win_color_depth_id {
> +       COLOR_DEPTH_P1,
> +       COLOR_DEPTH_P2,
> +       COLOR_DEPTH_P4,
> +       COLOR_DEPTH_P8,
> +       COLOR_DEPTH_B4G4R4A4,
> +       COLOR_DEPTH_B5G5R5A,
> +       COLOR_DEPTH_B5G6R5,
> +       COLOR_DEPTH_AB5G5R5,
> +       COLOR_DEPTH_B8G8R8A8 = 12,
> +       COLOR_DEPTH_R8G8B8A8,
> +       COLOR_DEPTH_B6x2G6x2R6x2A8,
> +       COLOR_DEPTH_R6x2G6x2B6x2A8,
> +       COLOR_DEPTH_YCbCr422,
> +       COLOR_DEPTH_YUV422,
> +       COLOR_DEPTH_YCbCr420P,
> +       COLOR_DEPTH_YUV420P,
> +       COLOR_DEPTH_YCbCr422P,
> +       COLOR_DEPTH_YUV422P,
> +       COLOR_DEPTH_YCbCr422R,
> +       COLOR_DEPTH_YUV422R,
> +       COLOR_DEPTH_YCbCr422RA,
> +       COLOR_DEPTH_YUV422RA,
> +};
> +
> +/* DC_CMD_DISPLAY_POWER_CONTROL 0x036 */
> +#define PW0_ENABLE             BIT(0)
> +#define PW1_ENABLE             BIT(2)
> +#define PW2_ENABLE             BIT(4)
> +#define PW3_ENABLE             BIT(6)
> +#define PW4_ENABLE             BIT(8)
> +#define PM0_ENABLE             BIT(16)
> +#define PM1_ENABLE             BIT(18)
> +#define SPI_ENABLE             BIT(24)
> +#define HSPI_ENABLE            BIT(25)
> +
> +/* DC_CMD_STATE_CONTROL 0x041 */
> +#define GENERAL_ACT_REQ                BIT(0)
> +#define WIN_A_ACT_REQ          BIT(1)
> +#define WIN_B_ACT_REQ          BIT(2)
> +#define WIN_C_ACT_REQ          BIT(3)
> +#define GENERAL_UPDATE         BIT(8)
> +#define WIN_A_UPDATE           BIT(9)
> +#define WIN_B_UPDATE           BIT(10)
> +#define WIN_C_UPDATE           BIT(11)
> +
> +/* DC_CMD_DISPLAY_WINDOW_HEADER 0x042 */
> +#define WINDOW_A_SELECT                BIT(4)
> +#define WINDOW_B_SELECT                BIT(5)
> +#define WINDOW_C_SELECT                BIT(6)
> +
> +/* DC_DISP_DISP_CLOCK_CONTROL 0x42e */
> +#define SHIFT_CLK_DIVIDER_SHIFT        0
> +#define SHIFT_CLK_DIVIDER_MASK (0xff << SHIFT_CLK_DIVIDER_SHIFT)
> +#define        PIXEL_CLK_DIVIDER_SHIFT 8
> +#define        PIXEL_CLK_DIVIDER_MSK   (0xf << PIXEL_CLK_DIVIDER_SHIFT)
> +enum {
> +       PIXEL_CLK_DIVIDER_PCD1,
> +       PIXEL_CLK_DIVIDER_PCD1H,
> +       PIXEL_CLK_DIVIDER_PCD2,
> +       PIXEL_CLK_DIVIDER_PCD3,
> +       PIXEL_CLK_DIVIDER_PCD4,
> +       PIXEL_CLK_DIVIDER_PCD6,
> +       PIXEL_CLK_DIVIDER_PCD8,
> +       PIXEL_CLK_DIVIDER_PCD9,
> +       PIXEL_CLK_DIVIDER_PCD12,
> +       PIXEL_CLK_DIVIDER_PCD16,
> +       PIXEL_CLK_DIVIDER_PCD18,
> +       PIXEL_CLK_DIVIDER_PCD24,
> +       PIXEL_CLK_DIVIDER_PCD13,
> +};
> +
> +/* DC_DISP_DISP_INTERFACE_CONTROL 0x42f */
> +#define DATA_FORMAT_SHIFT      0
> +#define DATA_FORMAT_MASK       (0xf << DATA_FORMAT_SHIFT)
> +enum {
> +       DATA_FORMAT_DF1P1C,
> +       DATA_FORMAT_DF1P2C24B,
> +       DATA_FORMAT_DF1P2C18B,
> +       DATA_FORMAT_DF1P2C16B,
> +       DATA_FORMAT_DF2S,
> +       DATA_FORMAT_DF3S,
> +       DATA_FORMAT_DFSPI,
> +       DATA_FORMAT_DF1P3C24B,
> +       DATA_FORMAT_DF1P3C18B,
> +};
> +#define DATA_ALIGNMENT_SHIFT   8
> +enum {
> +       DATA_ALIGNMENT_MSB,
> +       DATA_ALIGNMENT_LSB,
> +};
> +#define DATA_ORDER_SHIFT       9
> +enum {
> +       DATA_ORDER_RED_BLUE,
> +       DATA_ORDER_BLUE_RED,
> +};
> +
> +/* DC_DISP_DATA_ENABLE_OPTIONS 0x432 */
> +#define DE_SELECT_SHIFT                0
> +#define DE_SELECT_MASK         (0x3 << DE_SELECT_SHIFT)
> +#define DE_SELECT_ACTIVE_BLANK 0x0
> +#define DE_SELECT_ACTIVE       0x1
> +#define DE_SELECT_ACTIVE_IS    0x2
> +#define DE_CONTROL_SHIFT       2
> +#define DE_CONTROL_MASK                (0x7 << DE_CONTROL_SHIFT)
> +enum {
> +       DE_CONTROL_ONECLK,
> +       DE_CONTROL_NORMAL,
> +       DE_CONTROL_EARLY_EXT,
> +       DE_CONTROL_EARLY,
> +       DE_CONTROL_ACTIVE_BLANK,
> +};
> +
> +/* DC_WIN_WIN_OPTIONS 0x700 */
> +#define H_DIRECTION            BIT(0)
> +enum {
> +       H_DIRECTION_INCREMENT,
> +       H_DIRECTION_DECREMENT,
> +};
> +#define V_DIRECTION            BIT(2)
> +enum {
> +       V_DIRECTION_INCREMENT,
> +       V_DIRECTION_DECREMENT,
> +};
> +#define COLOR_EXPAND           BIT(6)
> +#define CP_ENABLE              BIT(16)
> +#define DV_ENABLE              BIT(20)
> +#define WIN_ENABLE             BIT(30)
> +
> +/* DC_WIN_BYTE_SWAP 0x701 */
> +#define BYTE_SWAP_SHIFT                0
> +enum {
> +       BYTE_SWAP_NOSWAP,
> +       BYTE_SWAP_SWAP2,
> +       BYTE_SWAP_SWAP4,
> +       BYTE_SWAP_SWAP4HW
> +};
> +
> +/* DC_WIN_POSITION 0x704 */
> +#define H_POSITION_SHIFT       0
> +#define H_POSITION_MASK                (0x1FFF << H_POSITION_SHIFT)
> +#define V_POSITION_SHIFT       16
> +#define V_POSITION_MASK                (0x1FFF << V_POSITION_SHIFT)
> +
> +/* DC_WIN_SIZE 0x705 */
> +#define H_SIZE_SHIFT           0
> +#define H_SIZE_MASK            (0x1FFF << H_SIZE_SHIFT)
> +#define V_SIZE_SHIFT           16
> +#define V_SIZE_MASK            (0x1FFF << V_SIZE_SHIFT)
> +
> +/* DC_WIN_PRESCALED_SIZE 0x706 */
> +#define H_PRESCALED_SIZE_SHIFT 0
> +#define H_PRESCALED_SIZE_MASK  (0x7FFF << H_PRESCALED_SIZE)
> +#define V_PRESCALED_SIZE_SHIFT 16
> +#define V_PRESCALED_SIZE_MASK  (0x1FFF << V_PRESCALED_SIZE)
> +
> +/* DC_WIN_DDA_INCREMENT 0x709 */
> +#define H_DDA_INC_SHIFT                0
> +#define H_DDA_INC_MASK         (0xFFFF << H_DDA_INC_SHIFT)
> +#define V_DDA_INC_SHIFT                16
> +#define V_DDA_INC_MASK         (0xFFFF << V_DDA_INC_SHIFT)
> +
> +#endif /* __ASM_ARCH_TEGRA_DC_H */
> diff --git a/arch/arm/include/asm/arch-tegra2/display.h b/arch/arm/include/asm/arch-tegra2/display.h
> new file mode 100644
> index 0000000..7795317
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-tegra2/display.h
> @@ -0,0 +1,152 @@
> +/*
> + *  (C) Copyright 2010
> + *  NVIDIA Corporation <www.nvidia.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __ASM_ARCH_TEGRA_DISPLAY_H
> +#define __ASM_ARCH_TEGRA_DISPLAY_H
> +
> +#include <asm/arch-tegra2/dc.h>
> +#include <fdtdec.h>
> +
> +/* This holds information about a window which can be displayed */
> +struct disp_ctl_win {
> +       enum win_color_depth_id fmt;    /* Color depth/format */
> +       unsigned        bpp;            /* Bits per pixel */
> +       phys_addr_t     phys_addr;      /* Physical address in memory */
> +       unsigned        x;              /* Horizontal address offset (bytes) */
> +       unsigned        y;              /* Veritical address offset (bytes) */
> +       unsigned        w;              /* Width of source window */
> +       unsigned        h;              /* Height of source window */
> +       unsigned        stride;         /* Number of bytes per line */
> +       unsigned        out_x;          /* Left edge of output window (col) */
> +       unsigned        out_y;          /* Top edge of output window (row) */
> +       unsigned        out_w;          /* Width of output window in pixels */
> +       unsigned        out_h;          /* Height of output window in pixels */
> +};
> +
> +#define FDT_LCD_TIMINGS        4
> +
> +enum {
> +       FDT_LCD_TIMING_REF_TO_SYNC,
> +       FDT_LCD_TIMING_SYNC_WIDTH,
> +       FDT_LCD_TIMING_BACK_PORCH,
> +       FDT_LCD_TIMING_FRONT_PORCH,
> +
> +       FDT_LCD_TIMING_COUNT,
> +};
> +
> +enum lcd_cache_t {
> +       FDT_LCD_CACHE_OFF               = 0,
> +       FDT_LCD_CACHE_WRITE_THROUGH     = 1 << 0,
> +       FDT_LCD_CACHE_WRITE_BACK        = 1 << 1,
> +       FDT_LCD_CACHE_FLUSH             = 1 << 2,
> +       FDT_LCD_CACHE_WRITE_BACK_FLUSH  = FDT_LCD_CACHE_WRITE_BACK |
> +                                               FDT_LCD_CACHE_FLUSH,
> +};
> +
> +/* Information about the display controller */
> +struct fdt_disp_config {
> +       int valid;                      /* config is valid */
> +       int width;                      /* width in pixels */
> +       int height;                     /* height in pixels */
> +       int bpp;                        /* number of bits per pixel */
> +
> +       /*
> +        * log2 of number of bpp, in general, unless it bpp is 24 in which
> +        * case this field holds 24 also! This is a U-Boot thing.
> +        */
> +       int log2_bpp;
> +       struct disp_ctlr *disp;         /* Display controller to use */
> +       fdt_addr_t frame_buffer;        /* Address of frame buffer */
> +       unsigned pixel_clock;           /* Pixel clock in Hz */
> +       uint horiz_timing[FDT_LCD_TIMING_COUNT];        /* Horizontal timing */
> +       uint vert_timing[FDT_LCD_TIMING_COUNT];         /* Vertical timing */
> +       int panel_node;                 /* node offset of panel information */
> +};
> +
> +/* Information about the LCD panel */
> +struct fdt_panel_config {
> +       int pwm_channel;                /* PWM channel to use for backlight */
> +       enum lcd_cache_t cache_type;
> +
> +       struct fdt_gpio_state backlight_en;     /* GPIO for backlight enable */
> +       struct fdt_gpio_state lvds_shutdown;    /* GPIO for lvds shutdown */
> +       struct fdt_gpio_state backlight_vdd;    /* GPIO for backlight vdd */
> +       struct fdt_gpio_state panel_vdd;        /* GPIO for panel vdd */
> +       /*
> +        * Panel required timings
> +        * Timing 1: delay between panel_vdd-rise and data-rise
> +        * Timing 2: delay between data-rise and backlight_vdd-rise
> +        * Timing 3: delay between backlight_vdd and pwm-rise
> +        * Timing 4: delay between pwm-rise and backlight_en-rise
> +        */
> +       uint panel_timings[FDT_LCD_TIMINGS];
> +};
> +
> +/**
> + * Register a new display based on device tree configuration.
> + *
> + * The frame buffer can be positioned by U-Boot or overriden by the fdt.
> + * You should pass in the U-Boot address here, and check the contents of
> + * struct fdt_disp_config to see what was actually chosen.
> + *
> + * @param blob                 Device tree blob
> + * @param default_lcd_base     Default address of LCD frame buffer
> + * @return 0 if ok, -1 on error (unsupported bits per pixel)
> + */
> +int tegra_display_probe(const void *blob, void *default_lcd_base);
> +
> +/**
> + * Return the current display configuration
> + *
> + * @return pointer to display configuration, or NULL if there is no valid
> + * config
> + */
> +struct fdt_disp_config *tegra_display_get_config(void);
> +
> +/**
> + * Perform the next stage of the LCD init if it is time to do so.
> + *
> + * LCD init can be time-consuming because of the number of delays we need
> + * while waiting for the backlight power supply, etc. This function can
> + * be called at various times during U-Boot operation to advance the
> + * initialization of the LCD to the next stage if sufficient time has
> + * passed since the last stage. It keeps track of what stage it is up to
> + * and the time that it is permitted to move to the next stage.
> + *
> + * The final call should have wait=1 to complete the init.
> + *
> + * @param blob fdt blob containing LCD information
> + * @param wait 1 to wait until all init is complete, and then return
> + *             0 to return immediately, potentially doing nothing if it is
> + *             not yet time for the next init.
> + */
> +int tegra_lcd_check_next_stage(const void *blob, int wait);
> +
> +/**
> + * Set up the maximum LCD size so we can size the frame buffer.
> + *
> + * @param blob fdt blob containing LCD information
> + */
> +void tegra_lcd_early_init(const void *blob);
> +
> +#endif /*__ASM_ARCH_TEGRA_DISPLAY_H*/
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index 3997bfa..b474ced 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -66,6 +66,7 @@ enum fdt_compat_id {
>         COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra2 memory timing table */
>         COMPAT_NVIDIA_TEGRA20_KBC,      /* Tegra2 Keyboard */
>         COMPAT_NVIDIA_TEGRA20_PWM,      /* Tegra 2 PWM controller */
> +       COMPAT_NVIDIA_TEGRA20_DC,       /* Tegra 2 Display controller */
> 
>         COMPAT_COUNT,
>  };
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 40b0aef..1021560 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -44,6 +44,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
>         COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
>         COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
>         COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
> +       COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
>  };
> 
>  const char *fdtdec_get_compatible(enum fdt_compat_id id)
> --
> 1.7.7.3
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------


More information about the U-Boot mailing list