David Hendricks (dhendrix@chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3116
-gerrit
commit 10991242c6f351bef7db5ac3bf3bc340983e8fac Author: Ronald G. Minnich rminnich@gmail.com Date: Thu Apr 18 18:09:24 2013 -0700
GOOGLE/SNOW: get graphics working
draft patch, needs cleanup, but we've got pictures.
Change-Id: I16e711c97e9d02c916824f621e2313297448732b Signed-off-by: Ronald G. Minnich rminnich@gmail.com --- src/cpu/samsung/exynos5-common/exynos-fb.c | 72 ++++++++++++++++++++++++----- src/cpu/samsung/exynos5-common/s5p-dp-reg.c | 6 +++ src/cpu/samsung/exynos5250/cpu.c | 1 + src/mainboard/google/snow/Kconfig | 2 + src/mainboard/google/snow/chromeos.c | 4 +- src/mainboard/google/snow/ramstage.c | 46 +++++++++++++++++- 6 files changed, 118 insertions(+), 13 deletions(-)
diff --git a/src/cpu/samsung/exynos5-common/exynos-fb.c b/src/cpu/samsung/exynos5-common/exynos-fb.c index 54a2d7a..cd50325 100644 --- a/src/cpu/samsung/exynos5-common/exynos-fb.c +++ b/src/cpu/samsung/exynos5-common/exynos-fb.c @@ -27,6 +27,7 @@ #include <arch/io.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <console/console.h> #include <cpu/samsung/exynos5250/cpu.h> #include <cpu/samsung/exynos5250/power.h> @@ -41,6 +42,24 @@ #include "cpu/samsung/exynos5250/s5p-dp.h" #include "s5p-dp-core.h"
+/* useful information. Here is the rough outline of how we bring up the display. + *1. Upon power-on Sink generates a hot plug detection pulse thru HPD + *2. Source determines video mode by reading DPCD receiver capability field (DPCD 00000h to + * 0000Dh) including eDP CP capability register (DPCD 0000Dh) + *3. Sink replies DPCD receiver capability field. + *4. Source starts EDID read thru I2C-over-AUX + *5. Sink replies EDID thru I2C-over-AUX + *6. Source determines link configuration, such as MAX_LINK_RATE and + * MAX_LANE_COUNT. Source also determines which type of eDP Authentication method + * to use and writes DPCD link configuration field (DPCD 00100h to 0010Ah) including eDP + * configuration set (DPCD 0010Ah). + *7. Source starts link training. Sink does clock recovery and equalization + *8. Source reads DPCD link status field (DPCD 00200h to 0020Bh) + *9. Sink replies DPCD link status field. If main link is not stable, Source repeats Step 7. + *10. Source sends MSA (Main Stream Attribute) data. Sink extracts video parameters and + * recovers stream clock. + *11. Source sends video data + */ /* To help debug any init errors here, define a list of possible errors */ enum { ERR_PLL_NOT_UNLOCKED = 2, @@ -114,7 +133,7 @@ static u32 calc_fbsize(vidinfo_t *panel_info) return ALIGN((panel_info->vl_col * panel_info->vl_row * ((1<<panel_info->vl_bpix) / 8)), 4096); } - +void *graphics; /* * Initialize display controller. * @@ -126,27 +145,37 @@ void fb_init(vidinfo_t *panel_info, void *lcdbase, { unsigned int val; u32 fbsize; - struct exynos5_fimd *fimd = + struct exynos5_fimd *fimd = //14400000 samsung_get_base_fimd(); - struct exynos5_disp_ctrl *disp_ctrl = + struct exynos5_disp_ctrl *disp_ctrl = //14420000 samsung_get_base_disp_ctrl();
+ graphics = lcdbase; + printk(BIOS_SPEW, "%s: fimd %p disp_ctrl %p\n", __func__, fimd, disp_ctrl); + printk(BIOS_SPEW, "pd %p\n", pd); + printk(BIOS_SPEW, "lcdbase %p\n", lcdbase); + printk(BIOS_SPEW, "pd->xres %d pd->yres %d\n", pd->xres, pd->yres); + printk(BIOS_SPEW, "Write %08x to %p\n", pd->ivclk | pd->fixvclk, &disp_ctrl->vidcon1); writel(pd->ivclk | pd->fixvclk, &disp_ctrl->vidcon1); val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET); + printk(BIOS_SPEW, "Write %08x to fimd->vidcon0\n", val); writel(val, &fimd->vidcon0);
val = (pd->vsync << VSYNC_PULSE_WIDTH_OFFSET) | (pd->lower_margin << V_FRONT_PORCH_OFFSET) | (pd->upper_margin << V_BACK_PORCH_OFFSET); + printk(BIOS_SPEW, "Write %08x to %p\n", val, &disp_ctrl->vidtcon0); writel(val, &disp_ctrl->vidtcon0);
val = (pd->hsync << HSYNC_PULSE_WIDTH_OFFSET) | (pd->right_margin << H_FRONT_PORCH_OFFSET) | (pd->left_margin << H_BACK_PORCH_OFFSET); + printk(BIOS_SPEW, "Write %08x to %p\n", val, &disp_ctrl->vidtcon1); writel(val, &disp_ctrl->vidtcon1);
val = ((pd->xres - 1) << HOZVAL_OFFSET) | ((pd->yres - 1) << LINEVAL_OFFSET); + printk(BIOS_SPEW, "Write %08x to %p\n", val, &disp_ctrl->vidtcon2); writel(val, &disp_ctrl->vidtcon2);
writel((unsigned int)lcdbase, &fimd->vidw00add0b0); @@ -154,10 +183,12 @@ void fb_init(vidinfo_t *panel_info, void *lcdbase, fbsize = calc_fbsize(panel_info); writel((unsigned int)lcdbase + fbsize, &fimd->vidw00add1b0);
+ printk(BIOS_SPEW, "Write %08x to %p\n", (unsigned int)pd->xres*2, &fimd->vidw00add0b0); writel(pd->xres * 2, &fimd->vidw00add2);
val = ((pd->xres - 1) << OSD_RIGHTBOTX_F_OFFSET); val |= ((pd->yres - 1) << OSD_RIGHTBOTY_F_OFFSET); + printk(BIOS_SPEW, "Write %08x to %p\n", val, &fimd->vidosd0b); writel(val, &fimd->vidosd0b); writel(pd->xres * pd->yres, &fimd->vidosd0c);
@@ -165,6 +196,7 @@ void fb_init(vidinfo_t *panel_info, void *lcdbase,
val = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET; val |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN; + printk(BIOS_SPEW, "Write %08x to %p\n", val, &fimd->wincon0); writel(val, &fimd->wincon0);
/* DPCLKCON_ENABLE */ @@ -191,7 +223,7 @@ static int s5p_dp_config_video(struct s5p_dp_device *dp, struct video_info *video_info) { int timeout = 0; - u32 start; + u32 start, end; struct exynos5_dp *base = dp->base;
s5p_dp_config_video_slave_mode(dp, video_info); @@ -206,16 +238,17 @@ static int s5p_dp_config_video(struct s5p_dp_device *dp, return -ERR_PLL_NOT_UNLOCKED; }
- start = get_timer(0); + start = timer_us(); + end = start + STREAM_ON_TIMEOUT*1000; do { if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) { timeout++; break; } - } while (get_timer(start) <= STREAM_ON_TIMEOUT); + } while (timer_us() < end);
if (!timeout) { - printk(BIOS_DEBUG, "Video Clock Not ok\n"); + printk(BIOS_DEBUG, "Video Clock Not ok after %d microseconds waiting\n", timer_us() - start); return -ERR_VIDEO_CLOCK_BAD; }
@@ -255,7 +288,7 @@ static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp) printk(BIOS_DEBUG, "DPCD read error\n"); return -ERR_DPCD_READ_ERROR1; } - + /* let's not do this and see if it gets better */ if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, DPCD_ENHANCED_FRAME_EN | (data & DPCD_LANE_COUNT_SET_MASK))) { @@ -408,23 +441,25 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, unsigned int max_lane, unsigned int max_rate) { + int pll_is_locked = 0; u32 data; u32 start; int lane; struct exynos5_dp *base = dp->base;
+ printk(BIOS_SPEW, "%s: start\n", __func__); /* Stop Video */ clrbits_le32(&base->video_ctl_1, VIDEO_EN);
start = get_timer(0); - while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { + while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) { if (get_timer(start) > PLL_LOCK_TIMEOUT) { /* Ignore this error, and try to continue */ printk(BIOS_ERR, "PLL is not locked yet.\n"); break; } } - + printk(BIOS_SPEW, "PLL is %slocked\n", pll_is_locked == PLL_LOCKED ? "": "un"); /* Reset Macro */ setbits_le32(&base->dp_phy_test, MACRO_RST);
@@ -448,6 +483,9 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+ printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__, + dp->link_train.link_rate, dp->link_train.lane_count); + if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n", @@ -470,21 +508,27 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, dp->link_train.link_rate = max_rate;
/* Set link rate and count as you want to establish*/ + printk(BIOS_SPEW, "Set link rate and count\n"); writel(dp->link_train.lane_count, &base->lane_count_set); writel(dp->link_train.link_rate, &base->link_bw_set);
/* Set sink to D0 (Sink Not Ready) mode. */ + printk(BIOS_SPEW, "Set sink rate to D0\n"); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0);
/* Start HW link training */ + printk(BIOS_SPEW, "Start Link hardware training\n"); writel(HW_TRAINING_EN, &base->dp_hw_link_training);
- /* Wait unitl HW link training done */ + /* Wait until HW link training done */ + printk(BIOS_SPEW, "Wait until HW link training done\n"); s5p_dp_wait_hw_link_training_done(dp); + printk(BIOS_SPEW, "HW link training done\n");
/* Get hardware link training status */ data = readl(&base->dp_hw_link_training); + printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data); if (data != 0) { printk(BIOS_DEBUG, " H/W link training failure: 0x%x\n", data); return -ERR_LINK_TRAINING_FAILURE; @@ -497,6 +541,8 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
data = readl(&base->lane_count_set); dp->link_train.lane_count = data; + printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n", + dp->link_train.link_rate, data);
return 0; } @@ -533,12 +579,14 @@ int dp_controller_init(struct s5p_dp_device *dp_device) /* Minimum delay after H/w Link training */ udelay(1000);
+ printk(BIOS_DEBUG, "call s5p_dp_enable_scramble\n"); ret = s5p_dp_enable_scramble(dp); if (ret) { printk(BIOS_DEBUG, "unable to set scramble mode\n"); return ret; }
+ printk(BIOS_DEBUG, "call s5p_dp_enable_rx_to_enhanced_mode\n"); ret = s5p_dp_enable_rx_to_enhanced_mode(dp); if (ret) { printk(BIOS_DEBUG, "unable to set enhanced mode\n"); @@ -553,7 +601,9 @@ int dp_controller_init(struct s5p_dp_device *dp_device) writel(dp->link_train.lane_count, &base->lane_count_set); writel(dp->link_train.link_rate, &base->link_bw_set);
+ printk(BIOS_DEBUG, "call s5p_dp_init_video\n"); s5p_dp_init_video(dp); + printk(BIOS_DEBUG, "call s5p_dp_config_video\n"); ret = s5p_dp_config_video(dp, dp->video_info); if (ret) { printk(BIOS_DEBUG, "unable to config video\n"); diff --git a/src/cpu/samsung/exynos5-common/s5p-dp-reg.c b/src/cpu/samsung/exynos5-common/s5p-dp-reg.c index 60e1398..49fe1cb 100644 --- a/src/cpu/samsung/exynos5-common/s5p-dp-reg.c +++ b/src/cpu/samsung/exynos5-common/s5p-dp-reg.c @@ -102,6 +102,7 @@ unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp) u32 reg;
reg = readl(&dp->base->dp_debug_ctl); + printk(BIOS_SPEW, "%s: reg is 0x%x, PLL_LOCK is 0x%x\n", __func__, reg, PLL_LOCK); if (reg & PLL_LOCK) return PLL_LOCKED; else @@ -351,11 +352,13 @@ int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp) u32 reg; struct exynos5_dp *base = dp->base;
+ printk(BIOS_SPEW, "%s: sys_ctl_1 is %p\n", __func__, &base->sys_ctl_1); reg = readl(&base->sys_ctl_1); writel(reg, &base->sys_ctl_1);
reg = readl(&base->sys_ctl_1);
+ printk(BIOS_SPEW, "%s: sys_ctl_1 is %08x, DET_STA is 0x%x\n", __func__, reg, DET_STA); if (!(reg & DET_STA)) return -1;
@@ -364,6 +367,7 @@ int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp)
reg = readl(&base->sys_ctl_2);
+ printk(BIOS_SPEW, "%s: sys_ctl_2 is %08x, CHA_STA is 0x%x\n", __func__, reg, CHA_STA); if (reg & CHA_STA) { printk(BIOS_DEBUG, "Input stream clk is changing\n"); return -1; @@ -452,6 +456,7 @@ void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp, u32 reg; struct exynos5_dp *base = dp->base;
+ printk(BIOS_SPEW, "%s: Start\n", __func__); reg = readl(&base->func_en_1); reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); reg |= MASTER_VID_FUNC_EN_N; @@ -474,6 +479,7 @@ void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; writel(reg, &base->soc_general_ctl); + printk(BIOS_SPEW, "%s: Done\n", __func__); }
void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp) diff --git a/src/cpu/samsung/exynos5250/cpu.c b/src/cpu/samsung/exynos5250/cpu.c index 09b670e..88cd90c 100644 --- a/src/cpu/samsung/exynos5250/cpu.c +++ b/src/cpu/samsung/exynos5250/cpu.c @@ -71,6 +71,7 @@ static void exynos_displayport_init(device_t dev) mmio_resource(dev, 1, lcdbase/KiB, fb_size + (KiB-1)/KiB); printk(BIOS_DEBUG, "Initializing exynos VGA, base %p\n",(void *)lcdbase); + memset((void *)lcdbase, 0x55, 0x100000); ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase); }
diff --git a/src/mainboard/google/snow/Kconfig b/src/mainboard/google/snow/Kconfig index 6d3d7c8..3df0b87 100644 --- a/src/mainboard/google/snow/Kconfig +++ b/src/mainboard/google/snow/Kconfig @@ -33,6 +33,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy select EXYNOS_DISPLAYPORT select CHROMEOS select DRIVER_TI_TPS65090 + select MAINBOARD_HAS_NATIVE_VGA_INIT + select MAINBOARD_DO_NATIVE_VGA_INIT
config MAINBOARD_DIR string diff --git a/src/mainboard/google/snow/chromeos.c b/src/mainboard/google/snow/chromeos.c index 6e46d13..e3bab8b 100644 --- a/src/mainboard/google/snow/chromeos.c +++ b/src/mainboard/google/snow/chromeos.c @@ -98,7 +98,9 @@ void fill_lb_gpios(struct lb_gpios *gpios)
int get_developer_mode_switch(void) { - return 0; + /* This should return 0, but we hardcode it to 1 to ensure coreboot + draws the dev mode screen while we're working on this patch. */ + return 1; }
int get_recovery_mode_switch(void) diff --git a/src/mainboard/google/snow/ramstage.c b/src/mainboard/google/snow/ramstage.c index 1cd84e8..c992c20 100644 --- a/src/mainboard/google/snow/ramstage.c +++ b/src/mainboard/google/snow/ramstage.c @@ -23,6 +23,7 @@ #include <drivers/ti/tps65090/tps65090.h> #include <cbmem.h> #include <delay.h> +#include <boot/coreboot_tables.h> #include <arch/cache.h> #include <arch/exception.h> #include <arch/gpio.h> @@ -41,6 +42,46 @@ #define DRAM_SIZE CONFIG_DRAM_SIZE_MB #define DRAM_END (DRAM_START + DRAM_SIZE) /* plus one... */
+int vbe_mode_info_valid(void); +int vbe_mode_info_valid(void) +{ + return 1; +} + +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer); +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) +{ + extern void *graphics; + printk(BIOS_SPEW, "fill_lb_framebuffer: graphics is %p\n", (void *)graphics); + framebuffer->physical_address = (u32) graphics; +/* + register "xres" = "1366" + register "yres" = "768" + register "bpp" = "16" + # complex magic timing! + register "clkval_f" = "2" + register "upper_margin" = "14" + register "lower_margin" = "3" + register "vsync" = "5" + register "left_margin" = "80" + register "right_margin" = "48" + register "hsync" = "32" +*/ + framebuffer->x_resolution = 1366; + framebuffer->y_resolution = 768; + framebuffer->bytes_per_line = 1366*2; + framebuffer->bits_per_pixel = 16; + framebuffer->red_mask_pos = 11; + framebuffer->red_mask_size = 5; + framebuffer->green_mask_pos = 6; + framebuffer->green_mask_size = 5; + framebuffer->blue_mask_pos = 0; + framebuffer->blue_mask_size = 5; + framebuffer->reserved_mask_pos = 0; + framebuffer->reserved_mask_size = 0; +} + + void hardwaremain(int boot_complete); void main(void) { @@ -221,6 +262,9 @@ static void mainboard_init(device_t dev) } while (!exynos_dp_hotplug());
exynos_dp_bridge_setup(); + snow_backlight_vdd(); + snow_backlight_pwm(); + snow_backlight_en(); for (dp_tries = 1; dp_tries <= SNOW_MAX_DP_TRIES; dp_tries++) { exynos_dp_bridge_init(); if (exynos_dp_hotplug()) { @@ -229,7 +273,7 @@ static void mainboard_init(device_t dev) }
if (dp_controller_init(&dp_device)) - continue; + break; // continue;
udelay(LCD_T3_DELAY_MS * 1000);