ソースを参照

Merge branch 'master' of git://git.denx.de/u-boot-sunxi

Tom Rini 6 年 前
コミット
2f07a9a6d1

+ 16 - 6
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) */
 };
 

+ 16 - 0
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

+ 1 - 1
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
 	}, {

+ 1 - 1
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>

+ 1 - 1
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>

+ 3 - 3
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

+ 1 - 1
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,

+ 60 - 12
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

+ 1 - 0
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

+ 19 - 13
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;
 }

+ 1 - 1
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