3 * NVIDIA Corporation <www.nvidia.com>
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/arch/clock.h>
11 #include <asm/arch/tegra.h>
12 #include <asm/arch/display.h>
13 #include <asm/arch/dc.h>
14 #include <asm/arch-tegra/clk_rst.h>
15 #include <asm/arch-tegra/timer.h>
17 static struct fdt_disp_config config
;
19 static void update_window(struct dc_ctlr
*dc
, struct disp_ctl_win
*win
)
21 unsigned h_dda
, v_dda
;
24 val
= readl(&dc
->cmd
.disp_win_header
);
25 val
|= WINDOW_A_SELECT
;
26 writel(val
, &dc
->cmd
.disp_win_header
);
28 writel(win
->fmt
, &dc
->win
.color_depth
);
30 clrsetbits_le32(&dc
->win
.byte_swap
, BYTE_SWAP_MASK
,
31 BYTE_SWAP_NOSWAP
<< BYTE_SWAP_SHIFT
);
33 val
= win
->out_x
<< H_POSITION_SHIFT
;
34 val
|= win
->out_y
<< V_POSITION_SHIFT
;
35 writel(val
, &dc
->win
.pos
);
37 val
= win
->out_w
<< H_SIZE_SHIFT
;
38 val
|= win
->out_h
<< V_SIZE_SHIFT
;
39 writel(val
, &dc
->win
.size
);
41 val
= (win
->w
* win
->bpp
/ 8) << H_PRESCALED_SIZE_SHIFT
;
42 val
|= win
->h
<< V_PRESCALED_SIZE_SHIFT
;
43 writel(val
, &dc
->win
.prescaled_size
);
45 writel(0, &dc
->win
.h_initial_dda
);
46 writel(0, &dc
->win
.v_initial_dda
);
48 h_dda
= (win
->w
* 0x1000) / max(win
->out_w
- 1, 1);
49 v_dda
= (win
->h
* 0x1000) / max(win
->out_h
- 1, 1);
51 val
= h_dda
<< H_DDA_INC_SHIFT
;
52 val
|= v_dda
<< V_DDA_INC_SHIFT
;
53 writel(val
, &dc
->win
.dda_increment
);
55 writel(win
->stride
, &dc
->win
.line_stride
);
56 writel(0, &dc
->win
.buf_stride
);
61 writel(val
, &dc
->win
.win_opt
);
63 writel((unsigned long)win
->phys_addr
, &dc
->winbuf
.start_addr
);
64 writel(win
->x
, &dc
->winbuf
.addr_h_offset
);
65 writel(win
->y
, &dc
->winbuf
.addr_v_offset
);
67 writel(0xff00, &dc
->win
.blend_nokey
);
68 writel(0xff00, &dc
->win
.blend_1win
);
70 val
= GENERAL_ACT_REQ
| WIN_A_ACT_REQ
;
71 val
|= GENERAL_UPDATE
| WIN_A_UPDATE
;
72 writel(val
, &dc
->cmd
.state_ctrl
);
75 static void write_pair(struct fdt_disp_config
*config
, int item
, u32
*reg
)
77 writel(config
->horiz_timing
[item
] |
78 (config
->vert_timing
[item
] << 16), reg
);
81 static int update_display_mode(struct dc_disp_reg
*disp
,
82 struct fdt_disp_config
*config
)
88 writel(0x0, &disp
->disp_timing_opt
);
89 write_pair(config
, FDT_LCD_TIMING_REF_TO_SYNC
, &disp
->ref_to_sync
);
90 write_pair(config
, FDT_LCD_TIMING_SYNC_WIDTH
, &disp
->sync_width
);
91 write_pair(config
, FDT_LCD_TIMING_BACK_PORCH
, &disp
->back_porch
);
92 write_pair(config
, FDT_LCD_TIMING_FRONT_PORCH
, &disp
->front_porch
);
94 writel(config
->width
| (config
->height
<< 16), &disp
->disp_active
);
96 val
= DE_SELECT_ACTIVE
<< DE_SELECT_SHIFT
;
97 val
|= DE_CONTROL_NORMAL
<< DE_CONTROL_SHIFT
;
98 writel(val
, &disp
->data_enable_opt
);
100 val
= DATA_FORMAT_DF1P1C
<< DATA_FORMAT_SHIFT
;
101 val
|= DATA_ALIGNMENT_MSB
<< DATA_ALIGNMENT_SHIFT
;
102 val
|= DATA_ORDER_RED_BLUE
<< DATA_ORDER_SHIFT
;
103 writel(val
, &disp
->disp_interface_ctrl
);
106 * The pixel clock divider is in 7.1 format (where the bottom bit
107 * represents 0.5). Here we calculate the divider needed to get from
108 * the display clock (typically 600MHz) to the pixel clock. We round
109 * up or down as requried.
111 rate
= clock_get_periph_rate(PERIPH_ID_DISP1
, CLOCK_ID_CGENERAL
);
112 div
= ((rate
* 2 + config
->pixel_clock
/ 2) / config
->pixel_clock
) - 2;
113 debug("Display clock %lu, divider %lu\n", rate
, div
);
115 writel(0x00010001, &disp
->shift_clk_opt
);
117 val
= PIXEL_CLK_DIVIDER_PCD1
<< PIXEL_CLK_DIVIDER_SHIFT
;
118 val
|= div
<< SHIFT_CLK_DIVIDER_SHIFT
;
119 writel(val
, &disp
->disp_clk_ctrl
);
124 /* Start up the display and turn on power to PWMs */
125 static void basic_init(struct dc_cmd_reg
*cmd
)
129 writel(0x00000100, &cmd
->gen_incr_syncpt_ctrl
);
130 writel(0x0000011a, &cmd
->cont_syncpt_vsync
);
131 writel(0x00000000, &cmd
->int_type
);
132 writel(0x00000000, &cmd
->int_polarity
);
133 writel(0x00000000, &cmd
->int_mask
);
134 writel(0x00000000, &cmd
->int_enb
);
136 val
= PW0_ENABLE
| PW1_ENABLE
| PW2_ENABLE
;
137 val
|= PW3_ENABLE
| PW4_ENABLE
| PM0_ENABLE
;
139 writel(val
, &cmd
->disp_pow_ctrl
);
141 val
= readl(&cmd
->disp_cmd
);
142 val
|= CTRL_MODE_C_DISPLAY
<< CTRL_MODE_SHIFT
;
143 writel(val
, &cmd
->disp_cmd
);
146 static void basic_init_timer(struct dc_disp_reg
*disp
)
148 writel(0x00000020, &disp
->mem_high_pri
);
149 writel(0x00000001, &disp
->mem_high_pri_timer
);
152 static const u32 rgb_enb_tab
[PIN_REG_COUNT
] = {
159 static const u32 rgb_polarity_tab
[PIN_REG_COUNT
] = {
166 static const u32 rgb_data_tab
[PIN_REG_COUNT
] = {
173 static const u32 rgb_sel_tab
[PIN_OUTPUT_SEL_COUNT
] = {
183 static void rgb_enable(struct dc_com_reg
*com
)
187 for (i
= 0; i
< PIN_REG_COUNT
; i
++) {
188 writel(rgb_enb_tab
[i
], &com
->pin_output_enb
[i
]);
189 writel(rgb_polarity_tab
[i
], &com
->pin_output_polarity
[i
]);
190 writel(rgb_data_tab
[i
], &com
->pin_output_data
[i
]);
193 for (i
= 0; i
< PIN_OUTPUT_SEL_COUNT
; i
++)
194 writel(rgb_sel_tab
[i
], &com
->pin_output_sel
[i
]);
197 int setup_window(struct disp_ctl_win
*win
, struct fdt_disp_config
*config
)
201 win
->w
= config
->width
;
202 win
->h
= config
->height
;
205 win
->out_w
= config
->width
;
206 win
->out_h
= config
->height
;
207 win
->phys_addr
= config
->frame_buffer
;
208 win
->stride
= config
->width
* (1 << config
->log2_bpp
) / 8;
209 debug("%s: depth = %d\n", __func__
, config
->log2_bpp
);
210 switch (config
->log2_bpp
) {
213 win
->fmt
= COLOR_DEPTH_R8G8B8A8
;
217 win
->fmt
= COLOR_DEPTH_B5G6R5
;
222 debug("Unsupported LCD bit depth");
229 struct fdt_disp_config
*tegra_display_get_config(void)
231 return config
.valid
? &config
: NULL
;
234 static void debug_timing(const char *name
, unsigned int timing
[])
239 debug("%s timing: ", name
);
240 for (i
= 0; i
< FDT_LCD_TIMING_COUNT
; i
++)
241 debug("%d ", timing
[i
]);
247 * Decode panel information from the fdt, according to a standard binding
249 * @param blob fdt blob
250 * @param node offset of fdt node to read from
251 * @param config structure to store fdt config into
252 * @return 0 if ok, -ve on error
254 static int tegra_decode_panel(const void *blob
, int node
,
255 struct fdt_disp_config
*config
)
257 int front
, back
, ref
;
259 config
->width
= fdtdec_get_int(blob
, node
, "xres", -1);
260 config
->height
= fdtdec_get_int(blob
, node
, "yres", -1);
261 config
->pixel_clock
= fdtdec_get_int(blob
, node
, "clock", 0);
262 if (!config
->pixel_clock
|| config
->width
== -1 ||
263 config
->height
== -1) {
264 debug("%s: Pixel parameters missing\n", __func__
);
265 return -FDT_ERR_NOTFOUND
;
268 back
= fdtdec_get_int(blob
, node
, "left-margin", -1);
269 front
= fdtdec_get_int(blob
, node
, "right-margin", -1);
270 ref
= fdtdec_get_int(blob
, node
, "hsync-len", -1);
271 if ((back
| front
| ref
) == -1) {
272 debug("%s: Horizontal parameters missing\n", __func__
);
273 return -FDT_ERR_NOTFOUND
;
276 /* Use a ref-to-sync of 1 always, and take this from the front porch */
277 config
->horiz_timing
[FDT_LCD_TIMING_REF_TO_SYNC
] = 1;
278 config
->horiz_timing
[FDT_LCD_TIMING_SYNC_WIDTH
] = ref
;
279 config
->horiz_timing
[FDT_LCD_TIMING_BACK_PORCH
] = back
;
280 config
->horiz_timing
[FDT_LCD_TIMING_FRONT_PORCH
] = front
-
281 config
->horiz_timing
[FDT_LCD_TIMING_REF_TO_SYNC
];
282 debug_timing("horiz", config
->horiz_timing
);
284 back
= fdtdec_get_int(blob
, node
, "upper-margin", -1);
285 front
= fdtdec_get_int(blob
, node
, "lower-margin", -1);
286 ref
= fdtdec_get_int(blob
, node
, "vsync-len", -1);
287 if ((back
| front
| ref
) == -1) {
288 debug("%s: Vertical parameters missing\n", __func__
);
289 return -FDT_ERR_NOTFOUND
;
292 config
->vert_timing
[FDT_LCD_TIMING_REF_TO_SYNC
] = 1;
293 config
->vert_timing
[FDT_LCD_TIMING_SYNC_WIDTH
] = ref
;
294 config
->vert_timing
[FDT_LCD_TIMING_BACK_PORCH
] = back
;
295 config
->vert_timing
[FDT_LCD_TIMING_FRONT_PORCH
] = front
-
296 config
->vert_timing
[FDT_LCD_TIMING_REF_TO_SYNC
];
297 debug_timing("vert", config
->vert_timing
);
303 * Decode the display controller information from the fdt.
305 * @param blob fdt blob
306 * @param config structure to store fdt config into
307 * @return 0 if ok, -ve on error
309 static int tegra_display_decode_config(const void *blob
,
310 struct fdt_disp_config
*config
)
315 /* TODO: Support multiple controllers */
316 node
= fdtdec_next_compatible(blob
, 0, COMPAT_NVIDIA_TEGRA20_DC
);
318 debug("%s: Cannot find display controller node in fdt\n",
322 config
->disp
= (struct disp_ctlr
*)fdtdec_get_addr(blob
, node
, "reg");
324 debug("%s: No display controller address\n", __func__
);
328 rgb
= fdt_subnode_offset(blob
, node
, "rgb");
330 config
->panel_node
= fdtdec_lookup_phandle(blob
, rgb
, "nvidia,panel");
331 if (!config
->panel_node
< 0) {
332 debug("%s: Cannot find panel information\n", __func__
);
336 if (tegra_decode_panel(blob
, config
->panel_node
, config
)) {
337 debug("%s: Failed to decode panel information\n", __func__
);
341 bpp
= fdtdec_get_int(blob
, config
->panel_node
, "nvidia,bits-per-pixel",
344 if (bpp
== (1 << bit
))
345 config
->log2_bpp
= bit
;
347 config
->log2_bpp
= bpp
;
349 debug("%s: Pixel bpp parameters missing\n", __func__
);
350 return -FDT_ERR_NOTFOUND
;
354 config
->valid
= 1; /* we have a valid configuration */
359 int tegra_display_probe(const void *blob
, void *default_lcd_base
)
361 struct disp_ctl_win window
;
364 if (tegra_display_decode_config(blob
, &config
))
367 config
.frame_buffer
= (u32
)default_lcd_base
;
369 dc
= (struct dc_ctlr
*)config
.disp
;
372 * A header file for clock constants was NAKed upstream.
373 * TODO: Put this into the FDT and fdt_lcd struct when we have clock
376 clock_start_periph_pll(PERIPH_ID_HOST1X
, CLOCK_ID_PERIPH
,
378 clock_start_periph_pll(PERIPH_ID_DISP1
, CLOCK_ID_CGENERAL
,
380 basic_init(&dc
->cmd
);
381 basic_init_timer(&dc
->disp
);
382 rgb_enable(&dc
->com
);
384 if (config
.pixel_clock
)
385 update_display_mode(&dc
->disp
, &config
);
387 if (setup_window(&window
, &config
))
390 update_window(dc
, &window
);