u-boot-brain/board/hisilicon/hikey/hikey.c
Alexander Graf 2184582560 hikey: Add MMU tables
The hikey runs with dcache disabled today. There really should be no reason
not to use caches on AArch64, so let's add MMU definitions and enable the
dcache.

Signed-off-by: Alexander Graf <agraf@suse.de>
2016-03-15 15:13:09 -04:00

419 lines
9.0 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>
#include <asm/armv8/mmu.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,
};
static struct mm_region hikey_mem_map[] = {
{
.base = 0x0UL,
.size = 0x80000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
.base = 0x80000000UL,
.size = 0x80000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
/* List terminator */
0,
}
};
struct mm_region *mem_map = hikey_mem_map;
#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 */
}