sdk-hwV1.3/lichee/brandy-2.0/spl/board/sun8iw21p1/board.c

407 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* Some init for sunxi platform.
*
*/
#include <common.h>
#include <libfdt.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <linux/compiler.h>
#include <linux/errno.h>
#include <private_boot0.h>
#include <arch/clock.h>
#include <arch/uart.h>
#include <arch/rtc.h>
#include <arch/gpio.h>
#ifdef CFG_BOOT0_LOAD_KERNEL
void rtc_set_vccio_det_spare(void)
{
u32 val = 0;
val = readl(SUNXI_RTC_BASE + 0x1f4);
val &= ~(0xff << 4);
val |= (VCCIO_THRESHOLD_VOLTAGE_2_9 | FORCE_DETECTER_OUTPUT);
val &= ~VCCIO_DET_BYPASS_EN;
writel(val, SUNXI_RTC_BASE + 0x1f4);
}
#endif
#ifndef FPGA_PLATFORM
int sunxi_board_init(void)
{
/*
* When waking up, don't change the voltage, frequency,
* cpu is easy to hang. We restore it in atf.
*/
/* set_pll_voltage(CONFIG_SUNXI_CORE_VOL); */
#ifdef CFG_SUNXI_POWER
if ((axp_init(0) >= 0) && (!super_standby_mode())) {
int sys_vol = (get_power_mode() & 0x3f);
int grain_size = get_power_mode() >> 6;
if (sys_vol != 0) {
switch (grain_size) {
case 0:
sys_vol = 500 + sys_vol * 10;
break;
case 1:
sys_vol = 500 + sys_vol * 20;
break;
case 2:
sys_vol = 500 + sys_vol * 50;
break;
case 3:
sys_vol = 500 + sys_vol * 100;
break;
}
if (sys_vol < 900)
sys_vol = 900;
else if (sys_vol > 1200)
sys_vol = 1200;
set_sys_voltage(sys_vol);
}
}
#endif
sunxi_board_pll_init();
printf("board init ok\n");
return 0;
}
#else
int sunxi_board_init(void)
{
printf("FPGA board init ok\n");
return 0;
}
#endif
int sunxi_assert_arisc(void)
{
printf("set arisc reset to assert state\n");
{
volatile unsigned long value;
value = readl(SUNXI_RCPUCFG_BASE + 0x0);
value &= ~1;
writel(value, SUNXI_RCPUCFG_BASE + 0x0);
}
return 0;
}
int sunxi_deassert_arisc(void)
{
printf("set arisc reset to de-assert state\n");
{
volatile unsigned long value;
value = readl(SUNXI_RCPUCFG_BASE + 0x0);
value |= 1;
writel(value, SUNXI_RCPUCFG_BASE + 0x0);
}
return 0;
}
uint8_t audioldo_check(void)
{
uint reg_val = 0;
uint roughtrim_val = 0, finetrim_val = 0;
/* reset */
reg_val = readl(CCMU_AUDIO_CODEC_BGR_REG);
reg_val &= ~(1 << 16);
writel(reg_val, CCMU_AUDIO_CODEC_BGR_REG);
udelay(2);
reg_val |= (1 << 16);
writel(reg_val, CCMU_AUDIO_CODEC_BGR_REG);
/* enable AUDIO gating */
reg_val = readl(CCMU_AUDIO_CODEC_BGR_REG);
reg_val |= (1 << 0);
writel(reg_val, CCMU_AUDIO_CODEC_BGR_REG);
/* enable pcrm CTRL */
reg_val = readl(ANA_PWR_RST_REG);
reg_val &= ~(1 << 0);
writel(reg_val, ANA_PWR_RST_REG);
/* read efuse */
printf("audio:avcc calibration\n");
reg_val = readl(SUNXI_SID_SRAM_BASE + 0x28);
roughtrim_val = (reg_val >> 0)& 0xF;
reg_val = readl(SUNXI_SID_SRAM_BASE + 0x24);
finetrim_val = (reg_val >> 16)& 0xFF;
if (roughtrim_val == 0 && finetrim_val == 0) {
reg_val = readl(SYNXI_VER_REG);
reg_val = (reg_val >> 0)& 0x7;
if (reg_val) {
/* printf("audio:chip not version A\n"); */
return 0;
} else {
roughtrim_val = 0x5;
finetrim_val = 0x19;
/* printf("audio:chip version A\n"); */
}
}
reg_val = readl(AUDIO_POWER_REG);
reg_val &= ~(0xF<<8|0xFF);
reg_val |= roughtrim_val<<8|finetrim_val;
writel(reg_val, AUDIO_POWER_REG);
return 0;
}
uint8_t sunxi_board_late_init(void)
{
#ifdef CFG_BOOT0_LOAD_KERNEL
rtc_set_vccio_det_spare();
#endif
audioldo_check();
return 0;
}
int sunxi_board_exit(void)
{
return 0;
}
#ifdef CFG_UPDATA_IRQ_TAB
#ifdef CFG_UPDATA_IRQ_TAB_DEBUG
#define irq_debug printf
#else
#define irq_debug(...) do { } while (0)
#endif
/*
* Table Format
* The first 16 byte is reserved for _table_head
* The last CPU_BANK_NUM word is resource for gpio mask
*
* ----------------
* | _table_head |
* ----------------
* | _table_entry |
* ----------------
* | ... |
* ----------------
* | GPIOA Mask |
* ----------------
* | ... |
* ---------------
*/
struct _table_head {
uint32_t tag;
uint32_t len;
uint32_t banks_off;
uint32_t banks_num;
} __packed;
struct _table_entry {
uint32_t status;
uint32_t type;
uint32_t flags;
uint32_t arch_irq;
} __packed;
#define CPU_BANK_NUM (16)
#define READY_TAG (('R' << 24) | ('E' << 16) | ('D' << 8) | 'Y')
static int update_irq_head_info(const void *fdt, int nodeoffset,
void *buf, int buf_len)
{
int len, i;
struct _table_head *head;
const uint32_t *data;
uint32_t *gpio_tab;
head = buf;
data = fdt_getprop(fdt, nodeoffset, "share-irq", &len);
if (len < 0) {
irq_debug("updata %s share-irq table failed,"
"not find share-irq property.\n",
fdt_get_name(fdt, nodeoffset, NULL));
return -ENODEV;
}
if ((len % (3 * 4)) != 0) {
irq_debug("%s share-irq table invalid format.\n",
fdt_get_name(fdt, nodeoffset, NULL));
return -ENODEV;
}
irq_debug("share_irq_table len=%d\n", len);
/*
* current we only support update gpio bank info.
* GPIO Table Format: major type flags
* type = 0 -> nomal interrupt
* type = 1 -> GPIOA
* type = 2 -> GPIOB
* ...
*
* flags = bank_mask
*/
gpio_tab = buf + buf_len - CPU_BANK_NUM * sizeof(uint32_t);
memset(gpio_tab, 0, CPU_BANK_NUM * sizeof(uint32_t));
for (i = 0; i < (len / 4); i += 3) {
uint32_t type = fdt32_to_cpu(data[i + 1]);
if (type == 0 || type >= CPU_BANK_NUM)
continue;
irq_debug("\t: GPIO%c = 0x%x\n", 'A' + type - 1, fdt32_to_cpu(data[i + 2]));
gpio_tab[type - 1] = fdt32_to_cpu(data[i + 2]);
}
head->tag = READY_TAG;
head->len = buf_len;
head->banks_off = (uint32_t)((void *)gpio_tab - buf);
head->banks_num = CPU_BANK_NUM;
return 0;
}
static int sunxi_find_irq_tab_rserved(const void *fdt,
int nodeoffset, uint32_t *addr, uint32_t *size)
{
int len;
const void *data;
data = fdt_getprop(fdt, nodeoffset, "memory-region", &len);
if (len < 0) {
irq_debug("find %s memory-region property failed",
fdt_get_name(fdt, nodeoffset, NULL));
return -ENODEV;
}
nodeoffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*(uint32_t *)data));
if (nodeoffset < 0) {
irq_debug("parse %s memory-region property failed, ret=%s",
fdt_get_name(fdt, nodeoffset, NULL),
fdt_strerror(nodeoffset));
return -ENODEV;
}
data = fdt_getprop(fdt, nodeoffset, "reg", &len);
if (len < 0) {
irq_debug("find %s memory-region property failed",
fdt_get_name(fdt, nodeoffset, NULL));
return -ENODEV;
}
if ((len % 4) != 0) {
irq_debug("%s reg invalid format, len=%d.\n", fdt_get_name(fdt, nodeoffset, NULL), len);
return -ENODEV;
}
/* ignore high word */
*addr = fdt32_to_cpu(*((uint32_t *)data + 1));
*size = fdt32_to_cpu(*((uint32_t *)data + 3));
irq_debug("irq table addr:0x%x len:0x%x\n", *addr, *size);
return 0;
}
void update_riscv_irq_tab(unsigned long elf_base, unsigned long fdt_addr, int idx)
{
int i, ret, nodeoffset, node;
const void *fdt = (void *)fdt_addr;
uint32_t *tab_info;
uint32_t addr, len;
ret = fdt_check_header(fdt);
if (ret < 0) {
printf("FDT: %s.\n", fdt_strerror(ret));
return;
}
node = fdt_path_offset(fdt, "/reserved-irq");
if (node < 0) {
printf("FDT: /reserved-irq node not found.\n");
return;
}
i = 0;
for (nodeoffset = fdt_first_subnode(fdt, node);
nodeoffset > 0;
nodeoffset = fdt_next_subnode(fdt, nodeoffset)) {
if (i++ != idx)
continue;
ret = sunxi_find_irq_tab_rserved(fdt, nodeoffset, &addr, &len);
if (ret)
break;
tab_info = elf_find_segment_offset(elf_base, ".share_irq_table");
if (!tab_info) {
irq_debug("firmware not support share-irq.\n");
return;
}
tab_info[0] = addr;
tab_info[1] = len;
irq_debug("0x%x -> 0x%x\n", addr, (uint32_t)tab_info);
update_irq_head_info(fdt, nodeoffset, (void *)addr, len);
break;
}
}
#endif
#ifdef CFG_RISCV_E907
void sunxi_e907_clock_init(uint32_t addr);
void sunxi_e907_clock_reset(void);
void boot_e907(phys_addr_t base, unsigned long fdt_addr)
{
uint32_t run_addr = 0;
(void)fdt_addr;
/* ISP needs, after boot0 runs successfully,
* you need to set the flag on rtc, and clear
* it in advance to prevent the small core from
* reading in advance
*/
#if CFG_BOOT0_LOAD_ISPPARM
/* Specific to fastboot*/
#ifdef CFG_SUNXI_SDMMC
int (*flash_read)(uint, uint, void *);
flash_read = mmc_bread_ext;
#elif CFG_SUNXI_SPINOR
int (*flash_read)(uint, uint, void *);
flash_read = spinor_read;
#endif /*sdmmc*/
if (load_isp_param(flash_read) != 0) {
printf("read isp param failed!!!\n");
}
extern void update_isp_param(void);
update_isp_param();
#endif
#ifdef CFG_BOOT0_WIRTE_RTC_TO_ISP
rtc_clear_isp_flag();
#endif
#ifdef CFG_UPDATA_IRQ_TAB
irq_debug("Try to Update Interrupt Table.\n");
update_riscv_irq_tab(base, fdt_addr, 0);
#endif
/* assert e907 */
sunxi_e907_clock_reset();
/* get boot address */
run_addr = elf_get_entry_addr(base);
/* load elf to target address */
load_elf_image(base);
/* de-assert e907 */
sunxi_e907_clock_init(run_addr);
}
#endif