This adds support for devices with R40 dual rank DRAM, and asymmetric
A64 DRAM devices like the Pinephone/3GB.
Also we enable automatic gzipped kernel support, and allow scripted
DT overlay support. The rest of the patches are cleanups, but also
some sunxi-specific preparatory patches for USB3.0 and improved HDMI
support. The bulk of those changes will go through other trees, though.

Build-tested for all 156 sunxi boards, and boot tested on a A64, A20, R40,
H5, H6 and H616 board. USB, SD card, eMMC, HDMI and Ethernet all work
there (where applicable), with the exception of Ethernet on the H5. Since
this is already broken in v2021.04, I will send a separate fix.
This commit is contained in:
Tom Rini 2021-04-16 08:30:25 -04:00
commit 7cb977fd51
9 changed files with 215 additions and 55 deletions

View file

@ -42,7 +42,7 @@
os = "u-boot";
arch = "arm64";
compression = "none";
load = <0x4a000000>;
load = <CONFIG_SYS_TEXT_BASE>;
u-boot-nodtb {
};
@ -86,7 +86,7 @@
};
configurations {
default = "config-1";
default = "@config-DEFAULT-SEQ";
@config-SEQ {
description = "NAME";

View file

@ -215,12 +215,17 @@ struct sunxi_mctl_ctl_reg {
#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE)
/* The eight data lines (DQn) plus DM, DQS and DQSN */
#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3)
struct dram_para {
struct rank_para {
u16 page_size;
u8 bus_full_width;
u8 dual_rank;
u8 row_bits;
u8 bank_bits;
};
struct dram_para {
u8 dual_rank;
u8 bus_full_width;
struct rank_para ranks[2];
const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
const u8 ac_delays[31];

View file

@ -973,6 +973,7 @@ config VIDEO_DE2
depends on SUNXI_DE2
select DM_VIDEO
select DISPLAY
select VIDEO_DW_HDMI
imply VIDEO_DT_SIMPLEFB
default y
---help---

View file

@ -399,18 +399,24 @@ static void mctl_set_cr(uint16_t socid, struct dram_para *para)
#else
#error Unsupported DRAM type!
#endif
(para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
(para->ranks[0].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
(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);
MCTL_CR_PAGE_SIZE(para->ranks[0].page_size) |
MCTL_CR_ROW_BITS(para->ranks[0].row_bits), &mctl_com->cr);
if (para->dual_rank && (socid == SOCID_A64 || socid == SOCID_R40)) {
writel((para->ranks[1].bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
MCTL_CR_DUAL_RANK |
MCTL_CR_PAGE_SIZE(para->ranks[1].page_size) |
MCTL_CR_ROW_BITS(para->ranks[1].row_bits), &mctl_com->cr_r1);
}
if (socid == SOCID_R40) {
if (para->dual_rank)
panic("Dual rank memory not supported\n");
/* Mux pin to A15 address line for single rank memory. */
setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
if (!para->dual_rank)
setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
}
}
@ -646,35 +652,105 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para)
return 0;
}
static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
/*
* Test if memory at offset offset matches memory at a certain base
*/
static bool mctl_mem_matches_base(u32 offset, ulong base)
{
/* Try to write different values to RAM at two addresses */
writel(0, base);
writel(0xaa55aa55, base + offset);
dsb();
/* Check if the same value is actually observed when reading back */
return readl(base) ==
readl(base + offset);
}
static void mctl_auto_detect_dram_size_rank(uint16_t socid, struct dram_para *para, ulong base, struct rank_para *rank)
{
/* detect row address bits */
para->page_size = 512;
para->row_bits = 16;
para->bank_bits = 2;
rank->page_size = 512;
rank->row_bits = 16;
rank->bank_bits = 2;
mctl_set_cr(socid, para);
for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
for (rank->row_bits = 11; rank->row_bits < 16; rank->row_bits++)
if (mctl_mem_matches_base((1 << (rank->row_bits + rank->bank_bits)) * rank->page_size, base))
break;
/* detect bank address bits */
para->bank_bits = 3;
rank->bank_bits = 3;
mctl_set_cr(socid, para);
for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
for (rank->bank_bits = 2; rank->bank_bits < 3; rank->bank_bits++)
if (mctl_mem_matches_base((1 << rank->bank_bits) * rank->page_size, base))
break;
/* detect page size */
para->page_size = 8192;
rank->page_size = 8192;
mctl_set_cr(socid, para);
for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
if (mctl_mem_matches(para->page_size))
for (rank->page_size = 512; rank->page_size < 8192; rank->page_size *= 2)
if (mctl_mem_matches_base(rank->page_size, base))
break;
}
static unsigned long mctl_calc_rank_size(struct rank_para *rank)
{
return (1UL << (rank->row_bits + rank->bank_bits)) * rank->page_size;
}
/*
* Because we cannot do mctl_phy_init(PIR_QSGATE) on R40 now (which leads
* to failure), it's needed to detect the rank count of R40 in another way.
*
* The code here is modelled after time_out_detect() in BSP, which tries to
* access the memory and check for error code.
*
* TODO: auto detect half DQ width here
*/
static void mctl_r40_detect_rank_count(struct dram_para *para)
{
ulong rank1_base = (ulong) CONFIG_SYS_SDRAM_BASE +
mctl_calc_rank_size(&para->ranks[0]);
struct sunxi_mctl_ctl_reg * const mctl_ctl =
(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
/* Enable read time out */
setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
(void) readl((void *) rank1_base);
udelay(10);
if (readl(&mctl_ctl->pgsr[0]) & (0x1 << 13)) {
clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
para->dual_rank = 0;
}
/* Reset PHY FIFO to clear it */
clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
udelay(100);
setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
/* Clear error status */
setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 24);
/* Clear time out flag */
clrbits_le32(&mctl_ctl->pgsr[0], 0x1 << 13);
/* Disable read time out */
clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
}
static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
{
mctl_auto_detect_dram_size_rank(socid, para, (ulong)CONFIG_SYS_SDRAM_BASE, &para->ranks[0]);
if ((socid == SOCID_A64 || socid == SOCID_R40) && para->dual_rank) {
mctl_auto_detect_dram_size_rank(socid, para, (ulong)CONFIG_SYS_SDRAM_BASE + mctl_calc_rank_size(&para->ranks[0]), &para->ranks[1]);
}
}
/*
* The actual values used here are taken from Allwinner provided boot0
* binaries, though they are probably board specific, so would likely benefit
@ -769,12 +845,23 @@ unsigned long sunxi_dram_init(void)
struct sunxi_mctl_ctl_reg * const mctl_ctl =
(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
unsigned long size;
struct dram_para para = {
.dual_rank = 1,
.bus_full_width = 1,
.row_bits = 15,
.bank_bits = 3,
.page_size = 4096,
.ranks = {
{
.row_bits = 15,
.bank_bits = 3,
.page_size = 4096,
},
{
.row_bits = 15,
.bank_bits = 3,
.page_size = 4096,
}
},
#if defined(CONFIG_MACH_SUN8I_H3)
.dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
@ -807,8 +894,6 @@ unsigned long sunxi_dram_init(void)
uint16_t socid = SOCID_H3;
#elif defined(CONFIG_MACH_SUN8I_R40)
uint16_t socid = SOCID_R40;
/* Currently we cannot support R40 with dual rank memory */
para.dual_rank = 0;
#elif defined(CONFIG_MACH_SUN8I_V3S)
uint16_t socid = SOCID_V3S;
#elif defined(CONFIG_MACH_SUN50I)
@ -843,9 +928,21 @@ unsigned long sunxi_dram_init(void)
setbits_le32(&mctl_com->cccr, 1 << 31);
udelay(10);
if (socid == SOCID_R40) {
mctl_r40_detect_rank_count(&para);
mctl_set_cr(SOCID_R40, &para);
}
mctl_auto_detect_dram_size(socid, &para);
mctl_set_cr(socid, &para);
return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
(para.dual_rank ? 2 : 1);
size = mctl_calc_rank_size(&para.ranks[0]);
if (socid == SOCID_A64 || socid == SOCID_R40) {
if (para.dual_rank)
size += mctl_calc_rank_size(&para.ranks[1]);
} else if (para.dual_rank) {
size *= 2;
}
return size;
}

View file

@ -6,6 +6,8 @@
obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o
obj-$(CONFIG_CLK_SUNXI) += clk_sun6i_rtc.o
obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o

View file

@ -43,6 +43,7 @@ static struct ccu_clk_gate h6_gates[] = {
[CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
[CLK_BUS_OHCI3] = GATE(0xa8c, BIT(3)),
[CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
[CLK_BUS_XHCI] = GATE(0xa8c, BIT(5)),
[CLK_BUS_EHCI3] = GATE(0xa8c, BIT(7)),
[CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
};
@ -71,6 +72,7 @@ static struct ccu_reset h6_resets[] = {
[RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
[RST_BUS_OHCI3] = RESET(0xa8c, BIT(19)),
[RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
[RST_BUS_XHCI] = RESET(0xa8c, BIT(21)),
[RST_BUS_EHCI3] = RESET(0xa8c, BIT(23)),
[RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
};

View file

@ -0,0 +1,35 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (C) 2018 Amarula Solutions.
* Copyright (C) 2020 Samuel Holland <samuel@sholland.org>
*/
#include <clk-uclass.h>
#include <dm.h>
static int clk_sun6i_rtc_enable(struct clk *clk)
{
return 0;
}
static const struct clk_ops clk_sun6i_rtc_ops = {
.enable = clk_sun6i_rtc_enable,
};
static const struct udevice_id sun6i_rtc_ids[] = {
{ .compatible = "allwinner,sun6i-a31-rtc" },
{ .compatible = "allwinner,sun8i-a23-rtc" },
{ .compatible = "allwinner,sun8i-h3-rtc" },
{ .compatible = "allwinner,sun8i-r40-rtc" },
{ .compatible = "allwinner,sun8i-v3-rtc" },
{ .compatible = "allwinner,sun50i-h5-rtc" },
{ .compatible = "allwinner,sun50i-h6-rtc" },
{ }
};
U_BOOT_DRIVER(clk_sun6i_rtc) = {
.name = "clk_sun6i_rtc",
.id = UCLASS_CLK,
.of_match = sun6i_rtc_ids,
.ops = &clk_sun6i_rtc_ops,
};

View file

@ -4,4 +4,4 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o
obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o

View file

@ -62,7 +62,7 @@
#define SDRAM_OFFSET(x) 0x2##x
#define CONFIG_SYS_SDRAM_BASE 0x20000000
#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* default load address */
/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here
/* 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. */
#define CONFIG_SPL_STACK_R_ADDR 0x2fe00000
@ -72,7 +72,7 @@
#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 */
/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here
/* 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. */
#define CONFIG_SPL_STACK_R_ADDR 0x4fe00000
@ -240,40 +240,44 @@ extern int soft_i2c_gpio_scl;
* There is no compression for arm64 kernels (yet), so leave some space
* for really big kernels, say 256MB for now.
* Scripts, PXE and DTBs should go afterwards, leaving the rest for the initrd.
* Align the initrd to a 2MB page.
*/
#define BOOTM_SIZE __stringify(0xa000000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(0080000))
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(FA00000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC00000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(FD00000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(FE00000))
#define BOOTM_SIZE __stringify(0xa000000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(0080000))
#define KERNEL_COMP_ADDR_R __stringify(SDRAM_OFFSET(4000000))
#define KERNEL_COMP_SIZE __stringify(0xb000000)
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(FA00000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC00000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(FD00000))
#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(FE00000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(FF00000))
#else
/*
* 160M RAM (256M minimum minus 64MB heap + 32MB for u-boot, stack, fb, etc.
* 32M uncompressed kernel, 16M compressed kernel, 1M fdt,
* 1M script, 1M pxe and the ramdisk at the end.
* 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end.
*/
#ifndef CONFIG_MACH_SUN8I_V3S
#define BOOTM_SIZE __stringify(0xa000000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(2000000))
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(3000000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(3100000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(3200000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(3300000))
#define BOOTM_SIZE __stringify(0xa000000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(2000000))
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(3000000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(3100000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(3200000))
#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(3300000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(3400000))
#else
/*
* 64M RAM minus 2MB heap + 16MB for u-boot, stack, fb, etc.
* 16M uncompressed kernel, 8M compressed kernel, 1M fdt,
* 1M script, 1M pxe and the ramdisk at the end.
* 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end.
*/
#define BOOTM_SIZE __stringify(0x2e00000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(1000000))
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(1800000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(1900000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(1A00000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(1B00000))
#define BOOTM_SIZE __stringify(0x2e00000)
#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(1000000))
#define FDT_ADDR_R __stringify(SDRAM_OFFSET(1800000))
#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(1900000))
#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(1A00000))
#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(1B00000))
#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(1C00000))
#endif
#endif
@ -283,8 +287,21 @@ extern int soft_i2c_gpio_scl;
"fdt_addr_r=" FDT_ADDR_R "\0" \
"scriptaddr=" SCRIPT_ADDR_R "\0" \
"pxefile_addr_r=" PXEFILE_ADDR_R "\0" \
"fdtoverlay_addr_r=" FDTOVERLAY_ADDR_R "\0" \
"ramdisk_addr_r=" RAMDISK_ADDR_R "\0"
#ifdef CONFIG_ARM64
#define MEM_LAYOUT_ENV_EXTRA_SETTINGS \
"kernel_comp_addr_r=" KERNEL_COMP_ADDR_R "\0" \
"kernel_comp_size=" KERNEL_COMP_SIZE "\0"
#else
#define MEM_LAYOUT_ENV_EXTRA_SETTINGS ""
#endif
#define DFU_ALT_INFO_RAM \
"dfu_alt_info_ram=" \
"kernel ram " KERNEL_ADDR_R " 0x1000000;" \
@ -435,6 +452,7 @@ extern int soft_i2c_gpio_scl;
#define CONFIG_EXTRA_ENV_SETTINGS \
CONSOLE_ENV_SETTINGS \
MEM_LAYOUT_ENV_SETTINGS \
MEM_LAYOUT_ENV_EXTRA_SETTINGS \
DFU_ALT_INFO_RAM \
"fdtfile=" FDTFILE "\0" \
"console=ttyS0,115200\0" \