[U-Boot] [RFC PATCH 0/4] sunxi: add support for Allwinner V3s

Hello everyone,
As I received my Lichee Pi Zero board (come with Allwinner V3s), I now ported mainline u-boot to it, as I cannot bear the BSP provided by Allwinner ;-)
Allwinner V3s is a low-end single-core Cortex-A7 SoC, with 64MB integrated DRAM, originally targeted on cameras.
Its LQFP package and integrated DRAM makes it easily for any amateur to design and solder a board for it.
This patchset contains 4 patches, they depends on the following patch:
http://lists.denx.de/pipermail/u-boot/2016-December/276960.html
and
http://lists.denx.de/pipermail/u-boot/2016-December/276961.html .
The first patch introduces DDR2 support to the H3-like DRAM controller driver in the U-Boot, which is the situation the integrated DRAM in V3s meet.
The second patch adds the basic code for V3s support, and introduces the SPL for it. With this patch, the code can compile, but cannot run.
The third patch introduces a "stub" device tree for V3s and the Lichee Pi Zero board. As they have now no mainline kernel support, the devicetree is only written to enable the UART on the chip.
the fourth patch specially changed some memory space settings for U-Boot for V3s, which made it suitable for the 64MiB integrated DRAM.

H3-like DRAM controller needs some special code to operate a DDR2 DRAM chip. Add the logic to probe such a chip.
As there's no commercial boards available now with H3 and DDR2 DRAM, the patch is developed and tested on a V3s chip, which has in-package DDR2 DRAM.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sun8i_h3.c | 114 ++++++++++++++++++++++++++++++++++-- board/sunxi/Kconfig | 11 ++++ 2 files changed, 120 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c index 8e2527dee1..a48320e01c 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -22,6 +22,9 @@ struct dram_para { u8 bus_width; u8 dual_rank; u8 row_bits; +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2 + u8 bank_bits; +#endif };
static inline int ns_to_t(int nanoseconds) @@ -136,36 +139,77 @@ static void mctl_set_timing_params(struct dram_para *para) struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tccd = 2; +#else + u8 tccd = 1; +#endif u8 tfaw = ns_to_t(50); +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 trrd = max(ns_to_t(10), 4); u8 trcd = ns_to_t(15); u8 trc = ns_to_t(53); u8 txp = max(ns_to_t(8), 3); u8 twtr = max(ns_to_t(8), 4); u8 trtp = max(ns_to_t(8), 4); +#else + u8 trrd = max(ns_to_t(10), 2); + u8 trcd = ns_to_t(20); + u8 trc = ns_to_t(65); + u8 txp = 2; + u8 twtr = max(ns_to_t(8), 2); + u8 trtp = max(ns_to_t(8), 2); +#endif u8 twr = max(ns_to_t(15), 3); u8 trp = ns_to_t(15); +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tras = ns_to_t(38); +#else + u8 tras = ns_to_t(45); +#endif u16 trefi = ns_to_t(7800) / 32; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u16 trfc = ns_to_t(350); +#else + u16 trfc = ns_to_t(328); +#endif
u8 tmrw = 0; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tmrd = 4; +#else + u8 tmrd = 2; +#endif u8 tmod = 12; u8 tcke = 3; u8 tcksrx = 5; u8 tcksre = 5; u8 tckesr = 4; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 trasmax = 24; +#else + u8 trasmax = 27; +#endif
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tcl = 6; /* CL 12 */ u8 tcwl = 4; /* CWL 8 */ u8 t_rdata_en = 4; u8 wr_latency = 2; - +#else + u8 tcl = 3; /* CL 12 */ + u8 tcwl = 3; /* CWL 8 */ + u8 t_rdata_en = 1; + u8 wr_latency = 1; +#endif + +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ +#else + u32 tdinit0 = (400 * CONFIG_DRAM_CLK) + 1; /* 400us */ + u32 tdinit1 = (500 * CONFIG_DRAM_CLK) / 1000 + 1; /* 500ns */ +#endif u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */
@@ -174,9 +218,15 @@ static void mctl_set_timing_params(struct dram_para *para) u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */
/* set mode register */ +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ writel(0x40, &mctl_ctl->mr[1]); writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ +#else + writel(0x263, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ + writel(0x4, &mctl_ctl->mr[1]); + writel(0x0, &mctl_ctl->mr[2]); /* CWL=8 */ +#endif writel(0x0, &mctl_ctl->mr[3]);
/* set DRAM timing */ @@ -244,7 +294,12 @@ static void mctl_zq_calibration(struct dram_para *para)
writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
- for (i = 0; i < 6; i++) { +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 + for (i = 0; i < 6; i++) +#else + for (i = 0; i < 4; i++) +#endif + { u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
writel((zq << 20) | (zq << 16) | (zq << 12) | @@ -266,7 +321,9 @@ static void mctl_zq_calibration(struct dram_para *para)
writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]); writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]); +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); +#endif } }
@@ -275,8 +332,16 @@ static void mctl_set_cr(struct dram_para *para) struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
- writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED | - MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) | + writel(MCTL_CR_BL8 | MCTL_CR_2T | +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 + MCTL_CR_DDR3 | MCTL_CR_EIGHT_BANKS | + MCTL_CR_BUS_WIDTH(para->bus_width) | +#else + (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) | + MCTL_CR_DDR2 | + MCTL_CR_32BIT /* fixme, thats wrong but what boot0 does */ | +#endif + MCTL_CR_INTERLEAVED | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); @@ -380,7 +445,10 @@ static int mctl_channel_init(struct dram_para *para)
mctl_zq_calibration(para);
- mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST | + mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 + PIR_DRAMRST | +#endif PIR_DRAMINIT | PIR_QSGATE);
/* detect ranks and bus width */ @@ -435,12 +503,29 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) /* detect row address bits */ para->page_size = 512; para->row_bits = 16; +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2 + para->bank_bits = 2; +#endif mctl_set_cr(para);
for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size)) +#else + if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size)) +#endif break;
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 + /* detect bank address bits */ + para->bank_bits = 3; + mctl_set_cr(para); + + for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++) + if (mctl_mem_matches((1 << para->bank_bits) * para->page_size)) + break; +#endif + /* detect page size */ para->page_size = 8192; mctl_set_cr(para); @@ -458,11 +543,19 @@ unsigned long sunxi_dram_init(void) (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
struct dram_para para = { +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 .read_delays = 0x00007979, /* dram_tpr12 */ .write_delays = 0x6aaa0000, /* dram_tpr11 */ +#else + .read_delays = 0x00007878, /* dram_tpr12 */ + .write_delays = 0x6a440000, /* dram_tpr11 */ +#endif .dual_rank = 0, .bus_width = 32, .row_bits = 15, +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2 + .bank_bits = 3, +#endif .page_size = 4096, };
@@ -477,7 +570,13 @@ unsigned long sunxi_dram_init(void) udelay(1);
/* odt delay */ +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel(0x0c000400, &mctl_ctl->odtcfg); +#else + writel(0x04000400, &mctl_ctl->odtcfg); + + clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); +#endif
/* clear credit value */ setbits_le32(&mctl_com->cccr, 1 << 31); @@ -486,6 +585,11 @@ unsigned long sunxi_dram_init(void) mctl_auto_detect_dram_size(¶); mctl_set_cr(¶);
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 return (1 << (para.row_bits + 3)) * para.page_size * (para.dual_rank ? 2 : 1); +#else + return (1 << (para.row_bits + para.bank_bits)) * para.page_size * + (para.dual_rank ? 2 : 1); +#endif } diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 4ddd992684..c11d40ee7e 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -260,6 +260,17 @@ config DRAM_ODT_CORRECTION then the correction is negative. Usually the value for this is 0. endif
+if SUNXI_H3_DW_DRAM +config SUNXI_H3_DRAM_DDR2 + bool "Board uses DDR2 DRAM" + default no + ---help--- + Only select this option when your board uses DDR2 DRAM chips instead + of DDR3 ones. + DDR2 chips needs some special probing logic, which will be included by + selecting this option. +endif + config SYS_CLK_FREQ default 816000000 if MACH_SUN50I default 912000000 if MACH_SUN7I

On Thu, Dec 29, 2016 at 03:00:58AM +0800, Icenowy Zheng wrote:
H3-like DRAM controller needs some special code to operate a DDR2 DRAM chip. Add the logic to probe such a chip.
As there's no commercial boards available now with H3 and DDR2 DRAM, the patch is developed and tested on a V3s chip, which has in-package DDR2 DRAM.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
It would have been great if your previous patch renaming the H3 symbol was part of that serie.
arch/arm/mach-sunxi/dram_sun8i_h3.c | 114 ++++++++++++++++++++++++++++++++++-- board/sunxi/Kconfig | 11 ++++ 2 files changed, 120 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c index 8e2527dee1..a48320e01c 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -22,6 +22,9 @@ struct dram_para { u8 bus_width; u8 dual_rank; u8 row_bits; +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2
- u8 bank_bits;
+#endif };
static inline int ns_to_t(int nanoseconds) @@ -136,36 +139,77 @@ static void mctl_set_timing_params(struct dram_para *para) struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tccd = 2; +#else
- u8 tccd = 1;
+#endif u8 tfaw = ns_to_t(50); +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 trrd = max(ns_to_t(10), 4); u8 trcd = ns_to_t(15); u8 trc = ns_to_t(53); u8 txp = max(ns_to_t(8), 3); u8 twtr = max(ns_to_t(8), 4); u8 trtp = max(ns_to_t(8), 4); +#else
- u8 trrd = max(ns_to_t(10), 2);
- u8 trcd = ns_to_t(20);
- u8 trc = ns_to_t(65);
- u8 txp = 2;
- u8 twtr = max(ns_to_t(8), 2);
- u8 trtp = max(ns_to_t(8), 2);
+#endif u8 twr = max(ns_to_t(15), 3); u8 trp = ns_to_t(15); +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tras = ns_to_t(38); +#else
- u8 tras = ns_to_t(45);
+#endif u16 trefi = ns_to_t(7800) / 32; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u16 trfc = ns_to_t(350); +#else
- u16 trfc = ns_to_t(328);
+#endif
u8 tmrw = 0; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tmrd = 4; +#else
- u8 tmrd = 2;
+#endif u8 tmod = 12; u8 tcke = 3; u8 tcksrx = 5; u8 tcksre = 5; u8 tckesr = 4; +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 trasmax = 24; +#else
- u8 trasmax = 27;
+#endif
Can't that be moved into a structure that would have different declaration, this is barely readable.
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u8 tcl = 6; /* CL 12 */ u8 tcwl = 4; /* CWL 8 */ u8 t_rdata_en = 4; u8 wr_latency = 2;
+#else
- u8 tcl = 3; /* CL 12 */
- u8 tcwl = 3; /* CWL 8 */
Aren't the comments supposed to change?
- u8 t_rdata_en = 1;
- u8 wr_latency = 1;
+#endif
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ +#else
- u32 tdinit0 = (400 * CONFIG_DRAM_CLK) + 1; /* 400us */
- u32 tdinit1 = (500 * CONFIG_DRAM_CLK) / 1000 + 1; /* 500ns */
+#endif u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */
@@ -174,9 +218,15 @@ static void mctl_set_timing_params(struct dram_para *para) u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */
/* set mode register */ +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ writel(0x40, &mctl_ctl->mr[1]); writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ +#else
- writel(0x263, &mctl_ctl->mr[0]); /* CL=11, WR=12 */
- writel(0x4, &mctl_ctl->mr[1]);
- writel(0x0, &mctl_ctl->mr[2]); /* CWL=8 */
Ditto
+#endif writel(0x0, &mctl_ctl->mr[3]);
/* set DRAM timing */ @@ -244,7 +294,12 @@ static void mctl_zq_calibration(struct dram_para *para)
writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
for (i = 0; i < 6; i++) {
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2
for (i = 0; i < 6; i++)
+#else
for (i = 0; i < 4; i++)
+#endif
{
This should also be put into that structure or a define.
u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf; writel((zq << 20) | (zq << 16) | (zq << 12) |
@@ -266,7 +321,9 @@ static void mctl_zq_calibration(struct dram_para *para)
writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]); writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); +#endif } }
@@ -275,8 +332,16 @@ static void mctl_set_cr(struct dram_para *para) struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
- writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) |
- writel(MCTL_CR_BL8 | MCTL_CR_2T |
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2
MCTL_CR_DDR3 | MCTL_CR_EIGHT_BANKS |
MCTL_CR_BUS_WIDTH(para->bus_width) |
+#else
(para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
MCTL_CR_DDR2 |
You can use a variable and then or is based on whether that option is enabled or not, this will be easier to read.
MCTL_CR_32BIT /* fixme, thats wrong but what boot0 does */ |
What's wrong about it?
+#endif
MCTL_CR_INTERLEAVED |
(para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
@@ -380,7 +445,10 @@ static int mctl_channel_init(struct dram_para *para)
mctl_zq_calibration(para);
- mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST |
- mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2
PIR_DRAMRST |
+#endif PIR_DRAMINIT | PIR_QSGATE);
/* detect ranks and bus width */ @@ -435,12 +503,29 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) /* detect row address bits */ para->page_size = 512; para->row_bits = 16; +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2
- para->bank_bits = 2;
+#endif mctl_set_cr(para);
for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size)) +#else
if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
+#endif
Can't you use bank_bits all the time?
break;
+#ifndef CONFIG_SUNXI_H3_DRAM_DDR2
- /* detect bank address bits */
- para->bank_bits = 3;
- mctl_set_cr(para);
- for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
break;
+#endif
- /* detect page size */ para->page_size = 8192; mctl_set_cr(para);
@@ -458,11 +543,19 @@ unsigned long sunxi_dram_init(void) (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
struct dram_para para = { +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 .read_delays = 0x00007979, /* dram_tpr12 */ .write_delays = 0x6aaa0000, /* dram_tpr11 */ +#else
.read_delays = 0x00007878, /* dram_tpr12 */
.write_delays = 0x6a440000, /* dram_tpr11 */
+#endif .dual_rank = 0, .bus_width = 32, .row_bits = 15, +#ifdef CONFIG_SUNXI_H3_DRAM_DDR2
.bank_bits = 3,
+#endif .page_size = 4096, };
@@ -477,7 +570,13 @@ unsigned long sunxi_dram_init(void) udelay(1);
/* odt delay */ +#ifndef CONFIG_SUNXI_H3_DRAM_DDR2 writel(0x0c000400, &mctl_ctl->odtcfg); +#else
- writel(0x04000400, &mctl_ctl->odtcfg);
- clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
+#endif
Some defines would be great.
Thanks! Maxime

Currently a working SPL for V3s can be built now.
The U-Boot main binary still cannot work.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/mach-sunxi/board.c | 9 +++++++-- arch/arm/mach-sunxi/cpu_info.c | 2 ++ board/sunxi/Kconfig | 13 ++++++++++++- include/configs/sun8i.h | 2 ++ 5 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 85a4ec3b0e..24f85206c8 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -161,6 +161,7 @@ enum sunxi_gpio_number { #define SUN8I_GPB_UART2 2 #define SUN8I_A33_GPB_UART0 3 #define SUN8I_A83T_GPB_UART0 2 +#define SUN8I_V3S_GPB_UART0 3 #define SUN50I_GPB_UART0 4
#define SUNXI_GPC_NAND 2 diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index aa11493748..3b28478e2d 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -110,6 +110,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(10), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_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); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN9I) sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0); @@ -180,10 +184,11 @@ void s_init(void) /* No H3 BSP, boot0 seems to not modify SUNXI_SRAMC_BASE + 0x44 */ #endif
-#if defined CONFIG_MACH_SUN6I || \ +#if (defined CONFIG_MACH_SUN6I || \ defined CONFIG_MACH_SUN7I || \ defined CONFIG_MACH_SUN8I || \ - defined CONFIG_MACH_SUN9I + defined CONFIG_MACH_SUN9I) && \ + !defined CONFIG_MACH_SUN8I_V3S /* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */ asm volatile( "mrc p15, 0, r0, c1, c0, 1\n" diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c index f1f6fd5ba4..15f1e0e45a 100644 --- a/arch/arm/mach-sunxi/cpu_info.c +++ b/arch/arm/mach-sunxi/cpu_info.c @@ -87,6 +87,8 @@ int print_cpuinfo(void) printf("CPU: Allwinner A83T (SUN8I %04x)\n", sunxi_get_sram_id()); #elif defined CONFIG_MACH_SUN8I_H3 printf("CPU: Allwinner H3 (SUN8I %04x)\n", sunxi_get_sram_id()); +#elif defined CONFIG_MACH_SUN8I_V3S + printf("CPU: Allwinner V3s (SUN8I %04x)\n", sunxi_get_sram_id()); #elif defined CONFIG_MACH_SUN9I puts("CPU: Allwinner A80 (SUN9I)\n"); #elif defined CONFIG_MACH_SUN50I diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index c11d40ee7e..09af3537b2 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -122,6 +122,17 @@ config MACH_SUN8I_H3 select SUNXI_H3_DW_DRAM select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+config MACH_SUN8I_V3S + bool "sun8i (Allwinner V3s)" + select CPU_V7 + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT + select SUNXI_GEN_SUN6I + select SUPPORT_SPL + select SUNXI_H3_DW_DRAM + select SUNXI_H3_DRAM_DDR2 + select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT + config MACH_SUN9I bool "sun9i (Allwinner A80)" select CPU_V7 @@ -138,7 +149,7 @@ endchoice # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" config MACH_SUN8I bool - default y if MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_H3 || MACH_SUN8I_A83T + default y if MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_H3 || MACH_SUN8I_A83T || MACH_SUN8I_V3S
config DRAM_TYPE int "sunxi dram type" diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h index a4c3fb69e4..6ac42acaea 100644 --- a/include/configs/sun8i.h +++ b/include/configs/sun8i.h @@ -21,6 +21,8 @@ #define CONFIG_SUNXI_USB_PHYS 4 #elif defined CONFIG_MACH_SUN8I_A83T #define CONFIG_SUNXI_USB_PHYS 3 +#elif defined CONFIG_MACH_SUN8I_V3S + #define CONFIG_SUNXI_USB_PHYS 1 #else #define CONFIG_SUNXI_USB_PHYS 2 #endif

As we have currently no mainline kernel support for V3s SoC, add a stub device tree for the SoC and the Lichee Pi Zero board.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/dts/Makefile | 2 + arch/arm/dts/sun8i-v3s-licheepi-zero.dts | 57 +++++++++++++ arch/arm/dts/sun8i-v3s.dtsi | 142 +++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 arch/arm/dts/sun8i-v3s-licheepi-zero.dts create mode 100644 arch/arm/dts/sun8i-v3s.dtsi
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 3ee608b5b4..469dd710cf 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -280,6 +280,8 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \ sun8i-h3-orangepi-plus.dtb \ sun8i-h3-orangepi-plus2e.dtb \ sun8i-h3-nanopi-neo.dtb +dtb-$(CONFIG_MACH_SUN8I_V3S) += \ + sun8i-v3s-licheepi-zero.dtb dtb-$(CONFIG_MACH_SUN50I) += \ sun50i-a64-pine64-plus.dtb \ sun50i-a64-pine64.dtb diff --git a/arch/arm/dts/sun8i-v3s-licheepi-zero.dts b/arch/arm/dts/sun8i-v3s-licheepi-zero.dts new file mode 100644 index 0000000000..6129a8bf89 --- /dev/null +++ b/arch/arm/dts/sun8i-v3s-licheepi-zero.dts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Icenowy Zheng icenowy@aosc.xyz + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "sun8i-v3s.dtsi" + +/ { + model = "Lichee Pi Zero"; + compatible = "licheepi,licheepi-zero", "allwinner,sun8i-v3s"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; diff --git a/arch/arm/dts/sun8i-v3s.dtsi b/arch/arm/dts/sun8i-v3s.dtsi new file mode 100644 index 0000000000..75b63250ac --- /dev/null +++ b/arch/arm/dts/sun8i-v3s.dtsi @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 Icenowy Zheng icenowy@aosc.xyz + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "skeleton.dtsi" + +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + osc32k: osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "osc32k"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart1: serial@01c28400 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28400 0x400>; + interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart2: serial@01c28800 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28800 0x400>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart3: serial@01c28c00 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28c00 0x400>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x1000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + }; +};

V3s devices won't have enough memory to load U-Boot binary at 0x4a000000, and they do not have enough memory to reserve 64MiB for malloc() (it has only 64MiB at all!) Change the text base to 0x41000000, and cut down malloc() reserved area to 4MB, in order to fit into the small DRAM of V3s.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- include/configs/sunxi-common.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index b0bfc0dfd7..15c672813f 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -76,7 +76,12 @@ #define SDRAM_OFFSET(x) 0x4##x #define CONFIG_SYS_SDRAM_BASE 0x40000000 #define CONFIG_SYS_LOAD_ADDR 0x42000000 /* default load address */ +/* V3s do not have enough memory to place code at 0x4a000000 */ +#ifndef CONFIG_MACH_SUN8I_V3S #define CONFIG_SYS_TEXT_BASE 0x4a000000 +#else +#define CONFIG_SYS_TEXT_BASE 0x41000000 +#endif /* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here * since it needs to fit in with the other values. By also #defining it * we get warnings if the Kconfig value mismatches. */ @@ -148,8 +153,13 @@ #define CONFIG_SYS_MMC_MAX_DEVICE 4 #endif
+#ifndef CONFIG_MACH_SUN8I_V3S /* 64MB of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (64 << 20)) +#else +/* 4MB of malloc() pool */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (4 << 20)) +#endif
/* * Miscellaneous configurable options

On Thu, Dec 29, 2016 at 03:01:01AM +0800, Icenowy Zheng wrote:
V3s devices won't have enough memory to load U-Boot binary at 0x4a000000, and they do not have enough memory to reserve 64MiB for malloc() (it has only 64MiB at all!) Change the text base to 0x41000000, and cut down malloc() reserved area to 4MB, in order to fit into the small DRAM of V3s.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
include/configs/sunxi-common.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index b0bfc0dfd7..15c672813f 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -76,7 +76,12 @@ #define SDRAM_OFFSET(x) 0x4##x #define CONFIG_SYS_SDRAM_BASE 0x40000000 #define CONFIG_SYS_LOAD_ADDR 0x42000000 /* default load address */ +/* V3s do not have enough memory to place code at 0x4a000000 */ +#ifndef CONFIG_MACH_SUN8I_V3S #define CONFIG_SYS_TEXT_BASE 0x4a000000 +#else +#define CONFIG_SYS_TEXT_BASE 0x41000000 +#endif /* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here
- since it needs to fit in with the other values. By also #defining it
- we get warnings if the Kconfig value mismatches. */
@@ -148,8 +153,13 @@ #define CONFIG_SYS_MMC_MAX_DEVICE 4 #endif
+#ifndef CONFIG_MACH_SUN8I_V3S /* 64MB of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (64 << 20)) +#else +/* 4MB of malloc() pool */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (4 << 20)) +#endif
Can't this be used for all the SoCs? Allocating 64MB seems way to much already :)
Maxime
participants (2)
-
Icenowy Zheng
-
Maxime Ripard