2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <console/console.h>
16 #include <device/mmio.h>
19 #include <device/device.h>
20 #include <soc/nvidia/tegra/dc.h>
21 #include <soc/display.h>
26 unsigned long READL(void *p
)
31 * In case of hard hung on readl(p), we can set dump > 1 to print out
32 * the address accessed.
35 printk(BIOS_SPEW
, "readl %p\n", p
);
39 printk(BIOS_SPEW
, "readl %p %08lx\n", p
, value
);
43 void WRITEL(unsigned long value
, void *p
)
46 printk(BIOS_SPEW
, "writel %p %08lx\n", p
, value
);
50 /* return in 1000ths of a Hertz */
51 static int tegra_calc_refresh(const struct soc_nvidia_tegra210_config
*config
)
54 int h_total
= htotal(config
);
55 int v_total
= vtotal(config
);
56 int pclk
= config
->pixel_clock
;
58 if (!pclk
|| !h_total
|| !v_total
)
60 refresh
= pclk
/ h_total
;
66 static void print_mode(const struct soc_nvidia_tegra210_config
*config
)
69 int refresh
= tegra_calc_refresh(config
);
71 "Panel Mode: %dx%d@%d.%03uHz pclk=%d\n",
72 config
->xres
, config
->yres
,
73 refresh
/ 1000, refresh
% 1000,
78 int update_display_mode(struct display_controller
*disp_ctrl
,
79 struct soc_nvidia_tegra210_config
*config
)
83 printk(BIOS_ERR
, "config: xres:yres: %d x %d\n ",
84 config
->xres
, config
->yres
);
85 printk(BIOS_ERR
, " href_sync:vref_sync: %d x %d\n ",
86 config
->href_to_sync
, config
->vref_to_sync
);
87 printk(BIOS_ERR
, " hsyn_width:vsyn_width: %d x %d\n ",
88 config
->hsync_width
, config
->vsync_width
);
89 printk(BIOS_ERR
, " hfnt_porch:vfnt_porch: %d x %d\n ",
90 config
->hfront_porch
, config
->vfront_porch
);
91 printk(BIOS_ERR
, " hbk_porch:vbk_porch: %d x %d\n ",
92 config
->hback_porch
, config
->vback_porch
);
94 WRITEL(0x0, &disp_ctrl
->disp
.disp_timing_opt
);
95 WRITEL(0x0, &disp_ctrl
->disp
.disp_color_ctrl
);
98 WRITEL(config
->win_opt
, &disp_ctrl
->disp
.disp_win_opt
);
100 WRITEL(config
->vref_to_sync
<< 16 | config
->href_to_sync
,
101 &disp_ctrl
->disp
.ref_to_sync
);
103 WRITEL(config
->vsync_width
<< 16 | config
->hsync_width
,
104 &disp_ctrl
->disp
.sync_width
);
107 WRITEL((config
->vback_porch
<< 16) | config
->hback_porch
,
108 &disp_ctrl
->disp
.back_porch
);
110 WRITEL((config
->vfront_porch
<< 16) | config
->hfront_porch
,
111 &disp_ctrl
->disp
.front_porch
);
113 WRITEL(config
->xres
| (config
->yres
<< 16),
114 &disp_ctrl
->disp
.disp_active
);
117 * PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv.
119 * default: Set both shift_clk_div and pixel_clock_div to 1
121 update_display_shift_clock_divider(disp_ctrl
, SHIFT_CLK_DIVIDER(1));
126 void update_display_shift_clock_divider(struct display_controller
*disp_ctrl
,
129 WRITEL((PIXEL_CLK_DIVIDER_PCD1
<< PIXEL_CLK_DIVIDER_SHIFT
) |
130 (shift_clock_div
& 0xff) << SHIFT_CLK_DIVIDER_SHIFT
,
131 &disp_ctrl
->disp
.disp_clk_ctrl
);
132 printk(BIOS_DEBUG
, "%s: ShiftClockDiv=%u\n",
133 __func__
, shift_clock_div
);
138 * set up window registers and activate window except two:
139 * frame buffer base address register (WINBUF_START_ADDR) and
140 * display enable register (_DISP_DISP_WIN_OPTIONS). This is
141 * because framebuffer is not available until payload stage.
143 void update_window(const struct soc_nvidia_tegra210_config
*config
)
145 struct display_controller
*disp_ctrl
=
146 (void *)config
->display_controller
;
149 WRITEL(WINDOW_A_SELECT
, &disp_ctrl
->cmd
.disp_win_header
);
151 WRITEL(((config
->yres
<< 16) | config
->xres
), &disp_ctrl
->win
.size
);
153 WRITEL(((config
->display_yres
<< 16) |
154 (config
->display_xres
*
155 config
->framebuffer_bits_per_pixel
/ 8)),
156 &disp_ctrl
->win
.prescaled_size
);
158 val
= ALIGN_UP((config
->display_xres
*
159 config
->framebuffer_bits_per_pixel
/ 8), 64);
160 WRITEL(val
, &disp_ctrl
->win
.line_stride
);
162 WRITEL(config
->color_depth
, &disp_ctrl
->win
.color_depth
);
163 WRITEL(COLOR_BLACK
, &disp_ctrl
->disp
.blend_background_color
);
165 WRITEL(((DDA_INC(config
->display_yres
, config
->yres
) << 16) |
166 DDA_INC(config
->display_xres
, config
->xres
)),
167 &disp_ctrl
->win
.dda_increment
);
169 WRITEL(DISP_CTRL_MODE_C_DISPLAY
, &disp_ctrl
->cmd
.disp_cmd
);
171 WRITEL(WRITE_MUX_ACTIVE
, &disp_ctrl
->cmd
.state_access
);
173 WRITEL(0, &disp_ctrl
->win
.buffer_addr_mode
);
175 val
= PW0_ENABLE
| PW1_ENABLE
| PW2_ENABLE
| PW3_ENABLE
|
176 PW4_ENABLE
| PM0_ENABLE
| PM1_ENABLE
;
177 WRITEL(val
, &disp_ctrl
->cmd
.disp_pow_ctrl
);
179 val
= GENERAL_UPDATE
| WIN_A_UPDATE
;
180 WRITEL(val
, &disp_ctrl
->cmd
.state_ctrl
);
182 val
= GENERAL_ACT_REQ
| WIN_A_ACT_REQ
;
183 WRITEL(val
, &disp_ctrl
->cmd
.state_ctrl
);
186 int tegra_dc_init(struct display_controller
*disp_ctrl
)
188 /* do not accept interrupts during initialization */
189 WRITEL(0x00000000, &disp_ctrl
->cmd
.int_mask
);
190 WRITEL(WRITE_MUX_ASSEMBLY
| READ_MUX_ASSEMBLY
,
191 &disp_ctrl
->cmd
.state_access
);
192 WRITEL(WINDOW_A_SELECT
, &disp_ctrl
->cmd
.disp_win_header
);
193 WRITEL(0x00000000, &disp_ctrl
->win
.win_opt
);
194 WRITEL(0x00000000, &disp_ctrl
->win
.byte_swap
);
195 WRITEL(0x00000000, &disp_ctrl
->win
.buffer_ctrl
);
197 WRITEL(0x00000000, &disp_ctrl
->win
.pos
);
198 WRITEL(0x00000000, &disp_ctrl
->win
.h_initial_dda
);
199 WRITEL(0x00000000, &disp_ctrl
->win
.v_initial_dda
);
200 WRITEL(0x00000000, &disp_ctrl
->win
.dda_increment
);
201 WRITEL(0x00000000, &disp_ctrl
->win
.dv_ctrl
);
203 WRITEL(0x01000000, &disp_ctrl
->win
.blend_layer_ctrl
);
204 WRITEL(0x00000000, &disp_ctrl
->win
.blend_match_select
);
205 WRITEL(0x00000000, &disp_ctrl
->win
.blend_nomatch_select
);
206 WRITEL(0x00000000, &disp_ctrl
->win
.blend_alpha_1bit
);
208 WRITEL(0x00000000, &disp_ctrl
->winbuf
.start_addr_hi
);
209 WRITEL(0x00000000, &disp_ctrl
->winbuf
.addr_h_offset
);
210 WRITEL(0x00000000, &disp_ctrl
->winbuf
.addr_v_offset
);
212 WRITEL(0x00000000, &disp_ctrl
->com
.crc_checksum
);
213 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[0]);
214 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[1]);
215 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[2]);
216 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[3]);
217 WRITEL(0x00000000, &disp_ctrl
->disp
.disp_signal_opt0
);
223 * Save mode to cb tables
225 void pass_mode_info_to_payload(
226 struct soc_nvidia_tegra210_config
*config
)
230 edid
.mode
.va
= config
->display_yres
;
231 edid
.mode
.ha
= config
->display_xres
;
232 edid_set_framebuffer_bits_per_pixel(&edid
,
233 config
->framebuffer_bits_per_pixel
, 64);
235 printk(BIOS_INFO
, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
236 " x_res x y_res: %d x %d, size: %d\n",
237 __func__
, edid
.bytes_per_line
,
238 edid
.framebuffer_bits_per_pixel
,
239 edid
.x_resolution
, edid
.y_resolution
,
240 (edid
.bytes_per_line
* edid
.y_resolution
));
242 set_vbe_mode_info_valid(&edid
, 0);