2 * Copyright (c) 2011 The Chromium OS Authors.
3 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/system.h>
14 #include <asm/arch/clock.h>
15 #include <asm/arch/funcmux.h>
16 #include <asm/arch/pinmux.h>
17 #include <asm/arch/pwm.h>
18 #include <asm/arch/display.h>
19 #include <asm/arch-tegra/timer.h>
21 DECLARE_GLOBAL_DATA_PTR
;
23 /* These are the stages we go throuh in enabling the LCD */
34 static enum stage_t stage
; /* Current stage we are at */
35 static unsigned long timer_next
; /* Time we can move onto next stage */
37 /* Our LCD config, set up in handle_stage() */
38 static struct fdt_panel_config config
;
39 struct fdt_disp_config
*disp_config
; /* Display controller config */
40 static struct fdt_disp_config dconfig
;
43 /* Maximum LCD size we support */
46 LCD_MAX_LOG2_BPP
= 4, /* 2^4 = 16 bpp */
49 vidinfo_t panel_info
= {
50 /* Insert a value here so that we don't end up in the BSS */
54 #if !CONFIG_IS_ENABLED(OF_CONTROL)
55 #error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
58 static void update_window(struct dc_ctlr
*dc
, struct disp_ctl_win
*win
)
60 unsigned h_dda
, v_dda
;
63 val
= readl(&dc
->cmd
.disp_win_header
);
64 val
|= WINDOW_A_SELECT
;
65 writel(val
, &dc
->cmd
.disp_win_header
);
67 writel(win
->fmt
, &dc
->win
.color_depth
);
69 clrsetbits_le32(&dc
->win
.byte_swap
, BYTE_SWAP_MASK
,
70 BYTE_SWAP_NOSWAP
<< BYTE_SWAP_SHIFT
);
72 val
= win
->out_x
<< H_POSITION_SHIFT
;
73 val
|= win
->out_y
<< V_POSITION_SHIFT
;
74 writel(val
, &dc
->win
.pos
);
76 val
= win
->out_w
<< H_SIZE_SHIFT
;
77 val
|= win
->out_h
<< V_SIZE_SHIFT
;
78 writel(val
, &dc
->win
.size
);
80 val
= (win
->w
* win
->bpp
/ 8) << H_PRESCALED_SIZE_SHIFT
;
81 val
|= win
->h
<< V_PRESCALED_SIZE_SHIFT
;
82 writel(val
, &dc
->win
.prescaled_size
);
84 writel(0, &dc
->win
.h_initial_dda
);
85 writel(0, &dc
->win
.v_initial_dda
);
87 h_dda
= (win
->w
* 0x1000) / max(win
->out_w
- 1, 1U);
88 v_dda
= (win
->h
* 0x1000) / max(win
->out_h
- 1, 1U);
90 val
= h_dda
<< H_DDA_INC_SHIFT
;
91 val
|= v_dda
<< V_DDA_INC_SHIFT
;
92 writel(val
, &dc
->win
.dda_increment
);
94 writel(win
->stride
, &dc
->win
.line_stride
);
95 writel(0, &dc
->win
.buf_stride
);
100 writel(val
, &dc
->win
.win_opt
);
102 writel((unsigned long)win
->phys_addr
, &dc
->winbuf
.start_addr
);
103 writel(win
->x
, &dc
->winbuf
.addr_h_offset
);
104 writel(win
->y
, &dc
->winbuf
.addr_v_offset
);
106 writel(0xff00, &dc
->win
.blend_nokey
);
107 writel(0xff00, &dc
->win
.blend_1win
);
109 val
= GENERAL_ACT_REQ
| WIN_A_ACT_REQ
;
110 val
|= GENERAL_UPDATE
| WIN_A_UPDATE
;
111 writel(val
, &dc
->cmd
.state_ctrl
);
114 static void write_pair(struct fdt_disp_config
*config
, int item
, u32
*reg
)
116 writel(config
->horiz_timing
[item
] |
117 (config
->vert_timing
[item
] << 16), reg
);
120 static int update_display_mode(struct dc_disp_reg
*disp
,
121 struct fdt_disp_config
*config
)
127 writel(0x0, &disp
->disp_timing_opt
);
128 write_pair(config
, FDT_LCD_TIMING_REF_TO_SYNC
, &disp
->ref_to_sync
);
129 write_pair(config
, FDT_LCD_TIMING_SYNC_WIDTH
, &disp
->sync_width
);
130 write_pair(config
, FDT_LCD_TIMING_BACK_PORCH
, &disp
->back_porch
);
131 write_pair(config
, FDT_LCD_TIMING_FRONT_PORCH
, &disp
->front_porch
);
133 writel(config
->width
| (config
->height
<< 16), &disp
->disp_active
);
135 val
= DE_SELECT_ACTIVE
<< DE_SELECT_SHIFT
;
136 val
|= DE_CONTROL_NORMAL
<< DE_CONTROL_SHIFT
;
137 writel(val
, &disp
->data_enable_opt
);
139 val
= DATA_FORMAT_DF1P1C
<< DATA_FORMAT_SHIFT
;
140 val
|= DATA_ALIGNMENT_MSB
<< DATA_ALIGNMENT_SHIFT
;
141 val
|= DATA_ORDER_RED_BLUE
<< DATA_ORDER_SHIFT
;
142 writel(val
, &disp
->disp_interface_ctrl
);
145 * The pixel clock divider is in 7.1 format (where the bottom bit
146 * represents 0.5). Here we calculate the divider needed to get from
147 * the display clock (typically 600MHz) to the pixel clock. We round
148 * up or down as requried.
150 rate
= clock_get_periph_rate(PERIPH_ID_DISP1
, CLOCK_ID_CGENERAL
);
151 div
= ((rate
* 2 + config
->pixel_clock
/ 2) / config
->pixel_clock
) - 2;
152 debug("Display clock %lu, divider %lu\n", rate
, div
);
154 writel(0x00010001, &disp
->shift_clk_opt
);
156 val
= PIXEL_CLK_DIVIDER_PCD1
<< PIXEL_CLK_DIVIDER_SHIFT
;
157 val
|= div
<< SHIFT_CLK_DIVIDER_SHIFT
;
158 writel(val
, &disp
->disp_clk_ctrl
);
163 /* Start up the display and turn on power to PWMs */
164 static void basic_init(struct dc_cmd_reg
*cmd
)
168 writel(0x00000100, &cmd
->gen_incr_syncpt_ctrl
);
169 writel(0x0000011a, &cmd
->cont_syncpt_vsync
);
170 writel(0x00000000, &cmd
->int_type
);
171 writel(0x00000000, &cmd
->int_polarity
);
172 writel(0x00000000, &cmd
->int_mask
);
173 writel(0x00000000, &cmd
->int_enb
);
175 val
= PW0_ENABLE
| PW1_ENABLE
| PW2_ENABLE
;
176 val
|= PW3_ENABLE
| PW4_ENABLE
| PM0_ENABLE
;
178 writel(val
, &cmd
->disp_pow_ctrl
);
180 val
= readl(&cmd
->disp_cmd
);
181 val
|= CTRL_MODE_C_DISPLAY
<< CTRL_MODE_SHIFT
;
182 writel(val
, &cmd
->disp_cmd
);
185 static void basic_init_timer(struct dc_disp_reg
*disp
)
187 writel(0x00000020, &disp
->mem_high_pri
);
188 writel(0x00000001, &disp
->mem_high_pri_timer
);
191 static const u32 rgb_enb_tab
[PIN_REG_COUNT
] = {
198 static const u32 rgb_polarity_tab
[PIN_REG_COUNT
] = {
205 static const u32 rgb_data_tab
[PIN_REG_COUNT
] = {
212 static const u32 rgb_sel_tab
[PIN_OUTPUT_SEL_COUNT
] = {
222 static void rgb_enable(struct dc_com_reg
*com
)
226 for (i
= 0; i
< PIN_REG_COUNT
; i
++) {
227 writel(rgb_enb_tab
[i
], &com
->pin_output_enb
[i
]);
228 writel(rgb_polarity_tab
[i
], &com
->pin_output_polarity
[i
]);
229 writel(rgb_data_tab
[i
], &com
->pin_output_data
[i
]);
232 for (i
= 0; i
< PIN_OUTPUT_SEL_COUNT
; i
++)
233 writel(rgb_sel_tab
[i
], &com
->pin_output_sel
[i
]);
236 static int setup_window(struct disp_ctl_win
*win
,
237 struct fdt_disp_config
*config
)
241 win
->w
= config
->width
;
242 win
->h
= config
->height
;
245 win
->out_w
= config
->width
;
246 win
->out_h
= config
->height
;
247 win
->phys_addr
= config
->frame_buffer
;
248 win
->stride
= config
->width
* (1 << config
->log2_bpp
) / 8;
249 debug("%s: depth = %d\n", __func__
, config
->log2_bpp
);
250 switch (config
->log2_bpp
) {
253 win
->fmt
= COLOR_DEPTH_R8G8B8A8
;
257 win
->fmt
= COLOR_DEPTH_B5G6R5
;
262 debug("Unsupported LCD bit depth");
270 * Return the current display configuration
272 * @return pointer to display configuration, or NULL if there is no valid
275 struct fdt_disp_config
*tegra_display_get_config(void)
277 return dconfig
.valid
? &dconfig
: NULL
;
280 static void debug_timing(const char *name
, unsigned int timing
[])
285 debug("%s timing: ", name
);
286 for (i
= 0; i
< FDT_LCD_TIMING_COUNT
; i
++)
287 debug("%d ", timing
[i
]);
293 * Decode panel information from the fdt, according to a standard binding
295 * @param blob fdt blob
296 * @param node offset of fdt node to read from
297 * @param config structure to store fdt config into
298 * @return 0 if ok, -ve on error
300 static int tegra_decode_panel(const void *blob
, int node
,
301 struct fdt_disp_config
*config
)
303 int front
, back
, ref
;
305 config
->width
= fdtdec_get_int(blob
, node
, "xres", -1);
306 config
->height
= fdtdec_get_int(blob
, node
, "yres", -1);
307 config
->pixel_clock
= fdtdec_get_int(blob
, node
, "clock", 0);
308 if (!config
->pixel_clock
|| config
->width
== -1 ||
309 config
->height
== -1) {
310 debug("%s: Pixel parameters missing\n", __func__
);
311 return -FDT_ERR_NOTFOUND
;
314 back
= fdtdec_get_int(blob
, node
, "left-margin", -1);
315 front
= fdtdec_get_int(blob
, node
, "right-margin", -1);
316 ref
= fdtdec_get_int(blob
, node
, "hsync-len", -1);
317 if ((back
| front
| ref
) == -1) {
318 debug("%s: Horizontal parameters missing\n", __func__
);
319 return -FDT_ERR_NOTFOUND
;
322 /* Use a ref-to-sync of 1 always, and take this from the front porch */
323 config
->horiz_timing
[FDT_LCD_TIMING_REF_TO_SYNC
] = 1;
324 config
->horiz_timing
[FDT_LCD_TIMING_SYNC_WIDTH
] = ref
;
325 config
->horiz_timing
[FDT_LCD_TIMING_BACK_PORCH
] = back
;
326 config
->horiz_timing
[FDT_LCD_TIMING_FRONT_PORCH
] = front
-
327 config
->horiz_timing
[FDT_LCD_TIMING_REF_TO_SYNC
];
328 debug_timing("horiz", config
->horiz_timing
);
330 back
= fdtdec_get_int(blob
, node
, "upper-margin", -1);
331 front
= fdtdec_get_int(blob
, node
, "lower-margin", -1);
332 ref
= fdtdec_get_int(blob
, node
, "vsync-len", -1);
333 if ((back
| front
| ref
) == -1) {
334 debug("%s: Vertical parameters missing\n", __func__
);
335 return -FDT_ERR_NOTFOUND
;
338 config
->vert_timing
[FDT_LCD_TIMING_REF_TO_SYNC
] = 1;
339 config
->vert_timing
[FDT_LCD_TIMING_SYNC_WIDTH
] = ref
;
340 config
->vert_timing
[FDT_LCD_TIMING_BACK_PORCH
] = back
;
341 config
->vert_timing
[FDT_LCD_TIMING_FRONT_PORCH
] = front
-
342 config
->vert_timing
[FDT_LCD_TIMING_REF_TO_SYNC
];
343 debug_timing("vert", config
->vert_timing
);
349 * Decode the display controller information from the fdt.
351 * @param blob fdt blob
352 * @param config structure to store fdt config into
353 * @return 0 if ok, -ve on error
355 static int tegra_display_decode_config(const void *blob
,
356 struct fdt_disp_config
*config
)
361 /* TODO: Support multiple controllers */
362 node
= fdtdec_next_compatible(blob
, 0, COMPAT_NVIDIA_TEGRA20_DC
);
364 debug("%s: Cannot find display controller node in fdt\n",
368 config
->disp
= (struct disp_ctlr
*)fdtdec_get_addr(blob
, node
, "reg");
370 debug("%s: No display controller address\n", __func__
);
374 rgb
= fdt_subnode_offset(blob
, node
, "rgb");
376 config
->panel_node
= fdtdec_lookup_phandle(blob
, rgb
, "nvidia,panel");
377 if (config
->panel_node
< 0) {
378 debug("%s: Cannot find panel information\n", __func__
);
382 if (tegra_decode_panel(blob
, config
->panel_node
, config
)) {
383 debug("%s: Failed to decode panel information\n", __func__
);
387 bpp
= fdtdec_get_int(blob
, config
->panel_node
, "nvidia,bits-per-pixel",
390 if (bpp
== (1 << bit
))
391 config
->log2_bpp
= bit
;
393 config
->log2_bpp
= bpp
;
395 debug("%s: Pixel bpp parameters missing\n", __func__
);
396 return -FDT_ERR_NOTFOUND
;
400 config
->valid
= 1; /* we have a valid configuration */
406 * Register a new display based on device tree configuration.
408 * The frame buffer can be positioned by U-Boot or overriden by the fdt.
409 * You should pass in the U-Boot address here, and check the contents of
410 * struct fdt_disp_config to see what was actually chosen.
412 * @param blob Device tree blob
413 * @param default_lcd_base Default address of LCD frame buffer
414 * @return 0 if ok, -1 on error (unsupported bits per pixel)
416 static int tegra_display_probe(const void *blob
, void *default_lcd_base
)
418 struct disp_ctl_win window
;
421 if (tegra_display_decode_config(blob
, &dconfig
))
424 dconfig
.frame_buffer
= (u32
)default_lcd_base
;
426 dc
= (struct dc_ctlr
*)dconfig
.disp
;
429 * A header file for clock constants was NAKed upstream.
430 * TODO: Put this into the FDT and fdt_lcd struct when we have clock
433 clock_start_periph_pll(PERIPH_ID_HOST1X
, CLOCK_ID_PERIPH
,
435 clock_start_periph_pll(PERIPH_ID_DISP1
, CLOCK_ID_CGENERAL
,
437 basic_init(&dc
->cmd
);
438 basic_init_timer(&dc
->disp
);
439 rgb_enable(&dc
->com
);
441 if (dconfig
.pixel_clock
)
442 update_display_mode(&dc
->disp
, &dconfig
);
444 if (setup_window(&window
, &dconfig
))
447 update_window(dc
, &window
);
452 static void update_panel_size(struct fdt_disp_config
*config
)
454 panel_info
.vl_col
= config
->width
;
455 panel_info
.vl_row
= config
->height
;
456 panel_info
.vl_bpix
= config
->log2_bpp
;
460 * Main init function called by lcd driver.
461 * Inits and then prints test pattern if required.
464 void lcd_ctrl_init(void *lcdbase
)
466 int type
= DCACHE_OFF
;
471 /* Make sure that we can acommodate the selected LCD */
472 assert(disp_config
->width
<= LCD_MAX_WIDTH
);
473 assert(disp_config
->height
<= LCD_MAX_HEIGHT
);
474 assert(disp_config
->log2_bpp
<= LCD_MAX_LOG2_BPP
);
475 if (disp_config
->width
<= LCD_MAX_WIDTH
476 && disp_config
->height
<= LCD_MAX_HEIGHT
477 && disp_config
->log2_bpp
<= LCD_MAX_LOG2_BPP
)
478 update_panel_size(disp_config
);
479 size
= lcd_get_size(&lcd_line_length
);
481 /* Set up the LCD caching as requested */
482 if (config
.cache_type
& FDT_LCD_CACHE_WRITE_THROUGH
)
483 type
= DCACHE_WRITETHROUGH
;
484 else if (config
.cache_type
& FDT_LCD_CACHE_WRITE_BACK
)
485 type
= DCACHE_WRITEBACK
;
486 mmu_set_region_dcache_behaviour(disp_config
->frame_buffer
, size
, type
);
488 /* Enable flushing after LCD writes if requested */
489 lcd_set_flush_dcache(config
.cache_type
& FDT_LCD_CACHE_FLUSH
);
491 debug("LCD frame buffer at %pa\n", &disp_config
->frame_buffer
);
494 ulong
calc_fbsize(void)
496 return (panel_info
.vl_col
* panel_info
.vl_row
*
497 NBITS(panel_info
.vl_bpix
)) / 8;
500 void lcd_setcolreg(ushort regno
, ushort red
, ushort green
, ushort blue
)
504 void tegra_lcd_early_init(const void *blob
)
507 * Go with the maximum size for now. We will fix this up after
508 * relocation. These values are only used for memory alocation.
510 panel_info
.vl_col
= LCD_MAX_WIDTH
;
511 panel_info
.vl_row
= LCD_MAX_HEIGHT
;
512 panel_info
.vl_bpix
= LCD_MAX_LOG2_BPP
;
516 * Decode the panel information from the fdt.
518 * @param blob fdt blob
519 * @param config structure to store fdt config into
520 * @return 0 if ok, -ve on error
522 static int fdt_decode_lcd(const void *blob
, struct fdt_panel_config
*config
)
526 disp_config
= tegra_display_get_config();
528 debug("%s: Display controller is not configured\n", __func__
);
531 display_node
= disp_config
->panel_node
;
532 if (display_node
< 0) {
533 debug("%s: No panel configuration available\n", __func__
);
537 config
->pwm_channel
= pwm_request(blob
, display_node
, "nvidia,pwm");
538 if (config
->pwm_channel
< 0) {
539 debug("%s: Unable to request PWM channel\n", __func__
);
543 config
->cache_type
= fdtdec_get_int(blob
, display_node
,
545 FDT_LCD_CACHE_WRITE_BACK_FLUSH
);
547 /* These GPIOs are all optional */
548 gpio_request_by_name_nodev(blob
, display_node
,
549 "nvidia,backlight-enable-gpios", 0,
550 &config
->backlight_en
, GPIOD_IS_OUT
);
551 gpio_request_by_name_nodev(blob
, display_node
,
552 "nvidia,lvds-shutdown-gpios", 0,
553 &config
->lvds_shutdown
, GPIOD_IS_OUT
);
554 gpio_request_by_name_nodev(blob
, display_node
,
555 "nvidia,backlight-vdd-gpios", 0,
556 &config
->backlight_vdd
, GPIOD_IS_OUT
);
557 gpio_request_by_name_nodev(blob
, display_node
,
558 "nvidia,panel-vdd-gpios", 0,
559 &config
->panel_vdd
, GPIOD_IS_OUT
);
561 return fdtdec_get_int_array(blob
, display_node
, "nvidia,panel-timings",
562 config
->panel_timings
, FDT_LCD_TIMINGS
);
566 * Handle the next stage of device init
568 static int handle_stage(const void *blob
)
570 debug("%s: stage %d\n", __func__
, stage
);
572 /* do the things for this stage */
575 /* Initialize the Tegra display controller */
576 if (tegra_display_probe(gd
->fdt_blob
, (void *)gd
->fb_base
)) {
577 printf("%s: Failed to probe display driver\n",
582 /* get panel details */
583 if (fdt_decode_lcd(blob
, &config
)) {
584 printf("No valid LCD information in device tree\n");
589 * It is possible that the FDT has requested that the LCD be
590 * disabled. We currently don't support this. It would require
591 * changes to U-Boot LCD subsystem to have LCD support
592 * compiled in but not used. An easier option might be to
593 * still have a frame buffer, but leave the backlight off and
594 * remove all mention of lcd in the stdout environment
598 funcmux_select(PERIPH_ID_DISP1
, FUNCMUX_DEFAULT
);
600 case STAGE_PANEL_VDD
:
601 if (dm_gpio_is_valid(&config
.panel_vdd
))
602 dm_gpio_set_value(&config
.panel_vdd
, 1);
605 if (dm_gpio_is_valid(&config
.lvds_shutdown
))
606 dm_gpio_set_value(&config
.lvds_shutdown
, 1);
608 case STAGE_BACKLIGHT_VDD
:
609 if (dm_gpio_is_valid(&config
.backlight_vdd
))
610 dm_gpio_set_value(&config
.backlight_vdd
, 1);
613 /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
614 pinmux_set_func(PMUX_PINGRP_GPU
, PMUX_FUNC_PWM
);
615 pinmux_tristate_disable(PMUX_PINGRP_GPU
);
617 pwm_enable(config
.pwm_channel
, 32768, 0xdf, 1);
619 case STAGE_BACKLIGHT_EN
:
620 if (dm_gpio_is_valid(&config
.backlight_en
))
621 dm_gpio_set_value(&config
.backlight_en
, 1);
627 /* set up timer for next stage */
628 timer_next
= timer_get_us();
629 if (stage
< FDT_LCD_TIMINGS
)
630 timer_next
+= config
.panel_timings
[stage
] * 1000;
632 /* move to next stage */
637 int tegra_lcd_check_next_stage(const void *blob
, int wait
)
639 if (stage
== STAGE_DONE
)
643 /* wait if we need to */
644 debug("%s: stage %d\n", __func__
, stage
);
645 if (stage
!= STAGE_START
) {
646 int delay
= timer_next
- timer_get_us();
656 if (handle_stage(blob
))
658 } while (wait
&& stage
!= STAGE_DONE
);
659 if (stage
== STAGE_DONE
)
660 debug("%s: LCD init complete\n", __func__
);
665 void lcd_enable(void)
668 * Backlight and power init will be done separately in
669 * tegra_lcd_check_next_stage(), which should be called in
672 * U-Boot code supports only colour depth, selected at compile time.
673 * The device tree setting should match this. Otherwise the display
674 * will not look right, and U-Boot may crash.
676 if (disp_config
->log2_bpp
!= LCD_BPP
) {
677 printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
678 " must match setting of LCD_BPP (%d)\n", __func__
,
679 disp_config
->log2_bpp
, disp_config
->bpp
, LCD_BPP
);