1*09f455dcSMasahiro Yamada /*
2*09f455dcSMasahiro Yamada  *  (C) Copyright 2010
3*09f455dcSMasahiro Yamada  *  NVIDIA Corporation <www.nvidia.com>
4*09f455dcSMasahiro Yamada  *
5*09f455dcSMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
6*09f455dcSMasahiro Yamada  */
7*09f455dcSMasahiro Yamada 
8*09f455dcSMasahiro Yamada #include <common.h>
9*09f455dcSMasahiro Yamada #include <asm/io.h>
10*09f455dcSMasahiro Yamada #include <asm/arch/clock.h>
11*09f455dcSMasahiro Yamada #include <asm/arch/tegra.h>
12*09f455dcSMasahiro Yamada #include <asm/arch/display.h>
13*09f455dcSMasahiro Yamada #include <asm/arch/dc.h>
14*09f455dcSMasahiro Yamada #include <asm/arch-tegra/clk_rst.h>
15*09f455dcSMasahiro Yamada #include <asm/arch-tegra/timer.h>
16*09f455dcSMasahiro Yamada 
17*09f455dcSMasahiro Yamada static struct fdt_disp_config config;
18*09f455dcSMasahiro Yamada 
19*09f455dcSMasahiro Yamada static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
20*09f455dcSMasahiro Yamada {
21*09f455dcSMasahiro Yamada 	unsigned h_dda, v_dda;
22*09f455dcSMasahiro Yamada 	unsigned long val;
23*09f455dcSMasahiro Yamada 
24*09f455dcSMasahiro Yamada 	val = readl(&dc->cmd.disp_win_header);
25*09f455dcSMasahiro Yamada 	val |= WINDOW_A_SELECT;
26*09f455dcSMasahiro Yamada 	writel(val, &dc->cmd.disp_win_header);
27*09f455dcSMasahiro Yamada 
28*09f455dcSMasahiro Yamada 	writel(win->fmt, &dc->win.color_depth);
29*09f455dcSMasahiro Yamada 
30*09f455dcSMasahiro Yamada 	clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK,
31*09f455dcSMasahiro Yamada 			BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT);
32*09f455dcSMasahiro Yamada 
33*09f455dcSMasahiro Yamada 	val = win->out_x << H_POSITION_SHIFT;
34*09f455dcSMasahiro Yamada 	val |= win->out_y << V_POSITION_SHIFT;
35*09f455dcSMasahiro Yamada 	writel(val, &dc->win.pos);
36*09f455dcSMasahiro Yamada 
37*09f455dcSMasahiro Yamada 	val = win->out_w << H_SIZE_SHIFT;
38*09f455dcSMasahiro Yamada 	val |= win->out_h << V_SIZE_SHIFT;
39*09f455dcSMasahiro Yamada 	writel(val, &dc->win.size);
40*09f455dcSMasahiro Yamada 
41*09f455dcSMasahiro Yamada 	val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT;
42*09f455dcSMasahiro Yamada 	val |= win->h << V_PRESCALED_SIZE_SHIFT;
43*09f455dcSMasahiro Yamada 	writel(val, &dc->win.prescaled_size);
44*09f455dcSMasahiro Yamada 
45*09f455dcSMasahiro Yamada 	writel(0, &dc->win.h_initial_dda);
46*09f455dcSMasahiro Yamada 	writel(0, &dc->win.v_initial_dda);
47*09f455dcSMasahiro Yamada 
48*09f455dcSMasahiro Yamada 	h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1U);
49*09f455dcSMasahiro Yamada 	v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1U);
50*09f455dcSMasahiro Yamada 
51*09f455dcSMasahiro Yamada 	val = h_dda << H_DDA_INC_SHIFT;
52*09f455dcSMasahiro Yamada 	val |= v_dda << V_DDA_INC_SHIFT;
53*09f455dcSMasahiro Yamada 	writel(val, &dc->win.dda_increment);
54*09f455dcSMasahiro Yamada 
55*09f455dcSMasahiro Yamada 	writel(win->stride, &dc->win.line_stride);
56*09f455dcSMasahiro Yamada 	writel(0, &dc->win.buf_stride);
57*09f455dcSMasahiro Yamada 
58*09f455dcSMasahiro Yamada 	val = WIN_ENABLE;
59*09f455dcSMasahiro Yamada 	if (win->bpp < 24)
60*09f455dcSMasahiro Yamada 		val |= COLOR_EXPAND;
61*09f455dcSMasahiro Yamada 	writel(val, &dc->win.win_opt);
62*09f455dcSMasahiro Yamada 
63*09f455dcSMasahiro Yamada 	writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr);
64*09f455dcSMasahiro Yamada 	writel(win->x, &dc->winbuf.addr_h_offset);
65*09f455dcSMasahiro Yamada 	writel(win->y, &dc->winbuf.addr_v_offset);
66*09f455dcSMasahiro Yamada 
67*09f455dcSMasahiro Yamada 	writel(0xff00, &dc->win.blend_nokey);
68*09f455dcSMasahiro Yamada 	writel(0xff00, &dc->win.blend_1win);
69*09f455dcSMasahiro Yamada 
70*09f455dcSMasahiro Yamada 	val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
71*09f455dcSMasahiro Yamada 	val |= GENERAL_UPDATE | WIN_A_UPDATE;
72*09f455dcSMasahiro Yamada 	writel(val, &dc->cmd.state_ctrl);
73*09f455dcSMasahiro Yamada }
74*09f455dcSMasahiro Yamada 
75*09f455dcSMasahiro Yamada static void write_pair(struct fdt_disp_config *config, int item, u32 *reg)
76*09f455dcSMasahiro Yamada {
77*09f455dcSMasahiro Yamada 	writel(config->horiz_timing[item] |
78*09f455dcSMasahiro Yamada 			(config->vert_timing[item] << 16), reg);
79*09f455dcSMasahiro Yamada }
80*09f455dcSMasahiro Yamada 
81*09f455dcSMasahiro Yamada static int update_display_mode(struct dc_disp_reg *disp,
82*09f455dcSMasahiro Yamada 		struct fdt_disp_config *config)
83*09f455dcSMasahiro Yamada {
84*09f455dcSMasahiro Yamada 	unsigned long val;
85*09f455dcSMasahiro Yamada 	unsigned long rate;
86*09f455dcSMasahiro Yamada 	unsigned long div;
87*09f455dcSMasahiro Yamada 
88*09f455dcSMasahiro Yamada 	writel(0x0, &disp->disp_timing_opt);
89*09f455dcSMasahiro Yamada 	write_pair(config, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync);
90*09f455dcSMasahiro Yamada 	write_pair(config, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width);
91*09f455dcSMasahiro Yamada 	write_pair(config, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch);
92*09f455dcSMasahiro Yamada 	write_pair(config, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch);
93*09f455dcSMasahiro Yamada 
94*09f455dcSMasahiro Yamada 	writel(config->width | (config->height << 16), &disp->disp_active);
95*09f455dcSMasahiro Yamada 
96*09f455dcSMasahiro Yamada 	val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
97*09f455dcSMasahiro Yamada 	val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
98*09f455dcSMasahiro Yamada 	writel(val, &disp->data_enable_opt);
99*09f455dcSMasahiro Yamada 
100*09f455dcSMasahiro Yamada 	val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT;
101*09f455dcSMasahiro Yamada 	val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
102*09f455dcSMasahiro Yamada 	val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
103*09f455dcSMasahiro Yamada 	writel(val, &disp->disp_interface_ctrl);
104*09f455dcSMasahiro Yamada 
105*09f455dcSMasahiro Yamada 	/*
106*09f455dcSMasahiro Yamada 	 * The pixel clock divider is in 7.1 format (where the bottom bit
107*09f455dcSMasahiro Yamada 	 * represents 0.5). Here we calculate the divider needed to get from
108*09f455dcSMasahiro Yamada 	 * the display clock (typically 600MHz) to the pixel clock. We round
109*09f455dcSMasahiro Yamada 	 * up or down as requried.
110*09f455dcSMasahiro Yamada 	 */
111*09f455dcSMasahiro Yamada 	rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL);
112*09f455dcSMasahiro Yamada 	div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2;
113*09f455dcSMasahiro Yamada 	debug("Display clock %lu, divider %lu\n", rate, div);
114*09f455dcSMasahiro Yamada 
115*09f455dcSMasahiro Yamada 	writel(0x00010001, &disp->shift_clk_opt);
116*09f455dcSMasahiro Yamada 
117*09f455dcSMasahiro Yamada 	val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
118*09f455dcSMasahiro Yamada 	val |= div << SHIFT_CLK_DIVIDER_SHIFT;
119*09f455dcSMasahiro Yamada 	writel(val, &disp->disp_clk_ctrl);
120*09f455dcSMasahiro Yamada 
121*09f455dcSMasahiro Yamada 	return 0;
122*09f455dcSMasahiro Yamada }
123*09f455dcSMasahiro Yamada 
124*09f455dcSMasahiro Yamada /* Start up the display and turn on power to PWMs */
125*09f455dcSMasahiro Yamada static void basic_init(struct dc_cmd_reg *cmd)
126*09f455dcSMasahiro Yamada {
127*09f455dcSMasahiro Yamada 	u32 val;
128*09f455dcSMasahiro Yamada 
129*09f455dcSMasahiro Yamada 	writel(0x00000100, &cmd->gen_incr_syncpt_ctrl);
130*09f455dcSMasahiro Yamada 	writel(0x0000011a, &cmd->cont_syncpt_vsync);
131*09f455dcSMasahiro Yamada 	writel(0x00000000, &cmd->int_type);
132*09f455dcSMasahiro Yamada 	writel(0x00000000, &cmd->int_polarity);
133*09f455dcSMasahiro Yamada 	writel(0x00000000, &cmd->int_mask);
134*09f455dcSMasahiro Yamada 	writel(0x00000000, &cmd->int_enb);
135*09f455dcSMasahiro Yamada 
136*09f455dcSMasahiro Yamada 	val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE;
137*09f455dcSMasahiro Yamada 	val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE;
138*09f455dcSMasahiro Yamada 	val |= PM1_ENABLE;
139*09f455dcSMasahiro Yamada 	writel(val, &cmd->disp_pow_ctrl);
140*09f455dcSMasahiro Yamada 
141*09f455dcSMasahiro Yamada 	val = readl(&cmd->disp_cmd);
142*09f455dcSMasahiro Yamada 	val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT;
143*09f455dcSMasahiro Yamada 	writel(val, &cmd->disp_cmd);
144*09f455dcSMasahiro Yamada }
145*09f455dcSMasahiro Yamada 
146*09f455dcSMasahiro Yamada static void basic_init_timer(struct dc_disp_reg *disp)
147*09f455dcSMasahiro Yamada {
148*09f455dcSMasahiro Yamada 	writel(0x00000020, &disp->mem_high_pri);
149*09f455dcSMasahiro Yamada 	writel(0x00000001, &disp->mem_high_pri_timer);
150*09f455dcSMasahiro Yamada }
151*09f455dcSMasahiro Yamada 
152*09f455dcSMasahiro Yamada static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
153*09f455dcSMasahiro Yamada 	0x00000000,
154*09f455dcSMasahiro Yamada 	0x00000000,
155*09f455dcSMasahiro Yamada 	0x00000000,
156*09f455dcSMasahiro Yamada 	0x00000000,
157*09f455dcSMasahiro Yamada };
158*09f455dcSMasahiro Yamada 
159*09f455dcSMasahiro Yamada static const u32 rgb_polarity_tab[PIN_REG_COUNT] = {
160*09f455dcSMasahiro Yamada 	0x00000000,
161*09f455dcSMasahiro Yamada 	0x01000000,
162*09f455dcSMasahiro Yamada 	0x00000000,
163*09f455dcSMasahiro Yamada 	0x00000000,
164*09f455dcSMasahiro Yamada };
165*09f455dcSMasahiro Yamada 
166*09f455dcSMasahiro Yamada static const u32 rgb_data_tab[PIN_REG_COUNT] = {
167*09f455dcSMasahiro Yamada 	0x00000000,
168*09f455dcSMasahiro Yamada 	0x00000000,
169*09f455dcSMasahiro Yamada 	0x00000000,
170*09f455dcSMasahiro Yamada 	0x00000000,
171*09f455dcSMasahiro Yamada };
172*09f455dcSMasahiro Yamada 
173*09f455dcSMasahiro Yamada static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = {
174*09f455dcSMasahiro Yamada 	0x00000000,
175*09f455dcSMasahiro Yamada 	0x00000000,
176*09f455dcSMasahiro Yamada 	0x00000000,
177*09f455dcSMasahiro Yamada 	0x00000000,
178*09f455dcSMasahiro Yamada 	0x00210222,
179*09f455dcSMasahiro Yamada 	0x00002200,
180*09f455dcSMasahiro Yamada 	0x00020000,
181*09f455dcSMasahiro Yamada };
182*09f455dcSMasahiro Yamada 
183*09f455dcSMasahiro Yamada static void rgb_enable(struct dc_com_reg *com)
184*09f455dcSMasahiro Yamada {
185*09f455dcSMasahiro Yamada 	int i;
186*09f455dcSMasahiro Yamada 
187*09f455dcSMasahiro Yamada 	for (i = 0; i < PIN_REG_COUNT; i++) {
188*09f455dcSMasahiro Yamada 		writel(rgb_enb_tab[i], &com->pin_output_enb[i]);
189*09f455dcSMasahiro Yamada 		writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]);
190*09f455dcSMasahiro Yamada 		writel(rgb_data_tab[i], &com->pin_output_data[i]);
191*09f455dcSMasahiro Yamada 	}
192*09f455dcSMasahiro Yamada 
193*09f455dcSMasahiro Yamada 	for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
194*09f455dcSMasahiro Yamada 		writel(rgb_sel_tab[i], &com->pin_output_sel[i]);
195*09f455dcSMasahiro Yamada }
196*09f455dcSMasahiro Yamada 
197*09f455dcSMasahiro Yamada static int setup_window(struct disp_ctl_win *win,
198*09f455dcSMasahiro Yamada 			struct fdt_disp_config *config)
199*09f455dcSMasahiro Yamada {
200*09f455dcSMasahiro Yamada 	win->x = 0;
201*09f455dcSMasahiro Yamada 	win->y = 0;
202*09f455dcSMasahiro Yamada 	win->w = config->width;
203*09f455dcSMasahiro Yamada 	win->h = config->height;
204*09f455dcSMasahiro Yamada 	win->out_x = 0;
205*09f455dcSMasahiro Yamada 	win->out_y = 0;
206*09f455dcSMasahiro Yamada 	win->out_w = config->width;
207*09f455dcSMasahiro Yamada 	win->out_h = config->height;
208*09f455dcSMasahiro Yamada 	win->phys_addr = config->frame_buffer;
209*09f455dcSMasahiro Yamada 	win->stride = config->width * (1 << config->log2_bpp) / 8;
210*09f455dcSMasahiro Yamada 	debug("%s: depth = %d\n", __func__, config->log2_bpp);
211*09f455dcSMasahiro Yamada 	switch (config->log2_bpp) {
212*09f455dcSMasahiro Yamada 	case 5:
213*09f455dcSMasahiro Yamada 	case 24:
214*09f455dcSMasahiro Yamada 		win->fmt = COLOR_DEPTH_R8G8B8A8;
215*09f455dcSMasahiro Yamada 		win->bpp = 32;
216*09f455dcSMasahiro Yamada 		break;
217*09f455dcSMasahiro Yamada 	case 4:
218*09f455dcSMasahiro Yamada 		win->fmt = COLOR_DEPTH_B5G6R5;
219*09f455dcSMasahiro Yamada 		win->bpp = 16;
220*09f455dcSMasahiro Yamada 		break;
221*09f455dcSMasahiro Yamada 
222*09f455dcSMasahiro Yamada 	default:
223*09f455dcSMasahiro Yamada 		debug("Unsupported LCD bit depth");
224*09f455dcSMasahiro Yamada 		return -1;
225*09f455dcSMasahiro Yamada 	}
226*09f455dcSMasahiro Yamada 
227*09f455dcSMasahiro Yamada 	return 0;
228*09f455dcSMasahiro Yamada }
229*09f455dcSMasahiro Yamada 
230*09f455dcSMasahiro Yamada struct fdt_disp_config *tegra_display_get_config(void)
231*09f455dcSMasahiro Yamada {
232*09f455dcSMasahiro Yamada 	return config.valid ? &config : NULL;
233*09f455dcSMasahiro Yamada }
234*09f455dcSMasahiro Yamada 
235*09f455dcSMasahiro Yamada static void debug_timing(const char *name, unsigned int timing[])
236*09f455dcSMasahiro Yamada {
237*09f455dcSMasahiro Yamada #ifdef DEBUG
238*09f455dcSMasahiro Yamada 	int i;
239*09f455dcSMasahiro Yamada 
240*09f455dcSMasahiro Yamada 	debug("%s timing: ", name);
241*09f455dcSMasahiro Yamada 	for (i = 0; i < FDT_LCD_TIMING_COUNT; i++)
242*09f455dcSMasahiro Yamada 		debug("%d ", timing[i]);
243*09f455dcSMasahiro Yamada 	debug("\n");
244*09f455dcSMasahiro Yamada #endif
245*09f455dcSMasahiro Yamada }
246*09f455dcSMasahiro Yamada 
247*09f455dcSMasahiro Yamada /**
248*09f455dcSMasahiro Yamada  * Decode panel information from the fdt, according to a standard binding
249*09f455dcSMasahiro Yamada  *
250*09f455dcSMasahiro Yamada  * @param blob		fdt blob
251*09f455dcSMasahiro Yamada  * @param node		offset of fdt node to read from
252*09f455dcSMasahiro Yamada  * @param config	structure to store fdt config into
253*09f455dcSMasahiro Yamada  * @return 0 if ok, -ve on error
254*09f455dcSMasahiro Yamada  */
255*09f455dcSMasahiro Yamada static int tegra_decode_panel(const void *blob, int node,
256*09f455dcSMasahiro Yamada 			      struct fdt_disp_config *config)
257*09f455dcSMasahiro Yamada {
258*09f455dcSMasahiro Yamada 	int front, back, ref;
259*09f455dcSMasahiro Yamada 
260*09f455dcSMasahiro Yamada 	config->width = fdtdec_get_int(blob, node, "xres", -1);
261*09f455dcSMasahiro Yamada 	config->height = fdtdec_get_int(blob, node, "yres", -1);
262*09f455dcSMasahiro Yamada 	config->pixel_clock = fdtdec_get_int(blob, node, "clock", 0);
263*09f455dcSMasahiro Yamada 	if (!config->pixel_clock || config->width == -1 ||
264*09f455dcSMasahiro Yamada 			config->height == -1) {
265*09f455dcSMasahiro Yamada 		debug("%s: Pixel parameters missing\n", __func__);
266*09f455dcSMasahiro Yamada 		return -FDT_ERR_NOTFOUND;
267*09f455dcSMasahiro Yamada 	}
268*09f455dcSMasahiro Yamada 
269*09f455dcSMasahiro Yamada 	back = fdtdec_get_int(blob, node, "left-margin", -1);
270*09f455dcSMasahiro Yamada 	front = fdtdec_get_int(blob, node, "right-margin", -1);
271*09f455dcSMasahiro Yamada 	ref = fdtdec_get_int(blob, node, "hsync-len", -1);
272*09f455dcSMasahiro Yamada 	if ((back | front | ref) == -1) {
273*09f455dcSMasahiro Yamada 		debug("%s: Horizontal parameters missing\n", __func__);
274*09f455dcSMasahiro Yamada 		return -FDT_ERR_NOTFOUND;
275*09f455dcSMasahiro Yamada 	}
276*09f455dcSMasahiro Yamada 
277*09f455dcSMasahiro Yamada 	/* Use a ref-to-sync of 1 always, and take this from the front porch */
278*09f455dcSMasahiro Yamada 	config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
279*09f455dcSMasahiro Yamada 	config->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
280*09f455dcSMasahiro Yamada 	config->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
281*09f455dcSMasahiro Yamada 	config->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
282*09f455dcSMasahiro Yamada 		config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC];
283*09f455dcSMasahiro Yamada 	debug_timing("horiz", config->horiz_timing);
284*09f455dcSMasahiro Yamada 
285*09f455dcSMasahiro Yamada 	back = fdtdec_get_int(blob, node, "upper-margin", -1);
286*09f455dcSMasahiro Yamada 	front = fdtdec_get_int(blob, node, "lower-margin", -1);
287*09f455dcSMasahiro Yamada 	ref = fdtdec_get_int(blob, node, "vsync-len", -1);
288*09f455dcSMasahiro Yamada 	if ((back | front | ref) == -1) {
289*09f455dcSMasahiro Yamada 		debug("%s: Vertical parameters missing\n", __func__);
290*09f455dcSMasahiro Yamada 		return -FDT_ERR_NOTFOUND;
291*09f455dcSMasahiro Yamada 	}
292*09f455dcSMasahiro Yamada 
293*09f455dcSMasahiro Yamada 	config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
294*09f455dcSMasahiro Yamada 	config->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
295*09f455dcSMasahiro Yamada 	config->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
296*09f455dcSMasahiro Yamada 	config->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
297*09f455dcSMasahiro Yamada 		config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC];
298*09f455dcSMasahiro Yamada 	debug_timing("vert", config->vert_timing);
299*09f455dcSMasahiro Yamada 
300*09f455dcSMasahiro Yamada 	return 0;
301*09f455dcSMasahiro Yamada }
302*09f455dcSMasahiro Yamada 
303*09f455dcSMasahiro Yamada /**
304*09f455dcSMasahiro Yamada  * Decode the display controller information from the fdt.
305*09f455dcSMasahiro Yamada  *
306*09f455dcSMasahiro Yamada  * @param blob		fdt blob
307*09f455dcSMasahiro Yamada  * @param config	structure to store fdt config into
308*09f455dcSMasahiro Yamada  * @return 0 if ok, -ve on error
309*09f455dcSMasahiro Yamada  */
310*09f455dcSMasahiro Yamada static int tegra_display_decode_config(const void *blob,
311*09f455dcSMasahiro Yamada 				       struct fdt_disp_config *config)
312*09f455dcSMasahiro Yamada {
313*09f455dcSMasahiro Yamada 	int node, rgb;
314*09f455dcSMasahiro Yamada 	int bpp, bit;
315*09f455dcSMasahiro Yamada 
316*09f455dcSMasahiro Yamada 	/* TODO: Support multiple controllers */
317*09f455dcSMasahiro Yamada 	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_DC);
318*09f455dcSMasahiro Yamada 	if (node < 0) {
319*09f455dcSMasahiro Yamada 		debug("%s: Cannot find display controller node in fdt\n",
320*09f455dcSMasahiro Yamada 		      __func__);
321*09f455dcSMasahiro Yamada 		return node;
322*09f455dcSMasahiro Yamada 	}
323*09f455dcSMasahiro Yamada 	config->disp = (struct disp_ctlr *)fdtdec_get_addr(blob, node, "reg");
324*09f455dcSMasahiro Yamada 	if (!config->disp) {
325*09f455dcSMasahiro Yamada 		debug("%s: No display controller address\n", __func__);
326*09f455dcSMasahiro Yamada 		return -1;
327*09f455dcSMasahiro Yamada 	}
328*09f455dcSMasahiro Yamada 
329*09f455dcSMasahiro Yamada 	rgb = fdt_subnode_offset(blob, node, "rgb");
330*09f455dcSMasahiro Yamada 
331*09f455dcSMasahiro Yamada 	config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
332*09f455dcSMasahiro Yamada 	if (config->panel_node < 0) {
333*09f455dcSMasahiro Yamada 		debug("%s: Cannot find panel information\n", __func__);
334*09f455dcSMasahiro Yamada 		return -1;
335*09f455dcSMasahiro Yamada 	}
336*09f455dcSMasahiro Yamada 
337*09f455dcSMasahiro Yamada 	if (tegra_decode_panel(blob, config->panel_node, config)) {
338*09f455dcSMasahiro Yamada 		debug("%s: Failed to decode panel information\n", __func__);
339*09f455dcSMasahiro Yamada 		return -1;
340*09f455dcSMasahiro Yamada 	}
341*09f455dcSMasahiro Yamada 
342*09f455dcSMasahiro Yamada 	bpp = fdtdec_get_int(blob, config->panel_node, "nvidia,bits-per-pixel",
343*09f455dcSMasahiro Yamada 			     -1);
344*09f455dcSMasahiro Yamada 	bit = ffs(bpp) - 1;
345*09f455dcSMasahiro Yamada 	if (bpp == (1 << bit))
346*09f455dcSMasahiro Yamada 		config->log2_bpp = bit;
347*09f455dcSMasahiro Yamada 	else
348*09f455dcSMasahiro Yamada 		config->log2_bpp = bpp;
349*09f455dcSMasahiro Yamada 	if (bpp == -1) {
350*09f455dcSMasahiro Yamada 		debug("%s: Pixel bpp parameters missing\n", __func__);
351*09f455dcSMasahiro Yamada 		return -FDT_ERR_NOTFOUND;
352*09f455dcSMasahiro Yamada 	}
353*09f455dcSMasahiro Yamada 	config->bpp = bpp;
354*09f455dcSMasahiro Yamada 
355*09f455dcSMasahiro Yamada 	config->valid = 1;	/* we have a valid configuration */
356*09f455dcSMasahiro Yamada 
357*09f455dcSMasahiro Yamada 	return 0;
358*09f455dcSMasahiro Yamada }
359*09f455dcSMasahiro Yamada 
360*09f455dcSMasahiro Yamada int tegra_display_probe(const void *blob, void *default_lcd_base)
361*09f455dcSMasahiro Yamada {
362*09f455dcSMasahiro Yamada 	struct disp_ctl_win window;
363*09f455dcSMasahiro Yamada 	struct dc_ctlr *dc;
364*09f455dcSMasahiro Yamada 
365*09f455dcSMasahiro Yamada 	if (tegra_display_decode_config(blob, &config))
366*09f455dcSMasahiro Yamada 		return -1;
367*09f455dcSMasahiro Yamada 
368*09f455dcSMasahiro Yamada 	config.frame_buffer = (u32)default_lcd_base;
369*09f455dcSMasahiro Yamada 
370*09f455dcSMasahiro Yamada 	dc = (struct dc_ctlr *)config.disp;
371*09f455dcSMasahiro Yamada 
372*09f455dcSMasahiro Yamada 	/*
373*09f455dcSMasahiro Yamada 	 * A header file for clock constants was NAKed upstream.
374*09f455dcSMasahiro Yamada 	 * TODO: Put this into the FDT and fdt_lcd struct when we have clock
375*09f455dcSMasahiro Yamada 	 * support there
376*09f455dcSMasahiro Yamada 	 */
377*09f455dcSMasahiro Yamada 	clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH,
378*09f455dcSMasahiro Yamada 			       144 * 1000000);
379*09f455dcSMasahiro Yamada 	clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL,
380*09f455dcSMasahiro Yamada 			       600 * 1000000);
381*09f455dcSMasahiro Yamada 	basic_init(&dc->cmd);
382*09f455dcSMasahiro Yamada 	basic_init_timer(&dc->disp);
383*09f455dcSMasahiro Yamada 	rgb_enable(&dc->com);
384*09f455dcSMasahiro Yamada 
385*09f455dcSMasahiro Yamada 	if (config.pixel_clock)
386*09f455dcSMasahiro Yamada 		update_display_mode(&dc->disp, &config);
387*09f455dcSMasahiro Yamada 
388*09f455dcSMasahiro Yamada 	if (setup_window(&window, &config))
389*09f455dcSMasahiro Yamada 		return -1;
390*09f455dcSMasahiro Yamada 
391*09f455dcSMasahiro Yamada 	update_window(dc, &window);
392*09f455dcSMasahiro Yamada 
393*09f455dcSMasahiro Yamada 	return 0;
394*09f455dcSMasahiro Yamada }
395