2 * This file is part of the coreboot project.
4 * Copyright 2013 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
21 #include <boot/tables.h>
23 #include <console/console.h>
26 #include <device/device.h>
29 #include <soc/addressmap.h>
30 #include <soc/clock.h>
31 #include <soc/display.h>
32 #include <soc/sdram.h>
33 #include <soc/nvidia/tegra/dc.h>
34 #include <soc/nvidia/tegra/pwm.h>
42 struct tegra_dc dc_data
;
45 unsigned long READL(void * p
)
50 * In case of hard hung on readl(p), we can set dump > 1 to print out
51 * the address accessed.
54 printk(BIOS_SPEW
, "readl %p\n", p
);
58 printk(BIOS_SPEW
, "readl %p %08lx\n", p
, value
);
62 void WRITEL(unsigned long value
, void * p
)
65 printk(BIOS_SPEW
, "writel %p %08lx\n", p
, value
);
69 /* return in 1000ths of a Hertz */
70 static int tegra_dc_calc_refresh(const struct soc_nvidia_tegra124_config
*config
)
72 int h_total
, v_total
, refresh
;
73 int pclk
= config
->pixel_clock
;
75 h_total
= config
->xres
+ config
->hfront_porch
+ config
->hback_porch
+
77 v_total
= config
->yres
+ config
->vfront_porch
+ config
->vback_porch
+
79 if (!pclk
|| !h_total
|| !v_total
)
81 refresh
= pclk
/ h_total
;
87 static void print_mode(const struct soc_nvidia_tegra124_config
*config
)
90 int refresh
= tegra_dc_calc_refresh(config
);
92 "MODE:%dx%d@%d.%03uHz pclk=%d\n",
93 config
->xres
, config
->yres
,
94 refresh
/ 1000, refresh
% 1000,
99 static int update_display_mode(struct display_controller
*disp_ctrl
,
100 struct soc_nvidia_tegra124_config
*config
)
104 WRITEL(0x1, &disp_ctrl
->disp
.disp_timing_opt
);
106 WRITEL(config
->vref_to_sync
<< 16 | config
->href_to_sync
,
107 &disp_ctrl
->disp
.ref_to_sync
);
109 WRITEL(config
->vsync_width
<< 16 | config
->hsync_width
,
110 &disp_ctrl
->disp
.sync_width
);
112 WRITEL(((config
->vback_porch
- config
->vref_to_sync
) << 16) | config
->hback_porch
,
113 &disp_ctrl
->disp
.back_porch
);
115 WRITEL(((config
->vfront_porch
+ config
->vref_to_sync
) << 16) | config
->hfront_porch
,
116 &disp_ctrl
->disp
.front_porch
);
118 WRITEL(config
->xres
| (config
->yres
<< 16),
119 &disp_ctrl
->disp
.disp_active
);
122 * We want to use PLLD_out0, which is PLLD / 2:
123 * PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv.
125 * Currently most panels work inside clock range 50MHz~100MHz, and PLLD
126 * has some requirements to have VCO in range 500MHz~1000MHz (see
127 * clock.c for more detail). To simplify calculation, we set
128 * PixelClockDiv to 1 and ShiftClockDiv to 1. In future these values
129 * may be calculated by clock_display, to allow wider frequency range.
131 * Note ShiftClockDiv is a 7.1 format value.
133 const u32 shift_clock_div
= 1;
134 WRITEL((PIXEL_CLK_DIVIDER_PCD1
<< PIXEL_CLK_DIVIDER_SHIFT
) |
135 ((shift_clock_div
- 1) * 2) << SHIFT_CLK_DIVIDER_SHIFT
,
136 &disp_ctrl
->disp
.disp_clk_ctrl
);
137 printk(BIOS_DEBUG
, "%s: PixelClock=%u, ShiftClockDiv=%u\n",
138 __func__
, config
->pixel_clock
, shift_clock_div
);
142 static void update_window(struct display_controller
*disp_ctrl
,
143 struct soc_nvidia_tegra124_config
*config
)
147 WRITEL(WINDOW_A_SELECT
, &disp_ctrl
->cmd
.disp_win_header
);
149 WRITEL(((config
->yres
<< 16) | config
->xres
), &disp_ctrl
->win
.size
);
150 WRITEL(((config
->yres
<< 16) |
151 (config
->xres
* config
->framebuffer_bits_per_pixel
/ 8)),
152 &disp_ctrl
->win
.prescaled_size
);
153 WRITEL(((config
->xres
* config
->framebuffer_bits_per_pixel
/ 8 + 31) /
154 32 * 32), &disp_ctrl
->win
.line_stride
);
156 WRITEL(config
->color_depth
, &disp_ctrl
->win
.color_depth
);
158 WRITEL(config
->framebuffer_base
, &disp_ctrl
->winbuf
.start_addr
);
159 WRITEL((V_DDA_INC(0x1000) | H_DDA_INC(0x1000)), &disp_ctrl
->win
.dda_increment
);
161 WRITEL(COLOR_WHITE
, &disp_ctrl
->disp
.blend_background_color
);
162 WRITEL(DISP_CTRL_MODE_C_DISPLAY
, &disp_ctrl
->cmd
.disp_cmd
);
164 WRITEL(WRITE_MUX_ACTIVE
, &disp_ctrl
->cmd
.state_access
);
166 val
= GENERAL_ACT_REQ
| WIN_A_ACT_REQ
;
167 val
|= GENERAL_UPDATE
| WIN_A_UPDATE
;
168 WRITEL(val
, &disp_ctrl
->cmd
.state_ctrl
);
171 val
= READL(&disp_ctrl
->win
.win_opt
);
172 WRITEL(val
| WIN_ENABLE
, &disp_ctrl
->win
.win_opt
);
175 static int tegra_dc_init(struct display_controller
*disp_ctrl
)
177 /* do not accept interrupts during initialization */
178 WRITEL(0x00000000, &disp_ctrl
->cmd
.int_mask
);
179 WRITEL(WRITE_MUX_ASSEMBLY
| READ_MUX_ASSEMBLY
,
180 &disp_ctrl
->cmd
.state_access
);
181 WRITEL(WINDOW_A_SELECT
, &disp_ctrl
->cmd
.disp_win_header
);
182 WRITEL(0x00000000, &disp_ctrl
->win
.win_opt
);
183 WRITEL(0x00000000, &disp_ctrl
->win
.byte_swap
);
184 WRITEL(0x00000000, &disp_ctrl
->win
.buffer_ctrl
);
186 WRITEL(0x00000000, &disp_ctrl
->win
.pos
);
187 WRITEL(0x00000000, &disp_ctrl
->win
.h_initial_dda
);
188 WRITEL(0x00000000, &disp_ctrl
->win
.v_initial_dda
);
189 WRITEL(0x00000000, &disp_ctrl
->win
.dda_increment
);
190 WRITEL(0x00000000, &disp_ctrl
->win
.dv_ctrl
);
192 WRITEL(0x01000000, &disp_ctrl
->win
.blend_layer_ctrl
);
193 WRITEL(0x00000000, &disp_ctrl
->win
.blend_match_select
);
194 WRITEL(0x00000000, &disp_ctrl
->win
.blend_nomatch_select
);
195 WRITEL(0x00000000, &disp_ctrl
->win
.blend_alpha_1bit
);
197 WRITEL(0x00000000, &disp_ctrl
->winbuf
.start_addr_hi
);
198 WRITEL(0x00000000, &disp_ctrl
->winbuf
.addr_h_offset
);
199 WRITEL(0x00000000, &disp_ctrl
->winbuf
.addr_v_offset
);
201 WRITEL(0x00000000, &disp_ctrl
->com
.crc_checksum
);
202 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[0]);
203 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[1]);
204 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[2]);
205 WRITEL(0x00000000, &disp_ctrl
->com
.pin_output_enb
[3]);
206 WRITEL(0x00000000, &disp_ctrl
->disp
.disp_signal_opt0
);
211 uint32_t fb_base_mb(void)
213 return sdram_max_addressable_mb() - FB_SIZE_MB
;
216 /* this is really aimed at the lcd panel. That said, there are two display
217 * devices on this part and we may someday want to extend it for other boards.
219 void display_startup(device_t dev
)
221 struct soc_nvidia_tegra124_config
*config
= dev
->chip_info
;
222 struct display_controller
*disp_ctrl
= (void *)config
->display_controller
;
223 struct pwm_controller
*pwm
= (void *)TEGRA_PWM_BASE
;
224 struct tegra_dc
*dc
= &dc_data
;
228 dc
->base
= (void *)TEGRA_ARM_DISPLAYA
;
230 config
->dc_data
= dc
;
232 /* Note dp_init may read EDID and change some config values. */
235 /* should probably just make it all MiB ... in future */
236 u32 framebuffer_size_mb
= config
->framebuffer_size
/ MiB
;
237 u32 framebuffer_base_mb
= config
->framebuffer_base
/ MiB
;
239 /* light it all up */
240 /* This one may have been done in romstage but that's ok for now. */
241 if (config
->panel_vdd_gpio
){
242 gpio_output(config
->panel_vdd_gpio
, 1);
243 printk(BIOS_SPEW
,"%s: panel_vdd setting gpio %08x to %d\n",
244 __func__
, config
->panel_vdd_gpio
, 1);
246 udelay(config
->vdd_delay_ms
* 1000);
247 if (config
->backlight_vdd_gpio
){
248 gpio_output(config
->backlight_vdd_gpio
, 1);
249 printk(BIOS_SPEW
,"%s: backlight vdd setting gpio %08x to %d\n",
250 __func__
, config
->backlight_vdd_gpio
, 1);
252 if (config
->lvds_shutdown_gpio
){
253 gpio_output(config
->lvds_shutdown_gpio
, 0);
254 printk(BIOS_SPEW
,"%s: lvds shutdown setting gpio %08x to %d\n",
255 __func__
, config
->lvds_shutdown_gpio
, 0);
258 if (framebuffer_size_mb
== 0){
259 framebuffer_size_mb
= ALIGN_UP(config
->xres
* config
->yres
*
260 (config
->framebuffer_bits_per_pixel
/ 8), MiB
)/MiB
;
263 if (! framebuffer_base_mb
)
264 framebuffer_base_mb
= fb_base_mb();
266 config
->framebuffer_size
= framebuffer_size_mb
* MiB
;
267 config
->framebuffer_base
= framebuffer_base_mb
* MiB
;
269 mmu_config_range(framebuffer_base_mb
, framebuffer_size_mb
,
270 config
->cache_policy
);
272 printk(BIOS_SPEW
, "LCD frame buffer at %dMiB to %dMiB\n", framebuffer_base_mb
,
273 framebuffer_base_mb
+ framebuffer_size_mb
);
275 /* GPIO magic here if needed to start powering up things. You
276 * really only want to enable vdd, wait a bit, and then enable
277 * the panel. However ... the timings in the tegra20 dts make
278 * no sense to me. I'm pretty sure they're wrong.
279 * The panel_vdd is done in the romstage, so we need only
280 * light things up here once we're sure it's all working.
283 /* The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
284 * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
285 * update_display_mode() for detail.
287 plld_rate
= clock_display(config
->pixel_clock
* 2);
288 if (plld_rate
== 0) {
289 printk(BIOS_ERR
, "dc: clock init failed\n");
291 } else if (plld_rate
!= config
->pixel_clock
* 2) {
292 printk(BIOS_WARNING
, "dc: plld rounded to %u\n", plld_rate
);
293 config
->pixel_clock
= plld_rate
/ 2;
297 if (tegra_dc_init(disp_ctrl
)) {
298 printk(BIOS_ERR
, "dc: init failed\n");
302 /* Configure dc mode */
303 if (update_display_mode(disp_ctrl
, config
)) {
304 printk(BIOS_ERR
, "dc: failed to configure display mode.\n");
311 /* Init frame buffer */
312 memset((void *)(framebuffer_base_mb
*MiB
), 0x00,
313 framebuffer_size_mb
*MiB
);
315 update_window(disp_ctrl
, config
);
317 /* Set up Tegra PWM n (where n is specified in config->pwm) to drive the
320 printk(BIOS_SPEW
, "%s: enable panel backlight pwm\n", __func__
);
321 WRITEL(((1 << NV_PWM_CSR_ENABLE_SHIFT
) |
322 (220 << NV_PWM_CSR_PULSE_WIDTH_SHIFT
) | /* 220/256 */
323 0x02e), /* frequency divider */
324 &pwm
->pwm
[config
->pwm
].csr
);
326 udelay(config
->pwm_to_bl_delay_ms
* 1000);
327 if (config
->backlight_en_gpio
){
328 gpio_output(config
->backlight_en_gpio
, 1);
329 printk(BIOS_SPEW
,"%s: backlight enable setting gpio %08x to %d\n",
330 __func__
, config
->backlight_en_gpio
, 1);
333 printk(BIOS_INFO
, "%s: display init done.\n", __func__
);
335 /* tell depthcharge ...
338 edid
.bytes_per_line
= ((config
->xres
* config
->framebuffer_bits_per_pixel
/ 8 + 31) /
340 edid
.x_resolution
= edid
.bytes_per_line
/ (config
->framebuffer_bits_per_pixel
/ 8);
341 edid
.y_resolution
= config
->yres
;
342 edid
.framebuffer_bits_per_pixel
= config
->framebuffer_bits_per_pixel
;
343 set_vbe_mode_info_valid(&edid
, (uintptr_t)(framebuffer_base_mb
*MiB
));