ARMv7: normalize ramstage code flow

In ram stage, all code flow should be tied to the resource allocator.
Stuff that has to happen before everything else goes into the mainboard
enable function in mainboard.c. This patch empties the main() wrapper
around hardwaremain.c, allowing to get rid of this special case in the
ARM port.

Change-Id: Ide91a23f1043b64acf64471f180a2297f0f40d97
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Signed-off-by: Gabe Black <gabeblack@chromium.org>
Reviewed-on: http://review.coreboot.org/3638
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Stefan Reinauer 2013-05-09 16:16:13 -07:00 committed by Stefan Reinauer
parent 78c3e33550
commit 2ae6d6f6de
6 changed files with 298 additions and 307 deletions

View File

@ -13,8 +13,6 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <console/console.h>
void hardwaremain(void); void hardwaremain(void);
void main(void) void main(void)
{ {

View File

@ -19,11 +19,11 @@
bootblock-y += wakeup.c bootblock-y += wakeup.c
romstage-y += mainboard.c
romstage-y += memory.c romstage-y += memory.c
romstage-y += romstage.c romstage-y += romstage.c
romstage-y += wakeup.c romstage-y += wakeup.c
# ramstage-y += ec.c # ramstage-y += ec.c
ramstage-y += mainboard.c
ramstage-y += ramstage.c ramstage-y += ramstage.c
ramstage-y += chromeos.c ramstage-y += chromeos.c

View File

@ -17,60 +17,255 @@
* MA 02111-1307 USA * MA 02111-1307 USA
*/ */
#include <stdlib.h>
#include <gpio.h>
#include <device/device.h>
#include <console/console.h> #include <console/console.h>
#include <device/device.h>
#include <cpu/samsung/exynos5-common/gpio.h> #include <device/i2c.h>
#include <drivers/ti/tps65090/tps65090.h>
#include <cbmem.h>
#include <delay.h>
#include <edid.h>
#include <vbe.h>
#include <boot/coreboot_tables.h>
#include <arch/cache.h>
#include <arch/exception.h>
#include <arch/gpio.h>
#include <cpu/samsung/exynos5-common/exynos-tmu.h>
#include <cpu/samsung/exynos5250/clk.h>
#include <cpu/samsung/exynos5250/cpu.h>
#include <cpu/samsung/exynos5250/gpio.h> #include <cpu/samsung/exynos5250/gpio.h>
#include <cpu/samsung/exynos5250/power.h>
#include "mainboard.h" #include <cpu/samsung/exynos5-common/i2c.h>
#include <cpu/samsung/exynos5-common/s5p-dp-core.h>
#define SNOW_BOARD_ID0_GPIO 88 /* GPD0, pin 0 */
#define SNOW_BOARD_ID1_GPIO 89 /* GPD0, pin 1 */
struct { /* convenient shorthand (in MB) */
enum mvl3 id0, id1; #define DRAM_START (CONFIG_SYS_SDRAM_BASE >> 20)
enum snow_board_config config; #define DRAM_SIZE CONFIG_DRAM_SIZE_MB
} snow_id_map[] = { #define DRAM_END (DRAM_START + DRAM_SIZE) /* plus one... */
/* ID0 ID1 config */
{ LOGIC_0, LOGIC_0, SNOW_CONFIG_SAMSUNG_MP }, static struct edid snow_edid = {
{ LOGIC_0, LOGIC_1, SNOW_CONFIG_ELPIDA_MP }, .ha = 1366,
{ LOGIC_1, LOGIC_0, SNOW_CONFIG_SAMSUNG_DVT }, .va = 768,
{ LOGIC_1, LOGIC_1, SNOW_CONFIG_ELPIDA_DVT }, .bpp = 16,
{ LOGIC_0, LOGIC_Z, SNOW_CONFIG_SAMSUNG_PVT },
{ LOGIC_1, LOGIC_Z, SNOW_CONFIG_ELPIDA_PVT },
{ LOGIC_Z, LOGIC_0, SNOW_CONFIG_SAMSUNG_MP },
{ LOGIC_Z, LOGIC_Z, SNOW_CONFIG_ELPIDA_MP },
{ LOGIC_Z, LOGIC_1, SNOW_CONFIG_RSVD },
}; };
int board_get_config(void) /* TODO: transplanted DP stuff, clean up once we have something that works */
static enum exynos5_gpio_pin dp_pd_l = GPIO_Y25; /* active low */
static enum exynos5_gpio_pin dp_rst_l = GPIO_X15; /* active low */
static enum exynos5_gpio_pin dp_hpd = GPIO_X07; /* active high */
static void exynos_dp_bridge_setup(void)
{ {
int i; exynos_pinmux_config(PERIPH_ID_DPHPD, 0);
int id0, id1;
enum snow_board_config config = SNOW_CONFIG_UNKNOWN;
id0 = gpio_read_mvl3(SNOW_BOARD_ID0_GPIO); gpio_set_value(dp_pd_l, 1);
id1 = gpio_read_mvl3(SNOW_BOARD_ID1_GPIO); gpio_cfg_pin(dp_pd_l, EXYNOS_GPIO_OUTPUT);
if (id0 < 0 || id1 < 0) gpio_set_pull(dp_pd_l, EXYNOS_GPIO_PULL_NONE);
return -1;
printk(BIOS_DEBUG, "%s: id0: %u, id1: %u\n", __func__, id0, id1);
for (i = 0; i < ARRAY_SIZE(snow_id_map); i++) { gpio_set_value(dp_rst_l, 0);
if (id0 == snow_id_map[i].id0 && id1 == snow_id_map[i].id1) { gpio_cfg_pin(dp_rst_l, EXYNOS_GPIO_OUTPUT);
config = snow_id_map[i].config; gpio_set_pull(dp_rst_l, EXYNOS_GPIO_PULL_NONE);
break; udelay(10);
} gpio_set_value(dp_rst_l, 1);
} }
return config; static void exynos_dp_bridge_init(void)
{
/* De-assert PD (and possibly RST) to power up the bridge */
gpio_set_value(dp_pd_l, 1);
gpio_set_value(dp_rst_l, 1);
/*
* We need to wait for 90ms after bringing up the bridge since
* there is a phantom "high" on the HPD chip during its
* bootup. The phantom high comes within 7ms of de-asserting
* PD and persists for at least 15ms. The real high comes
* roughly 50ms after PD is de-asserted. The phantom high
* makes it hard for us to know when the NXP chip is up.
*/
udelay(90000);
}
static int exynos_dp_hotplug(void)
{
/* Check HPD. If it's high, we're all good. */
return gpio_get_value(dp_hpd) ? 0 : 1;
}
static void exynos_dp_reset(void)
{
gpio_set_value(dp_pd_l, 0);
gpio_set_value(dp_rst_l, 0);
/* paranoid delay period (300ms) */
udelay(300 * 1000);
}
/*
* This delay is T3 in the LCD timing spec (defined as >200ms). We set
* this down to 60ms since that's the approximate maximum amount of time
* it'll take a bridge to start outputting LVDS data. The delay of
* >200ms is just a conservative value to avoid turning on the backlight
* when there's random LCD data on the screen. Shaving 140ms off the
* boot is an acceptable trade-off.
*/
#define LCD_T3_DELAY_MS 60
#define LCD_T5_DELAY_MS 10
#define LCD_T6_DELAY_MS 10
static void snow_backlight_pwm(void)
{
/*Configure backlight PWM as a simple output high (100% brightness) */
gpio_direction_output(GPIO_B20, 1);
udelay(LCD_T6_DELAY_MS * 1000);
}
static void snow_backlight_en(void)
{
/* * Configure GPIO for LCD_BL_EN */
gpio_direction_output(GPIO_X30, 1);
}
#define TPS69050_BUS 4 /* Snow-specific */
#define FET1_CTRL 0x0f
#define FET6_CTRL 0x14
static void snow_lcd_vdd(void)
{
/* Enable FET6, lcd panel */
tps65090_fet_enable(TPS69050_BUS, FET6_CTRL);
}
static void snow_backlight_vdd(void)
{
/* Enable FET1, backlight */
tps65090_fet_enable(TPS69050_BUS, FET1_CTRL);
udelay(LCD_T5_DELAY_MS * 1000);
}
//static struct video_info smdk5250_dp_config = {
static struct video_info snow_dp_video_info = {
/* FIXME: fix video_info struct to use const for name */
.name = (char *)"eDP-LVDS NXP PTN3460",
.h_sync_polarity = 0,
.v_sync_polarity = 0,
.interlaced = 0,
.color_space = COLOR_RGB,
.dynamic_range = VESA,
.ycbcr_coeff = COLOR_YCBCR601,
.color_depth = COLOR_8,
.link_rate = LINK_RATE_2_70GBPS,
.lane_count = LANE_COUNT2,
};
/* FIXME: move some place more appropriate */
#define EXYNOS5250_DP1_BASE 0x145b0000
#define SNOW_MAX_DP_TRIES 5
/*
* This function disables the USB3.0 PLL to save power
*/
static void disable_usb30_pll(void)
{
enum exynos5_gpio_pin usb3_pll_l = GPIO_Y11;
gpio_direction_output(usb3_pll_l, 0);
}
/* this happens after cpu_init where exynos resources are set */
static void mainboard_init(device_t dev)
{
int dp_tries;
struct s5p_dp_device dp_device = {
.base = (struct exynos5_dp *)EXYNOS5250_DP1_BASE,
.video_info = &snow_dp_video_info,
};
void *fb_addr;
i2c_init(TPS69050_BUS, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
i2c_init(7, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
tmu_init(&exynos5250_tmu_info);
/* Clock Gating all the unused IP's to save power */
clock_gate();
/* Disable USB3.0 PLL to save 250mW of power */
disable_usb30_pll();
fb_addr = cbmem_find(CBMEM_ID_CONSOLE);
set_vbe_mode_info_valid(&snow_edid, (uintptr_t)(fb_addr) + 64*KiB);
snow_lcd_vdd();
do {
udelay(50);
} while (!exynos_dp_hotplug());
exynos_dp_bridge_setup();
for (dp_tries = 1; dp_tries <= SNOW_MAX_DP_TRIES; dp_tries++) {
exynos_dp_bridge_init();
if (exynos_dp_hotplug()) {
exynos_dp_reset();
continue;
}
if (dp_controller_init(&dp_device))
continue;
udelay(LCD_T3_DELAY_MS * 1000);
snow_backlight_vdd();
snow_backlight_pwm();
snow_backlight_en();
/* if we're here, we're successful */
break;
}
if (dp_tries > SNOW_MAX_DP_TRIES)
printk(BIOS_ERR, "%s: Failed to set up displayport\n", __func__);
}
static void mainboard_enable(device_t dev)
{
dev->ops->init = &mainboard_init;
/* set up coreboot tables */
high_tables_size = CONFIG_COREBOOT_TABLES_SIZE;
high_tables_base = CONFIG_SYS_SDRAM_BASE +
((unsigned)CONFIG_DRAM_SIZE_MB << 20ULL) -
CONFIG_COREBOOT_TABLES_SIZE;
cbmem_init(high_tables_base, high_tables_size);
/* set up dcache and MMU */
/* FIXME: this should happen via resource allocator */
exynos5250_config_l2_cache();
mmu_init();
mmu_config_range(0, DRAM_START, DCACHE_OFF);
mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK);
mmu_config_range(DRAM_END, 4096 - DRAM_END, DCACHE_OFF);
dcache_invalidate_all();
dcache_mmu_enable();
/* this is going to move, but we must have it now and we're
* not sure where */
exception_init();
const unsigned epll_hz = 192000000;
const unsigned sample_rate = 48000;
const unsigned lr_frame_size = 256;
clock_epll_set_rate(epll_hz);
clock_select_i2s_clk_source();
clock_set_i2s_clk_prescaler(epll_hz, sample_rate * lr_frame_size);
power_enable_xclkout();
} }
#if 0
struct chip_operations mainboard_ops = { struct chip_operations mainboard_ops = {
.name = "Samsung/Google ARM Chromebook", .name = "Samsung/Google ARM Chromebook",
.enable_dev = mainboard_enable, .enable_dev = mainboard_enable,
}; };
#endif

View File

@ -19,22 +19,6 @@
#ifndef MAINBOARD_H #ifndef MAINBOARD_H
#define MAINBOARD_H #define MAINBOARD_H
enum snow_board_config {
SNOW_CONFIG_UNKNOWN = -1,
SNOW_CONFIG_SAMSUNG_EVT,
SNOW_CONFIG_ELPIDA_EVT,
SNOW_CONFIG_SAMSUNG_DVT,
SNOW_CONFIG_ELPIDA_DVT,
SNOW_CONFIG_SAMSUNG_PVT,
SNOW_CONFIG_ELPIDA_PVT,
SNOW_CONFIG_SAMSUNG_MP,
SNOW_CONFIG_ELPIDA_MP,
SNOW_CONFIG_RSVD,
};
int board_get_config(void);
enum { enum {
SNOW_IS_NOT_WAKEUP, // A normal boot (not suspend/resume). SNOW_IS_NOT_WAKEUP, // A normal boot (not suspend/resume).
SNOW_WAKEUP_DIRECT, // A wake up event that can be resumed any time. SNOW_WAKEUP_DIRECT, // A wake up event that can be resumed any time.

View File

@ -23,13 +23,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <console/console.h> #include <console/console.h>
#include <gpio.h>
#include <cpu/samsung/exynos5-common/gpio.h>
#include <cpu/samsung/exynos5250/gpio.h>
#include <cpu/samsung/exynos5250/setup.h> #include <cpu/samsung/exynos5250/setup.h>
#include <cpu/samsung/exynos5250/dmc.h> #include <cpu/samsung/exynos5250/dmc.h>
#include <cpu/samsung/exynos5250/clock_init.h> #include <cpu/samsung/exynos5250/clock_init.h>
#include "mainboard.h" #include "mainboard.h"
struct mem_timings mem_timings[] = { const struct mem_timings mem_timings[] = {
{ {
.mem_manuf = MEM_MANUF_ELPIDA, .mem_manuf = MEM_MANUF_ELPIDA,
.mem_type = DDR_MODE_DDR3, .mem_type = DDR_MODE_DDR3,
@ -450,6 +453,61 @@ struct mem_timings mem_timings[] = {
} }
}; };
#define SNOW_BOARD_ID0_GPIO 88 /* GPD0, pin 0 */
#define SNOW_BOARD_ID1_GPIO 89 /* GPD0, pin 1 */
enum snow_board_config {
SNOW_CONFIG_UNKNOWN = -1,
SNOW_CONFIG_SAMSUNG_EVT,
SNOW_CONFIG_ELPIDA_EVT,
SNOW_CONFIG_SAMSUNG_DVT,
SNOW_CONFIG_ELPIDA_DVT,
SNOW_CONFIG_SAMSUNG_PVT,
SNOW_CONFIG_ELPIDA_PVT,
SNOW_CONFIG_SAMSUNG_MP,
SNOW_CONFIG_ELPIDA_MP,
SNOW_CONFIG_RSVD,
};
struct {
enum mvl3 id0, id1;
enum snow_board_config config;
} snow_id_map[] = {
/* ID0 ID1 config */
{ LOGIC_0, LOGIC_0, SNOW_CONFIG_SAMSUNG_MP },
{ LOGIC_0, LOGIC_1, SNOW_CONFIG_ELPIDA_MP },
{ LOGIC_1, LOGIC_0, SNOW_CONFIG_SAMSUNG_DVT },
{ LOGIC_1, LOGIC_1, SNOW_CONFIG_ELPIDA_DVT },
{ LOGIC_0, LOGIC_Z, SNOW_CONFIG_SAMSUNG_PVT },
{ LOGIC_1, LOGIC_Z, SNOW_CONFIG_ELPIDA_PVT },
{ LOGIC_Z, LOGIC_0, SNOW_CONFIG_SAMSUNG_MP },
{ LOGIC_Z, LOGIC_Z, SNOW_CONFIG_ELPIDA_MP },
{ LOGIC_Z, LOGIC_1, SNOW_CONFIG_RSVD },
};
static int board_get_config(void)
{
int i;
int id0, id1;
enum snow_board_config config = SNOW_CONFIG_UNKNOWN;
id0 = gpio_read_mvl3(SNOW_BOARD_ID0_GPIO);
id1 = gpio_read_mvl3(SNOW_BOARD_ID1_GPIO);
if (id0 < 0 || id1 < 0)
return -1;
printk(BIOS_DEBUG, "%s: id0: %u, id1: %u\n", __func__, id0, id1);
for (i = 0; i < ARRAY_SIZE(snow_id_map); i++) {
if (id0 == snow_id_map[i].id0 && id1 == snow_id_map[i].id1) {
config = snow_id_map[i].config;
break;
}
}
return config;
}
struct mem_timings *get_mem_timings(void) struct mem_timings *get_mem_timings(void)
{ {
int i; int i;
@ -457,7 +515,7 @@ struct mem_timings *get_mem_timings(void)
enum ddr_mode mem_type; enum ddr_mode mem_type;
unsigned int frequency_mhz; unsigned int frequency_mhz;
enum mem_manuf mem_manuf; enum mem_manuf mem_manuf;
struct mem_timings *mem; const struct mem_timings *mem;
board_config = board_get_config(); board_config = board_get_config();
switch (board_config) { switch (board_config) {
@ -487,7 +545,7 @@ struct mem_timings *get_mem_timings(void)
if (mem->mem_type == mem_type && if (mem->mem_type == mem_type &&
mem->frequency_mhz == frequency_mhz && mem->frequency_mhz == frequency_mhz &&
mem->mem_manuf == mem_manuf) mem->mem_manuf == mem_manuf)
return mem; return (struct mem_timings *)mem;
} }
return NULL; return NULL;

View File

@ -17,252 +17,8 @@
* MA 02111-1307 USA * MA 02111-1307 USA
*/ */
#include <console/console.h>
#include <device/device.h>
#include <device/i2c.h>
#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>
#include <cpu/samsung/exynos5-common/exynos-tmu.h>
#include <cpu/samsung/exynos5250/clk.h>
#include <cpu/samsung/exynos5250/cpu.h>
#include <cpu/samsung/exynos5250/gpio.h>
#include <cpu/samsung/exynos5250/power.h>
#include <cpu/samsung/exynos5-common/i2c.h>
#include <cpu/samsung/exynos5-common/s5p-dp-core.h>
/* convenient shorthand (in MB) */
#define DRAM_START (CONFIG_SYS_SDRAM_BASE >> 20)
#define DRAM_SIZE CONFIG_DRAM_SIZE_MB
#define DRAM_END (DRAM_START + DRAM_SIZE) /* plus one... */
void hardwaremain(void); void hardwaremain(void);
void main(void) void main(void)
{ {
/* FIXME this should be moved elsewhere. We don't want ramstage.c */
/* set up coreboot tables */
high_tables_size = CONFIG_COREBOOT_TABLES_SIZE;
high_tables_base = CONFIG_SYS_SDRAM_BASE +
((unsigned)CONFIG_DRAM_SIZE_MB << 20ULL) -
CONFIG_COREBOOT_TABLES_SIZE;
cbmem_init(high_tables_base, high_tables_size);
/* set up dcache and MMU */
/* FIXME: this should happen via resource allocator */
exynos5250_config_l2_cache();
mmu_init();
mmu_config_range(0, DRAM_START, DCACHE_OFF);
mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK);
mmu_config_range(DRAM_END, 4096 - DRAM_END, DCACHE_OFF);
dcache_invalidate_all();
dcache_mmu_enable();
/* this is going to move, but we must have it now and we're
* not sure where */
exception_init();
const unsigned epll_hz = 192000000;
const unsigned sample_rate = 48000;
const unsigned lr_frame_size = 256;
clock_epll_set_rate(epll_hz);
clock_select_i2s_clk_source();
clock_set_i2s_clk_prescaler(epll_hz, sample_rate * lr_frame_size);
power_enable_xclkout();
hardwaremain(); hardwaremain();
} }
/* TODO: transplanted DP stuff, clean up once we have something that works */
static enum exynos5_gpio_pin dp_pd_l = GPIO_Y25; /* active low */
static enum exynos5_gpio_pin dp_rst_l = GPIO_X15; /* active low */
static enum exynos5_gpio_pin dp_hpd = GPIO_X07; /* active high */
static void exynos_dp_bridge_setup(void)
{
exynos_pinmux_config(PERIPH_ID_DPHPD, 0);
gpio_set_value(dp_pd_l, 1);
gpio_cfg_pin(dp_pd_l, EXYNOS_GPIO_OUTPUT);
gpio_set_pull(dp_pd_l, EXYNOS_GPIO_PULL_NONE);
gpio_set_value(dp_rst_l, 0);
gpio_cfg_pin(dp_rst_l, EXYNOS_GPIO_OUTPUT);
gpio_set_pull(dp_rst_l, EXYNOS_GPIO_PULL_NONE);
udelay(10);
gpio_set_value(dp_rst_l, 1);
}
static void exynos_dp_bridge_init(void)
{
/* De-assert PD (and possibly RST) to power up the bridge */
gpio_set_value(dp_pd_l, 1);
gpio_set_value(dp_rst_l, 1);
/*
* We need to wait for 90ms after bringing up the bridge since
* there is a phantom "high" on the HPD chip during its
* bootup. The phantom high comes within 7ms of de-asserting
* PD and persists for at least 15ms. The real high comes
* roughly 50ms after PD is de-asserted. The phantom high
* makes it hard for us to know when the NXP chip is up.
*/
udelay(90000);
}
static int exynos_dp_hotplug(void)
{
/* Check HPD. If it's high, we're all good. */
return gpio_get_value(dp_hpd) ? 0 : 1;
}
static void exynos_dp_reset(void)
{
gpio_set_value(dp_pd_l, 0);
gpio_set_value(dp_rst_l, 0);
/* paranoid delay period (300ms) */
udelay(300 * 1000);
}
/*
* This delay is T3 in the LCD timing spec (defined as >200ms). We set
* this down to 60ms since that's the approximate maximum amount of time
* it'll take a bridge to start outputting LVDS data. The delay of
* >200ms is just a conservative value to avoid turning on the backlight
* when there's random LCD data on the screen. Shaving 140ms off the
* boot is an acceptable trade-off.
*/
#define LCD_T3_DELAY_MS 60
#define LCD_T5_DELAY_MS 10
#define LCD_T6_DELAY_MS 10
static void snow_backlight_pwm(void)
{
/*Configure backlight PWM as a simple output high (100% brightness) */
gpio_direction_output(GPIO_B20, 1);
udelay(LCD_T6_DELAY_MS * 1000);
}
static void snow_backlight_en(void)
{
/* * Configure GPIO for LCD_BL_EN */
gpio_direction_output(GPIO_X30, 1);
}
#define TPS69050_BUS 4 /* Snow-specific */
#define FET1_CTRL 0x0f
#define FET6_CTRL 0x14
static void snow_lcd_vdd(void)
{
/* Enable FET6, lcd panel */
tps65090_fet_enable(TPS69050_BUS, FET6_CTRL);
}
static void snow_backlight_vdd(void)
{
/* Enable FET1, backlight */
tps65090_fet_enable(TPS69050_BUS, FET1_CTRL);
udelay(LCD_T5_DELAY_MS * 1000);
}
//static struct video_info smdk5250_dp_config = {
static struct video_info snow_dp_video_info = {
/* FIXME: fix video_info struct to use const for name */
.name = (char *)"eDP-LVDS NXP PTN3460",
.h_sync_polarity = 0,
.v_sync_polarity = 0,
.interlaced = 0,
.color_space = COLOR_RGB,
.dynamic_range = VESA,
.ycbcr_coeff = COLOR_YCBCR601,
.color_depth = COLOR_8,
.link_rate = LINK_RATE_2_70GBPS,
.lane_count = LANE_COUNT2,
};
/* FIXME: move some place more appropriate */
#define EXYNOS5250_DP1_BASE 0x145b0000
#define SNOW_MAX_DP_TRIES 5
/*
* This function disables the USB3.0 PLL to save power
*/
static void disable_usb30_pll(void)
{
enum exynos5_gpio_pin usb3_pll_l = GPIO_Y11;
gpio_direction_output(usb3_pll_l, 0);
}
/* this happens after cpu_init where exynos resources are set */
static void mainboard_init(device_t dev)
{
int dp_tries;
struct s5p_dp_device dp_device = {
.base = (struct exynos5_dp *)EXYNOS5250_DP1_BASE,
.video_info = &snow_dp_video_info,
};
i2c_init(TPS69050_BUS, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
i2c_init(7, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
tmu_init(&exynos5250_tmu_info);
/* Clock Gating all the unused IP's to save power */
clock_gate();
/* Disable USB3.0 PLL to save 250mW of power */
disable_usb30_pll();
snow_lcd_vdd();
do {
udelay(50);
} while (!exynos_dp_hotplug());
exynos_dp_bridge_setup();
for (dp_tries = 1; dp_tries <= SNOW_MAX_DP_TRIES; dp_tries++) {
exynos_dp_bridge_init();
if (exynos_dp_hotplug()) {
exynos_dp_reset();
continue;
}
if (dp_controller_init(&dp_device))
continue;
udelay(LCD_T3_DELAY_MS * 1000);
snow_backlight_vdd();
snow_backlight_pwm();
snow_backlight_en();
/* if we're here, we're successful */
break;
}
if (dp_tries > SNOW_MAX_DP_TRIES)
printk(BIOS_ERR, "%s: Failed to set up displayport\n", __func__);
}
static void mainboard_enable(device_t dev)
{
dev->ops->init = &mainboard_init;
}
struct chip_operations mainboard_ops = {
.name = "Samsung/Google ARM Chromebook",
.enable_dev = mainboard_enable,
};