GOOGLE/SNOW: get graphics working

This adds support for display bring-up on Snow. It
includes framebuffer initialization and LCD enable functions.

Change-Id: I16e711c97e9d02c916824f621e2313297448732b
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: http://review.coreboot.org/3116
Tested-by: build bot (Jenkins)
This commit is contained in:
Ronald G. Minnich 2013-04-18 18:09:24 -07:00
parent 2c88cc0696
commit 2810afa57d
5 changed files with 113 additions and 37 deletions

View File

@ -27,6 +27,7 @@
#include <arch/io.h> #include <arch/io.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <console/console.h> #include <console/console.h>
#include <cpu/samsung/exynos5250/cpu.h> #include <cpu/samsung/exynos5250/cpu.h>
#include <cpu/samsung/exynos5250/power.h> #include <cpu/samsung/exynos5250/power.h>
@ -41,6 +42,28 @@
#include "cpu/samsung/exynos5250/s5p-dp.h" #include "cpu/samsung/exynos5250/s5p-dp.h"
#include "s5p-dp-core.h" #include "s5p-dp-core.h"
/*
* 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 */ /* To help debug any init errors here, define a list of possible errors */
enum { enum {
ERR_PLL_NOT_UNLOCKED = 2, ERR_PLL_NOT_UNLOCKED = 2,
@ -126,10 +149,8 @@ void fb_init(vidinfo_t *panel_info, void *lcdbase,
{ {
unsigned int val; unsigned int val;
u32 fbsize; u32 fbsize;
struct exynos5_fimd *fimd = struct exynos5_fimd *fimd = samsung_get_base_fimd();
samsung_get_base_fimd(); struct exynos5_disp_ctrl *disp_ctrl = samsung_get_base_disp_ctrl();
struct exynos5_disp_ctrl *disp_ctrl =
samsung_get_base_disp_ctrl();
writel(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); val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET);
@ -191,7 +212,7 @@ static int s5p_dp_config_video(struct s5p_dp_device *dp,
struct video_info *video_info) struct video_info *video_info)
{ {
int timeout = 0; int timeout = 0;
u32 start; u32 start, end;
struct exynos5_dp *base = dp->base; struct exynos5_dp *base = dp->base;
s5p_dp_config_video_slave_mode(dp, video_info); s5p_dp_config_video_slave_mode(dp, video_info);
@ -206,16 +227,18 @@ static int s5p_dp_config_video(struct s5p_dp_device *dp,
return -ERR_PLL_NOT_UNLOCKED; return -ERR_PLL_NOT_UNLOCKED;
} }
start = get_timer(0); start = timer_us();
end = start + STREAM_ON_TIMEOUT*1000;
do { do {
if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) { if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) {
timeout++; timeout++;
break; break;
} }
} while (get_timer(start) <= STREAM_ON_TIMEOUT); } while (timer_us() < end);
if (!timeout) { if (!timeout) {
printk(BIOS_DEBUG, "Video Clock Not ok\n"); printk(BIOS_ERR, "Video Clock Not ok after %uus.\n",
timer_us() - start);
return -ERR_VIDEO_CLOCK_BAD; return -ERR_VIDEO_CLOCK_BAD;
} }
@ -255,7 +278,6 @@ static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp)
printk(BIOS_DEBUG, "DPCD read error\n"); printk(BIOS_DEBUG, "DPCD read error\n");
return -ERR_DPCD_READ_ERROR1; return -ERR_DPCD_READ_ERROR1;
} }
if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
DPCD_ENHANCED_FRAME_EN | DPCD_ENHANCED_FRAME_EN |
(data & DPCD_LANE_COUNT_SET_MASK))) { (data & DPCD_LANE_COUNT_SET_MASK))) {
@ -408,6 +430,7 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
unsigned int max_lane, unsigned int max_lane,
unsigned int max_rate) unsigned int max_rate)
{ {
int pll_is_locked = 0;
u32 data; u32 data;
u32 start; u32 start;
int lane; int lane;
@ -417,14 +440,15 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
clrbits_le32(&base->video_ctl_1, VIDEO_EN); clrbits_le32(&base->video_ctl_1, VIDEO_EN);
start = get_timer(0); 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) { if (get_timer(start) > PLL_LOCK_TIMEOUT) {
/* Ignore this error, and try to continue */ /* Ignore this error, and try to continue */
printk(BIOS_ERR, "PLL is not locked yet.\n"); printk(BIOS_ERR, "PLL is not locked yet.\n");
break; break;
} }
} }
printk(BIOS_SPEW, "PLL is %slocked\n",
pll_is_locked == PLL_LOCKED ? "": "not ");
/* Reset Macro */ /* Reset Macro */
setbits_le32(&base->dp_phy_test, MACRO_RST); setbits_le32(&base->dp_phy_test, MACRO_RST);
@ -448,6 +472,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_bandwidth(dp, &dp->link_train.link_rate);
s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); 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) && if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
(dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n", printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n",
@ -480,13 +507,14 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
/* Start HW link training */ /* Start HW link training */
writel(HW_TRAINING_EN, &base->dp_hw_link_training); writel(HW_TRAINING_EN, &base->dp_hw_link_training);
/* Wait unitl HW link training done */ /* Wait until HW link training done */
s5p_dp_wait_hw_link_training_done(dp); s5p_dp_wait_hw_link_training_done(dp);
/* Get hardware link training status */ /* Get hardware link training status */
data = readl(&base->dp_hw_link_training); data = readl(&base->dp_hw_link_training);
printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data);
if (data != 0) { if (data != 0) {
printk(BIOS_DEBUG, " H/W link training failure: 0x%x\n", data); printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data);
return -ERR_LINK_TRAINING_FAILURE; return -ERR_LINK_TRAINING_FAILURE;
} }
@ -497,6 +525,8 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
data = readl(&base->lane_count_set); data = readl(&base->lane_count_set);
dp->link_train.lane_count = data; 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; return 0;
} }
@ -510,24 +540,19 @@ int dp_controller_init(struct s5p_dp_device *dp_device)
struct s5p_dp_device *dp = dp_device; struct s5p_dp_device *dp = dp_device;
struct exynos5_dp *base; struct exynos5_dp *base;
//dp->base = (struct exynos5_dp *)addr;
/* yes. we're a snow. Yet somehow our config is from a development kit?
* This Must Change */
//dp->video_info = &smdk5250_dp_config;
clock_init_dp_clock(); clock_init_dp_clock();
power_enable_dp_phy(); power_enable_dp_phy();
ret = s5p_dp_init_dp(dp); ret = s5p_dp_init_dp(dp);
if (ret) { if (ret) {
printk(BIOS_DEBUG, "%s: Could not initialize dp\n", __func__); printk(BIOS_ERR, "%s: Could not initialize dp\n", __func__);
return ret; return ret;
} }
ret = s5p_dp_hw_link_training(dp, dp->video_info->lane_count, ret = s5p_dp_hw_link_training(dp, dp->video_info->lane_count,
dp->video_info->link_rate); dp->video_info->link_rate);
if (ret) { if (ret) {
printk(BIOS_DEBUG, "unable to do link train\n"); printk(BIOS_ERR, "unable to do link train\n");
return ret; return ret;
} }
/* Minimum delay after H/w Link training */ /* Minimum delay after H/w Link training */
@ -535,13 +560,13 @@ int dp_controller_init(struct s5p_dp_device *dp_device)
ret = s5p_dp_enable_scramble(dp); ret = s5p_dp_enable_scramble(dp);
if (ret) { if (ret) {
printk(BIOS_DEBUG, "unable to set scramble mode\n"); printk(BIOS_ERR, "unable to set scramble mode\n");
return ret; return ret;
} }
ret = s5p_dp_enable_rx_to_enhanced_mode(dp); ret = s5p_dp_enable_rx_to_enhanced_mode(dp);
if (ret) { if (ret) {
printk(BIOS_DEBUG, "unable to set enhanced mode\n"); printk(BIOS_ERR, "unable to set enhanced mode\n");
return ret; return ret;
} }
@ -556,7 +581,7 @@ int dp_controller_init(struct s5p_dp_device *dp_device)
s5p_dp_init_video(dp); s5p_dp_init_video(dp);
ret = s5p_dp_config_video(dp, dp->video_info); ret = s5p_dp_config_video(dp, dp->video_info);
if (ret) { if (ret) {
printk(BIOS_DEBUG, "unable to config video\n"); printk(BIOS_ERR, "unable to config video\n");
return ret; return ret;
} }
@ -576,10 +601,5 @@ int lcd_ctrl_init(vidinfo_t *panel_info,
fimd_bypass(); fimd_bypass();
fb_init(panel_info, lcdbase, panel_data); fb_init(panel_info, lcdbase, panel_data);
printk(BIOS_SPEW,
"fb_init(%p, %p, %p) done\n", panel_info, lcdbase, panel_data);
/* Enable flushing after LCD writes if requested */
// forget it. lcd_set_flush_dcache(1);
return ret; return ret;
} }

View File

@ -129,7 +129,8 @@ int s5p_dp_init_analog_func(struct s5p_dp_device *dp)
start = get_timer(0); start = get_timer(0);
while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
if (get_timer(start) > PLL_LOCK_TIMEOUT) { if (get_timer(start) > PLL_LOCK_TIMEOUT) {
printk(BIOS_DEBUG, "%s: PLL is not locked yet\n", __func__); printk(BIOS_ERR, "%s: PLL is not locked\n",
__func__);
return -1; return -1;
} }
} }
@ -176,9 +177,6 @@ int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
/* Enable AUX CH operation */ /* Enable AUX CH operation */
setbits_le32(&base->aux_ch_ctl_2, AUX_EN); setbits_le32(&base->aux_ch_ctl_2, AUX_EN);
printk(BIOS_DEBUG, "%s: base: 0x%p, &base->aux_ch_ctl_2: 0x%p, aux_ch_ctl_2: 0x%08x\n",
__func__, base, &base->aux_ch_ctl_2, readl(&base->aux_ch_ctl_2));
/* Is AUX CH command reply received? */ /* Is AUX CH command reply received? */
reg = readl(&base->dp_int_sta); reg = readl(&base->dp_int_sta);
while (!(reg & RPLY_RECEIV)) while (!(reg & RPLY_RECEIV))
@ -189,8 +187,9 @@ int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
/* Clear interrupt source for AUX CH access error */ /* Clear interrupt source for AUX CH access error */
reg = readl(&base->dp_int_sta); reg = readl(&base->dp_int_sta);
printk(BIOS_DEBUG, "%s: dp_int_sta: 0x%02x\n", __func__, reg);
if (reg & AUX_ERR) { if (reg & AUX_ERR) {
printk(BIOS_ERR, "%s: AUX_ERR encountered, dp_int_sta: "
"0x%02x\n", __func__, reg);
writel(AUX_ERR, &base->dp_int_sta); writel(AUX_ERR, &base->dp_int_sta);
return -1; return -1;
} }
@ -198,7 +197,7 @@ int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
/* Check AUX CH error access status */ /* Check AUX CH error access status */
reg = readl(&base->dp_int_sta); reg = readl(&base->dp_int_sta);
if ((reg & AUX_STATUS_MASK) != 0) { if ((reg & AUX_STATUS_MASK) != 0) {
printk(BIOS_DEBUG, "AUX CH error happens: %d\n\n", printk(BIOS_ERR, "AUX CH error happens: %d\n\n",
reg & AUX_STATUS_MASK); reg & AUX_STATUS_MASK);
return -1; return -1;
} }

View File

@ -5,6 +5,7 @@
#include <console/console.h> #include <console/console.h>
#include <device/device.h> #include <device/device.h>
#include <cbmem.h> #include <cbmem.h>
#include <arch/cache.h>
#include <cpu/samsung/exynos5250/fimd.h> #include <cpu/samsung/exynos5250/fimd.h>
#include <cpu/samsung/exynos5-common/s5p-dp-core.h> #include <cpu/samsung/exynos5-common/s5p-dp-core.h>
#include "chip.h" #include "chip.h"
@ -32,7 +33,6 @@ static void exynos_displayport_init(device_t dev)
unsigned long int fb_size; unsigned long int fb_size;
u32 lcdbase; u32 lcdbase;
printk(BIOS_SPEW, "%s: dev 0x%p, conf 0x%p\n", __func__, dev, conf);
memset(&vi, 0, sizeof(vi)); memset(&vi, 0, sizeof(vi));
memset(&panel, 0, sizeof(panel)); memset(&panel, 0, sizeof(panel));
@ -61,16 +61,35 @@ static void exynos_displayport_init(device_t dev)
* The size is a magic number from hardware. Allocate enough for the * The size is a magic number from hardware. Allocate enough for the
* frame buffer and color map. * frame buffer and color map.
*/ */
fb_size = conf->xres * conf->yres * sizeof(unsigned long); fb_size = conf->xres * conf->yres * (conf->bpp / 8);
lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, fb_size + 64*KiB); lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, fb_size + 64*KiB);
printk(BIOS_SPEW, "lcd colormap base is %p\n", (void *)(lcdbase)); printk(BIOS_SPEW, "lcd colormap base is %p\n", (void *)(lcdbase));
mmio_resource(dev, 0, lcdbase/KiB, 64); mmio_resource(dev, 0, lcdbase/KiB, 64);
vi.cmap = (void *)lcdbase; vi.cmap = (void *)lcdbase;
/*
* We need to clean and invalidate the framebuffer region and disable
* caching as well. We assume that our dcache <--> memory address
* space is identity-mapped in 1MB chunks, so align accordingly.
*
* Note: We may want to do something clever to ensure the framebuffer
* region is aligned such that we don't change dcache policy for other
* stuff inadvertantly.
*
* FIXME: Is disabling/re-enabling the MMU entirely necessary?
*/
uint32_t lower = ALIGN_DOWN(lcdbase, MiB);
uint32_t upper = ALIGN_UP(lcdbase + fb_size + 64*KiB, MiB);
dcache_clean_invalidate_by_mva(lower, upper - lower);
dcache_mmu_disable();
mmu_config_range(lower/MiB, (upper - lower)/MiB, DCACHE_OFF);
dcache_mmu_enable();
lcdbase += 64*KiB; lcdbase += 64*KiB;
mmio_resource(dev, 1, lcdbase/KiB, (fb_size + KiB - 1)/KiB); mmio_resource(dev, 1, lcdbase/KiB, (fb_size + KiB - 1)/KiB);
printk(BIOS_DEBUG, printk(BIOS_DEBUG,
"Initializing exynos VGA, base %p\n",(void *)lcdbase); "Initializing exynos VGA, base %p\n", (void *)lcdbase);
memset((void *)lcdbase, 0, fb_size); /* clear the framebuffer */
ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase); ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase);
} }

View File

@ -33,6 +33,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
select EXYNOS_DISPLAYPORT select EXYNOS_DISPLAYPORT
select CHROMEOS select CHROMEOS
select DRIVER_TI_TPS65090 select DRIVER_TI_TPS65090
select MAINBOARD_HAS_NATIVE_VGA_INIT
select MAINBOARD_DO_NATIVE_VGA_INIT
config MAINBOARD_DIR config MAINBOARD_DIR
string string

View File

@ -23,6 +23,7 @@
#include <drivers/ti/tps65090/tps65090.h> #include <drivers/ti/tps65090/tps65090.h>
#include <cbmem.h> #include <cbmem.h>
#include <delay.h> #include <delay.h>
#include <boot/coreboot_tables.h>
#include <arch/cache.h> #include <arch/cache.h>
#include <arch/exception.h> #include <arch/exception.h>
#include <arch/gpio.h> #include <arch/gpio.h>
@ -41,6 +42,41 @@
#define DRAM_SIZE CONFIG_DRAM_SIZE_MB #define DRAM_SIZE CONFIG_DRAM_SIZE_MB
#define DRAM_END (DRAM_START + DRAM_SIZE) /* plus one... */ #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)
{
/*
* The address returned points at the LCD colormap base. The
* 64KiB offset points at the LCD base.
*/
framebuffer->physical_address =
(u32)cbmem_find(CBMEM_ID_CONSOLE) + 64*KiB;
printk(BIOS_SPEW, "%s: framebuffer->physical address is 0x%llx\n",
__func__, framebuffer->physical_address);
framebuffer->x_resolution = 1366;
framebuffer->y_resolution = 768;
framebuffer->bits_per_pixel = 16;
framebuffer->bytes_per_line =
(framebuffer->x_resolution * framebuffer->bits_per_pixel) / 8;
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 hardwaremain(int boot_complete);
void main(void) void main(void)
{ {