Commit 87540de3af515a907d91b08e298cd0da11d23bfa

Authored by Wei Ni
Committed by Tom Warren
1 parent e1ae0d1f71

tegra: Add SOC support for display/lcd

Add support for the LCD peripheral at the Tegra2 SOC level. A separate
LCD driver will use this functionality to configure the display.

Signed-off-by: Mayuresh Kulkarni <mkulkarni@nvidia.com>
Mayuresh Kulkarni:
- changes to remove bitfields and clean up for submission

Signed-off-by: Simon Glass <sjg@chromium.org>
Simon Glass:
- simplify code, move clock control into here, clean-up
Signed-off-by: Tom Warren <twarren@nvidia.com>

Showing 6 changed files with 1109 additions and 0 deletions Side-by-side Diff

arch/arm/cpu/armv7/tegra20/Makefile
... ... @@ -29,6 +29,7 @@
29 29  
30 30 COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
31 31 COBJS-$(CONFIG_PWM_TEGRA) += pwm.o
  32 +COBJS-$(CONFIG_VIDEO_TEGRA) += display.o
32 33  
33 34 COBJS := $(COBJS-y)
34 35 SRCS := $(COBJS:.o=.c)
arch/arm/cpu/armv7/tegra20/display.c
  1 +/*
  2 + * (C) Copyright 2010
  3 + * NVIDIA Corporation <www.nvidia.com>
  4 + *
  5 + * See file CREDITS for list of people who contributed to this
  6 + * project.
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License as
  10 + * published by the Free Software Foundation; either version 2 of
  11 + * the License, or (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the Free Software
  20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 + * MA 02111-1307 USA
  22 + */
  23 +
  24 +#include <common.h>
  25 +#include <asm/io.h>
  26 +#include <asm/arch/clock.h>
  27 +#include <asm/arch/tegra.h>
  28 +#include <asm/arch/display.h>
  29 +#include <asm/arch/dc.h>
  30 +#include <asm/arch-tegra/clk_rst.h>
  31 +#include <asm/arch-tegra/timer.h>
  32 +
  33 +static struct fdt_disp_config config;
  34 +
  35 +static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
  36 +{
  37 + unsigned h_dda, v_dda;
  38 + unsigned long val;
  39 +
  40 + val = readl(&dc->cmd.disp_win_header);
  41 + val |= WINDOW_A_SELECT;
  42 + writel(val, &dc->cmd.disp_win_header);
  43 +
  44 + writel(win->fmt, &dc->win.color_depth);
  45 +
  46 + clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK,
  47 + BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT);
  48 +
  49 + val = win->out_x << H_POSITION_SHIFT;
  50 + val |= win->out_y << V_POSITION_SHIFT;
  51 + writel(val, &dc->win.pos);
  52 +
  53 + val = win->out_w << H_SIZE_SHIFT;
  54 + val |= win->out_h << V_SIZE_SHIFT;
  55 + writel(val, &dc->win.size);
  56 +
  57 + val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT;
  58 + val |= win->h << V_PRESCALED_SIZE_SHIFT;
  59 + writel(val, &dc->win.prescaled_size);
  60 +
  61 + writel(0, &dc->win.h_initial_dda);
  62 + writel(0, &dc->win.v_initial_dda);
  63 +
  64 + h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1);
  65 + v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1);
  66 +
  67 + val = h_dda << H_DDA_INC_SHIFT;
  68 + val |= v_dda << V_DDA_INC_SHIFT;
  69 + writel(val, &dc->win.dda_increment);
  70 +
  71 + writel(win->stride, &dc->win.line_stride);
  72 + writel(0, &dc->win.buf_stride);
  73 +
  74 + val = WIN_ENABLE;
  75 + if (win->bpp < 24)
  76 + val |= COLOR_EXPAND;
  77 + writel(val, &dc->win.win_opt);
  78 +
  79 + writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr);
  80 + writel(win->x, &dc->winbuf.addr_h_offset);
  81 + writel(win->y, &dc->winbuf.addr_v_offset);
  82 +
  83 + writel(0xff00, &dc->win.blend_nokey);
  84 + writel(0xff00, &dc->win.blend_1win);
  85 +
  86 + val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
  87 + val |= GENERAL_UPDATE | WIN_A_UPDATE;
  88 + writel(val, &dc->cmd.state_ctrl);
  89 +}
  90 +
  91 +static void write_pair(struct fdt_disp_config *config, int item, u32 *reg)
  92 +{
  93 + writel(config->horiz_timing[item] |
  94 + (config->vert_timing[item] << 16), reg);
  95 +}
  96 +
  97 +static int update_display_mode(struct dc_disp_reg *disp,
  98 + struct fdt_disp_config *config)
  99 +{
  100 + unsigned long val;
  101 + unsigned long rate;
  102 + unsigned long div;
  103 +
  104 + writel(0x0, &disp->disp_timing_opt);
  105 + write_pair(config, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync);
  106 + write_pair(config, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width);
  107 + write_pair(config, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch);
  108 + write_pair(config, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch);
  109 +
  110 + writel(config->width | (config->height << 16), &disp->disp_active);
  111 +
  112 + val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
  113 + val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
  114 + writel(val, &disp->data_enable_opt);
  115 +
  116 + val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT;
  117 + val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
  118 + val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
  119 + writel(val, &disp->disp_interface_ctrl);
  120 +
  121 + /*
  122 + * The pixel clock divider is in 7.1 format (where the bottom bit
  123 + * represents 0.5). Here we calculate the divider needed to get from
  124 + * the display clock (typically 600MHz) to the pixel clock. We round
  125 + * up or down as requried.
  126 + */
  127 + rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL);
  128 + div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2;
  129 + debug("Display clock %lu, divider %lu\n", rate, div);
  130 +
  131 + writel(0x00010001, &disp->shift_clk_opt);
  132 +
  133 + val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
  134 + val |= div << SHIFT_CLK_DIVIDER_SHIFT;
  135 + writel(val, &disp->disp_clk_ctrl);
  136 +
  137 + return 0;
  138 +}
  139 +
  140 +/* Start up the display and turn on power to PWMs */
  141 +static void basic_init(struct dc_cmd_reg *cmd)
  142 +{
  143 + u32 val;
  144 +
  145 + writel(0x00000100, &cmd->gen_incr_syncpt_ctrl);
  146 + writel(0x0000011a, &cmd->cont_syncpt_vsync);
  147 + writel(0x00000000, &cmd->int_type);
  148 + writel(0x00000000, &cmd->int_polarity);
  149 + writel(0x00000000, &cmd->int_mask);
  150 + writel(0x00000000, &cmd->int_enb);
  151 +
  152 + val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE;
  153 + val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE;
  154 + val |= PM1_ENABLE;
  155 + writel(val, &cmd->disp_pow_ctrl);
  156 +
  157 + val = readl(&cmd->disp_cmd);
  158 + val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT;
  159 + writel(val, &cmd->disp_cmd);
  160 +}
  161 +
  162 +static void basic_init_timer(struct dc_disp_reg *disp)
  163 +{
  164 + writel(0x00000020, &disp->mem_high_pri);
  165 + writel(0x00000001, &disp->mem_high_pri_timer);
  166 +}
  167 +
  168 +static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
  169 + 0x00000000,
  170 + 0x00000000,
  171 + 0x00000000,
  172 + 0x00000000,
  173 +};
  174 +
  175 +static const u32 rgb_polarity_tab[PIN_REG_COUNT] = {
  176 + 0x00000000,
  177 + 0x01000000,
  178 + 0x00000000,
  179 + 0x00000000,
  180 +};
  181 +
  182 +static const u32 rgb_data_tab[PIN_REG_COUNT] = {
  183 + 0x00000000,
  184 + 0x00000000,
  185 + 0x00000000,
  186 + 0x00000000,
  187 +};
  188 +
  189 +static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = {
  190 + 0x00000000,
  191 + 0x00000000,
  192 + 0x00000000,
  193 + 0x00000000,
  194 + 0x00210222,
  195 + 0x00002200,
  196 + 0x00020000,
  197 +};
  198 +
  199 +static void rgb_enable(struct dc_com_reg *com)
  200 +{
  201 + int i;
  202 +
  203 + for (i = 0; i < PIN_REG_COUNT; i++) {
  204 + writel(rgb_enb_tab[i], &com->pin_output_enb[i]);
  205 + writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]);
  206 + writel(rgb_data_tab[i], &com->pin_output_data[i]);
  207 + }
  208 +
  209 + for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
  210 + writel(rgb_sel_tab[i], &com->pin_output_sel[i]);
  211 +}
  212 +
  213 +int setup_window(struct disp_ctl_win *win, struct fdt_disp_config *config)
  214 +{
  215 + win->x = 0;
  216 + win->y = 0;
  217 + win->w = config->width;
  218 + win->h = config->height;
  219 + win->out_x = 0;
  220 + win->out_y = 0;
  221 + win->out_w = config->width;
  222 + win->out_h = config->height;
  223 + win->phys_addr = config->frame_buffer;
  224 + win->stride = config->width * (1 << config->log2_bpp) / 8;
  225 + debug("%s: depth = %d\n", __func__, config->log2_bpp);
  226 + switch (config->log2_bpp) {
  227 + case 5:
  228 + case 24:
  229 + win->fmt = COLOR_DEPTH_R8G8B8A8;
  230 + win->bpp = 32;
  231 + break;
  232 + case 4:
  233 + win->fmt = COLOR_DEPTH_B5G6R5;
  234 + win->bpp = 16;
  235 + break;
  236 +
  237 + default:
  238 + debug("Unsupported LCD bit depth");
  239 + return -1;
  240 + }
  241 +
  242 + return 0;
  243 +}
  244 +
  245 +struct fdt_disp_config *tegra_display_get_config(void)
  246 +{
  247 + return config.valid ? &config : NULL;
  248 +}
  249 +
  250 +static void debug_timing(const char *name, unsigned int timing[])
  251 +{
  252 +#ifdef DEBUG
  253 + int i;
  254 +
  255 + debug("%s timing: ", name);
  256 + for (i = 0; i < FDT_LCD_TIMING_COUNT; i++)
  257 + debug("%d ", timing[i]);
  258 + debug("\n");
  259 +#endif
  260 +}
  261 +
  262 +/**
  263 + * Decode panel information from the fdt, according to a standard binding
  264 + *
  265 + * @param blob fdt blob
  266 + * @param node offset of fdt node to read from
  267 + * @param config structure to store fdt config into
  268 + * @return 0 if ok, -ve on error
  269 + */
  270 +static int tegra_decode_panel(const void *blob, int node,
  271 + struct fdt_disp_config *config)
  272 +{
  273 + int front, back, ref;
  274 +
  275 + config->width = fdtdec_get_int(blob, node, "xres", -1);
  276 + config->height = fdtdec_get_int(blob, node, "yres", -1);
  277 + config->pixel_clock = fdtdec_get_int(blob, node, "clock", 0);
  278 + if (!config->pixel_clock || config->width == -1 ||
  279 + config->height == -1) {
  280 + debug("%s: Pixel parameters missing\n", __func__);
  281 + return -FDT_ERR_NOTFOUND;
  282 + }
  283 +
  284 + back = fdtdec_get_int(blob, node, "left-margin", -1);
  285 + front = fdtdec_get_int(blob, node, "right-margin", -1);
  286 + ref = fdtdec_get_int(blob, node, "hsync-len", -1);
  287 + if ((back | front | ref) == -1) {
  288 + debug("%s: Horizontal parameters missing\n", __func__);
  289 + return -FDT_ERR_NOTFOUND;
  290 + }
  291 +
  292 + /* Use a ref-to-sync of 1 always, and take this from the front porch */
  293 + config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
  294 + config->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
  295 + config->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
  296 + config->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
  297 + config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC];
  298 + debug_timing("horiz", config->horiz_timing);
  299 +
  300 + back = fdtdec_get_int(blob, node, "upper-margin", -1);
  301 + front = fdtdec_get_int(blob, node, "lower-margin", -1);
  302 + ref = fdtdec_get_int(blob, node, "vsync-len", -1);
  303 + if ((back | front | ref) == -1) {
  304 + debug("%s: Vertical parameters missing\n", __func__);
  305 + return -FDT_ERR_NOTFOUND;
  306 + }
  307 +
  308 + config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
  309 + config->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
  310 + config->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
  311 + config->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
  312 + config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC];
  313 + debug_timing("vert", config->vert_timing);
  314 +
  315 + return 0;
  316 +}
  317 +
  318 +/**
  319 + * Decode the display controller information from the fdt.
  320 + *
  321 + * @param blob fdt blob
  322 + * @param config structure to store fdt config into
  323 + * @return 0 if ok, -ve on error
  324 + */
  325 +static int tegra_display_decode_config(const void *blob,
  326 + struct fdt_disp_config *config)
  327 +{
  328 + int node, rgb;
  329 + int bpp, bit;
  330 +
  331 + /* TODO: Support multiple controllers */
  332 + node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_DC);
  333 + if (node < 0) {
  334 + debug("%s: Cannot find display controller node in fdt\n",
  335 + __func__);
  336 + return node;
  337 + }
  338 + config->disp = (struct disp_ctlr *)fdtdec_get_addr(blob, node, "reg");
  339 + if (!config->disp) {
  340 + debug("%s: No display controller address\n", __func__);
  341 + return -1;
  342 + }
  343 +
  344 + rgb = fdt_subnode_offset(blob, node, "rgb");
  345 +
  346 + config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
  347 + if (!config->panel_node < 0) {
  348 + debug("%s: Cannot find panel information\n", __func__);
  349 + return -1;
  350 + }
  351 +
  352 + if (tegra_decode_panel(blob, config->panel_node, config)) {
  353 + debug("%s: Failed to decode panel information\n", __func__);
  354 + return -1;
  355 + }
  356 +
  357 + bpp = fdtdec_get_int(blob, config->panel_node, "nvidia,bits-per-pixel",
  358 + -1);
  359 + bit = ffs(bpp) - 1;
  360 + if (bpp == (1 << bit))
  361 + config->log2_bpp = bit;
  362 + else
  363 + config->log2_bpp = bpp;
  364 + if (bpp == -1) {
  365 + debug("%s: Pixel bpp parameters missing\n", __func__);
  366 + return -FDT_ERR_NOTFOUND;
  367 + }
  368 + config->bpp = bpp;
  369 +
  370 + config->valid = 1; /* we have a valid configuration */
  371 +
  372 + return 0;
  373 +}
  374 +
  375 +int tegra_display_probe(const void *blob, void *default_lcd_base)
  376 +{
  377 + struct disp_ctl_win window;
  378 + struct dc_ctlr *dc;
  379 +
  380 + if (tegra_display_decode_config(blob, &config))
  381 + return -1;
  382 +
  383 + config.frame_buffer = (u32)default_lcd_base;
  384 +
  385 + dc = (struct dc_ctlr *)config.disp;
  386 +
  387 + /*
  388 + * A header file for clock constants was NAKed upstream.
  389 + * TODO: Put this into the FDT and fdt_lcd struct when we have clock
  390 + * support there
  391 + */
  392 + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH,
  393 + 144 * 1000000);
  394 + clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL,
  395 + 600 * 1000000);
  396 + basic_init(&dc->cmd);
  397 + basic_init_timer(&dc->disp);
  398 + rgb_enable(&dc->com);
  399 +
  400 + if (config.pixel_clock)
  401 + update_display_mode(&dc->disp, &config);
  402 +
  403 + if (setup_window(&window, &config))
  404 + return -1;
  405 +
  406 + update_window(dc, &window);
  407 +
  408 + return 0;
  409 +}
arch/arm/include/asm/arch-tegra20/dc.h
  1 +/*
  2 + * (C) Copyright 2010
  3 + * NVIDIA Corporation <www.nvidia.com>
  4 + *
  5 + * See file CREDITS for list of people who contributed to this
  6 + * project.
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License as
  10 + * published by the Free Software Foundation; either version 2 of
  11 + * the License, or (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the Free Software
  20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 + * MA 02111-1307 USA
  22 + */
  23 +
  24 +#ifndef __ASM_ARCH_TEGRA_DC_H
  25 +#define __ASM_ARCH_TEGRA_DC_H
  26 +
  27 +/* Register definitions for the Tegra display controller */
  28 +
  29 +/* CMD register 0x000 ~ 0x43 */
  30 +struct dc_cmd_reg {
  31 + /* Address 0x000 ~ 0x002 */
  32 + uint gen_incr_syncpt; /* _CMD_GENERAL_INCR_SYNCPT_0 */
  33 + uint gen_incr_syncpt_ctrl; /* _CMD_GENERAL_INCR_SYNCPT_CNTRL_0 */
  34 + uint gen_incr_syncpt_err; /* _CMD_GENERAL_INCR_SYNCPT_ERROR_0 */
  35 +
  36 + uint reserved0[5]; /* reserved_0[5] */
  37 +
  38 + /* Address 0x008 ~ 0x00a */
  39 + uint win_a_incr_syncpt; /* _CMD_WIN_A_INCR_SYNCPT_0 */
  40 + uint win_a_incr_syncpt_ctrl; /* _CMD_WIN_A_INCR_SYNCPT_CNTRL_0 */
  41 + uint win_a_incr_syncpt_err; /* _CMD_WIN_A_INCR_SYNCPT_ERROR_0 */
  42 +
  43 + uint reserved1[5]; /* reserved_1[5] */
  44 +
  45 + /* Address 0x010 ~ 0x012 */
  46 + uint win_b_incr_syncpt; /* _CMD_WIN_B_INCR_SYNCPT_0 */
  47 + uint win_b_incr_syncpt_ctrl; /* _CMD_WIN_B_INCR_SYNCPT_CNTRL_0 */
  48 + uint win_b_incr_syncpt_err; /* _CMD_WIN_B_INCR_SYNCPT_ERROR_0 */
  49 +
  50 + uint reserved2[5]; /* reserved_2[5] */
  51 +
  52 + /* Address 0x018 ~ 0x01a */
  53 + uint win_c_incr_syncpt; /* _CMD_WIN_C_INCR_SYNCPT_0 */
  54 + uint win_c_incr_syncpt_ctrl; /* _CMD_WIN_C_INCR_SYNCPT_CNTRL_0 */
  55 + uint win_c_incr_syncpt_err; /* _CMD_WIN_C_INCR_SYNCPT_ERROR_0 */
  56 +
  57 + uint reserved3[13]; /* reserved_3[13] */
  58 +
  59 + /* Address 0x028 */
  60 + uint cont_syncpt_vsync; /* _CMD_CONT_SYNCPT_VSYNC_0 */
  61 +
  62 + uint reserved4[7]; /* reserved_4[7] */
  63 +
  64 + /* Address 0x030 ~ 0x033 */
  65 + uint ctxsw; /* _CMD_CTXSW_0 */
  66 + uint disp_cmd_opt0; /* _CMD_DISPLAY_COMMAND_OPTION0_0 */
  67 + uint disp_cmd; /* _CMD_DISPLAY_COMMAND_0 */
  68 + uint sig_raise; /* _CMD_SIGNAL_RAISE_0 */
  69 +
  70 + uint reserved5[2]; /* reserved_0[2] */
  71 +
  72 + /* Address 0x036 ~ 0x03e */
  73 + uint disp_pow_ctrl; /* _CMD_DISPLAY_POWER_CONTROL_0 */
  74 + uint int_stat; /* _CMD_INT_STATUS_0 */
  75 + uint int_mask; /* _CMD_INT_MASK_0 */
  76 + uint int_enb; /* _CMD_INT_ENABLE_0 */
  77 + uint int_type; /* _CMD_INT_TYPE_0 */
  78 + uint int_polarity; /* _CMD_INT_POLARITY_0 */
  79 + uint sig_raise1; /* _CMD_SIGNAL_RAISE1_0 */
  80 + uint sig_raise2; /* _CMD_SIGNAL_RAISE2_0 */
  81 + uint sig_raise3; /* _CMD_SIGNAL_RAISE3_0 */
  82 +
  83 + uint reserved6; /* reserved_6 */
  84 +
  85 + /* Address 0x040 ~ 0x043 */
  86 + uint state_access; /* _CMD_STATE_ACCESS_0 */
  87 + uint state_ctrl; /* _CMD_STATE_CONTROL_0 */
  88 + uint disp_win_header; /* _CMD_DISPLAY_WINDOW_HEADER_0 */
  89 + uint reg_act_ctrl; /* _CMD_REG_ACT_CONTROL_0 */
  90 +};
  91 +
  92 +enum {
  93 + PIN_REG_COUNT = 4,
  94 + PIN_OUTPUT_SEL_COUNT = 7,
  95 +};
  96 +
  97 +/* COM register 0x300 ~ 0x329 */
  98 +struct dc_com_reg {
  99 + /* Address 0x300 ~ 0x301 */
  100 + uint crc_ctrl; /* _COM_CRC_CONTROL_0 */
  101 + uint crc_checksum; /* _COM_CRC_CHECKSUM_0 */
  102 +
  103 + /* _COM_PIN_OUTPUT_ENABLE0/1/2/3_0: Address 0x302 ~ 0x305 */
  104 + uint pin_output_enb[PIN_REG_COUNT];
  105 +
  106 + /* _COM_PIN_OUTPUT_POLARITY0/1/2/3_0: Address 0x306 ~ 0x309 */
  107 + uint pin_output_polarity[PIN_REG_COUNT];
  108 +
  109 + /* _COM_PIN_OUTPUT_DATA0/1/2/3_0: Address 0x30a ~ 0x30d */
  110 + uint pin_output_data[PIN_REG_COUNT];
  111 +
  112 + /* _COM_PIN_INPUT_ENABLE0_0: Address 0x30e ~ 0x311 */
  113 + uint pin_input_enb[PIN_REG_COUNT];
  114 +
  115 + /* Address 0x312 ~ 0x313 */
  116 + uint pin_input_data0; /* _COM_PIN_INPUT_DATA0_0 */
  117 + uint pin_input_data1; /* _COM_PIN_INPUT_DATA1_0 */
  118 +
  119 + /* _COM_PIN_OUTPUT_SELECT0/1/2/3/4/5/6_0: Address 0x314 ~ 0x31a */
  120 + uint pin_output_sel[PIN_OUTPUT_SEL_COUNT];
  121 +
  122 + /* Address 0x31b ~ 0x329 */
  123 + uint pin_misc_ctrl; /* _COM_PIN_MISC_CONTROL_0 */
  124 + uint pm0_ctrl; /* _COM_PM0_CONTROL_0 */
  125 + uint pm0_duty_cycle; /* _COM_PM0_DUTY_CYCLE_0 */
  126 + uint pm1_ctrl; /* _COM_PM1_CONTROL_0 */
  127 + uint pm1_duty_cycle; /* _COM_PM1_DUTY_CYCLE_0 */
  128 + uint spi_ctrl; /* _COM_SPI_CONTROL_0 */
  129 + uint spi_start_byte; /* _COM_SPI_START_BYTE_0 */
  130 + uint hspi_wr_data_ab; /* _COM_HSPI_WRITE_DATA_AB_0 */
  131 + uint hspi_wr_data_cd; /* _COM_HSPI_WRITE_DATA_CD */
  132 + uint hspi_cs_dc; /* _COM_HSPI_CS_DC_0 */
  133 + uint scratch_reg_a; /* _COM_SCRATCH_REGISTER_A_0 */
  134 + uint scratch_reg_b; /* _COM_SCRATCH_REGISTER_B_0 */
  135 + uint gpio_ctrl; /* _COM_GPIO_CTRL_0 */
  136 + uint gpio_debounce_cnt; /* _COM_GPIO_DEBOUNCE_COUNTER_0 */
  137 + uint crc_checksum_latched; /* _COM_CRC_CHECKSUM_LATCHED_0 */
  138 +};
  139 +
  140 +enum dc_disp_h_pulse_pos {
  141 + H_PULSE0_POSITION_A,
  142 + H_PULSE0_POSITION_B,
  143 + H_PULSE0_POSITION_C,
  144 + H_PULSE0_POSITION_D,
  145 + H_PULSE0_POSITION_COUNT,
  146 +};
  147 +
  148 +struct _disp_h_pulse {
  149 + /* _DISP_H_PULSE0/1/2_CONTROL_0 */
  150 + uint h_pulse_ctrl;
  151 + /* _DISP_H_PULSE0/1/2_POSITION_A/B/C/D_0 */
  152 + uint h_pulse_pos[H_PULSE0_POSITION_COUNT];
  153 +};
  154 +
  155 +enum dc_disp_v_pulse_pos {
  156 + V_PULSE0_POSITION_A,
  157 + V_PULSE0_POSITION_B,
  158 + V_PULSE0_POSITION_C,
  159 + V_PULSE0_POSITION_COUNT,
  160 +};
  161 +
  162 +struct _disp_v_pulse0 {
  163 + /* _DISP_H_PULSE0/1_CONTROL_0 */
  164 + uint v_pulse_ctrl;
  165 + /* _DISP_H_PULSE0/1_POSITION_A/B/C_0 */
  166 + uint v_pulse_pos[V_PULSE0_POSITION_COUNT];
  167 +};
  168 +
  169 +struct _disp_v_pulse2 {
  170 + /* _DISP_H_PULSE2/3_CONTROL_0 */
  171 + uint v_pulse_ctrl;
  172 + /* _DISP_H_PULSE2/3_POSITION_A_0 */
  173 + uint v_pulse_pos_a;
  174 +};
  175 +
  176 +enum dc_disp_h_pulse_reg {
  177 + H_PULSE0,
  178 + H_PULSE1,
  179 + H_PULSE2,
  180 + H_PULSE_COUNT,
  181 +};
  182 +
  183 +enum dc_disp_pp_select {
  184 + PP_SELECT_A,
  185 + PP_SELECT_B,
  186 + PP_SELECT_C,
  187 + PP_SELECT_D,
  188 + PP_SELECT_COUNT,
  189 +};
  190 +
  191 +/* DISP register 0x400 ~ 0x4c1 */
  192 +struct dc_disp_reg {
  193 + /* Address 0x400 ~ 0x40a */
  194 + uint disp_signal_opt0; /* _DISP_DISP_SIGNAL_OPTIONS0_0 */
  195 + uint disp_signal_opt1; /* _DISP_DISP_SIGNAL_OPTIONS1_0 */
  196 + uint disp_win_opt; /* _DISP_DISP_WIN_OPTIONS_0 */
  197 + uint mem_high_pri; /* _DISP_MEM_HIGH_PRIORITY_0 */
  198 + uint mem_high_pri_timer; /* _DISP_MEM_HIGH_PRIORITY_TIMER_0 */
  199 + uint disp_timing_opt; /* _DISP_DISP_TIMING_OPTIONS_0 */
  200 + uint ref_to_sync; /* _DISP_REF_TO_SYNC_0 */
  201 + uint sync_width; /* _DISP_SYNC_WIDTH_0 */
  202 + uint back_porch; /* _DISP_BACK_PORCH_0 */
  203 + uint disp_active; /* _DISP_DISP_ACTIVE_0 */
  204 + uint front_porch; /* _DISP_FRONT_PORCH_0 */
  205 +
  206 + /* Address 0x40b ~ 0x419: _DISP_H_PULSE0/1/2_ */
  207 + struct _disp_h_pulse h_pulse[H_PULSE_COUNT];
  208 +
  209 + /* Address 0x41a ~ 0x421 */
  210 + struct _disp_v_pulse0 v_pulse0; /* _DISP_V_PULSE0_ */
  211 + struct _disp_v_pulse0 v_pulse1; /* _DISP_V_PULSE1_ */
  212 +
  213 + /* Address 0x422 ~ 0x425 */
  214 + struct _disp_v_pulse2 v_pulse3; /* _DISP_V_PULSE2_ */
  215 + struct _disp_v_pulse2 v_pulse4; /* _DISP_V_PULSE3_ */
  216 +
  217 + /* Address 0x426 ~ 0x429 */
  218 + uint m0_ctrl; /* _DISP_M0_CONTROL_0 */
  219 + uint m1_ctrl; /* _DISP_M1_CONTROL_0 */
  220 + uint di_ctrl; /* _DISP_DI_CONTROL_0 */
  221 + uint pp_ctrl; /* _DISP_PP_CONTROL_0 */
  222 +
  223 + /* Address 0x42a ~ 0x42d: _DISP_PP_SELECT_A/B/C/D_0 */
  224 + uint pp_select[PP_SELECT_COUNT];
  225 +
  226 + /* Address 0x42e ~ 0x435 */
  227 + uint disp_clk_ctrl; /* _DISP_DISP_CLOCK_CONTROL_0 */
  228 + uint disp_interface_ctrl; /* _DISP_DISP_INTERFACE_CONTROL_0 */
  229 + uint disp_color_ctrl; /* _DISP_DISP_COLOR_CONTROL_0 */
  230 + uint shift_clk_opt; /* _DISP_SHIFT_CLOCK_OPTIONS_0 */
  231 + uint data_enable_opt; /* _DISP_DATA_ENABLE_OPTIONS_0 */
  232 + uint serial_interface_opt; /* _DISP_SERIAL_INTERFACE_OPTIONS_0 */
  233 + uint lcd_spi_opt; /* _DISP_LCD_SPI_OPTIONS_0 */
  234 + uint border_color; /* _DISP_BORDER_COLOR_0 */
  235 +
  236 + /* Address 0x436 ~ 0x439 */
  237 + uint color_key0_lower; /* _DISP_COLOR_KEY0_LOWER_0 */
  238 + uint color_key0_upper; /* _DISP_COLOR_KEY0_UPPER_0 */
  239 + uint color_key1_lower; /* _DISP_COLOR_KEY1_LOWER_0 */
  240 + uint color_key1_upper; /* _DISP_COLOR_KEY1_UPPER_0 */
  241 +
  242 + uint reserved0[2]; /* reserved_0[2] */
  243 +
  244 + /* Address 0x43c ~ 0x442 */
  245 + uint cursor_foreground; /* _DISP_CURSOR_FOREGROUND_0 */
  246 + uint cursor_background; /* _DISP_CURSOR_BACKGROUND_0 */
  247 + uint cursor_start_addr; /* _DISP_CURSOR_START_ADDR_0 */
  248 + uint cursor_start_addr_ns; /* _DISP_CURSOR_START_ADDR_NS_0 */
  249 + uint cursor_pos; /* _DISP_CURSOR_POSITION_0 */
  250 + uint cursor_pos_ns; /* _DISP_CURSOR_POSITION_NS_0 */
  251 + uint seq_ctrl; /* _DISP_INIT_SEQ_CONTROL_0 */
  252 +
  253 + /* Address 0x442 ~ 0x446 */
  254 + uint spi_init_seq_data_a; /* _DISP_SPI_INIT_SEQ_DATA_A_0 */
  255 + uint spi_init_seq_data_b; /* _DISP_SPI_INIT_SEQ_DATA_B_0 */
  256 + uint spi_init_seq_data_c; /* _DISP_SPI_INIT_SEQ_DATA_C_0 */
  257 + uint spi_init_seq_data_d; /* _DISP_SPI_INIT_SEQ_DATA_D_0 */
  258 +
  259 + uint reserved1[0x39]; /* reserved1[0x39], */
  260 +
  261 + /* Address 0x480 ~ 0x484 */
  262 + uint dc_mccif_fifoctrl; /* _DISP_DC_MCCIF_FIFOCTRL_0 */
  263 + uint mccif_disp0a_hyst; /* _DISP_MCCIF_DISPLAY0A_HYST_0 */
  264 + uint mccif_disp0b_hyst; /* _DISP_MCCIF_DISPLAY0B_HYST_0 */
  265 + uint mccif_disp0c_hyst; /* _DISP_MCCIF_DISPLAY0C_HYST_0 */
  266 + uint mccif_disp1b_hyst; /* _DISP_MCCIF_DISPLAY1B_HYST_0 */
  267 +
  268 + uint reserved2[0x3b]; /* reserved2[0x3b] */
  269 +
  270 + /* Address 0x4c0 ~ 0x4c1 */
  271 + uint dac_crt_ctrl; /* _DISP_DAC_CRT_CTRL_0 */
  272 + uint disp_misc_ctrl; /* _DISP_DISP_MISC_CONTROL_0 */
  273 +};
  274 +
  275 +enum dc_winc_filter_p {
  276 + WINC_FILTER_COUNT = 0x10,
  277 +};
  278 +
  279 +/* Window A/B/C register 0x500 ~ 0x628 */
  280 +struct dc_winc_reg {
  281 +
  282 + /* Address 0x500 */
  283 + uint color_palette; /* _WINC_COLOR_PALETTE_0 */
  284 +
  285 + uint reserved0[0xff]; /* reserved_0[0xff] */
  286 +
  287 + /* Address 0x600 */
  288 + uint palette_color_ext; /* _WINC_PALETTE_COLOR_EXT_0 */
  289 +
  290 + /* _WINC_H_FILTER_P00~0F_0 */
  291 + /* Address 0x601 ~ 0x610 */
  292 + uint h_filter_p[WINC_FILTER_COUNT];
  293 +
  294 + /* Address 0x611 ~ 0x618 */
  295 + uint csc_yof; /* _WINC_CSC_YOF_0 */
  296 + uint csc_kyrgb; /* _WINC_CSC_KYRGB_0 */
  297 + uint csc_kur; /* _WINC_CSC_KUR_0 */
  298 + uint csc_kvr; /* _WINC_CSC_KVR_0 */
  299 + uint csc_kug; /* _WINC_CSC_KUG_0 */
  300 + uint csc_kvg; /* _WINC_CSC_KVG_0 */
  301 + uint csc_kub; /* _WINC_CSC_KUB_0 */
  302 + uint csc_kvb; /* _WINC_CSC_KVB_0 */
  303 +
  304 + /* Address 0x619 ~ 0x628: _WINC_V_FILTER_P00~0F_0 */
  305 + uint v_filter_p[WINC_FILTER_COUNT];
  306 +};
  307 +
  308 +/* WIN A/B/C Register 0x700 ~ 0x714*/
  309 +struct dc_win_reg {
  310 + /* Address 0x700 ~ 0x714 */
  311 + uint win_opt; /* _WIN_WIN_OPTIONS_0 */
  312 + uint byte_swap; /* _WIN_BYTE_SWAP_0 */
  313 + uint buffer_ctrl; /* _WIN_BUFFER_CONTROL_0 */
  314 + uint color_depth; /* _WIN_COLOR_DEPTH_0 */
  315 + uint pos; /* _WIN_POSITION_0 */
  316 + uint size; /* _WIN_SIZE_0 */
  317 + uint prescaled_size; /* _WIN_PRESCALED_SIZE_0 */
  318 + uint h_initial_dda; /* _WIN_H_INITIAL_DDA_0 */
  319 + uint v_initial_dda; /* _WIN_V_INITIAL_DDA_0 */
  320 + uint dda_increment; /* _WIN_DDA_INCREMENT_0 */
  321 + uint line_stride; /* _WIN_LINE_STRIDE_0 */
  322 + uint buf_stride; /* _WIN_BUF_STRIDE_0 */
  323 + uint uv_buf_stride; /* _WIN_UV_BUF_STRIDE_0 */
  324 + uint buffer_addr_mode; /* _WIN_BUFFER_ADDR_MODE_0 */
  325 + uint dv_ctrl; /* _WIN_DV_CONTROL_0 */
  326 + uint blend_nokey; /* _WIN_BLEND_NOKEY_0 */
  327 + uint blend_1win; /* _WIN_BLEND_1WIN_0 */
  328 + uint blend_2win_x; /* _WIN_BLEND_2WIN_X_0 */
  329 + uint blend_2win_y; /* _WIN_BLEND_2WIN_Y_0 */
  330 + uint blend_3win_xy; /* _WIN_BLEND_3WIN_XY_0 */
  331 + uint hp_fetch_ctrl; /* _WIN_HP_FETCH_CONTROL_0 */
  332 +};
  333 +
  334 +/* WINBUF A/B/C Register 0x800 ~ 0x80a */
  335 +struct dc_winbuf_reg {
  336 + /* Address 0x800 ~ 0x80a */
  337 + uint start_addr; /* _WINBUF_START_ADDR_0 */
  338 + uint start_addr_ns; /* _WINBUF_START_ADDR_NS_0 */
  339 + uint start_addr_u; /* _WINBUF_START_ADDR_U_0 */
  340 + uint start_addr_u_ns; /* _WINBUF_START_ADDR_U_NS_0 */
  341 + uint start_addr_v; /* _WINBUF_START_ADDR_V_0 */
  342 + uint start_addr_v_ns; /* _WINBUF_START_ADDR_V_NS_0 */
  343 + uint addr_h_offset; /* _WINBUF_ADDR_H_OFFSET_0 */
  344 + uint addr_h_offset_ns; /* _WINBUF_ADDR_H_OFFSET_NS_0 */
  345 + uint addr_v_offset; /* _WINBUF_ADDR_V_OFFSET_0 */
  346 + uint addr_v_offset_ns; /* _WINBUF_ADDR_V_OFFSET_NS_0 */
  347 + uint uflow_status; /* _WINBUF_UFLOW_STATUS_0 */
  348 +};
  349 +
  350 +/* Display Controller (DC_) regs */
  351 +struct dc_ctlr {
  352 + struct dc_cmd_reg cmd; /* CMD register 0x000 ~ 0x43 */
  353 + uint reserved0[0x2bc];
  354 +
  355 + struct dc_com_reg com; /* COM register 0x300 ~ 0x329 */
  356 + uint reserved1[0xd6];
  357 +
  358 + struct dc_disp_reg disp; /* DISP register 0x400 ~ 0x4c1 */
  359 + uint reserved2[0x3e];
  360 +
  361 + struct dc_winc_reg winc; /* Window A/B/C 0x500 ~ 0x628 */
  362 + uint reserved3[0xd7];
  363 +
  364 + struct dc_win_reg win; /* WIN A/B/C 0x700 ~ 0x714*/
  365 + uint reserved4[0xeb];
  366 +
  367 + struct dc_winbuf_reg winbuf; /* WINBUF A/B/C 0x800 ~ 0x80a */
  368 +};
  369 +
  370 +#define BIT(pos) (1U << pos)
  371 +
  372 +/* DC_CMD_DISPLAY_COMMAND 0x032 */
  373 +#define CTRL_MODE_SHIFT 5
  374 +#define CTRL_MODE_MASK (0x3 << CTRL_MODE_SHIFT)
  375 +enum {
  376 + CTRL_MODE_STOP,
  377 + CTRL_MODE_C_DISPLAY,
  378 + CTRL_MODE_NC_DISPLAY,
  379 +};
  380 +
  381 +/* _WIN_COLOR_DEPTH_0 */
  382 +enum win_color_depth_id {
  383 + COLOR_DEPTH_P1,
  384 + COLOR_DEPTH_P2,
  385 + COLOR_DEPTH_P4,
  386 + COLOR_DEPTH_P8,
  387 + COLOR_DEPTH_B4G4R4A4,
  388 + COLOR_DEPTH_B5G5R5A,
  389 + COLOR_DEPTH_B5G6R5,
  390 + COLOR_DEPTH_AB5G5R5,
  391 + COLOR_DEPTH_B8G8R8A8 = 12,
  392 + COLOR_DEPTH_R8G8B8A8,
  393 + COLOR_DEPTH_B6x2G6x2R6x2A8,
  394 + COLOR_DEPTH_R6x2G6x2B6x2A8,
  395 + COLOR_DEPTH_YCbCr422,
  396 + COLOR_DEPTH_YUV422,
  397 + COLOR_DEPTH_YCbCr420P,
  398 + COLOR_DEPTH_YUV420P,
  399 + COLOR_DEPTH_YCbCr422P,
  400 + COLOR_DEPTH_YUV422P,
  401 + COLOR_DEPTH_YCbCr422R,
  402 + COLOR_DEPTH_YUV422R,
  403 + COLOR_DEPTH_YCbCr422RA,
  404 + COLOR_DEPTH_YUV422RA,
  405 +};
  406 +
  407 +/* DC_CMD_DISPLAY_POWER_CONTROL 0x036 */
  408 +#define PW0_ENABLE BIT(0)
  409 +#define PW1_ENABLE BIT(2)
  410 +#define PW2_ENABLE BIT(4)
  411 +#define PW3_ENABLE BIT(6)
  412 +#define PW4_ENABLE BIT(8)
  413 +#define PM0_ENABLE BIT(16)
  414 +#define PM1_ENABLE BIT(18)
  415 +#define SPI_ENABLE BIT(24)
  416 +#define HSPI_ENABLE BIT(25)
  417 +
  418 +/* DC_CMD_STATE_CONTROL 0x041 */
  419 +#define GENERAL_ACT_REQ BIT(0)
  420 +#define WIN_A_ACT_REQ BIT(1)
  421 +#define WIN_B_ACT_REQ BIT(2)
  422 +#define WIN_C_ACT_REQ BIT(3)
  423 +#define GENERAL_UPDATE BIT(8)
  424 +#define WIN_A_UPDATE BIT(9)
  425 +#define WIN_B_UPDATE BIT(10)
  426 +#define WIN_C_UPDATE BIT(11)
  427 +
  428 +/* DC_CMD_DISPLAY_WINDOW_HEADER 0x042 */
  429 +#define WINDOW_A_SELECT BIT(4)
  430 +#define WINDOW_B_SELECT BIT(5)
  431 +#define WINDOW_C_SELECT BIT(6)
  432 +
  433 +/* DC_DISP_DISP_CLOCK_CONTROL 0x42e */
  434 +#define SHIFT_CLK_DIVIDER_SHIFT 0
  435 +#define SHIFT_CLK_DIVIDER_MASK (0xff << SHIFT_CLK_DIVIDER_SHIFT)
  436 +#define PIXEL_CLK_DIVIDER_SHIFT 8
  437 +#define PIXEL_CLK_DIVIDER_MSK (0xf << PIXEL_CLK_DIVIDER_SHIFT)
  438 +enum {
  439 + PIXEL_CLK_DIVIDER_PCD1,
  440 + PIXEL_CLK_DIVIDER_PCD1H,
  441 + PIXEL_CLK_DIVIDER_PCD2,
  442 + PIXEL_CLK_DIVIDER_PCD3,
  443 + PIXEL_CLK_DIVIDER_PCD4,
  444 + PIXEL_CLK_DIVIDER_PCD6,
  445 + PIXEL_CLK_DIVIDER_PCD8,
  446 + PIXEL_CLK_DIVIDER_PCD9,
  447 + PIXEL_CLK_DIVIDER_PCD12,
  448 + PIXEL_CLK_DIVIDER_PCD16,
  449 + PIXEL_CLK_DIVIDER_PCD18,
  450 + PIXEL_CLK_DIVIDER_PCD24,
  451 + PIXEL_CLK_DIVIDER_PCD13,
  452 +};
  453 +
  454 +/* DC_DISP_DISP_INTERFACE_CONTROL 0x42f */
  455 +#define DATA_FORMAT_SHIFT 0
  456 +#define DATA_FORMAT_MASK (0xf << DATA_FORMAT_SHIFT)
  457 +enum {
  458 + DATA_FORMAT_DF1P1C,
  459 + DATA_FORMAT_DF1P2C24B,
  460 + DATA_FORMAT_DF1P2C18B,
  461 + DATA_FORMAT_DF1P2C16B,
  462 + DATA_FORMAT_DF2S,
  463 + DATA_FORMAT_DF3S,
  464 + DATA_FORMAT_DFSPI,
  465 + DATA_FORMAT_DF1P3C24B,
  466 + DATA_FORMAT_DF1P3C18B,
  467 +};
  468 +#define DATA_ALIGNMENT_SHIFT 8
  469 +enum {
  470 + DATA_ALIGNMENT_MSB,
  471 + DATA_ALIGNMENT_LSB,
  472 +};
  473 +#define DATA_ORDER_SHIFT 9
  474 +enum {
  475 + DATA_ORDER_RED_BLUE,
  476 + DATA_ORDER_BLUE_RED,
  477 +};
  478 +
  479 +/* DC_DISP_DATA_ENABLE_OPTIONS 0x432 */
  480 +#define DE_SELECT_SHIFT 0
  481 +#define DE_SELECT_MASK (0x3 << DE_SELECT_SHIFT)
  482 +#define DE_SELECT_ACTIVE_BLANK 0x0
  483 +#define DE_SELECT_ACTIVE 0x1
  484 +#define DE_SELECT_ACTIVE_IS 0x2
  485 +#define DE_CONTROL_SHIFT 2
  486 +#define DE_CONTROL_MASK (0x7 << DE_CONTROL_SHIFT)
  487 +enum {
  488 + DE_CONTROL_ONECLK,
  489 + DE_CONTROL_NORMAL,
  490 + DE_CONTROL_EARLY_EXT,
  491 + DE_CONTROL_EARLY,
  492 + DE_CONTROL_ACTIVE_BLANK,
  493 +};
  494 +
  495 +/* DC_WIN_WIN_OPTIONS 0x700 */
  496 +#define H_DIRECTION BIT(0)
  497 +enum {
  498 + H_DIRECTION_INCREMENT,
  499 + H_DIRECTION_DECREMENT,
  500 +};
  501 +#define V_DIRECTION BIT(2)
  502 +enum {
  503 + V_DIRECTION_INCREMENT,
  504 + V_DIRECTION_DECREMENT,
  505 +};
  506 +#define COLOR_EXPAND BIT(6)
  507 +#define CP_ENABLE BIT(16)
  508 +#define DV_ENABLE BIT(20)
  509 +#define WIN_ENABLE BIT(30)
  510 +
  511 +/* DC_WIN_BYTE_SWAP 0x701 */
  512 +#define BYTE_SWAP_SHIFT 0
  513 +#define BYTE_SWAP_MASK (3 << BYTE_SWAP_SHIFT)
  514 +enum {
  515 + BYTE_SWAP_NOSWAP,
  516 + BYTE_SWAP_SWAP2,
  517 + BYTE_SWAP_SWAP4,
  518 + BYTE_SWAP_SWAP4HW
  519 +};
  520 +
  521 +/* DC_WIN_POSITION 0x704 */
  522 +#define H_POSITION_SHIFT 0
  523 +#define H_POSITION_MASK (0x1FFF << H_POSITION_SHIFT)
  524 +#define V_POSITION_SHIFT 16
  525 +#define V_POSITION_MASK (0x1FFF << V_POSITION_SHIFT)
  526 +
  527 +/* DC_WIN_SIZE 0x705 */
  528 +#define H_SIZE_SHIFT 0
  529 +#define H_SIZE_MASK (0x1FFF << H_SIZE_SHIFT)
  530 +#define V_SIZE_SHIFT 16
  531 +#define V_SIZE_MASK (0x1FFF << V_SIZE_SHIFT)
  532 +
  533 +/* DC_WIN_PRESCALED_SIZE 0x706 */
  534 +#define H_PRESCALED_SIZE_SHIFT 0
  535 +#define H_PRESCALED_SIZE_MASK (0x7FFF << H_PRESCALED_SIZE)
  536 +#define V_PRESCALED_SIZE_SHIFT 16
  537 +#define V_PRESCALED_SIZE_MASK (0x1FFF << V_PRESCALED_SIZE)
  538 +
  539 +/* DC_WIN_DDA_INCREMENT 0x709 */
  540 +#define H_DDA_INC_SHIFT 0
  541 +#define H_DDA_INC_MASK (0xFFFF << H_DDA_INC_SHIFT)
  542 +#define V_DDA_INC_SHIFT 16
  543 +#define V_DDA_INC_MASK (0xFFFF << V_DDA_INC_SHIFT)
  544 +
  545 +#endif /* __ASM_ARCH_TEGRA_DC_H */
arch/arm/include/asm/arch-tegra20/display.h
  1 +/*
  2 + * (C) Copyright 2010
  3 + * NVIDIA Corporation <www.nvidia.com>
  4 + *
  5 + * See file CREDITS for list of people who contributed to this
  6 + * project.
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License as
  10 + * published by the Free Software Foundation; either version 2 of
  11 + * the License, or (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the Free Software
  20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 + * MA 02111-1307 USA
  22 + */
  23 +
  24 +#ifndef __ASM_ARCH_TEGRA_DISPLAY_H
  25 +#define __ASM_ARCH_TEGRA_DISPLAY_H
  26 +
  27 +#include <asm/arch/dc.h>
  28 +#include <fdtdec.h>
  29 +
  30 +/* This holds information about a window which can be displayed */
  31 +struct disp_ctl_win {
  32 + enum win_color_depth_id fmt; /* Color depth/format */
  33 + unsigned bpp; /* Bits per pixel */
  34 + phys_addr_t phys_addr; /* Physical address in memory */
  35 + unsigned x; /* Horizontal address offset (bytes) */
  36 + unsigned y; /* Veritical address offset (bytes) */
  37 + unsigned w; /* Width of source window */
  38 + unsigned h; /* Height of source window */
  39 + unsigned stride; /* Number of bytes per line */
  40 + unsigned out_x; /* Left edge of output window (col) */
  41 + unsigned out_y; /* Top edge of output window (row) */
  42 + unsigned out_w; /* Width of output window in pixels */
  43 + unsigned out_h; /* Height of output window in pixels */
  44 +};
  45 +
  46 +#define FDT_LCD_TIMINGS 4
  47 +
  48 +enum {
  49 + FDT_LCD_TIMING_REF_TO_SYNC,
  50 + FDT_LCD_TIMING_SYNC_WIDTH,
  51 + FDT_LCD_TIMING_BACK_PORCH,
  52 + FDT_LCD_TIMING_FRONT_PORCH,
  53 +
  54 + FDT_LCD_TIMING_COUNT,
  55 +};
  56 +
  57 +enum lcd_cache_t {
  58 + FDT_LCD_CACHE_OFF = 0,
  59 + FDT_LCD_CACHE_WRITE_THROUGH = 1 << 0,
  60 + FDT_LCD_CACHE_WRITE_BACK = 1 << 1,
  61 + FDT_LCD_CACHE_FLUSH = 1 << 2,
  62 + FDT_LCD_CACHE_WRITE_BACK_FLUSH = FDT_LCD_CACHE_WRITE_BACK |
  63 + FDT_LCD_CACHE_FLUSH,
  64 +};
  65 +
  66 +/* Information about the display controller */
  67 +struct fdt_disp_config {
  68 + int valid; /* config is valid */
  69 + int width; /* width in pixels */
  70 + int height; /* height in pixels */
  71 + int bpp; /* number of bits per pixel */
  72 +
  73 + /*
  74 + * log2 of number of bpp, in general, unless it bpp is 24 in which
  75 + * case this field holds 24 also! This is a U-Boot thing.
  76 + */
  77 + int log2_bpp;
  78 + struct disp_ctlr *disp; /* Display controller to use */
  79 + fdt_addr_t frame_buffer; /* Address of frame buffer */
  80 + unsigned pixel_clock; /* Pixel clock in Hz */
  81 + uint horiz_timing[FDT_LCD_TIMING_COUNT]; /* Horizontal timing */
  82 + uint vert_timing[FDT_LCD_TIMING_COUNT]; /* Vertical timing */
  83 + int panel_node; /* node offset of panel information */
  84 +};
  85 +
  86 +/* Information about the LCD panel */
  87 +struct fdt_panel_config {
  88 + int pwm_channel; /* PWM channel to use for backlight */
  89 + enum lcd_cache_t cache_type;
  90 +
  91 + struct fdt_gpio_state backlight_en; /* GPIO for backlight enable */
  92 + struct fdt_gpio_state lvds_shutdown; /* GPIO for lvds shutdown */
  93 + struct fdt_gpio_state backlight_vdd; /* GPIO for backlight vdd */
  94 + struct fdt_gpio_state panel_vdd; /* GPIO for panel vdd */
  95 + /*
  96 + * Panel required timings
  97 + * Timing 1: delay between panel_vdd-rise and data-rise
  98 + * Timing 2: delay between data-rise and backlight_vdd-rise
  99 + * Timing 3: delay between backlight_vdd and pwm-rise
  100 + * Timing 4: delay between pwm-rise and backlight_en-rise
  101 + */
  102 + uint panel_timings[FDT_LCD_TIMINGS];
  103 +};
  104 +
  105 +/**
  106 + * Register a new display based on device tree configuration.
  107 + *
  108 + * The frame buffer can be positioned by U-Boot or overriden by the fdt.
  109 + * You should pass in the U-Boot address here, and check the contents of
  110 + * struct fdt_disp_config to see what was actually chosen.
  111 + *
  112 + * @param blob Device tree blob
  113 + * @param default_lcd_base Default address of LCD frame buffer
  114 + * @return 0 if ok, -1 on error (unsupported bits per pixel)
  115 + */
  116 +int tegra_display_probe(const void *blob, void *default_lcd_base);
  117 +
  118 +/**
  119 + * Return the current display configuration
  120 + *
  121 + * @return pointer to display configuration, or NULL if there is no valid
  122 + * config
  123 + */
  124 +struct fdt_disp_config *tegra_display_get_config(void);
  125 +
  126 +/**
  127 + * Perform the next stage of the LCD init if it is time to do so.
  128 + *
  129 + * LCD init can be time-consuming because of the number of delays we need
  130 + * while waiting for the backlight power supply, etc. This function can
  131 + * be called at various times during U-Boot operation to advance the
  132 + * initialization of the LCD to the next stage if sufficient time has
  133 + * passed since the last stage. It keeps track of what stage it is up to
  134 + * and the time that it is permitted to move to the next stage.
  135 + *
  136 + * The final call should have wait=1 to complete the init.
  137 + *
  138 + * @param blob fdt blob containing LCD information
  139 + * @param wait 1 to wait until all init is complete, and then return
  140 + * 0 to return immediately, potentially doing nothing if it is
  141 + * not yet time for the next init.
  142 + */
  143 +int tegra_lcd_check_next_stage(const void *blob, int wait);
  144 +
  145 +/**
  146 + * Set up the maximum LCD size so we can size the frame buffer.
  147 + *
  148 + * @param blob fdt blob containing LCD information
  149 + */
  150 +void tegra_lcd_early_init(const void *blob);
  151 +
  152 +#endif /*__ASM_ARCH_TEGRA_DISPLAY_H*/
... ... @@ -67,6 +67,7 @@
67 67 COMPAT_NVIDIA_TEGRA20_KBC, /* Tegra20 Keyboard */
68 68 COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */
69 69 COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */
  70 + COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */
70 71  
71 72 COMPAT_COUNT,
72 73 };
... ... @@ -44,6 +44,7 @@
44 44 COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
45 45 COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
46 46 COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
  47 + COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
47 48 };
48 49  
49 50 const char *fdtdec_get_compatible(enum fdt_compat_id id)