aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/arch-sunxi/spl.h22
-rw-r--r--arch/arm/mach-sunxi/Kconfig16
-rw-r--r--arch/arm/mach-sunxi/board.c2
-rw-r--r--arch/arm/mach-sunxi/dram_sun4i.c2
-rw-r--r--arch/arm/mach-sunxi/p2wi.c2
-rw-r--r--board/sunxi/README.nand6
-rw-r--r--board/sunxi/README.sunxi642
-rw-r--r--board/sunxi/board.c72
-rw-r--r--configs/pine64_plus_defconfig1
-rw-r--r--drivers/pwm/sunxi_pwm.c32
-rw-r--r--drivers/video/sunxi/sunxi_display.c2
11 files changed, 120 insertions, 39 deletions
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index 55f2deb..4baba38 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -9,7 +9,17 @@
#define BOOT0_MAGIC "eGON.BT0"
#define SPL_SIGNATURE "SPL" /* marks "sunxi" SPL header */
-#define SPL_HEADER_VERSION 2
+#define SPL_MAJOR_BITS 3
+#define SPL_MINOR_BITS 5
+#define SPL_VERSION(maj, min) \
+ ((((maj) & ((1U << SPL_MAJOR_BITS) - 1)) << SPL_MINOR_BITS) | \
+ ((min) & ((1U << SPL_MINOR_BITS) - 1)))
+
+#define SPL_HEADER_VERSION SPL_VERSION(0, 2)
+
+#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1)
+#define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2)
+#define SPL_DRAM_HEADER_VERSION SPL_VERSION(0, 3)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -45,14 +55,14 @@ struct boot_file_head {
uint32_t pub_head_size;
uint8_t spl_signature[4];
};
- uint32_t fel_script_address;
+ uint32_t fel_script_address; /* since v0.1, set by sunxi-fel */
/*
* If the fel_uEnv_length member below is set to a non-zero value,
* it specifies the size (byte count) of data at fel_script_address.
* At the same time this indicates that the data is in uEnv.txt
* compatible format, ready to be imported via "env import -t".
*/
- uint32_t fel_uEnv_length;
+ uint32_t fel_uEnv_length; /* since v0.1, set by sunxi-fel */
/*
* Offset of an ASCIIZ string (relative to the SPL header), which
* contains the default device tree name (CONFIG_DEFAULT_DEVICE_TREE).
@@ -60,11 +70,11 @@ struct boot_file_head {
* by flash programming tools for providing nice informative messages
* to the users.
*/
- uint32_t dt_name_offset;
- uint32_t reserved1;
+ uint32_t dt_name_offset; /* since v0.2, set by mksunxiboot */
+ uint32_t dram_size; /* in MiB, since v0.3, set by SPL */
uint32_t boot_media; /* written here by the boot ROM */
/* A padding area (may be used for storing text strings) */
- uint32_t string_pool[13];
+ uint32_t string_pool[13]; /* since v0.2, filled by mksunxiboot */
/* The header must be a multiple of 32 bytes (for VBAR alignment) */
};
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 686f38f..6277abc 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -140,6 +140,12 @@ config MACH_SUNXI_H3_H5
select SUNXI_GEN_SUN6I
select SUPPORT_SPL
+# TODO: try out A80's 8GiB DRAM space
+config SUNXI_DRAM_MAX_SIZE
+ hex
+ default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6
+ default 0x80000000
+
choice
prompt "Sunxi SoC Variant"
optional
@@ -970,4 +976,14 @@ config SPL_SPI_SUNXI
sunxi SPI Flash. It uses the same method as the boot ROM, so does
not need any extra configuration.
+config PINE64_DT_SELECTION
+ bool "Enable Pine64 device tree selection code"
+ depends on MACH_SUN50I
+ help
+ The original Pine A64 and Pine A64+ are similar but different
+ boards and can be differed by the DRAM size. Pine A64 has
+ 512MiB DRAM, and Pine A64+ has 1GiB or 2GiB. By selecting this
+ option, the device tree selection code specific to Pine64 which
+ utilizes the DRAM size will be enabled.
+
endif
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index d22a84e..b74eaf2 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -52,7 +52,7 @@ static struct mm_region sunxi_mem_map[] = {
/* RAM */
.virt = 0x40000000UL,
.phys = 0x40000000UL,
- .size = 0x80000000UL,
+ .size = 0xC0000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
diff --git a/arch/arm/mach-sunxi/dram_sun4i.c b/arch/arm/mach-sunxi/dram_sun4i.c
index 8562302..396c042 100644
--- a/arch/arm/mach-sunxi/dram_sun4i.c
+++ b/arch/arm/mach-sunxi/dram_sun4i.c
@@ -5,7 +5,7 @@
* (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
*
* Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c
- * and earlier U-Boot Allwiner A10 SPL work
+ * and earlier U-Boot Allwinner A10 SPL work
*
* (C) Copyright 2007-2012
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
diff --git a/arch/arm/mach-sunxi/p2wi.c b/arch/arm/mach-sunxi/p2wi.c
index 82ad254..e84e1d8 100644
--- a/arch/arm/mach-sunxi/p2wi.c
+++ b/arch/arm/mach-sunxi/p2wi.c
@@ -5,7 +5,7 @@
* (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
* http://linux-sunxi.org
*
- * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work
+ * Based on sun6i sources and earlier U-Boot Allwinner A10 SPL work
*
* (C) Copyright 2006-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
diff --git a/board/sunxi/README.nand b/board/sunxi/README.nand
index a5d4ff0..98ebe5f 100644
--- a/board/sunxi/README.nand
+++ b/board/sunxi/README.nand
@@ -20,9 +20,9 @@ pages.
In order to accomodate that, we create a tool that will generate an
SPL image that is ready to be programmed directly embedding the ECCs,
randomized, and with the necessary bits needed to reduce the number of
-bitflips. The U-Boot build system, when configured for the NAND will
-also generate the image sunxi-spl-with-ecc.bin that will have been
-generated by that tool.
+bitflips. The U-Boot build system, when configured for the NAND (with
+CONFIG_NAND=y) will also generate the image sunxi-spl-with-ecc.bin
+that will have been generated by that tool.
In order to flash your U-Boot image onto a board, assuming that the
board is in FEL mode, you'll need the sunxi-tools that you can find at
diff --git a/board/sunxi/README.sunxi64 b/board/sunxi/README.sunxi64
index df1dbc8..bba2e01 100644
--- a/board/sunxi/README.sunxi64
+++ b/board/sunxi/README.sunxi64
@@ -130,7 +130,7 @@ U-Boot prompt on the serial console.
(Legacy) boot0 method
---------------------
-boot0 is Allwiner's secondary program loader and it can be used as some kind
+boot0 is Allwinner's secondary program loader and it can be used as some kind
of SPL replacement to get U-Boot up and running from an microSD card.
For some time using boot0 was the only option to get the Pine64 booted.
With working DRAM init code in U-Boot's SPL this is no longer necessary,
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index d1d7f9f..b196d48 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -255,9 +255,42 @@ int board_init(void)
return soft_i2c_board_init();
}
+/*
+ * On older SoCs the SPL is actually at address zero, so using NULL as
+ * an error value does not work.
+ */
+#define INVALID_SPL_HEADER ((void *)~0UL)
+
+static struct boot_file_head * get_spl_header(uint8_t req_version)
+{
+ struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
+ uint8_t spl_header_version = spl->spl_signature[3];
+
+ /* Is there really the SPL header (still) there? */
+ if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
+ return INVALID_SPL_HEADER;
+
+ if (spl_header_version < req_version) {
+ printf("sunxi SPL version mismatch: expected %u, got %u\n",
+ req_version, spl_header_version);
+ return INVALID_SPL_HEADER;
+ }
+
+ return spl;
+}
+
int dram_init(void)
{
- gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE);
+ struct boot_file_head *spl = get_spl_header(SPL_DRAM_HEADER_VERSION);
+
+ if (spl == INVALID_SPL_HEADER)
+ gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
+ PHYS_SDRAM_0_SIZE);
+ else
+ gd->ram_size = (phys_addr_t)spl->dram_size << 20;
+
+ if (gd->ram_size > CONFIG_SUNXI_DRAM_MAX_SIZE)
+ gd->ram_size = CONFIG_SUNXI_DRAM_MAX_SIZE;
return 0;
}
@@ -521,6 +554,21 @@ int board_mmc_init(bd_t *bis)
#endif
#ifdef CONFIG_SPL_BUILD
+
+static void sunxi_spl_store_dram_size(phys_addr_t dram_size)
+{
+ struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
+
+ if (spl == INVALID_SPL_HEADER)
+ return;
+
+ /* Promote the header version for U-Boot proper, if needed. */
+ if (spl->spl_signature[3] < SPL_DRAM_HEADER_VERSION)
+ spl->spl_signature[3] = SPL_DRAM_HEADER_VERSION;
+
+ spl->dram_size = dram_size >> 20;
+}
+
void sunxi_board_init(void)
{
int power_failed = 0;
@@ -589,6 +637,8 @@ void sunxi_board_init(void)
if (!gd->ram_size)
hang();
+ sunxi_spl_store_dram_size(gd->ram_size);
+
/*
* Only clock up the CPU to full speed if we are reasonably
* assured it's being powered with suitable core voltage
@@ -662,16 +712,11 @@ void get_board_serial(struct tag_serialnr *serialnr)
*/
static void parse_spl_header(const uint32_t spl_addr)
{
- struct boot_file_head *spl = (void *)(ulong)spl_addr;
- if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
- return; /* signature mismatch, no usable header */
+ struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
- uint8_t spl_header_version = spl->spl_signature[3];
- if (spl_header_version != SPL_HEADER_VERSION) {
- printf("sunxi SPL version mismatch: expected %u, got %u\n",
- SPL_HEADER_VERSION, spl_header_version);
+ if (spl == INVALID_SPL_HEADER)
return;
- }
+
if (!spl->fel_script_address)
return;
@@ -806,11 +851,11 @@ int ft_board_setup(void *blob, bd_t *bd)
#ifdef CONFIG_SPL_LOAD_FIT
int board_fit_config_name_match(const char *name)
{
- struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
- const char *cmp_str = (void *)(ulong)SPL_ADDR;
+ struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
+ const char *cmp_str = (const char *)spl;
/* Check if there is a DT name stored in the SPL header and use that. */
- if (spl->dt_name_offset) {
+ if (spl != INVALID_SPL_HEADER && spl->dt_name_offset) {
cmp_str += spl->dt_name_offset;
} else {
#ifdef CONFIG_DEFAULT_DEVICE_TREE
@@ -820,6 +865,7 @@ int board_fit_config_name_match(const char *name)
#endif
};
+#ifdef CONFIG_PINE64_DT_SELECTION
/* Differentiate the two Pine64 board DTs by their DRAM size. */
if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) {
if ((gd->ram_size > 512 * 1024 * 1024))
@@ -829,5 +875,7 @@ int board_fit_config_name_match(const char *name)
} else {
return strcmp(name, cmp_str);
}
+#endif
+ return strcmp(name, cmp_str);
}
#endif
diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig
index 14ccc9b..a5b87b9 100644
--- a/configs/pine64_plus_defconfig
+++ b/configs/pine64_plus_defconfig
@@ -3,6 +3,7 @@ CONFIG_ARCH_SUNXI=y
CONFIG_SPL=y
CONFIG_MACH_SUN50I=y
CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+CONFIG_PINE64_DT_SELECTION=y
CONFIG_NR_DRAM_BANKS=1
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
# CONFIG_CMD_FLASH is not set
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c
index 3c7dffd..8a55e4f 100644
--- a/drivers/pwm/sunxi_pwm.c
+++ b/drivers/pwm/sunxi_pwm.c
@@ -67,49 +67,55 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel,
{
struct sunxi_pwm_priv *priv = dev_get_priv(dev);
struct sunxi_pwm *regs = priv->regs;
- int prescaler;
- u32 v, period = 0, duty;
- u64 scaled_freq = 0;
+ int best_prescaler = 0;
+ u32 v, best_period = 0, duty;
+ u64 best_scaled_freq = 0;
const u32 nsecs_per_sec = 1000000000U;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
- for (prescaler = 0; prescaler < SUNXI_PWM_CTRL_PRESCALE0_MASK;
+ for (int prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK;
prescaler++) {
+ u32 period = 0;
+ u64 scaled_freq = 0;
if (!prescaler_table[prescaler])
continue;
scaled_freq = lldiv(OSC_24MHZ, prescaler_table[prescaler]);
period = lldiv(scaled_freq * period_ns, nsecs_per_sec);
- if (period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX)
- break;
+ if ((period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) &&
+ best_period < period) {
+ best_period = period;
+ best_scaled_freq = scaled_freq;
+ best_prescaler = prescaler;
+ }
}
- if (period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) {
+ if (best_period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) {
debug("%s: failed to find prescaler value\n", __func__);
return -EINVAL;
}
- duty = lldiv(scaled_freq * duty_ns, nsecs_per_sec);
+ duty = lldiv(best_scaled_freq * duty_ns, nsecs_per_sec);
- if (priv->prescaler != prescaler) {
+ if (priv->prescaler != best_prescaler) {
/* Mask clock to update prescaler */
v = readl(&regs->ctrl);
v &= ~SUNXI_PWM_CTRL_CLK_GATE;
writel(v, &regs->ctrl);
v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
- v |= (priv->prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
+ v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
writel(v, &regs->ctrl);
v |= SUNXI_PWM_CTRL_CLK_GATE;
writel(v, &regs->ctrl);
- priv->prescaler = prescaler;
+ priv->prescaler = best_prescaler;
}
- writel(SUNXI_PWM_CH0_PERIOD_PRD(period) |
+ writel(SUNXI_PWM_CH0_PERIOD_PRD(best_period) |
SUNXI_PWM_CH0_PERIOD_DUTY(duty), &regs->ch0_period);
debug("%s: prescaler: %d, period: %d, duty: %d\n",
__func__, priv->prescaler,
- period, duty);
+ best_period, duty);
return 0;
}
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index 5c8f88c..6dd9bec 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -460,7 +460,7 @@ static void sunxi_composer_init(void)
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
}
-static u32 sunxi_rgb2yuv_coef[12] = {
+static const u32 sunxi_rgb2yuv_coef[12] = {
0x00000107, 0x00000204, 0x00000064, 0x00000108,
0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808