Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- typedef __builtin_va_list va_list;
- #define va_start(ap, param) __builtin_va_start(ap, param)
- #define va_end(ap) __builtin_va_end(ap)
- #define va_arg(ap, type) __builtin_va_arg(ap, type)
- #define _U 0x01 /* upper */
- #define _L 0x02 /* lower */
- #define _D 0x04 /* digit */
- #define _C 0x08 /* cntrl */
- #define _P 0x10 /* punct */
- #define _S 0x20 /* white space (space/lf/tab) */
- #define _X 0x40 /* hex digit */
- #define _SP 0x80 /* hard space (0x20) */
- const unsigned char _ctype[] = {
- _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
- _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
- _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
- _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
- _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
- _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
- _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
- _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
- _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
- _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
- _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
- _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
- _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
- _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
- _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
- _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
- _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
- _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
- _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
- _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
- _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
- _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
- #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
- #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
- // from u-boot printf
- struct printf_info {
- char *bf; /* Digit buffer */
- char zs; /* non-zero if a digit has been written */
- char *outstr; /* Next output position for sprintf() */
- /* Output a character */
- void (*putc)(struct printf_info *info, char ch);
- };
- static void out(struct printf_info *info, char c)
- {
- *info->bf++ = c;
- }
- static void out_dgt(struct printf_info *info, char dgt)
- {
- out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
- info->zs = 1;
- }
- static void div_out(struct printf_info *info, unsigned long *num,
- unsigned long div)
- {
- unsigned char dgt = 0;
- while (*num >= div) {
- *num -= div;
- dgt++;
- }
- if (info->zs || dgt > 0)
- out_dgt(info, dgt);
- }
- static void pointer(struct printf_info *info, const char *fmt, void *ptr)
- {
- #ifdef DEBUG
- unsigned long num = (uintptr_t)ptr;
- unsigned long div;
- #endif
- switch (*fmt) {
- #ifdef DEBUG
- case 'a':
- switch (fmt[1]) {
- case 'p':
- default:
- num = *(phys_addr_t *)ptr;
- break;
- }
- break;
- #endif
- #ifdef CONFIG_SPL_NET_SUPPORT
- case 'm':
- return mac_address_string(info, ptr, false);
- case 'M':
- return mac_address_string(info, ptr, true);
- case 'I':
- if (fmt[1] == '4')
- return ip4_addr_string(info, ptr);
- #endif
- default:
- break;
- }
- #ifdef DEBUG
- div = 1UL << (sizeof(long) * 8 - 4);
- for (; div; div /= 0x10)
- div_out(info, &num, div);
- #endif
- }
- static int _vprintf(struct printf_info *info, const char *fmt, va_list va)
- {
- char ch;
- char *p;
- unsigned long num;
- char buf[12];
- unsigned long div;
- while ((ch = *(fmt++))) {
- if (ch != '%') {
- info->putc(info, ch);
- } else {
- int lz = 0;
- int width = 0;
- int islong = 0;
- ch = *(fmt++);
- if (ch == '-')
- ch = *(fmt++);
- if (ch == '0') {
- ch = *(fmt++);
- lz = 1;
- }
- if (ch >= '0' && ch <= '9') {
- width = 0;
- while (ch >= '0' && ch <= '9') {
- width = (width * 10) + ch - '0';
- ch = *fmt++;
- }
- }
- if (ch == 'l') {
- ch = *(fmt++);
- islong = 1;
- }
- info->bf = buf;
- p = info->bf;
- info->zs = 0;
- switch (ch) {
- case '\0':
- goto abort;
- case 'u':
- case 'd':
- div = 1000000000;
- if (islong) {
- num = va_arg(va, unsigned long);
- if (sizeof(long) > 4)
- div *= div * 10;
- } else {
- num = va_arg(va, unsigned int);
- }
- if (ch == 'd') {
- if (islong && (long)num < 0) {
- num = -(long)num;
- out(info, '-');
- } else if (!islong && (int)num < 0) {
- num = -(int)num;
- out(info, '-');
- }
- }
- if (!num) {
- out_dgt(info, 0);
- } else {
- /* HACK MANUEL!!!!!!!!!!!!!!!!!!!!!!!!!
- for (; div; div /= 10)
- div_out(info, &num, div);
- */
- }
- break;
- case 'x':
- if (islong) {
- num = va_arg(va, unsigned long);
- div = 1UL << (sizeof(long) * 8 - 4);
- } else {
- num = va_arg(va, unsigned int);
- div = 0x10000000;
- }
- if (!num) {
- out_dgt(info, 0);
- } else {
- for (; div; div /= 0x10)
- div_out(info, &num, div);
- }
- break;
- case 'c':
- out(info, (char)(va_arg(va, int)));
- break;
- case 's':
- p = va_arg(va, char*);
- break;
- case 'p':
- pointer(info, fmt, va_arg(va, void *));
- while (isalnum(fmt[0]))
- fmt++;
- break;
- case '%':
- out(info, '%');
- default:
- break;
- }
- *info->bf = 0;
- info->bf = p;
- while (*info->bf++ && width > 0)
- width--;
- while (width-- > 0)
- info->putc(info, lz ? '0' : ' ');
- if (p) {
- while ((ch = *p++))
- info->putc(info, ch);
- }
- }
- }
- abort:
- return 0;
- }
- static void putc_normal(struct printf_info *info, char ch)
- {
- //putc(ch);
- uart0_putc(ch);
- }
- int printf(const char *fmt, ...)
- {
- struct printf_info info;
- va_list va;
- int ret;
- info.putc = putc_normal;
- va_start(va, fmt);
- ret = _vprintf(&info, fmt, va);
- va_end(va);
- return ret;
- }
- /*
- * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
- * Partially based on the uart code from ar100-info
- *
- * (C) Copyright 2013 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
- /*
- * Partially based on the sunxi gpio code from U-Boot
- *
- * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
- *
- * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
- *
- * (C) Copyright 2007-2011
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * Tom Cubie <tangliang@allwinnertech.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- typedef unsigned int u32;
- #define set_wbit(addr, v) (*((volatile unsigned long *)(addr)) |= (unsigned long)(v))
- #define readl(addr) (*((volatile unsigned long *)(addr)))
- #define writel(v, addr) (*((volatile unsigned long *)(addr)) = (unsigned long)(v))
- #define SUNXI_UART0_BASE 0x01C28000
- #define SUNXI_PIO_BASE 0x01C20800
- #define AW_CCM_BASE 0x01c20000
- #define AW_SRAMCTRL_BASE 0x01c00000
- #define H6_UART0_BASE 0x05000000
- #define H6_PIO_BASE 0x0300B000
- #define H6_CCM_BASE 0x03001000
- #define H6_SRAMCTRL_BASE 0x03000000
- /*****************************************************************************
- * GPIO code, borrowed from U-Boot *
- *****************************************************************************/
- #define SUNXI_GPIO_A 0
- #define SUNXI_GPIO_B 1
- #define SUNXI_GPIO_C 2
- #define SUNXI_GPIO_D 3
- #define SUNXI_GPIO_E 4
- #define SUNXI_GPIO_F 5
- #define SUNXI_GPIO_G 6
- #define SUNXI_GPIO_H 7
- #define SUNXI_GPIO_I 8
- struct sunxi_gpio {
- u32 cfg[4];
- u32 dat;
- u32 drv[2];
- u32 pull[2];
- };
- struct sunxi_gpio_reg {
- struct sunxi_gpio gpio_bank[10];
- };
- #define GPIO_BANK(pin) ((pin) >> 5)
- #define GPIO_NUM(pin) ((pin) & 0x1F)
- #define GPIO_CFG_INDEX(pin) (((pin) & 0x1F) >> 3)
- #define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1F) & 0x7) << 2)
- #define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
- #define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
- /* GPIO bank sizes */
- #define SUNXI_GPIO_A_NR (32)
- #define SUNXI_GPIO_B_NR (32)
- #define SUNXI_GPIO_C_NR (32)
- #define SUNXI_GPIO_D_NR (32)
- #define SUNXI_GPIO_E_NR (32)
- #define SUNXI_GPIO_F_NR (32)
- #define SUNXI_GPIO_G_NR (32)
- #define SUNXI_GPIO_H_NR (32)
- #define SUNXI_GPIO_I_NR (32)
- #define SUNXI_GPIO_NEXT(__gpio) ((__gpio##_START) + (__gpio##_NR) + 0)
- enum sunxi_gpio_number {
- SUNXI_GPIO_A_START = 0,
- SUNXI_GPIO_B_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_A),
- SUNXI_GPIO_C_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_B),
- SUNXI_GPIO_D_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_C),
- SUNXI_GPIO_E_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_D),
- SUNXI_GPIO_F_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_E),
- SUNXI_GPIO_G_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_F),
- SUNXI_GPIO_H_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_G),
- SUNXI_GPIO_I_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_H),
- };
- /* SUNXI GPIO number definitions */
- #define SUNXI_GPA(_nr) (SUNXI_GPIO_A_START + (_nr))
- #define SUNXI_GPB(_nr) (SUNXI_GPIO_B_START + (_nr))
- #define SUNXI_GPC(_nr) (SUNXI_GPIO_C_START + (_nr))
- #define SUNXI_GPD(_nr) (SUNXI_GPIO_D_START + (_nr))
- #define SUNXI_GPE(_nr) (SUNXI_GPIO_E_START + (_nr))
- #define SUNXI_GPF(_nr) (SUNXI_GPIO_F_START + (_nr))
- #define SUNXI_GPG(_nr) (SUNXI_GPIO_G_START + (_nr))
- #define SUNXI_GPH(_nr) (SUNXI_GPIO_H_START + (_nr))
- #define SUNXI_GPI(_nr) (SUNXI_GPIO_I_START + (_nr))
- /* GPIO pin function config */
- #define SUNXI_GPIO_INPUT (0)
- #define SUNXI_GPIO_OUTPUT (1)
- #define SUN4I_GPB_UART0 (2)
- #define SUN5I_GPB_UART0 (2)
- #define SUN6I_GPH_UART0 (2)
- #define SUN8I_H3_GPA_UART0 (2)
- #define SUN8I_V3S_GPB_UART0 (3)
- #define SUN50I_H5_GPA_UART0 (2)
- #define SUN50I_H6_GPH_UART0 (2)
- #define SUN50I_A64_GPB_UART0 (4)
- #define SUNXI_GPF_UART0 (4)
- /* GPIO pin pull-up/down config */
- #define SUNXI_GPIO_PULL_DISABLE (0)
- #define SUNXI_GPIO_PULL_UP (1)
- #define SUNXI_GPIO_PULL_DOWN (2)
- static u32 pio_base;
- int sunxi_gpio_set_cfgpin(u32 pin, u32 val)
- {
- u32 cfg;
- u32 bank = GPIO_BANK(pin);
- u32 index = GPIO_CFG_INDEX(pin);
- u32 offset = GPIO_CFG_OFFSET(pin);
- struct sunxi_gpio *pio =
- &((struct sunxi_gpio_reg *)pio_base)->gpio_bank[bank];
- cfg = readl(&pio->cfg[0] + index);
- cfg &= ~(0xf << offset);
- cfg |= val << offset;
- writel(cfg, &pio->cfg[0] + index);
- return 0;
- }
- int sunxi_gpio_set_pull(u32 pin, u32 val)
- {
- u32 cfg;
- u32 bank = GPIO_BANK(pin);
- u32 index = GPIO_PULL_INDEX(pin);
- u32 offset = GPIO_PULL_OFFSET(pin);
- struct sunxi_gpio *pio =
- &((struct sunxi_gpio_reg *)pio_base)->gpio_bank[bank];
- cfg = readl(&pio->pull[0] + index);
- cfg &= ~(0x3 << offset);
- cfg |= val << offset;
- writel(cfg, &pio->pull[0] + index);
- return 0;
- }
- int sunxi_gpio_output(u32 pin, u32 val)
- {
- u32 dat;
- u32 bank = GPIO_BANK(pin);
- u32 num = GPIO_NUM(pin);
- struct sunxi_gpio *pio =
- &((struct sunxi_gpio_reg *)pio_base)->gpio_bank[bank];
- dat = readl(&pio->dat);
- if(val)
- dat |= 1 << num;
- else
- dat &= ~(1 << num);
- writel(dat, &pio->dat);
- return 0;
- }
- int sunxi_gpio_input(u32 pin)
- {
- u32 dat;
- u32 bank = GPIO_BANK(pin);
- u32 num = GPIO_NUM(pin);
- struct sunxi_gpio *pio =
- &((struct sunxi_gpio_reg *)pio_base)->gpio_bank[bank];
- dat = readl(&pio->dat);
- dat >>= num;
- return (dat & 0x1);
- }
- int gpio_direction_input(unsigned gpio)
- {
- sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
- return sunxi_gpio_input(gpio);
- }
- int gpio_direction_output(unsigned gpio, int value)
- {
- sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
- return sunxi_gpio_output(gpio, value);
- }
- /*****************************************************************************
- * Nearly all the Allwinner SoCs are using the same VER_REG register for *
- * runtime SoC type identification. For additional details see: *
- * *
- * https://linux-sunxi.org/SRAM_Controller_Register_Guide *
- * *
- * Allwinner A80 is an oddball and has a non-standard address of the VER_REG *
- * *
- * Allwinner A10s and A13 are using the same SoC type id, but they can be *
- * differentiated using a certain part of the SID register. *
- * *
- * Allwinner H6 has its memory map totally reworked, but the SRAM controller *
- * remains similar; the base of it is moved to 0x03000000. *
- *****************************************************************************/
- #define VER_REG (AW_SRAMCTRL_BASE + 0x24)
- #define H6_VER_REG (H6_SRAMCTRL_BASE + 0x24)
- #define SUN4I_SID_BASE 0x01C23800
- #define SUN8I_SID_BASE 0x03006000
- #define SID_PRCTL 0x40 /* SID program/read control register */
- #define SID_RDKEY 0x60 /* SID read key value register */
- #define SID_OP_LOCK 0xAC /* Efuse operation lock value */
- #define SID_READ_START (1 << 1) /* bit 1 of SID_PRCTL, Software Read Start */
- u32 sid_read_key(u32 sid_base, u32 offset)
- {
- u32 reg_val;
- reg_val = (offset & 0x1FF) << 16; /* PG_INDEX value */
- reg_val |= (SID_OP_LOCK << 8) | SID_READ_START; /* request read access */
- writel(reg_val, sid_base + SID_PRCTL);
- while (readl(sid_base + SID_PRCTL) & SID_READ_START) ; /* wait while busy */
- reg_val = readl(sid_base + SID_RDKEY); /* read SID key value */
- writel(0, sid_base + SID_PRCTL); /* clear SID_PRCTL (removing SID_OP_LOCK) */
- return reg_val;
- }
- static u32 soc_id;
- void soc_detection_init(void)
- {
- u32 midr;
- asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (midr));
- if (((midr >> 4) & 0xFFF) == 0xC0F) {
- soc_id = 0x1639; /* ARM Cortex-A15, so likely Allwinner A80 */
- } else {
- u32 reg;
- /*
- * This register is GICD_IIDR on H6, but unmapped according to
- * other known SoCs' user manuals.
- */
- reg = readl(0x03021008);
- if ((reg & 0xfff) == 0x43b) /* Found GICv2 here, so it's a H6 */
- reg = H6_VER_REG;
- else
- reg = VER_REG;
- set_wbit(reg, 1 << 15);
- soc_id = readl(reg) >> 16;
- }
- }
- /* Most SoCs can reliably be distinguished by simply checking their ID value */
- #define soc_is_a10() (soc_id == 0x1623)
- #define soc_is_a20() (soc_id == 0x1651)
- #define soc_is_a31() (soc_id == 0x1633)
- #define soc_is_a80() (soc_id == 0x1639)
- #define soc_is_a64() (soc_id == 0x1689)
- #define soc_is_h5() (soc_id == 0x1718)
- #define soc_is_h6() (soc_id == 0x1728)
- #define soc_is_r40() (soc_id == 0x1701)
- #define soc_is_v3s() (soc_id == 0x1681)
- /* A10s and A13 share the same ID, so we need a little more effort on those */
- int soc_is_a10s(void)
- {
- return soc_id == 0x1625 &&
- (readl(SUN4I_SID_BASE + 8) & 0xf000) == 0x7000;
- }
- int soc_is_a13(void)
- {
- return soc_id == 0x1625 &&
- (readl(SUN4I_SID_BASE + 8) & 0xf000) != 0x7000;
- }
- /* H2+ and H3 share the same ID, we can differentiate them by SID_RKEY0 */
- int soc_is_h2_plus(void)
- {
- if (soc_id != 0x1680) return 0;
- u32 sid0 = sid_read_key(SUN8I_SID_BASE, 0);
- return (sid0 & 0xff) == 0x42 || (sid0 & 0xff) == 0x83;
- }
- int soc_is_h3(void)
- {
- if (soc_id != 0x1680) return 0;
- u32 sid0 = sid_read_key(SUN8I_SID_BASE, 0);
- /*
- * Note: according to Allwinner sources, H3 is expected
- * to show up as 0x00, 0x81 or ("H3D") 0x58 here.
- */
- return (sid0 & 0xff) != 0x42 && (sid0 & 0xff) != 0x83;
- }
- /*****************************************************************************
- * UART is mostly the same on A10/A13/A20/A31/H3/A64, except that newer SoCs *
- * have changed the APB numbering scheme (A10/A13/A20 used to have APB0 and *
- * APB1 names, but newer SoCs just have renamed them into APB1 and APB2). *
- * The constants below are using the new APB numbering convention. *
- * Also the newer SoCs have introduced the APB2_RESET register, but writing *
- * to it effectively goes nowhere on older SoCs and is harmless. *
- *****************************************************************************/
- #define CONFIG_CONS_INDEX 1
- #define APB2_CFG (AW_CCM_BASE + 0x058)
- #define APB2_GATE (AW_CCM_BASE + 0x06C)
- #define APB2_RESET (AW_CCM_BASE + 0x2D8)
- #define APB2_GATE_UART_SHIFT (16)
- #define APB2_RESET_UART_SHIFT (16)
- #define H6_UART_GATE_RESET (H6_CCM_BASE + 0x90C)
- #define H6_UART_GATE_SHIFT (0)
- #define H6_UART_RESET_SHIFT (16)
- void clock_init_uart_legacy(void)
- {
- /* Open the clock gate for UART0 */
- set_wbit(APB2_GATE, 1 << (APB2_GATE_UART_SHIFT + CONFIG_CONS_INDEX - 1));
- /* Deassert UART0 reset (only needed on A31/A64/H3) */
- set_wbit(APB2_RESET, 1 << (APB2_RESET_UART_SHIFT + CONFIG_CONS_INDEX - 1));
- }
- void clock_init_uart_h6(void)
- {
- /* Open the clock gate for UART0 */
- set_wbit(H6_UART_GATE_RESET, 1 << (H6_UART_GATE_SHIFT + CONFIG_CONS_INDEX - 1));
- /* Deassert UART0 reset */
- set_wbit(H6_UART_GATE_RESET, 1 << (H6_UART_RESET_SHIFT + CONFIG_CONS_INDEX - 1));
- }
- void clock_init_uart(void)
- {
- if (soc_is_h6())
- clock_init_uart_h6();
- else
- clock_init_uart_legacy();
- }
- /*****************************************************************************
- * UART0 pins muxing is different for different SoC variants. *
- * Allwinner A13 is a bit special, because there are no dedicated UART0 pins *
- * and they are shared with MMC0. *
- *****************************************************************************/
- void gpio_init(void)
- {
- if (soc_is_a10() || soc_is_a20() || soc_is_r40()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB_UART0);
- sunxi_gpio_set_pull(SUNXI_GPB(23), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_a10s()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB_UART0);
- sunxi_gpio_set_pull(SUNXI_GPB(20), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_a13()) {
- /* Disable PB19/PB20 as UART0 to avoid conflict */
- gpio_direction_input(SUNXI_GPB(19));
- gpio_direction_input(SUNXI_GPB(20));
- /* Use SD breakout board to access UART0 on MMC0 pins */
- sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUNXI_GPF_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0);
- sunxi_gpio_set_pull(SUNXI_GPF(4), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_a31()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0);
- sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_a64()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_A64_GPB_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_A64_GPB_UART0);
- sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_h3() || soc_is_h2_plus()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPA(4), SUN8I_H3_GPA_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPA(5), SUN8I_H3_GPA_UART0);
- sunxi_gpio_set_pull(SUNXI_GPA(5), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_h5()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPA(4), SUN50I_H5_GPA_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPA(5), SUN50I_H5_GPA_UART0);
- sunxi_gpio_set_pull(SUNXI_GPA(5), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_h6()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H6_GPH_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H6_GPH_UART0);
- sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP);
- } else if (soc_is_v3s()) {
- sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN8I_V3S_GPB_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_V3S_GPB_UART0);
- sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
- } else {
- /* Unknown SoC */
- while (1) {}
- }
- }
- /*****************************************************************************/
- static u32 uart0_base;
- #define UART0_RBR (uart0_base + 0x0) /* receive buffer register */
- #define UART0_THR (uart0_base + 0x0) /* transmit holding register */
- #define UART0_DLL (uart0_base + 0x0) /* divisor latch low register */
- #define UART0_DLH (uart0_base + 0x4) /* divisor latch high register */
- #define UART0_IER (uart0_base + 0x4) /* interrupt enable reigster */
- #define UART0_IIR (uart0_base + 0x8) /* interrupt identity register */
- #define UART0_FCR (uart0_base + 0x8) /* fifo control register */
- #define UART0_LCR (uart0_base + 0xc) /* line control register */
- #define UART0_LSR (uart0_base + 0x14) /* line status register */
- #define BAUD_115200 (0xD) /* 24 * 1000 * 1000 / 16 / 115200 = 13 */
- #define NO_PARITY (0)
- #define ONE_STOP_BIT (0)
- #define DAT_LEN_8_BITS (3)
- #define LC_8_N_1 (NO_PARITY << 3 | ONE_STOP_BIT << 2 | DAT_LEN_8_BITS)
- void uart0_init(void)
- {
- clock_init_uart();
- /* select dll dlh */
- writel(0x80, UART0_LCR);
- /* set baudrate */
- writel(0, UART0_DLH);
- writel(BAUD_115200, UART0_DLL);
- /* set line control */
- writel(LC_8_N_1, UART0_LCR);
- }
- void uart0_putc(char c)
- {
- while (!(readl(UART0_LSR) & (1 << 6))) {}
- writel(c, UART0_THR);
- }
- void uart0_puts(const char *s)
- {
- while (*s) {
- if (*s == '\n')
- uart0_putc('\r');
- uart0_putc(*s++);
- }
- }
- /*****************************************************************************/
- /* A workaround for https://patchwork.ozlabs.org/patch/622173 */
- void __attribute__((section(".start"))) __attribute__((naked)) start(void)
- {
- asm volatile("b main \n"
- ".long 0xffffffff \n"
- ".long 0xffffffff \n"
- ".long 0xffffffff \n");
- }
- #define EFUSE_LCJS (0x48)
- #define EFUSE_ROTPK (0x70)
- void print_chip_id() {
- uart0_puts("chip_id: ");
- u32 chip_id[4];
- u32 i = 0;
- for(i=0; i < 4; i++) {
- chip_id[i] = sid_read_key(SUN8I_SID_BASE, 4*i);
- printf("%x:", chip_id[i]);
- }
- uart0_puts("\r\n");
- }
- void print_rotpk() {
- uart0_puts("rotpk_hash: ");
- u32 rotpk_hash[8];
- u32 i = 0;
- for(i=0; i < 8; i++) {
- rotpk_hash[i] = sid_read_key(SUN8I_SID_BASE, EFUSE_ROTPK+4*i);
- printf("%08x:", rotpk_hash[i]);
- }
- uart0_puts("\r\n");
- }
- void print_lcjs() {
- uart0_puts("LCJS: ");
- u32 LCJS = sid_read_key(SUN8I_SID_BASE, EFUSE_LCJS);
- printf("%08x:", LCJS);
- uart0_puts("\r\n");
- }
- void print_secure() {
- uart0_puts("try read sram A2:");
- if (readl(0x40004) == 0) {
- uart0_puts("0x40004==0 non-secure\r\n");
- } else {
- uart0_puts("0x40004!=0 secure\r\n");
- }
- uart0_puts("\r\n");
- }
- void print_stuff() {
- print_chip_id();
- print_rotpk();
- print_lcjs();
- print_secure();
- uart0_puts("\r\n\n");
- }
- enum { BOOT_DEVICE_UNK, BOOT_DEVICE_FEL, BOOT_DEVICE_MMC0, BOOT_DEVICE_SPI };
- int get_boot_device(void)
- {
- u32 *spl_signature = (void *)0x4;
- if (soc_is_a64() || soc_is_a80() || soc_is_h5())
- spl_signature = (void *)0x10004;
- if (soc_is_h6())
- spl_signature = (void *)0x20004;
- /* Check the eGON.BT0 magic in the SPL header */
- if (spl_signature[0] != 0x4E4F4765 || spl_signature[1] != 0x3054422E)
- return BOOT_DEVICE_FEL;
- u32 boot_dev = spl_signature[9] & 0xFF; /* offset into SPL = 0x28 */
- if (boot_dev == 0)
- return BOOT_DEVICE_MMC0;
- if (boot_dev == 3)
- return BOOT_DEVICE_SPI;
- return BOOT_DEVICE_UNK;
- }
- void bases_init(void)
- {
- if (soc_is_h6()) {
- pio_base = H6_PIO_BASE;
- uart0_base = H6_UART0_BASE;
- } else {
- pio_base = SUNXI_PIO_BASE;
- uart0_base = SUNXI_UART0_BASE;
- }
- }
- int __attribute__((section(".start"))) main(void)
- {
- soc_detection_init();
- bases_init();
- gpio_init();
- uart0_init();
- uart0_puts("\nHello from ");
- if (soc_is_a10())
- uart0_puts("Allwinner A10!\n");
- else if (soc_is_a10s())
- uart0_puts("Allwinner A10s!\n");
- else if (soc_is_a13())
- uart0_puts("Allwinner A13!\n");
- else if (soc_is_a20())
- uart0_puts("Allwinner A20!\n");
- else if (soc_is_a31())
- uart0_puts("Allwinner A31/A31s!\n");
- else if (soc_is_a64())
- uart0_puts("Allwinner A64!\n");
- else if (soc_is_h2_plus())
- uart0_puts("Allwinner H2+!\n");
- else if (soc_is_h3())
- uart0_puts("Allwinner H3!\n");
- else if (soc_is_h5())
- uart0_puts("Allwinner H5!\n");
- else if (soc_is_h6())
- uart0_puts("Allwinner H6!\n");
- else if (soc_is_r40())
- uart0_puts("Allwinner R40!\n");
- else if (soc_is_v3s())
- uart0_puts("Allwinner V3s!\n");
- else
- uart0_puts("unknown Allwinner SoC!\n");
- //asm("smc #0");
- asm volatile (
- ".arch_extension sec\n"
- "smc #0"
- );
- switch (get_boot_device()) {
- case BOOT_DEVICE_FEL:
- print_stuff();
- uart0_puts("Returning back to FEL.\n");
- return 0;
- case BOOT_DEVICE_MMC0:
- uart0_puts("Booted from MMC0, entering an infinite loop.\n");
- while (1) {}
- case BOOT_DEVICE_SPI:
- uart0_puts("Booted from SPI0, entering an infinite loop.\n");
- while (1) {}
- default:
- uart0_puts("Booted from unknown media, entering an infinite loop.\n");
- while (1) {}
- };
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement