u-boot-brain/board/hisilicon/hikey/hikey.c
Peter Griffin 9c71bcdc81 ARM: hikey: hi6220: Migrate over to DM_SERIAL and use UART3 by default.
Use DM for the pl01x serial driver on hikey. Also allow UART0 or
UART3 to be chosen via Kconfig.

By default we now output to UART3 as the latest version of ATF outputs
to this UART. Also UART3 comes out on the LS connector, as opposed to
UART0 which goes to a unpopulated header.

As part of this change we also enable CONFIG_BOARD_EARLY_INIT_F and
call the pinmux configuration code for the UART. Before we were
relying on ATF having already configured the pin configuration.

NB: Upstream Linux kernel doesn't yet support UART3, so serial console
will still be output on UART0 when booting a upstream kernel.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
2015-09-28 10:48:22 -04:00

398 lines
8.6 KiB
C

/*
* (C) Copyright 2015 Linaro
* Peter Griffin <peter.griffin@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <dm/platform_data/serial_pl01x.h>
#include <errno.h>
#include <malloc.h>
#include <netdev.h>
#include <asm/io.h>
#include <usb.h>
#include <power/hi6553_pmic.h>
#include <asm-generic/gpio.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/gpio.h>
#include <asm/arch/periph.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/hi6220.h>
/*TODO drop this table in favour of device tree */
static const struct hikey_gpio_platdata hi6220_gpio[] = {
{ 0, HI6220_GPIO_BASE(0)},
{ 1, HI6220_GPIO_BASE(1)},
{ 2, HI6220_GPIO_BASE(2)},
{ 3, HI6220_GPIO_BASE(3)},
{ 4, HI6220_GPIO_BASE(4)},
{ 5, HI6220_GPIO_BASE(5)},
{ 6, HI6220_GPIO_BASE(6)},
{ 7, HI6220_GPIO_BASE(7)},
{ 8, HI6220_GPIO_BASE(8)},
{ 9, HI6220_GPIO_BASE(9)},
{ 10, HI6220_GPIO_BASE(10)},
{ 11, HI6220_GPIO_BASE(11)},
{ 12, HI6220_GPIO_BASE(12)},
{ 13, HI6220_GPIO_BASE(13)},
{ 14, HI6220_GPIO_BASE(14)},
{ 15, HI6220_GPIO_BASE(15)},
{ 16, HI6220_GPIO_BASE(16)},
{ 17, HI6220_GPIO_BASE(17)},
{ 18, HI6220_GPIO_BASE(18)},
{ 19, HI6220_GPIO_BASE(19)},
};
U_BOOT_DEVICES(hi6220_gpios) = {
{ "gpio_hi6220", &hi6220_gpio[0] },
{ "gpio_hi6220", &hi6220_gpio[1] },
{ "gpio_hi6220", &hi6220_gpio[2] },
{ "gpio_hi6220", &hi6220_gpio[3] },
{ "gpio_hi6220", &hi6220_gpio[4] },
{ "gpio_hi6220", &hi6220_gpio[5] },
{ "gpio_hi6220", &hi6220_gpio[6] },
{ "gpio_hi6220", &hi6220_gpio[7] },
{ "gpio_hi6220", &hi6220_gpio[8] },
{ "gpio_hi6220", &hi6220_gpio[9] },
{ "gpio_hi6220", &hi6220_gpio[10] },
{ "gpio_hi6220", &hi6220_gpio[11] },
{ "gpio_hi6220", &hi6220_gpio[12] },
{ "gpio_hi6220", &hi6220_gpio[13] },
{ "gpio_hi6220", &hi6220_gpio[14] },
{ "gpio_hi6220", &hi6220_gpio[15] },
{ "gpio_hi6220", &hi6220_gpio[16] },
{ "gpio_hi6220", &hi6220_gpio[17] },
{ "gpio_hi6220", &hi6220_gpio[18] },
{ "gpio_hi6220", &hi6220_gpio[19] },
};
DECLARE_GLOBAL_DATA_PTR;
static const struct pl01x_serial_platdata serial_platdata = {
#if CONFIG_CONS_INDEX == 1
.base = HI6220_UART0_BASE,
#elif CONFIG_CONS_INDEX == 4
.base = HI6220_UART3_BASE,
#else
#error "Unsuported console index value."
#endif
.type = TYPE_PL011,
.clock = 19200000
};
U_BOOT_DEVICE(hikey_seriala) = {
.name = "serial_pl01x",
.platdata = &serial_platdata,
};
#ifdef CONFIG_BOARD_EARLY_INIT_F
int board_uart_init(void)
{
switch (CONFIG_CONS_INDEX) {
case 1:
hi6220_pinmux_config(PERIPH_ID_UART0);
break;
case 4:
hi6220_pinmux_config(PERIPH_ID_UART3);
break;
default:
debug("%s: Unsupported UART selected\n", __func__);
return -1;
}
return 0;
}
int board_early_init_f(void)
{
board_uart_init();
return 0;
}
#endif
struct peri_sc_periph_regs *peri_sc =
(struct peri_sc_periph_regs *)HI6220_PERI_BASE;
struct alwayson_sc_regs *ao_sc =
(struct alwayson_sc_regs *)ALWAYSON_CTRL_BASE;
/* status offset from enable reg */
#define STAT_EN_OFF 0x2
void hi6220_clk_enable(u32 bitfield, unsigned int *clk_base)
{
uint32_t data;
data = readl(clk_base);
data |= bitfield;
writel(bitfield, clk_base);
do {
data = readl(clk_base + STAT_EN_OFF);
} while ((data & bitfield) == 0);
}
/* status offset from disable reg */
#define STAT_DIS_OFF 0x1
void hi6220_clk_disable(u32 bitfield, unsigned int *clk_base)
{
uint32_t data;
data = readl(clk_base);
data |= bitfield;
writel(data, clk_base);
do {
data = readl(clk_base + STAT_DIS_OFF);
} while (data & bitfield);
}
#define EYE_PATTERN 0x70533483
int board_usb_init(int index, enum usb_init_type init)
{
unsigned int data;
/* enable USB clock */
hi6220_clk_enable(PERI_CLK0_USBOTG, &peri_sc->clk0_en);
/* take usb IPs out of reset */
writel(PERI_RST0_USBOTG_BUS | PERI_RST0_POR_PICOPHY |
PERI_RST0_USBOTG | PERI_RST0_USBOTG_32K,
&peri_sc->rst0_dis);
do {
data = readl(&peri_sc->rst0_stat);
data &= PERI_RST0_USBOTG_BUS | PERI_RST0_POR_PICOPHY |
PERI_RST0_USBOTG | PERI_RST0_USBOTG_32K;
} while (data);
/*CTRL 5*/
data = readl(&peri_sc->ctrl5);
data &= ~PERI_CTRL5_PICOPHY_BC_MODE;
data |= PERI_CTRL5_USBOTG_RES_SEL | PERI_CTRL5_PICOPHY_ACAENB;
data |= 0x300;
writel(data, &peri_sc->ctrl5);
/*CTRL 4*/
/* configure USB PHY */
data = readl(&peri_sc->ctrl4);
/* make PHY out of low power mode */
data &= ~PERI_CTRL4_PICO_SIDDQ;
data &= ~PERI_CTRL4_PICO_OGDISABLE;
data |= PERI_CTRL4_PICO_VBUSVLDEXTSEL | PERI_CTRL4_PICO_VBUSVLDEXT;
writel(data, &peri_sc->ctrl4);
writel(EYE_PATTERN, &peri_sc->ctrl8);
mdelay(5);
return 0;
}
static int config_sd_carddetect(void)
{
int ret;
/* configure GPIO8 as nopull */
writel(0, 0xf8001830);
gpio_request(8, "SD CD");
gpio_direction_input(8);
ret = gpio_get_value(8);
if (!ret) {
printf("%s: SD card present\n", __func__);
return 1;
}
printf("%s: SD card not present\n", __func__);
return 0;
}
static void mmc1_init_pll(void)
{
uint32_t data;
/* select SYSPLL as the source of MMC1 */
/* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */
writel(1 << 11 | 1 << 27, &peri_sc->clk0_sel);
do {
data = readl(&peri_sc->clk0_sel);
} while (!(data & (1 << 11)));
/* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */
writel(1 << 30, &peri_sc->clk0_sel);
do {
data = readl(&peri_sc->clk0_sel);
} while (data & (1 << 14));
hi6220_clk_enable(PERI_CLK0_MMC1, &peri_sc->clk0_en);
hi6220_clk_enable(PERI_CLK12_MMC1_SRC, &peri_sc->clk12_en);
do {
/* 1.2GHz / 50 = 24MHz */
writel(0x31 | (1 << 7), &peri_sc->clkcfg8bit2);
data = readl(&peri_sc->clkcfg8bit2);
} while ((data & 0x31) != 0x31);
}
static void mmc1_reset_clk(void)
{
unsigned int data;
/* disable mmc1 bus clock */
hi6220_clk_disable(PERI_CLK0_MMC1, &peri_sc->clk0_dis);
/* enable mmc1 bus clock */
hi6220_clk_enable(PERI_CLK0_MMC1, &peri_sc->clk0_en);
/* reset mmc1 clock domain */
writel(PERI_RST0_MMC1, &peri_sc->rst0_en);
/* bypass mmc1 clock phase */
data = readl(&peri_sc->ctrl2);
data |= 3 << 2;
writel(data, &peri_sc->ctrl2);
/* disable low power */
data = readl(&peri_sc->ctrl13);
data |= 1 << 4;
writel(data, &peri_sc->ctrl13);
do {
data = readl(&peri_sc->rst0_stat);
} while (!(data & PERI_RST0_MMC1));
/* unreset mmc0 clock domain */
writel(PERI_RST0_MMC1, &peri_sc->rst0_dis);
do {
data = readl(&peri_sc->rst0_stat);
} while (data & PERI_RST0_MMC1);
}
/* PMU SSI is the IP that maps the external PMU hi6553 registers as IO */
static void hi6220_pmussi_init(void)
{
uint32_t data;
/* Take PMUSSI out of reset */
writel(ALWAYSON_SC_PERIPH_RST4_DIS_PRESET_PMUSSI_N,
&ao_sc->rst4_dis);
do {
data = readl(&ao_sc->rst4_stat);
} while (data & ALWAYSON_SC_PERIPH_RST4_DIS_PRESET_PMUSSI_N);
/* set PMU SSI clock latency for read operation */
data = readl(&ao_sc->mcu_subsys_ctrl3);
data &= ~ALWAYSON_SC_MCU_SUBSYS_CTRL3_RCLK_MASK;
data |= ALWAYSON_SC_MCU_SUBSYS_CTRL3_RCLK_3;
writel(data, &ao_sc->mcu_subsys_ctrl3);
/* enable PMUSSI clock */
data = ALWAYSON_SC_PERIPH_CLK5_EN_PCLK_PMUSSI_CCPU |
ALWAYSON_SC_PERIPH_CLK5_EN_PCLK_PMUSSI_MCU;
hi6220_clk_enable(data, &ao_sc->clk5_en);
/* Output high to PMIC on PWR_HOLD_GPIO0_0 */
gpio_request(0, "PWR_HOLD_GPIO0_0");
gpio_direction_output(0, 1);
}
int misc_init_r(void)
{
return 0;
}
int board_init(void)
{
return 0;
}
#ifdef CONFIG_GENERIC_MMC
static int init_dwmmc(void)
{
int ret;
#ifdef CONFIG_DWMMC
/* mmc0 clocks are already configured by ATF */
ret = hi6220_pinmux_config(PERIPH_ID_SDMMC0);
if (ret)
printf("%s: Error configuring pinmux for eMMC (%d)\n"
, __func__, ret);
ret |= hi6220_dwmci_add_port(0, HI6220_MMC0_BASE, 8);
if (ret)
printf("%s: Error adding eMMC port (%d)\n", __func__, ret);
/* take mmc1 (sd slot) out of reset, configure clocks and pinmuxing */
mmc1_init_pll();
mmc1_reset_clk();
ret |= hi6220_pinmux_config(PERIPH_ID_SDMMC1);
if (ret)
printf("%s: Error configuring pinmux for eMMC (%d)\n"
, __func__, ret);
config_sd_carddetect();
ret |= hi6220_dwmci_add_port(1, HI6220_MMC1_BASE, 4);
if (ret)
printf("%s: Error adding SD port (%d)\n", __func__, ret);
#endif
return ret;
}
/* setup board specific PMIC */
int power_init_board(void)
{
/* init the hi6220 pmussi ip */
hi6220_pmussi_init();
power_hi6553_init((u8 *)HI6220_PMUSSI_BASE);
return 0;
}
int board_mmc_init(bd_t *bis)
{
int ret;
/* add the eMMC and sd ports */
ret = init_dwmmc();
if (ret)
debug("init_dwmmc failed\n");
return ret;
}
#endif
int dram_init(void)
{
gd->ram_size = PHYS_SDRAM_1_SIZE;
return 0;
}
void dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
}
/* Use the Watchdog to cause reset */
void reset_cpu(ulong addr)
{
/* TODO program the watchdog */
}