Merge tag 'u-boot-amlogic-next-20251219' of https://source.denx.de/u-boot/custodians/u-boot-amlogic into next

- Add u-boot SPL support for GX SoCs
- meson_gx_mmc: reduce maximum frequency
- Add support for EFI capsule updates on all Amlogic boards
This commit is contained in:
Tom Rini
2025-12-19 10:30:26 -06:00
48 changed files with 3449 additions and 52 deletions

View File

@@ -186,6 +186,7 @@ F: drivers/video/meson/
F: drivers/watchdog/meson_gxbb_wdt.c
F: include/configs/meson64.h
F: include/configs/meson64_android.h
F: tools/amlimage*
F: doc/board/amlogic/
N: meson

View File

@@ -2,6 +2,7 @@
/*
* Copyright (c) 2019 BayLibre, SAS.
* Author: Maxime Jourdan <mjourdan@baylibre.com>
* Copyright (c) 2023 Ferass El Hafidi <funderscore@postmarketos.org>
*/
/ {
@@ -15,6 +16,12 @@
soc {
bootph-all;
};
#if defined(CONFIG_BINMAN)
binman: binman {
multiple-images;
};
#endif
};
&vpu {
@@ -30,3 +37,121 @@
<0x0 0xc883c000 0x0 0x1000>;
reg-names = "hdmitx", "hhi";
};
#if defined(CONFIG_BINMAN)
/* binman configuration on GXBB and GXL */
&binman {
u-boot-amlogic {
filename = "u-boot-meson-with-spl.bin";
pad-byte = <0xff>;
mkimage {
filename = "spl/u-boot-spl-signed.bin";
/* args are per-SoC, and defined in meson-(gxbb/gxl)-u-boot.dtsi */
u-boot-spl {
};
};
fit: fit {
description = "ATF and U-Boot images";
#address-cells = <1>;
fit,fdt-list = "of-list";
fit,external-offset = <CONFIG_FIT_EXTERNAL_OFFSET>;
fit,align = <512>;
offset = <CONFIG_SPL_PAD_TO>;
images {
u-boot {
description = "U-Boot";
type = "standalone";
os = "u-boot";
arch = "arm64";
compression = "none";
load = <CONFIG_TEXT_BASE>;
entry = <CONFIG_TEXT_BASE>;
u-boot-nodtb {
};
#if CONFIG_IS_ENABLED(FIT_SIGNATURE) && CONFIG_IS_ENABLED(SHA256)
hash {
algo = "sha256";
};
#endif
};
atf {
description = "ARM Trusted Firmware";
type = "firmware";
os = "arm-trusted-firmware";
arch = "arm64";
compression = "none";
/*
* load and entry are SoC-specific, and thus
* defined in meson-(gxbb/gxl)-u-boot.dtsi
*/
atf-bl31 {
filename = "bl31.bin";
};
#if CONFIG_IS_ENABLED(FIT_SIGNATURE) && CONFIG_IS_ENABLED(SHA256)
hash {
algo = "sha256";
};
#endif
};
scp {
description = "SCP BL30 Firmware";
type = "scp";
arch = "arm"; /* The Cortex-M core is used as SCP */
compression = "none";
/*
* On GXBB the base address of the SCP firmware doesn't matter as SPL will
* send the firmware to the SCP anyway, and can get the base address from the
* FIT. On GXL it matters, as BL31 is supposed to send the firmware, so set the
* base address to what GXL BL2 would load the binary to.
*/
load = <0x13c0000>;
scp {
filename = "scp.bin";
};
hash {
/*
* The hash is used by the SCP and passed to it
* by U-Boot SPL.
*/
algo = "sha256";
};
};
@fdt-SEQ {
description = "NAME";
type = "flat_dt";
compression = "none";
#if CONFIG_IS_ENABLED(FIT_SIGNATURE) && CONFIG_IS_ENABLED(SHA256)
hash {
algo = "sha256";
};
#endif
};
};
configurations {
default = "@config-DEFAULT-SEQ";
@config-SEQ {
description = "NAME.dtb";
fdt = "fdt-SEQ";
firmware = "atf";
loadables = "scp", "u-boot";
};
};
};
};
};
#endif

View File

@@ -4,7 +4,7 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"
&ethmac {
snps,reset-gpio = <&gpio GPIOZ_14 0>;

View File

@@ -4,7 +4,7 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"
&ethmac {
snps,reset-gpio = <&gpio GPIOZ_14 0>;

View File

@@ -4,7 +4,7 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"
/ {
smbios {

View File

@@ -4,4 +4,4 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"

View File

@@ -4,4 +4,4 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"

View File

@@ -0,0 +1,27 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#if defined(CONFIG_BINMAN)
/* GXBB-specific binman configuration */
&binman {
u-boot-amlogic {
mkimage {
args = "-n", "gxbb", "-T", "amlimage";
};
fit: fit {
images {
atf {
load = <0x10100000>;
entry = <0x10100000>;
};
};
};
};
};
#endif

View File

@@ -4,7 +4,7 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"
&ethmac {
snps,reset-gpio = <&gpio GPIOZ_14 0>;

View File

@@ -4,7 +4,7 @@
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include "meson-gx-u-boot.dtsi"
#include "meson-gxbb-u-boot.dtsi"
&ethmac {
snps,reset-gpio = <&gpio GPIOZ_14 0>;

View File

@@ -5,3 +5,23 @@
*/
#include "meson-gx-u-boot.dtsi"
#if defined(CONFIG_BINMAN)
/* GXL-specific binman configuration */
&binman {
u-boot-amlogic {
mkimage {
args = "-n", "gxl", "-T", "amlimage";
};
fit: fit {
images {
atf {
load = <0x5100000>;
entry = <0x5100000>;
};
};
};
};
};
#endif

View File

@@ -21,6 +21,8 @@ int meson_get_boot_device(void);
int meson_get_soc_rev(char *buff, size_t buff_len);
void meson_setup_capsule(void);
/**
* meson_get_socinfo - retrieve cpu_id of the Amlogic SoC
*

View File

@@ -87,6 +87,7 @@
#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
#define HHI_SYS_PLL_CNTL1 0x2fc /* 0xbf offset in data sheet */
#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */
#define HHI_SYS_PLL_CNTL2 0x304 /* 0xc1 offset in data sheet */
#define HHI_SYS_PLL_CNTL3 0x308 /* 0xc2 offset in data sheet */
@@ -114,4 +115,17 @@
ulong meson_measure_clk_rate(unsigned int clk);
#if defined(CONFIG_SPL_BUILD)
#define HHI_SCC_CNTL0_FINAL_MUX_SEL BIT(11)
#define HHI_SCC_CNTL0_FINAL_DYN_MUX_SEL BIT(10)
#define HHI_SCC_CNTL0_MUX0_DIVN_TCNT (0x3f << 4)
#define HHI_SCC_CNTL0_MUX1_DIVN_TCNT (0x3f << 20)
#define HHI_SCC_CNTL0_POSTMUX0 BIT(2)
#define HHI_SCC_CNTL0_POSTMUX1 BIT(18)
#define HHI_SCC_CNTL0_PREMUX0 3
#define HHI_SCC_CNTL0_PREMUX1 (3 << 16)
#define HHI_SCC_CNTL0_DYN_ENABLE BIT(26)
#define HHI_SCC_CNTL0_BUSY BIT(28)
#endif
#endif

View File

@@ -0,0 +1,341 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#ifndef DRAM_GX_H
#define DRAM_GX_H
/*
* Registers
*/
/* PCTL */
#define DDR0_PCTL_BASE 0xc8839000
/* DDR1_PCTL_BASE is DDR0_PCTL_BASE + 0x400 */
/* DMC */
#define DMC_REG_BASE 0xc8838000
#define DMC_REQ_CTRL (DMC_REG_BASE + (0x00 << 2))
#define DMC_SOFT_RST (DMC_REG_BASE + (0x01 << 2))
#define DMC_SOFT_RST1 (DMC_REG_BASE + (0x02 << 2))
#define DMC_RST_STS (DMC_REG_BASE + (0x03 << 2))
#define DMC_VERSION (DMC_REG_BASE + (0x05 << 2))
#define DMC_REFR_CTRL1 (DMC_REG_BASE + (0x23 << 2))
#define DMC_REFR_CTRL2 (DMC_REG_BASE + (0x24 << 2))
#define DMC_PCTL_LP_CTRL (DMC_REG_BASE + (0x46 << 2))
#define DMC_AM0_QOS_INC (DMC_REG_BASE + (0x62 << 2))
#define DMC_AM0_QOS_DEC (DMC_REG_BASE + (0x64 << 2))
#define DMC_AM0_QOS_DIS (DMC_REG_BASE + (0x66 << 2))
#define DMC_AM1_QOS_INC (DMC_REG_BASE + (0x6c << 2))
#define DMC_AM1_QOS_DEC (DMC_REG_BASE + (0x6e << 2))
#define DMC_AM1_QOS_DIS (DMC_REG_BASE + (0x70 << 2))
#define DMC_AM2_QOS_INC (DMC_REG_BASE + (0x76 << 2))
#define DMC_AM2_QOS_DEC (DMC_REG_BASE + (0x78 << 2))
#define DMC_AM2_QOS_DIS (DMC_REG_BASE + (0x7a << 2))
#define DMC_AM3_QOS_INC (DMC_REG_BASE + (0x80 << 2))
#define DMC_AM3_QOS_DEC (DMC_REG_BASE + (0x82 << 2))
#define DMC_AM3_QOS_DIS (DMC_REG_BASE + (0x84 << 2))
#define DMC_AM4_QOS_INC (DMC_REG_BASE + (0x8a << 2))
#define DMC_AM4_QOS_DEC (DMC_REG_BASE + (0x8c << 2))
#define DMC_AM4_QOS_DIS (DMC_REG_BASE + (0x8e << 2))
#define DMC_AM5_QOS_INC (DMC_REG_BASE + (0x94 << 2))
#define DMC_AM5_QOS_DEC (DMC_REG_BASE + (0x96 << 2))
#define DMC_AM5_QOS_DIS (DMC_REG_BASE + (0x98 << 2))
#define DMC_AM6_QOS_INC (DMC_REG_BASE + (0x9e << 2))
#define DMC_AM6_QOS_DEC (DMC_REG_BASE + (0xa0 << 2))
#define DMC_AM6_QOS_DIS (DMC_REG_BASE + (0xa2 << 2))
#define DMC_AM7_QOS_INC (DMC_REG_BASE + (0xa8 << 2))
#define DMC_AM7_QOS_DEC (DMC_REG_BASE + (0xaa << 2))
#define DMC_AM7_QOS_DIS (DMC_REG_BASE + (0xac << 2))
#define DMC_AXI0_QOS_INC (DMC_REG_BASE + (0xb2 << 2))
#define DMC_AXI0_QOS_DEC (DMC_REG_BASE + (0xb4 << 2))
#define DMC_AXI0_QOS_DIS (DMC_REG_BASE + (0xb6 << 2))
#define DMC_AXI0_QOS_CTRL1 (DMC_REG_BASE + (0xb9 << 2))
#define DMC_AXI1_QOS_INC (DMC_REG_BASE + (0xbc << 2))
#define DMC_AXI1_QOS_DEC (DMC_REG_BASE + (0xbe << 2))
#define DMC_AXI1_QOS_DIS (DMC_REG_BASE + (0xc0 << 2))
#define DMC_AXI2_QOS_INC (DMC_REG_BASE + (0xc6 << 2))
#define DMC_AXI2_QOS_DEC (DMC_REG_BASE + (0xc8 << 2))
#define DMC_AXI2_QOS_DIS (DMC_REG_BASE + (0xca << 2))
#define DMC_AXI3_QOS_INC (DMC_REG_BASE + (0xd0 << 2))
#define DMC_AXI3_QOS_DEC (DMC_REG_BASE + (0xd2 << 2))
#define DMC_AXI3_QOS_DIS (DMC_REG_BASE + (0xd4 << 2))
#define DMC_AXI4_QOS_INC (DMC_REG_BASE + (0xda << 2))
#define DMC_AXI4_QOS_DEC (DMC_REG_BASE + (0xdc << 2))
#define DMC_AXI4_QOS_DIS (DMC_REG_BASE + (0xde << 2))
#define DMC_AXI5_QOS_INC (DMC_REG_BASE + (0xe4 << 2))
#define DMC_AXI5_QOS_DEC (DMC_REG_BASE + (0xe6 << 2))
#define DMC_AXI5_QOS_DIS (DMC_REG_BASE + (0xe8 << 2))
#define DMC_AXI6_QOS_INC (DMC_REG_BASE + (0xee << 2))
#define DMC_AXI6_QOS_DEC (DMC_REG_BASE + (0xf0 << 2))
#define DMC_AXI6_QOS_DIS (DMC_REG_BASE + (0xf2 << 2))
#define DMC_AXI7_QOS_INC (DMC_REG_BASE + (0xf8 << 2))
#define DMC_AXI7_QOS_DEC (DMC_REG_BASE + (0xfa << 2))
#define DMC_AXI7_QOS_DIS (DMC_REG_BASE + (0xfc << 2))
/* DDR MMC */
#define AM_DDR_PLL_CNTL0 (DDR_MMC_BASE + 0x00)
#define AM_DDR_PLL_CNTL1 (DDR_MMC_BASE + 0x04)
#define AM_DDR_PLL_CNTL2 (DDR_MMC_BASE + 0x08)
#define AM_DDR_PLL_CNTL3 (DDR_MMC_BASE + 0x0c)
#define AM_DDR_PLL_CNTL4 (DDR_MMC_BASE + 0x10)
#if defined(CONFIG_MESON_GXBB)
#define AM_DDR_PLL_STS (DDR_MMC_BASE + 0x14)
#else
#define AM_DDR_PLL_CNTL5 (DDR_MMC_BASE + 0x14)
#endif
#define DDR0_CLK_CTRL (DDR_MMC_BASE + 0x400)
/* DMC SEC */
#define DMC_SEC_REG_BASE 0xda838400
#define DMC_SEC_CTRL (DMC_SEC_REG_BASE + (0x00 << 2))
#define DMC_SEC_RANGE_CTRL (DMC_SEC_REG_BASE + (0x07 << 2))
#define DMC_SEC_AXI_PORT_CTRL (DMC_SEC_REG_BASE + (0x0e << 2))
#define DMC_VDEC_SEC_READ_CTRL (DMC_SEC_REG_BASE + (0x10 << 2))
#define DMC_VDEC_SEC_WRITE_CTRL (DMC_SEC_REG_BASE + (0x11 << 2))
#define DMC_VDEC_SEC_CFG (DMC_SEC_REG_BASE + (0x12 << 2))
#define DMC_HCODEC_SEC_READ_CTRL (DMC_SEC_REG_BASE + (0x17 << 2))
#define DMC_HCODEC_SEC_WRITE_CTRL (DMC_SEC_REG_BASE + (0x18 << 2))
#define DMC_HCODEC_SEC_CFG (DMC_SEC_REG_BASE + (0x19 << 2))
#define DMC_HEVC_SEC_READ_CTRL (DMC_SEC_REG_BASE + (0x1e << 2))
#define DMC_HEVC_SEC_WRITE_CTRL (DMC_SEC_REG_BASE + (0x1f << 2))
#define DMC_HEVC_SEC_CFG (DMC_SEC_REG_BASE + (0x20 << 2))
#define DMC_VPU_SEC_READ_CTRL (DMC_SEC_REG_BASE + (0x32 << 2))
#define DMC_VPU_SEC_WRITE_CTRL (DMC_SEC_REG_BASE + (0x33 << 2))
#define DMC_VPU_SEC_CFG (DMC_SEC_REG_BASE + (0x25 << 2))
#define DMC_GE2D_SEC_CTRL (DMC_SEC_REG_BASE + (0x34 << 2))
#define DMC_PARSER_SEC_CTRL (DMC_SEC_REG_BASE + (0x35 << 2))
#define DMC_DEV_SEC_READ_CTRL (DMC_SEC_REG_BASE + (0x36 << 2))
#define DMC_DEV_SEC_WRITE_CTRL (DMC_SEC_REG_BASE + (0x37 << 2))
#define DMC_WTCH0_CTRL (DMC_SEC_REG_BASE + (0xa9 << 2))
#define DMC_WTCH1_CTRL (DMC_SEC_REG_BASE + (0xb0 << 2))
#define DDR0_ADDRMAP_0 (DMC_SEC_REG_BASE + (0xd0 << 2))
#define DDR0_ADDRMAP_1 (DMC_SEC_REG_BASE + (0xd1 << 2))
#define DDR0_ADDRMAP_2 (DMC_SEC_REG_BASE + (0xd2 << 2))
#define DDR0_ADDRMAP_3 (DMC_SEC_REG_BASE + (0xd3 << 2))
#define DDR0_ADDRMAP_4 (DMC_SEC_REG_BASE + (0xd4 << 2))
#define DDR1_ADDRMAP_0 (DMC_SEC_REG_BASE + (0xd5 << 2))
#define DDR1_ADDRMAP_1 (DMC_SEC_REG_BASE + (0xd6 << 2))
#define DDR1_ADDRMAP_2 (DMC_SEC_REG_BASE + (0xd7 << 2))
#define DDR1_ADDRMAP_3 (DMC_SEC_REG_BASE + (0xd8 << 2))
#define DDR1_ADDRMAP_4 (DMC_SEC_REG_BASE + (0xd9 << 2))
#if defined(CONFIG_MESON_GXL)
#define DMC_DES_KEY0_H (DMC_SEC_REG_BASE + (0x90 << 2))
#define DMC_DES_KEY0_L (DMC_SEC_REG_BASE + (0x91 << 2))
#define DMC_DES_KEY1_H (DMC_SEC_REG_BASE + (0x92 << 2))
#define DMC_DES_KEY1_L (DMC_SEC_REG_BASE + (0x93 << 2))
#define DMC_DES_CTRL (DMC_SEC_REG_BASE + (0x9d << 2))
#endif
#define DMC_DDR_CTRL (DMC_SEC_REG_BASE + (0xda << 2))
#define AM_ANALOG_TOP_REG1 (0xc8834400 + (0x6f << 2))
/* Macros */
#define DQSCORR_DX(dx) \
if ((readl(dx) & ~(0xe00)) && ((readl(dx) >> 8) & ~(0xe00))) \
writel((((readl(dx) & ~(0xe00)) * 95) / 100) | \
(((((readl(dx) >> 8) & ~(0xe00)) * 88) / 100) << 8) | \
(((((readl(dx) >> 8) & ~(0xe00)) * 88) / 100) << 16), \
dx); \
else if (((readl(dx) >> 8) & ~(0xe00))) \
writel((95 / 100) | \
(((((readl(dx) >> 8) & ~(0xe00)) * 88) / 100) << 8) | \
(((((readl(dx) >> 8) & ~(0xe00)) * 88) / 100) << 16), \
dx); \
else if (((readl(dx)) & ~(0xe00))) \
writel((((readl(dx) & ~(0xe00)) * 95) / 100) | \
(((88) / 100) << 8) | (((88) / 100) << 16), \
dx); \
else \
writel((95 / 100) | \
((88 / 100) << 8) | ((88 / 100) << 16), dx)
#define DMC_ENABLE_REGION(REGION) \
writel(0xffffffff, REGION## _SEC_CFG); \
writel(0x55555555, REGION## _SEC_WRITE_CTRL); \
writel(0x55555555, REGION## _SEC_READ_CTRL)
/* TODO: Timeout */
#define WAIT_FOR(a) \
while (!(readl(a) & 1)) \
; \
if (!(readl(a) & 1)) \
panic("%s: init failed, err=%d", __func__, -ETIMEDOUT)
/**
* Register values
**/
/*
* PLL
*/
#define DDR_CLK_CNTL_CLKGEN_SOFTRESET BIT(28)
#define DDR_CLK_CNTL_PHY_CLK_ENABLE BIT(29)
#define DDR_CLK_CNTL_DDRPLL_ENABLE BIT(31)
/*
* PCTL
*/
/* PCTL_SCTL: state control register (S905X datasheet p.451) */
#define PCTL_SCTL_CFG_STATE BIT(0)
#define PCTL_SCTL_GO_STATE BIT(1)
/* PCTL_STAT */
#define PCTL_STAT_ACCESS (BIT(1) | BIT(0))
/* PCTL_POWCTL: power control */
#define PCTL_POWCTL_POWERON BIT(0)
/*
* PUB
*/
/* PUB_PGSR0: PHY General Status Register 0 */
#define PUB_PGSR0_IDONE BIT(0) /* Initialization Done */
#define PUB_PGSR0_PLDONE BIT(1) /* PLL Lock Done */
#define PUB_PGSR0_DCDONE BIT(2) /* DDL Calibration Done */
#define PUB_PGSR0_ZCDONE BIT(3) /* Impedance Calibration Done */
#define PUB_PGSR0_DIDONE BIT(4) /* DRAM Initialization Done */
#define PUB_PGSR0_WLDONE BIT(5) /* Write Leveling Done */
#define PUB_PGSR0_QSGDONE BIT(6) /* DQS Gate Training Done */
#define PUB_PGSR0_WLADONE BIT(7) /* Write Leveling Adjust Done */
#define PUB_PGSR0_RDDONE BIT(8) /* Read Bit Deskew Done */
#define PUB_PGSR0_WDDONE BIT(9) /* Write Bit Deskew Done */
#define PUB_PGSR0_REDONE BIT(10) /* Read Eye Training Done */
#define PUB_PGSR0_WEDONE BIT(11) /* Write Eye Training Done */
#define PUB_PGSR0_ZCERR BIT(20) /* Impedance Calib Error */
#define PUB_PGSR0_WLERR BIT(21) /* Write Leveling Error */
#define PUB_PGSR0_QSGERR BIT(22) /* DQS Gate Training Error */
#define PUB_PGSR0_WLAERR BIT(23) /* Write Leveling Adj Error */
#define PUB_PGSR0_RDERR BIT(24) /* Read Bit Deskew Error */
#define PUB_PGSR0_WDERR BIT(25) /* Write Bit Deskew Error */
#define PUB_PGSR0_REERR BIT(26) /* Read Eye Training Error */
#define PUB_PGSR0_WEERR BIT(27) /* Write Eye Training Error */
/* PUB_PIR: PHY init register */
#define PUB_PIR_INIT BIT(0)
#define PUB_PIR_ZCAL BIT(1)
#define PUB_PIR_CA BIT(2)
#define PUB_PIR_PLLINIT BIT(4)
#define PUB_PIR_DCAL BIT(5)
#define PUB_PIR_PHYRST BIT(6)
#define PUB_PIR_DRAMRST BIT(7)
#define PUB_PIR_DRAMINIT BIT(8)
#define PUB_PIR_WL BIT(9)
#define PUB_PIR_QSGATE BIT(10)
#define PUB_PIR_WLADJ BIT(11)
#define PUB_PIR_RDDSKW BIT(12)
#define PUB_PIR_WRDSKW BIT(13)
#define PUB_PIR_RDEYE BIT(14)
#define PUB_PIR_WREYE BIT(15)
#define PUB_PIR_ICPC BIT(16)
#define PUB_PIR_PLLBYP BIT(17)
#define PUB_PIR_CTLDINIT BIT(18)
#define PUB_PIR_RDIMMINIT BIT(19)
#define PUB_PIR_CLRSR BIT(27)
#define PUB_PIR_LOCKBYP BIT(28)
#define PUB_PIR_DCALBYP BIT(29)
#define PUB_PIR_ZCALBYP BIT(30)
#define PUB_PIR_INITBYP BIT(31)
#define PUB_PIR_FINAL_STEP (PUB_PIR_INIT | PUB_PIR_ZCAL | \
PUB_PIR_PLLINIT | PUB_PIR_DCAL | PUB_PIR_PHYRST | PUB_PIR_DRAMRST | \
PUB_PIR_DRAMINIT | PUB_PIR_WL | PUB_PIR_QSGATE | PUB_PIR_WLADJ | \
PUB_PIR_RDDSKW | PUB_PIR_WRDSKW | PUB_PIR_RDEYE | PUB_PIR_WREYE)
/* Struct which holds timings (see dram-settings-gx.h) */
struct meson_gx_dram_timings {
u8 drv;
u8 odt;
u8 rtp;
u8 wtr;
u8 rp;
u8 rcd;
u8 ras;
u8 rrd;
u8 rc;
u8 mrd;
u8 mod;
u8 faw;
u8 wlmrd;
u8 wlo;
ushort rfc;
u8 xp;
ushort xs;
ushort dllk;
u8 cke;
u8 rtodt;
u8 rtw;
u8 refi;
u8 refi_mddr3;
u8 cl;
u8 wr;
u8 cwl;
u8 al;
u8 dqs;
u8 cksre;
u8 cksrx;
u8 zqcs;
u8 xpdll;
ushort exsr;
ushort zqcl;
ushort zqcsi;
u8 rpab;
u8 rppb;
u8 tccdl;
u8 tdqsck;
u8 tdqsckmax;
u8 tckesr;
u8 tdpd;
u8 taond_aofd;
};
#if defined(CONFIG_MESON_GXBB)
# include <asm/arch/dram-gxbb.h>
#elif defined(CONFIG_MESON_GXL)
# include <asm/arch/dram-gxl.h>
#endif
/* Functions */
int dram_init(void);
void meson_dram_prepare_pctl(void);
void meson_dram_phy_init(void);
void meson_dram_phy_setup_ranks(void);
void meson_dram_finalise_init(void);
extern const struct meson_gx_dram_timings timings;
#endif

View File

@@ -0,0 +1,168 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#ifndef DRAM_GXBB_H
#define DRAM_GXBB_H
/* PUB (not much documented) */
#define DDR0_PUB_REG_BASE 0xc8836000
#define DDR0_PUB_PIR (DDR0_PUB_REG_BASE + (0x01 << 2))
#define DDR0_PUB_PGCR1 (DDR0_PUB_REG_BASE + (0x03 << 2))
#define DDR0_PUB_PGCR2 (DDR0_PUB_REG_BASE + (0x04 << 2))
#define DDR0_PUB_PGCR3 (DDR0_PUB_REG_BASE + (0x05 << 2))
#define DDR0_PUB_PGSR0 (DDR0_PUB_REG_BASE + (0x06 << 2))
#define DDR0_PUB_ACLCDLR (DDR0_PUB_REG_BASE + (0x0F << 2))
#define DDR0_PUB_ACBDLR0 (DDR0_PUB_REG_BASE + (0x10 << 2))
#define DDR0_PUB_ACIOCR1 (DDR0_PUB_REG_BASE + (0x1B << 2))
#define DDR0_PUB_ACIOCR2 (DDR0_PUB_REG_BASE + (0x1C << 2))
#define DDR0_PUB_ACIOCR3 (DDR0_PUB_REG_BASE + (0x1D << 2))
#define DDR0_PUB_ACIOCR4 (DDR0_PUB_REG_BASE + (0x1E << 2))
#define DDR0_PUB_ACIOCR5 (DDR0_PUB_REG_BASE + (0x1F << 2))
#define DDR0_PUB_DXCCR (DDR0_PUB_REG_BASE + (0x20 << 2))
#define DDR0_PUB_DSGCR (DDR0_PUB_REG_BASE + (0x21 << 2))
#define DDR0_PUB_DCR (DDR0_PUB_REG_BASE + (0x22 << 2))
#define DDR0_PUB_DTPR0 (DDR0_PUB_REG_BASE + (0x23 << 2))
#define DDR0_PUB_DTPR1 (DDR0_PUB_REG_BASE + (0x24 << 2))
#define DDR0_PUB_DTPR2 (DDR0_PUB_REG_BASE + (0x25 << 2))
#define DDR0_PUB_DTPR3 (DDR0_PUB_REG_BASE + (0x26 << 2))
#define DDR0_PUB_MR0 (DDR0_PUB_REG_BASE + (0x27 << 2))
#define DDR0_PUB_MR1 (DDR0_PUB_REG_BASE + (0x28 << 2))
#define DDR0_PUB_MR2 (DDR0_PUB_REG_BASE + (0x29 << 2))
#define DDR0_PUB_MR3 (DDR0_PUB_REG_BASE + (0x2A << 2))
#define DDR0_PUB_ODTCR (DDR0_PUB_REG_BASE + (0x2B << 2))
#define DDR0_PUB_DTCR (DDR0_PUB_REG_BASE + (0x2C << 2))
#define DDR0_PUB_DTAR0 (DDR0_PUB_REG_BASE + (0x2D << 2))
#define DDR0_PUB_DTAR1 (DDR0_PUB_REG_BASE + (0x2E << 2))
#define DDR0_PUB_DTAR2 (DDR0_PUB_REG_BASE + (0x2F << 2))
#define DDR0_PUB_DTAR3 (DDR0_PUB_REG_BASE + (0x30 << 2))
#define DDR0_PUB_IOVCR0 (DDR0_PUB_REG_BASE + (0x8E << 2))
#define DDR0_PUB_IOVCR1 (DDR0_PUB_REG_BASE + (0x8F << 2))
#define DDR0_PUB_ZQCR (DDR0_PUB_REG_BASE + (0x90 << 2))
#define DDR0_PUB_ZQ0PR (DDR0_PUB_REG_BASE + (0x91 << 2))
#define DDR0_PUB_ZQ1PR (DDR0_PUB_REG_BASE + (0x95 << 2))
#define DDR0_PUB_ZQ2PR (DDR0_PUB_REG_BASE + (0x99 << 2))
#define DDR0_PUB_ZQ3PR (DDR0_PUB_REG_BASE + (0x9D << 2))
#define DDR0_PUB_DX0GCR1 (DDR0_PUB_REG_BASE + (0xA1 << 2))
#define DDR0_PUB_DX0GCR2 (DDR0_PUB_REG_BASE + (0xA2 << 2))
#define DDR0_PUB_DX0GCR3 (DDR0_PUB_REG_BASE + (0xA3 << 2))
#define DDR0_PUB_DX0LCDLR0 (DDR0_PUB_REG_BASE + (0xAE << 2))
#define DDR0_PUB_DX0LCDLR2 (DDR0_PUB_REG_BASE + (0xB0 << 2))
#define DDR0_PUB_DX0GTR (DDR0_PUB_REG_BASE + (0xB2 << 2))
#define DDR0_PUB_DX1GTR (DDR0_PUB_REG_BASE + (0xD2 << 2))
#define DDR0_PUB_DX2GTR (DDR0_PUB_REG_BASE + (0xF2 << 2))
#define DDR0_PUB_DX3GTR (DDR0_PUB_REG_BASE + (0x112 << 2))
#define DDR0_PUB_DX1GCR1 (DDR0_PUB_REG_BASE + (0xC1 << 2))
#define DDR0_PUB_DX1GCR2 (DDR0_PUB_REG_BASE + (0xC2 << 2))
#define DDR0_PUB_DX1GCR3 (DDR0_PUB_REG_BASE + (0xC3 << 2))
#define DDR0_PUB_DX1LCDLR0 (DDR0_PUB_REG_BASE + (0xCE << 2))
#define DDR0_PUB_DX1LCDLR2 (DDR0_PUB_REG_BASE + (0xD0 << 2))
#define DDR0_PUB_DX2GCR1 (DDR0_PUB_REG_BASE + (0xE1 << 2))
#define DDR0_PUB_DX2GCR2 (DDR0_PUB_REG_BASE + (0xE2 << 2))
#define DDR0_PUB_DX2GCR3 (DDR0_PUB_REG_BASE + (0xE3 << 2))
#define DDR0_PUB_DX2LCDLR2 (DDR0_PUB_REG_BASE + (0xF0 << 2))
#define DDR0_PUB_DX3GCR1 (DDR0_PUB_REG_BASE + (0x101 << 2))
#define DDR0_PUB_DX3GCR2 (DDR0_PUB_REG_BASE + (0x102 << 2))
#define DDR0_PUB_DX3GCR3 (DDR0_PUB_REG_BASE + (0x103 << 2))
#define DDR0_PUB_DX3LCDLR0 (DDR0_PUB_REG_BASE + (0x10E << 2))
#define DDR0_PUB_DX3LCDLR2 (DDR0_PUB_REG_BASE + (0x110 << 2))
/* PCTL */
#define DDR0_PCTL_BASE 0xc8839000
/* DDR1_PCTL_BASE is DDR0_PCTL_BASE + 0x400 */
#define PCTL_SCFG (DDR0_PCTL_BASE + 0x000)
#define PCTL_SCTL (DDR0_PCTL_BASE + (0x1 << 2))
#define PCTL_STAT (DDR0_PCTL_BASE + (0x2 << 2))
#define PCTL_POWSTAT (DDR0_PCTL_BASE + (0x12 << 2))
#define PCTL_POWCTL (DDR0_PCTL_BASE + (0x11 << 2))
#define PCTL_CMDTSTAT (DDR0_PCTL_BASE + (0x13 << 2))
#define PCTL_CMDTSTATEN (DDR0_PCTL_BASE + (0x14 << 2))
#define PCTL_PPCFG (DDR0_PCTL_BASE + (0x21 << 2))
#define PCTL_MCFG (DDR0_PCTL_BASE + (0x20 << 2))
#define PCTL_MCFG1 (DDR0_PCTL_BASE + (0x1f << 2))
#define PCTL_TCKSRE (DDR0_PCTL_BASE + (0x49 << 2))
#define PCTL_TZQCSI (DDR0_PCTL_BASE + (0x47 << 2))
#define PCTL_TINIT (DDR0_PCTL_BASE + (0x31 << 2))
#define PCTL_TOGCNT1U (DDR0_PCTL_BASE + (0x30 << 2))
#define PCTL_TCKE (DDR0_PCTL_BASE + (0x4b << 2))
#define PCTL_TMOD (DDR0_PCTL_BASE + (0x4c << 2))
#define PCTL_TEXSR (DDR0_PCTL_BASE + (0x43 << 2))
#define PCTL_TAL (DDR0_PCTL_BASE + (0x39 << 2))
#define PCTL_TRTP (DDR0_PCTL_BASE + (0x40 << 2))
#define PCTL_TCKSRX (DDR0_PCTL_BASE + (0x4a << 2))
#define PCTL_TRTW (DDR0_PCTL_BASE + (0x38 << 2))
#define PCTL_TCWL (DDR0_PCTL_BASE + (0x3b << 2))
#define PCTL_TWR (DDR0_PCTL_BASE + (0x41 << 2))
#define PCTL_TCL (DDR0_PCTL_BASE + (0x3a << 2))
#define PCTL_TDQS (DDR0_PCTL_BASE + (0x48 << 2))
#define PCTL_TRSTH (DDR0_PCTL_BASE + (0x32 << 2))
#define PCTL_TRCD (DDR0_PCTL_BASE + (0x3e << 2))
#define PCTL_TXP (DDR0_PCTL_BASE + (0x44 << 2))
#define PCTL_TOGCNT100N (DDR0_PCTL_BASE + (0x33 << 2))
#define PCTL_TMRD (DDR0_PCTL_BASE + (0x35 << 2))
#define PCTL_TREFI (DDR0_PCTL_BASE + (0x34 << 2))
#define PCTL_TRAS (DDR0_PCTL_BASE + (0x3c << 2))
#define PCTL_TREFI_MEM_DDR3 (DDR0_PCTL_BASE + (0x52 << 2))
#define PCTL_TWTR (DDR0_PCTL_BASE + (0x42 << 2))
#define PCTL_TRC (DDR0_PCTL_BASE + (0x3d << 2))
#define PCTL_TRFC (DDR0_PCTL_BASE + (0x36 << 2))
#define PCTL_TCKESR (DDR0_PCTL_BASE + (0x50 << 2))
#define PCTL_TZQCL (DDR0_PCTL_BASE + (0x4e << 2))
#define PCTL_TRRD (DDR0_PCTL_BASE + (0x3f << 2))
#define PCTL_TRP (DDR0_PCTL_BASE + (0x37 << 2))
#define PCTL_TZQCS (DDR0_PCTL_BASE + (0x46 << 2))
#define PCTL_TXPDLL (DDR0_PCTL_BASE + (0x45 << 2))
#define PCTL_DFIODTCFG (DDR0_PCTL_BASE + (0x91 << 2))
#define PCTL_DFIODTCFG1 (DDR0_PCTL_BASE + (0x92 << 2))
#define PCTL_DFITCTRLDELAY (DDR0_PCTL_BASE + (0x90 << 2))
#define PCTL_DFITPHYWRLAT (DDR0_PCTL_BASE + (0x95 << 2))
#define PCTL_DFITPHYWRDATA (DDR0_PCTL_BASE + (0x94 << 2))
#define PCTL_DFITRDDATAEN (DDR0_PCTL_BASE + (0x98 << 2))
#define PCTL_DFITPHYRDLAT (DDR0_PCTL_BASE + (0x99 << 2))
#define PCTL_DFITPHYUPDTYPE1 (DDR0_PCTL_BASE + (0x9d << 2))
#define PCTL_DFISTCFG0 (DDR0_PCTL_BASE + (0xb1 << 2))
#define PCTL_DFISTCFG1 (DDR0_PCTL_BASE + (0xb2 << 2))
#define PCTL_DFISTSTAT0 (DDR0_PCTL_BASE + (0xb0 << 2))
#define PCTL_DFILPCFG0 (DDR0_PCTL_BASE + (0xbc << 2))
#define PCTL_DFITCTRLUPDMIN (DDR0_PCTL_BASE + (0xa0 << 2))
#define PCTL_DFITDRAMCLKEN (DDR0_PCTL_BASE + (0xb4 << 2))
#define PCTL_DFITDRAMCLKDIS (DDR0_PCTL_BASE + (0xb5 << 2))
/* DDR MMC (see dram-gx.h for more details) */
#define DDR_MMC_BASE 0xc8836800
#define DDR0_SOFT_RESET (DDR_MMC_BASE + 0x404)
#define DDR_CLK_CNTL (DDR_MMC_BASE + 0x18)
#define DDR0_APD_CTRL (DDR_MMC_BASE + 0x408)
/* These will get optimized out by the compiler */
#define AM_DDR_PLL_CNTL5 0
#define PCTL_TCCD 0
#define PCTL_TFAW 0
#endif

View File

@@ -0,0 +1,193 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#ifndef DRAM_GXL_H
#define DRAM_GXL_H
/* PUB (not much documented) */
#define DDR0_PUB_REG_BASE 0xc8836000
#define DDR0_PUB_PIR (DDR0_PUB_REG_BASE + (0x01 << 2))
#define DDR0_PUB_PGCR1 (DDR0_PUB_REG_BASE + (0x05 << 2))
#define DDR0_PUB_PGCR2 (DDR0_PUB_REG_BASE + (0x06 << 2))
#define DDR0_PUB_PGCR3 (DDR0_PUB_REG_BASE + (0x07 << 2))
#define DDR0_PUB_PGCR4 (DDR0_PUB_REG_BASE + (0x08 << 2))
#define DDR0_PUB_PGCR5 (DDR0_PUB_REG_BASE + (0x09 << 2))
#define DDR0_PUB_PGCR6 (DDR0_PUB_REG_BASE + (0x0a << 2))
#define DDR0_PUB_PGSR0 (DDR0_PUB_REG_BASE + (0x0d << 2))
#define DDR0_PUB_ACLCDLR (DDR0_PUB_REG_BASE + (0x160 << 2))
#define DDR0_PUB_ACMDLR0 (DDR0_PUB_REG_BASE + (0x168 << 2))
#define DDR0_PUB_ACBDLR0 (DDR0_PUB_REG_BASE + (0x150 << 2))
#define DDR0_PUB_ACBDLR1 (DDR0_PUB_REG_BASE + (0x151 << 2))
#define DDR0_PUB_ACBDLR2 (DDR0_PUB_REG_BASE + (0x152 << 2))
#define DDR0_PUB_ACBDLR3 (DDR0_PUB_REG_BASE + (0x153 << 2))
#define DDR0_PUB_ACBDLR6 (DDR0_PUB_REG_BASE + (0x156 << 2))
#define DDR0_PUB_ACBDLR7 (DDR0_PUB_REG_BASE + (0x157 << 2))
#define DDR0_PUB_ACBDLR8 (DDR0_PUB_REG_BASE + (0x158 << 2))
#define DDR0_PUB_ACBDLR9 (DDR0_PUB_REG_BASE + (0x159 << 2))
#define DDR0_PUB_ACIOCR1 (DDR0_PUB_REG_BASE + (0x141 << 2))
#define DDR0_PUB_ACIOCR2 (DDR0_PUB_REG_BASE + (0x142 << 2))
#define DDR0_PUB_ACIOCR3 (DDR0_PUB_REG_BASE + (0x143 << 2))
#define DDR0_PUB_ACIOCR4 (DDR0_PUB_REG_BASE + (0x144 << 2))
#define DDR0_PUB_ACIOCR5 (DDR0_PUB_REG_BASE + (0x145 << 2))
#define DDR0_PUB_PTR3 (DDR0_PUB_REG_BASE + (0x13 << 2))
#define DDR0_PUB_PTR4 (DDR0_PUB_REG_BASE + (0x14 << 2))
#define DDR0_PUB_DXCCR (DDR0_PUB_REG_BASE + (0x22 << 2))
#define DDR0_PUB_DSGCR (DDR0_PUB_REG_BASE + (0x24 << 2))
#define DDR0_PUB_DCR (DDR0_PUB_REG_BASE + (0x40 << 2))
#define DDR0_PUB_DTPR0 (DDR0_PUB_REG_BASE + (0x44 << 2))
#define DDR0_PUB_DTPR1 (DDR0_PUB_REG_BASE + (0x45 << 2))
#define DDR0_PUB_DTPR2 (DDR0_PUB_REG_BASE + (0x46 << 2))
#define DDR0_PUB_DTPR3 (DDR0_PUB_REG_BASE + (0x47 << 2))
#define DDR0_PUB_DTPR4 (DDR0_PUB_REG_BASE + (0x48 << 2))
#define DDR0_PUB_DTPR5 (DDR0_PUB_REG_BASE + (0x49 << 2))
#define DDR0_PUB_MR0 (DDR0_PUB_REG_BASE + (0x60 << 2))
#define DDR0_PUB_MR1 (DDR0_PUB_REG_BASE + (0x61 << 2))
#define DDR0_PUB_MR2 (DDR0_PUB_REG_BASE + (0x62 << 2))
#define DDR0_PUB_MR3 (DDR0_PUB_REG_BASE + (0x63 << 2))
#define DDR0_PUB_MR4 (DDR0_PUB_REG_BASE + (0x64 << 2))
#define DDR0_PUB_MR5 (DDR0_PUB_REG_BASE + (0x65 << 2))
#define DDR0_PUB_MR6 (DDR0_PUB_REG_BASE + (0x66 << 2))
#define DDR0_PUB_MR11 (DDR0_PUB_REG_BASE + (0x6b << 2))
#define DDR0_PUB_ODTCR (DDR0_PUB_REG_BASE + (0x26 << 2))
#define DDR0_PUB_DTCR (DDR0_PUB_REG_BASE + (0x80 << 2))
#define DDR0_PUB_DTCR1 (DDR0_PUB_REG_BASE + (0x81 << 2))
#define DDR0_PUB_DTAR0 (DDR0_PUB_REG_BASE + (0x82 << 2))
#define DDR0_PUB_DTAR1 (DDR0_PUB_REG_BASE + (0x83 << 2))
#define DDR0_PUB_DTAR2 (DDR0_PUB_REG_BASE + (0x84 << 2))
#define DDR0_PUB_DTAR3 (DDR0_PUB_REG_BASE + (0x85 << 2))
#define DDR0_PUB_RANKIDR (DDR0_PUB_REG_BASE + (0x137 << 2))
#define DDR0_PUB_IOVCR0 (DDR0_PUB_REG_BASE + (0x148 << 2))
#define DDR0_PUB_IOVCR1 (DDR0_PUB_REG_BASE + (0x149 << 2))
#define DDR0_PUB_VTCR0 (DDR0_PUB_REG_BASE + (0x14a << 2))
#define DDR0_PUB_VTCR1 (DDR0_PUB_REG_BASE + (0x14b << 2))
#define DDR0_PUB_ZQCR (DDR0_PUB_REG_BASE + (0x1a0 << 2))
#define DDR0_PUB_ZQ0PR (DDR0_PUB_REG_BASE + (0x1a1 << 2))
#define DDR0_PUB_ZQ1PR (DDR0_PUB_REG_BASE + (0x1a5 << 2))
#define DDR0_PUB_ZQ2PR (DDR0_PUB_REG_BASE + (0x1a9 << 2))
#define DDR0_PUB_ZQ3PR (DDR0_PUB_REG_BASE + (0x1ad << 2))
#define DDR0_PUB_DX0GCR1 (DDR0_PUB_REG_BASE + (0x1c1 << 2))
#define DDR0_PUB_DX0GCR2 (DDR0_PUB_REG_BASE + (0x1c2 << 2))
#define DDR0_PUB_DX0GCR3 (DDR0_PUB_REG_BASE + (0x1c3 << 2))
#define DDR0_PUB_DX0GCR4 (DDR0_PUB_REG_BASE + (0x1c4 << 2))
#define DDR0_PUB_DX0LCDLR0 (DDR0_PUB_REG_BASE + (0x1e0 << 2))
#define DDR0_PUB_DX0LCDLR2 (DDR0_PUB_REG_BASE + (0x1e2 << 2))
#define DDR0_PUB_DX0GTR (DDR0_PUB_REG_BASE + (0x1f0 << 2))
#define DDR0_PUB_DX1GTR (DDR0_PUB_REG_BASE + (0x230 << 2))
#define DDR0_PUB_DX2GTR (DDR0_PUB_REG_BASE + (0x270 << 2))
#define DDR0_PUB_DX3GTR (DDR0_PUB_REG_BASE + (0x2b0 << 2))
#define DDR0_PUB_DX1GCR1 (DDR0_PUB_REG_BASE + (0x201 << 2))
#define DDR0_PUB_DX1GCR2 (DDR0_PUB_REG_BASE + (0x202 << 2))
#define DDR0_PUB_DX1GCR3 (DDR0_PUB_REG_BASE + (0x203 << 2))
#define DDR0_PUB_DX1GCR4 (DDR0_PUB_REG_BASE + (0x204 << 2))
#define DDR0_PUB_DX1LCDLR0 (DDR0_PUB_REG_BASE + (0x220 << 2))
#define DDR0_PUB_DX1LCDLR2 (DDR0_PUB_REG_BASE + (0x222 << 2))
#define DDR0_PUB_DX2GCR0 (DDR0_PUB_REG_BASE + (0x240 << 2))
#define DDR0_PUB_DX2GCR1 (DDR0_PUB_REG_BASE + (0x241 << 2))
#define DDR0_PUB_DX2GCR2 (DDR0_PUB_REG_BASE + (0x242 << 2))
#define DDR0_PUB_DX2GCR3 (DDR0_PUB_REG_BASE + (0x243 << 2))
#define DDR0_PUB_DX2GCR4 (DDR0_PUB_REG_BASE + (0x244 << 2))
#define DDR0_PUB_DX2LCDLR0 (DDR0_PUB_REG_BASE + (0x260 << 2))
#define DDR0_PUB_DX2LCDLR2 (DDR0_PUB_REG_BASE + (0x262 << 2))
#define DDR0_PUB_DX3GCR0 (DDR0_PUB_REG_BASE + (0x280 << 2))
#define DDR0_PUB_DX3GCR1 (DDR0_PUB_REG_BASE + (0x281 << 2))
#define DDR0_PUB_DX3GCR2 (DDR0_PUB_REG_BASE + (0x282 << 2))
#define DDR0_PUB_DX3GCR3 (DDR0_PUB_REG_BASE + (0x283 << 2))
#define DDR0_PUB_DX3GCR4 (DDR0_PUB_REG_BASE + (0x284 << 2))
#define DDR0_PUB_DX3LCDLR0 (DDR0_PUB_REG_BASE + (0x2a0 << 2))
#define DDR0_PUB_DX3LCDLR2 (DDR0_PUB_REG_BASE + (0x2a2 << 2))
/* PCTL */
#define DMC_PCTL_BASE 0xc8839000
#define PCTL_SCFG (DDR0_PCTL_BASE + 0x000)
#define PCTL_SCTL (DDR0_PCTL_BASE + (0x1 << 2))
#define PCTL_STAT (DDR0_PCTL_BASE + (0x48 << 2))
#define PCTL_CMDTSTAT (DDR0_PCTL_BASE + (0x48 << 2))
#define PCTL_PPCFG (DDR0_PCTL_BASE + (0x43 << 2))
#define PCTL_ZQCFG (DDR0_PCTL_BASE + (0x44 << 2))
#define PCTL_MCFG (DDR0_PCTL_BASE + (0x41 << 2))
#define PCTL_MCFG1 (DDR0_PCTL_BASE + (0x42 << 2))
#define PCTL_TCKSRE (DDR0_PCTL_BASE + (0x1a << 2))
#define PCTL_TZQCSI (DDR0_PCTL_BASE + (0x19 << 2))
#define PCTL_TCKE (DDR0_PCTL_BASE + (0x1c << 2))
#define PCTL_TMOD (DDR0_PCTL_BASE + (0x1d << 2))
#define PCTL_TEXSR (DDR0_PCTL_BASE + (0x15 << 2))
#define PCTL_TAL (DDR0_PCTL_BASE + (0x50 << 2))
#define PCTL_TCCD (DDR0_PCTL_BASE + (0x52 << 2))
#define PCTL_TRTP (DDR0_PCTL_BASE + (0x12 << 2))
#define PCTL_TFAW (DDR0_PCTL_BASE + (0x11 << 2))
#define PCTL_TCKSRX (DDR0_PCTL_BASE + (0x1b << 2))
#define PCTL_TRTW (DDR0_PCTL_BASE + (0x9 << 2))
#define PCTL_TCWL (DDR0_PCTL_BASE + (0xc << 2))
#define PCTL_TWR (DDR0_PCTL_BASE + (0x13 << 2))
#define PCTL_TCL (DDR0_PCTL_BASE + (0xb << 2))
#define PCTL_TDQS (DDR0_PCTL_BASE + (0x1e << 2))
#define PCTL_TRCD (DDR0_PCTL_BASE + (0xf << 2))
#define PCTL_TXP (DDR0_PCTL_BASE + (0x16 << 2))
#define PCTL_TMRD (DDR0_PCTL_BASE + (0x6 << 2))
#define PCTL_TRAS (DDR0_PCTL_BASE + (0xd << 2))
#define PCTL_TREFI_MEM_DDR3 (DDR0_PCTL_BASE + (0x24 << 2)) // replaced by TREFI
#define PCTL_TWTR (DDR0_PCTL_BASE + (0x14 << 2))
#define PCTL_TRC (DDR0_PCTL_BASE + (0xe << 2))
#define PCTL_TRFC (DDR0_PCTL_BASE + (0x7 << 2))
#define PCTL_TCKESR (DDR0_PCTL_BASE + (0x22 << 2))
#define PCTL_TZQCL (DDR0_PCTL_BASE + (0x20 << 2))
#define PCTL_TRRD (DDR0_PCTL_BASE + (0x10 << 2))
#define PCTL_TRP (DDR0_PCTL_BASE + (0x8 << 2))
#define PCTL_TZQCS (DDR0_PCTL_BASE + (0x18 << 2))
#define PCTL_TXPDLL (DDR0_PCTL_BASE + (0x17 << 2))
#define PCTL_DFIODTCFG (DDR0_PCTL_BASE + (0x27 << 2))
#define PCTL_DFIODTCFG1 (DDR0_PCTL_BASE + (0x28 << 2))
#define PCTL_DFITCTRLDELAY (DDR0_PCTL_BASE + (0x26 << 2))
#define PCTL_DFITPHYWRLAT (DDR0_PCTL_BASE + (0x2b << 2))
#define PCTL_DFITPHYWRDATA (DDR0_PCTL_BASE + (0x2a << 2))
#define PCTL_DFITRDDATAEN (DDR0_PCTL_BASE + (0x2c << 2))
#define PCTL_DFITPHYRDLAT (DDR0_PCTL_BASE + (0x2d << 2))
#define PCTL_DFITPHYUPDTYPE0 (DDR0_PCTL_BASE + (0x2e << 2))
#define PCTL_DFITPHYUPDTYPE1 (DDR0_PCTL_BASE + (0x2f << 2))
#define PCTL_DFIUPDCFG (DDR0_PCTL_BASE + (0x35 << 2))
#define PCTL_DFISTCFG0 (DDR0_PCTL_BASE + (0x3c << 2))
#define PCTL_DFISTCFG1 (DDR0_PCTL_BASE + (0x3d << 2))
#define PCTL_DFISTSTAT0 (DDR0_PCTL_BASE + (0x46 << 2))
#define PCTL_DFILPCFG0 (DDR0_PCTL_BASE + (0x40 << 2))
#define PCTL_DFITCTRLUPDMIN (DDR0_PCTL_BASE + (0x32 << 2))
#define PCTL_DFITCTRLUPDMAX (DDR0_PCTL_BASE + (0x33 << 2))
#define PCTL_DFITDRAMCLKEN (DDR0_PCTL_BASE + (0x3e << 2))
#define PCTL_DFITDRAMCLKDIS (DDR0_PCTL_BASE + (0x3f << 2))
/* DDR MMC (see dram-gx.h for more details) */
#define DDR_MMC_BASE 0xc8837000
#define DDR0_SOFT_RESET (DDR_MMC_BASE + 0x20)
#define AM_DDR_PLL_STS (DDR_MMC_BASE + 0x18)
#define DDR_CLK_CNTL (DDR_MMC_BASE + 0x1c)
#define DDR0_APD_CTRL (DDR_MMC_BASE + 0x24)
#endif

View File

@@ -0,0 +1,296 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2023-2024, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#ifndef DRAM_SETTINGS_GX_H
#define DRAM_SETTINGS_GX_H
#include <linux/bitops.h>
#include <asm/arch/dram-gx.h>
/*
* These registers are pretty similar to other DRAM registers found in
* Allwinner A31/sun6i. Some of these registers also exist in some Rockchip
* SoCs and the TI KeyStone3.
*/
/* DMC control register */
#if defined(CONFIG_DRAM_TWO_IDENTICAL_RANKS) || defined(CONFIG_DRAM_ONE_RANK)
#define DMC_DRAM_SIZE_SHIFT 6
#else
#define DMC_DRAM_SIZE_SHIFT 7
#endif
#define DMC_CTRL_CHANNEL BIT(6) /* Channel 0 only */
#if defined(CONFIG_DRAM_DDR4)
#define DMC_CTRL_DDR_TYPE BIT(22) | BIT(20) /* DDR4 */
#else
#define DMC_CTRL_DDR_TYPE 0
#endif
#if defined(CONFIG_DRAM_ONE_RANK) || defined(CONFIG_DRAM_TWO_DIFF_RANKS)
#define DMC_CTRL_RANK BIT(21) /* Enable rank 1 */
#elif defined(CONFIG_DRAM_TWO_IDENTICAL_RANKS)
#define DMC_CTRL_RANK BIT(22) /* Rank 0 and 1 are identical */
#elif defined(CONFIG_DRAM_16BIT_RANK)
#define DMC_CTRL_RANK BIT(16) /* 16-bit Rank 0 */
#endif
#define DMC_CTRL DMC_CTRL_CHANNEL | DMC_CTRL_RANK | DMC_CTRL_DDR_TYPE
/* Mode Register */
#if defined(CONFIG_MESON_GXL) && defined(CONFIG_DRAM_DDR4)
#define PUB_MR0 4 | (((((timings.cl - 9) >> 1) & 7) << 4)) | \
((((timings.wr - 10) >> 1) & 7) << 9)
#define PUB_MR1 (timings.odt << 8) | (timings.drv << 1) | 0x81
#define PUB_MR2 (((timings.cwl - 6) >> 1) & 7) << 3 | 0xc0
#define PUB_MR3 0
#define PUB_MR4 8
#else
#define PUB_MR0 (((timings.cl - 4) & 8) >> 1) | \
(((timings.cl - 4) & 7) << 4) | \
(((timings.wr <= 8 ? (timings.wr - 4) : (timings.wr >> 1)) & 7) << 9) | 0x1c00
#define PUB_MR1 (timings.drv << 1) | \
((timings.odt & 1) << 2) | \
(((timings.odt >> 1) & 1) << 6) | \
(((timings.odt >> 2) & 1) << 9) | \
BIT(7) | \
((timings.al ? ((timings.cl - timings.al) & 3) : 0) << 3)
#define PUB_MR2 BIT(6) | (((timings.cwl - 5) & 7) << 3)
#endif
#define PUB_MR3 0
#if defined(CONFIG_MESON_GXL)
#if defined(CONFIG_DRAM_DDR3)
#define PUB_MR4 0
#define PUB_MR5 0x420
#elif defined(CONFIG_DRAM_DDR4)
#define PUB_MR5 0x400
#endif
#define PUB_MR6 0x800
#endif
/* ODT Configuration Register */
#if defined(CONFIG_MESON_GXBB)
#define PUB_ODTCR 0x210000
#elif defined(CONFIG_MESON_GXL)
#define PUB_ODTCR 0x30000
#endif
/* DDR Timing Parameter */
#if defined(CONFIG_MESON_GXBB)
#define PUB_DTPR0 timings.rtp | \
(timings.wtr << 4) | \
(timings.rp << 8) | \
(timings.ras << 16) | \
(timings.rrd << 22) | \
(timings.rcd << 26)
#define PUB_DTPR1 (timings.mod << 2) | \
(timings.faw << 5) | \
(timings.rfc << 11) | \
(timings.wlmrd << 20) | \
(timings.wlo << 26)
#define PUB_DTPR2 timings.xs | \
(timings.xp << 10) | \
(timings.dllk << 19)
#define PUB_DTPR3 0 | \
(0 << 3) | \
(timings.rc << 6) | \
(timings.cke << 13) | \
(timings.mrd << 18) | \
(0 << 29)
#elif defined(CONFIG_MESON_GXL)
#define PUB_DTPR0 timings.rtp | \
(timings.rp << 8) | \
(timings.ras << 16) | \
(timings.rrd << 24)
#define PUB_DTPR1 (timings.wlmrd << 24) | \
(timings.faw << 16) | \
timings.mrd
#define PUB_DTPR2 timings.xs | \
(timings.cke << 16)
#define PUB_DTPR3 (timings.dllk << 16) | (4 << 28)
#define PUB_DTPR4 timings.xp | BIT(11) | (timings.rfc << 0x10)
#define PUB_DTPR5 (timings.rc << 16) | (timings.rcd << 8) | \
timings.wtr
#endif
#if defined(CONFIG_MESON_GXBB)
#define PUB_PGCR0 0x7D81E3F
#define PUB_PGCR1 0x380C6A0
#define PUB_PGCR2 (0x1F12480 & 0xefffffff)
#define PUB_PGCR3 0xC0AAFE60
#elif defined(CONFIG_MESON_GXL)
#define PUB_PGCR0 0x7d81e3f
#define PUB_PGCR1 0x2004620
#define PUB_PGCR2 (0xf05f97 & 0xefffffff)
#if defined(CONFIG_DRAM_DDR3)
#define PUB_PGCR3 0xc0aae860
#elif defined(CONFIG_DRAM_DDR4)
#define PUB_PGCR3 0xc0aae860 | 0x4000000
#endif
#endif
#if defined(CONFIG_MESON_GXBB)
#define PUB_DXCCR 0x181884
#define PUB_DTCR 0x4300308f
#define PUB_DSGCR 0x20645A
#define PUB_ZQ0PR 0x69
#define PUB_ZQ1PR 0x69
#define PUB_ZQ2PR 0x69
#define PUB_ZQ3PR 0x69
#elif defined(CONFIG_MESON_GXL)
#define PUB_DXCCR 0x20c01204
#if defined(CONFIG_DRAM_DDR4)
#define PUB_DTCR 0x80003187 | 0x40
#else
#define PUB_DTCR 0x80003187
#endif
#define PUB_DTCR1 0x00010237 /* XXX: Needed? */
#define PUB_DSGCR (0x20641b | 0x800004) /* Works on DDR4 too? */
#if defined(CONFIG_DRAM_DDR3)
#define PUB_ZQ0PR 0x5d95d
#define PUB_ZQ1PR 0x5d95d
#define PUB_ZQ2PR 0x5d95d
#define PUB_ZQ3PR 0x1dd1d
#elif defined(CONFIG_DRAM_DDR4)
#define PUB_ZQ0PR 0x775d
#define PUB_ZQ1PR 0x6fc5d
#define PUB_ZQ2PR 0x6fc5d
#define PUB_ZQ3PR 0x1dd1d
#endif
#endif
#if defined(CONFIG_DRAM_DDR3)
#define PUB_DCR 0xb
#elif defined(CONFIG_DRAM_DDR4)
#define PUB_DCR 0x1800040c
#endif
#define PUB_DTAR (0 | (0 << 12) | (0 << 28)) /* Uh? */
#define PCTL0_1US_PCK 0x1C8
#define PCTL0_100NS_PCK 0x2D
#define PCTL0_INIT_US 0x2
#define PCTL0_RSTH_US 0x2
/* Mode Config(?) */
#if defined(CONFIG_MESON_GXBB)
#define PCTL0_MCFG ((((timings.faw + timings.rrd - 1) / timings.rrd) & 3) << 0x12) | \
(0xa2f21 & 0xfff3ffff)
#define PCTL0_MCFG1 (((timings.rrd - ((timings.faw - (timings.faw / timings.rrd) * \
timings.rrd) & 0xff)) & 7) << 8) | \
(0x80200000 & 0xfffffcff)
#elif defined(CONFIG_MESON_GXL)
#if defined(CONFIG_DRAM_DDR3)
#define PCTL0_MCFG_DDRTYPE 0
#elif defined(CONFIG_DRAM_DDR4)
#define PCTL0_MCFG_DDRTYPE BIT(4)
#endif
#define PCTL0_MCFG (0xa2f21 & 0xffffff8f) | PCTL0_MCFG_DDRTYPE
/* XXX: What is this? ↓ ??? */
#define PCTL0_MCFG1 0
#endif
#define PCTL0_SCFG 0xF01
#if defined(CONFIG_MESON_GXL) && defined(CONFIG_DRAM_16BIT_RANK)
#define PCTL0_PPCFG 0x1fd
#else
#define PCTL0_PPCFG 0x1e0
#endif
#define PCTL0_DFISTCFG0 0x4
#define PCTL0_DFISTCFG1 0x1
#define PCTL0_DFITCTRLDELAY 0x2
#if defined(CONFIG_MESON_GXBB)
#define PCTL0_DFITPHYWRDATA 0x1
#else
#define PCTL0_DFITPHYWRDATA 0x2
#endif
#if defined(CONFIG_MESON_GXBB)
#define PCTL0_DFITPHYWRLTA (timings.cwl + timings.al - \
(((timings.cwl + timings.al) % 2) ? 3 : 4)) / 2
#define PCTL0_DFITRDDATAEN (timings.cl + timings.al - \
(((timings.cl + timings.al) % 2) ? 3 : 4)) / 2
#define PCTL0_DFITPHYRDLAT ((timings.cl + timings.al) % 2) ? 14 : 16
#elif defined(CONFIG_MESON_GXL)
#define PCTL0_DFITPHYWRLTA ((timings.cwl + timings.al) - 2)
#define PCTL0_DFITRDDATAEN ((timings.cl + timings.al) - 4)
#define PCTL0_DFITPHYRDLAT 0x16
#endif
#define PCTL0_DFITDRAMCLKDIS 1
#define PCTL0_DFITDRAMCLKEN 1
#if defined(CONFIG_MESON_GXBB)
#define PCTL0_DFITPHYUPDTYPE1 0x200
#else
#define PCTL0_DFITPHYUPDTYPE0 16
#define PCTL0_DFITPHYUPDTYPE1 16
#define PCTL0_DFITCTRLUPDMAX 64
#define PCTL0_DFIUPDCFG 3
#endif
#define PCTL0_DFITCTRLUPDMIN 16
#define PCTL0_CMDTSTATEN 1
#if defined(CONFIG_DRAM_ONE_RANK) || defined(CONFIG_DRAM_16BIT_RANK)
#define PCTL0_DFIODTCFG 0x808
#elif defined(CONFIG_DRAM_TWO_DIFF_RANKS)
#define PCTL0_DFIODTCFG 0xc0c
#elif defined(CONFIG_DRAM_TWO_IDENTICAL_RANKS)
#define PCTL0_DFIODTCFG 0x8
#endif
#if defined(CONFIG_MESON_GXBB)
#define PCTL0_DFIODTCFG1 (0 | (6 << 16))
#elif defined(CONFIG_MESON_GXL)
#if defined(CONFIG_DRAM_16BIT_RANK)
#define PCTL0_DFIODTCFG1 ((6 << 16) | (8 << 16))
#else
#define PCTL0_DFIODTCFG1 ((6 << 16) | (3 << 25) | (8 << 16))
#endif
#endif
#define PCTL0_DFILPCFG0 (1 | (3 << 4) | BIT(8) | (3 << 12) | \
(7 << 16) | BIT(24) | (3 << 28))
#if defined(CONFIG_MESON_GXBB)
#define PUB_ACBDLR0 0x10
#elif defined(CONFIG_MESON_GXL)
#if defined(CONFIG_DRAM_DDR3)
#define PUB_ACBDLR0 0
#define PUB_ACBDLR3 0
#define PUB_ACLCDLR 48
#elif defined(CONFIG_DRAM_DDR4)
#define PUB_ACBDLR0 0x3f
#define PUB_ACBDLR3 0x10
#define PUB_ACLCDLR 0x28
#else
#define PUB_ACBDLR0 0
#define PUB_ACBDLR3 0
#define PUB_ACLCDLR 48
#endif
#endif
#define LPDDR3_CA0 2
#define LPDDR3_CA1 0
#define LPDDR3_REMAP 3
#define LPDDR3_WL 1
/* PLL */
#if defined(CONFIG_MESON_GXBB)
#define DDR_PLL_CNTL1 0x69c80000
#define DDR_PLL_CNTL2 0xca463823
#define DDR_PLL_CNTL3 0xc00023
#define DDR_PLL_CNTL4 0x303500
#define DDR_PLL_CNTL5 0 /* Unused */
#elif defined(CONFIG_MESON_GXL)
#define DDR_PLL_CNTL1 0xaa203
#define DDR_PLL_CNTL2 0x2919a288
#define DDR_PLL_CNTL3 0x3e3b744
#define DDR_PLL_CNTL4 0xc0101
#define DDR_PLL_CNTL5 0xe600001e
#endif
#endif /* DRAM_SETTINGS_GX_H */

View File

@@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2024, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#ifndef DRAM_TIMINGS_GX_H
#define DRAM_TIMINGS_GX_H
/*
* DRAM timings
* It looks like those are quite similar in regular boards based on reference
* designs and not using counterfeit RAM chips. Those are hacked around by lowbin
* TV box vendors to support lowbin RAM chips, however. Here, we are hardcoding
* timings, which *will* cause issues on lowbin boards, but should be fine on other
* boards derived from Amlogic reference designs.
*/
/*
* TODO:
* - Add timings for different DRAM clocks
* - Support overwriting those if board needs different timings (how?)
* - Other things
*/
#if defined(CONFIG_DRAM_DDR3)
/* DDR3: 912 MHz */
const struct meson_gx_dram_timings timings = {
.drv = 0,
.odt = 2,
/* Timings */
.rtp = 0x7,
.wtr = 0x7,
.rp = 0xd,
.rcd = 0xd,
.ras = 0x25,
.rrd = 0x7,
.rc = 0x34,
.mrd = 0x6, /* Should be < 8 */
.mod = 0x4,
.faw = 0x21,
.wlmrd = 0x28,
.wlo = 0x7,
.rfc = 0x118,
.xp = 0x7,
.xs = 0x200,
.dllk = 0x200,
.cke = 0x5,
.rtodt = 0x0,
.rtw = 0x7,
.refi = 0x4e,
.refi_mddr3 = 0x4,
.cl = 0xd,
.wr = 0x10,
.cwl = 0x9,
.al = 0x0,
.dqs = 0x17,
.cksre = 0xf,
.cksrx = 0xf,
.zqcs = 0x40,
.xpdll = 0x17,
.exsr = 0x200, /* Should be < 0x3ff */
.zqcl = 0x88,
.zqcsi = 0x3e8,
.rpab = 0x0,
.rppb = 0x0,
.tdqsck = 0x0,
.tdqsckmax = 0x0,
.tckesr = 0x0,
.tdpd = 0x0,
.taond_aofd = 0x0,
.tccdl = 0, /* Unused on GXBB */
};
#elif defined(CONFIG_DRAM_DDR4)
/* DDR4: 1080 MHz */
const struct meson_gx_dram_timings timings = {
.drv = 1,
.odt = 1,
/* Timings */
.rtp = 9,
.wtr = 9,
.rp = 0x10, // ddr_clk < 1200
.rcd = 0x10, // ddr_clk < 1200
.ras = 35 * 1.2,
.rrd = 6,
.rc = 0x3a,
.mrd = 8,
.mod = 24,
.faw = 35 * 1.2,
.rfc = 350 * 1.2,
.wlmrd = 40,
.wlo = 9.5 * 1.2,
.xs = 512,
.xp = 7,
.cke = 5,
.dllk = 1024,
.rtodt = 0,
.rtw = 8,
.refi = 76,
.refi_mddr3 = 4,
.cl = 0x10, // ddr_clk < 1200
.wr = 0x12,
.cwl = 12,
.al = 0,
.exsr = 1024,
.dqs = 9,
.cksre = 15,
.cksrx = 15,
.zqcs = 128,
.zqcl = 256,
.xpdll = 23,
.zqcsi = 1000,
.tccdl = 6, // ddr_clk < 1200
};
#endif
#endif

View File

@@ -12,7 +12,10 @@
#define GX_FIRMWARE_MEM_SIZE 0x1000000
#define GX_MB_SRAM_BASE 0xd9013800
#define GX_AOBUS_BASE 0xc8100000
#define GX_SEC_HIU_MB_BASE 0xda83c400
#define GX_SEC_AOBUS_BASE 0xda100000
#define GX_PERIPHS_BASE 0xc8834400
#define GX_HIU_BASE 0xc883c000
#define GX_ETH_BASE 0xc9410000
@@ -24,6 +27,10 @@
#define GX_AO_SEC_GP_CFG3 GX_AO_ADDR(0x93)
#define GX_AO_SEC_GP_CFG4 GX_AO_ADDR(0x94)
#define GX_AO_SEC_GP_CFG5 GX_AO_ADDR(0x95)
#define GX_AO_SEC_SD_CFG15 GX_AO_ADDR(0x8f)
#define GX_SEC_AO_ADDR(off) (GX_SEC_AOBUS_BASE + ((off) << 2))
#define GX_SEC_AO_SEC_GP_CFG0 GX_SEC_AO_ADDR(0x90)
#define GX_AO_BOOT_DEVICE 0xF
#define GX_AO_MEM_SIZE_MASK 0xFFFF0000
@@ -41,4 +48,38 @@
#define GX_GPIO_IN(n) GX_PERIPHS_ADDR(_GX_GPIO_OFF(n) + 1)
#define GX_GPIO_OUT(n) GX_PERIPHS_ADDR(_GX_GPIO_OFF(n) + 2)
/* Mailbox registers */
#define GX_SEC_HIU_MB_ADDR(off) (GX_SEC_HIU_MB_BASE + ((off) << 2))
#define GX_SEC_HIU_MAILBOX_SET_0 GX_SEC_HIU_MB_ADDR(0x01)
#define GX_SEC_HIU_MAILBOX_STAT_0 GX_SEC_HIU_MB_ADDR(0x02)
#define GX_SEC_HIU_MAILBOX_CLR_0 GX_SEC_HIU_MB_ADDR(0x03)
/* Mailbox commands */
#define GX_MB_CMD_SHA 0xc0de0001
#define GX_MB_CMD_DATA 0xc0dec0de
#define GX_MB_CMD_END 0xe00de00d
#define GX_MB_CMD_OP_SHA 0xc0de0002
#define GX_MB_CMD_DATA_LEN 0xc0dec0d0
/* PIN_MUX registers */
#define GX_PIN_MUX_REG1 (0xda834400 + (0x2d << 2))
#define GX_PIN_MUX_REG2 (0xda834400 + (0x2e << 2))
#define GX_PIN_MUX_REG3 (0xda834400 + (0x2f << 2))
#define GX_PIN_MUX_REG7 (0xda834400 + (0x33 << 2))
/* PWM registers */
#define GX_PWM_PWM_B (0xc1100000 + (0x2155 << 2))
#define GX_PWM_PWM_D (0xc1100000 + (0x2195 << 2))
#define GX_PWM_MISC_REG_CD (0xc1100000 + (0x2196 << 2))
#define GX_PWM_MISC_REG_AB (0xc1100000 + (0x2156 << 2))
/* Non-DM MMC init */
#if CONFIG_IS_ENABLED(MMC) && !CONFIG_IS_ENABLED(DM_MMC)
struct mmc *meson_mmc_init(int mmc_no);
#endif
#if !CONFIG_IS_ENABLED(WDT_MESON_GXBB) && defined(CONFIG_SPL_BUILD)
#define GX_WDT_CTRL_REG 0xc11098d0
#endif
#endif /* __GX_H__ */

View File

@@ -17,6 +17,8 @@ config MESON64_COMMON
config MESON_GX
bool
select MESON64_COMMON
select SUPPORT_SPL
select BINMAN if SPL
choice
prompt "Platform select"
@@ -69,7 +71,7 @@ config SYS_SOC
default "meson"
config SYS_MALLOC_F_LEN
default 0x1000
default 0x2000
config SYS_VENDOR
string "Vendor name"
@@ -93,4 +95,112 @@ config SYS_BOARD
Based on this option board/<CONFIG_SYS_VENDOR>/<CONFIG_SYS_BOARD> will
be used.
if MESON_GX && SPL
config SPL_SYS_MALLOC_F_LEN
default 0x2000
choice
prompt "DRAM rank mode"
help
Choose rank mode. This heavily depends on the board and you should
leave the board default set if you don't know what this is.
If you choose the wrong rank mode DRAM init in SPL may either fail
or in rare occasions require multiple resets before it succeeds.
config DRAM_ONE_RANK
bool "One rank"
config DRAM_TWO_IDENTICAL_RANKS
bool "Two identical ranks"
if MESON_GXBB
config DRAM_TWO_DIFF_RANKS
bool "Two different ranks"
endif
if MESON_GXL
config DRAM_16BIT_RANK
bool "One 16-bit rank"
endif
endchoice
choice
prompt "DRAM memory type"
default DRAM_DDR3
help
Select the DDR type according to your board design. GXBB/S905
currently only supports DDR3.
config DRAM_DDR3
bool "DDR3"
if MESON_GXL
config DRAM_DDR4
bool "DDR4"
endif
endchoice
config DRAM_DQS_CORR
bool "Enable DQS correction"
config DRAM_CLK
int "DRAM clock"
default 912
help
This option contains the DRAM clock to use in MHz.
config DRAM_SIZE
int "DRAM size"
default 1024
help
This option contains the DRAM size. Units in MB.
choice
prompt "Enable DRAM 2T mode"
default DRAM_1T_MODE
help
Choose whenever to use 2T mode or not.
config DRAM_1T_MODE
bool "Use DRAM 1T mode"
config DRAM_2T_MODE
bool "Use DRAM 2T mode"
endchoice
choice
prompt "Set VDDEE init voltage"
default SPL_MESON_GX_VDDEE_1000MV
help
This option is used to set the VDDEE voltage on boot up.
If unsure, leave it to the board default.
config SPL_MESON_GX_VDDEE_1000MV
bool "Set VDDEE to 1000 mv"
config SPL_MESON_GX_VDDEE_1100MV
bool "Set VDDEE to 1100 mv"
endchoice
choice
prompt "Set VCCK init voltage"
default SPL_MESON_GX_VCCK_1100MV
help
This option is used to set the VCCK voltage on boot up.
If unsure, leave it to the board default.
config SPL_MESON_GX_VCCK_1000MV
bool "Set VCCK to 1000 mv"
config SPL_MESON_GX_VCCK_1100MV
bool "Set VCCK to 1100 mv"
config SPL_MESON_GX_VCCK_1120MV
bool "Set VCCK to 1120 mv"
endchoice
endif
endif

View File

@@ -2,8 +2,18 @@
#
# Copyright (c) 2016 Beniamino Galvani <b.galvani@gmail.com>
obj-y += board-common.o sm.o board-info.o
obj-y += board-common.o sm.o board-info.o capsule.o
obj-$(CONFIG_MESON_GX) += board-gx.o
ifeq ($(CONFIG_SPL_BUILD),y)
obj-$(CONFIG_MESON_GXBB) += dram-gxbb.o
obj-$(CONFIG_MESON_GXL) += dram-gxl.o
obj-$(CONFIG_MESON_GX) += dram-gx.o
obj-$(CONFIG_MESON_GXBB) += spl-gxbb.o
obj-$(CONFIG_MESON_GXL) += spl-gxl.o
obj-$(CONFIG_MESON_GX) += spl-gx.o
obj-$(CONFIG_MESON_GX) += spl.o
endif
obj-$(CONFIG_MESON_AXG) += board-axg.o
obj-$(CONFIG_MESON_G12A) += board-g12a.o
obj-$(CONFIG_MESON_A1) += board-a1.o

View File

@@ -30,6 +30,7 @@ __weak int board_init(void)
return 0;
}
#ifndef CONFIG_SPL_BUILD
int dram_init(void)
{
const fdt64_t *val;
@@ -49,6 +50,7 @@ int dram_init(void)
return 0;
}
#endif
__weak int meson_ft_board_setup(void *blob, struct bd_info *bd)
{
@@ -145,10 +147,24 @@ int board_late_init(void)
{
meson_set_boot_source();
if (CONFIG_IS_ENABLED(DFU) && CONFIG_IS_ENABLED(EFI_LOADER)) {
/* Generate dfu_string for EFI capsule updates */
meson_setup_capsule();
}
return meson_board_late_init();
}
void reset_cpu(void)
{
#if CONFIG_SPL_BUILD
/*
* We do not have BL31 running yet, so no PSCI.
* Instead, let the watchdog reset the board.
*/
for (;;)
;
#else
psci_system_reset();
#endif
}

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <asm/arch/boot.h>
#include <dm.h>
#include <efi_loader.h>
#include <mmc.h>
/*
* To be able to support multiple devices and flash to the correct one we need
* to automatically generate the dfu_string and fw_name to match the device we
* are booted from. This is done by meson_setup_capsule() which is then called
* in board_late_init(). Right now we support EFI capsule updates on SPI flash,
* eMMC and SD cards.
*/
struct efi_fw_image fw_images[] = {
{
.image_index = 1,
},
};
struct efi_capsule_update_info update_info = {
.dfu_string = NULL, /* to be set in meson_capsule_setup */
.num_images = ARRAY_SIZE(fw_images),
.images = fw_images,
};
/*
* TODO: Support usecase e.g. FIT image on eMMC + SPL on SD.
*/
void meson_setup_capsule(void)
{
static char dfu_string[32] = { 0 };
int mmc_devnum = 0; /* mmc0 => SD card */
u32 max_size = 0x2000; /* 4 MB (MMC sectors are 512 bytes each) */
u32 offset = 0x1; /* offset for flashing to eMMC/SD */
int boot_device = meson_get_boot_device();
switch (boot_device) {
case BOOT_DEVICE_EMMC:
mmc_devnum = 1; /* mmc1 is always eMMC */
fallthrough;
case BOOT_DEVICE_SD:
snprintf(dfu_string, 32, "mmc %d=u-boot.bin raw %d %d", mmc_devnum, offset, max_size);
fw_images[0].fw_name = u"U_BOOT_MESON_MMC";
break;
case BOOT_DEVICE_SPI:
/* We assume there's only one SPI flash */
fw_images[0].fw_name = u"U_BOOT_MESON_SPI";
snprintf(dfu_string, 32, "sf 0:0=u-boot.bin raw 0 %d", max_size);
break;
default:
debug("setup_capsule: Boot device %d unsupported\n", boot_device);
return;
}
debug("EFI Capsule DFU string: %s", dfu_string);
update_info.dfu_string = dfu_string;
}

View File

@@ -0,0 +1,419 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <init.h>
#include <asm/unaligned.h>
#include <linux/libfdt.h>
#include <config.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/dram-gx.h>
#include <asm/arch/gx.h>
#include <asm/arch/clock-gx.h>
#include <asm/arch/dram-settings-gx.h>
#include <asm/arch/dram-timings-gx.h>
#include <linux/delay.h>
/*
* Meson GX common shared DRAM init code
*
* See dram-gxbb.c and dram-gxl.c for gxbb/gxl-specific code
*/
void meson_dram_pll_init(void)
{
setbits_32(AM_ANALOG_TOP_REG1, 1);
setbits_32(GX_HIU_BASE + HHI_MPLL_CNTL5, 1);
clrbits_32(AM_DDR_PLL_CNTL4, BIT(12));
setbits_32(AM_DDR_PLL_CNTL4, BIT(12));
udelay(10);
do {
if (IS_ENABLED(CONFIG_MESON_GXBB))
writel(1 << 29, AM_DDR_PLL_CNTL0);
writel(DDR_PLL_CNTL1, AM_DDR_PLL_CNTL1);
writel(DDR_PLL_CNTL2, AM_DDR_PLL_CNTL2);
writel(DDR_PLL_CNTL3, AM_DDR_PLL_CNTL3);
writel(DDR_PLL_CNTL4, AM_DDR_PLL_CNTL4);
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
if (CONFIG_DRAM_CLK >= 375 && CONFIG_DRAM_CLK <= 749)
writel((1 << 29) | ((2 << 16) | (1 << 9) |
(((CONFIG_DRAM_CLK / 6) * 6) / 12)), AM_DDR_PLL_CNTL0);
else if (CONFIG_DRAM_CLK >= 750 && CONFIG_DRAM_CLK <= 1449)
writel((1 << 29) | ((1 << 16) | (1 << 9) |
(((CONFIG_DRAM_CLK / 12) * 12) / 24)), AM_DDR_PLL_CNTL0);
clrbits_32(AM_DDR_PLL_CNTL0, 1 << 29);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel(DDR_PLL_CNTL5, AM_DDR_PLL_CNTL5);
if (CONFIG_DRAM_CLK >= 399 && CONFIG_DRAM_CLK <= 799)
writel(((1 << 16) | ((1 << 2) | 1) |
((CONFIG_DRAM_CLK / 12) << 4)) |
((1 << 31) | (1 << 29) | (1 << 28)), AM_DDR_PLL_CNTL0);
else if (CONFIG_DRAM_CLK >= 800 && CONFIG_DRAM_CLK <= 1498)
writel(((1 << 16) | (1 << 2) |
((CONFIG_DRAM_CLK / 24) << 4)) |
((1 << 31) | (1 << 29) | (1 << 28)), AM_DDR_PLL_CNTL0);
}
udelay(200);
} while (!((readl(AM_DDR_PLL_STS) >> 0x1F) & 1));
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
writel(DDR_CLK_CNTL_CLKGEN_SOFTRESET |
DDR_CLK_CNTL_PHY_CLK_ENABLE |
DDR_CLK_CNTL_DDRPLL_ENABLE, DDR_CLK_CNTL);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel(DDR_CLK_CNTL_CLKGEN_SOFTRESET |
DDR_CLK_CNTL_PHY_CLK_ENABLE |
DDR_CLK_CNTL_DDRPLL_ENABLE |
0xa005 /* unknown */, DDR_CLK_CNTL);
}
printf("DRAM clock: %d MHz\n", CONFIG_DRAM_CLK);
}
void meson_dram_phy_prepare(void)
{
/* Release reset of DLL */
writel(0xffffffff, DMC_SOFT_RST);
writel(0xffffffff, DMC_SOFT_RST1);
udelay(10);
/* Enable UPCTL and PUB clock */
if (IS_ENABLED(CONFIG_MESON_GXBB))
writel(0x550620, DMC_PCTL_LP_CTRL);
else if (IS_ENABLED(CONFIG_MESON_GXL))
writel(0, DMC_PCTL_LP_CTRL);
writel(0xf, DDR0_SOFT_RESET);
udelay(10);
}
void meson_dram_set_memory_timings(void)
{
/* Set memory timings */
writel(timings.rfc, PCTL_TRFC);
if (IS_ENABLED(CONFIG_MESON_GXL))
writel(timings.faw, PCTL_TFAW);
writel(timings.refi_mddr3, PCTL_TREFI_MEM_DDR3);
writel(timings.mrd, PCTL_TMRD);
if (IS_ENABLED(CONFIG_MESON_GXL))
writel((timings.rp << 16) | timings.rp, PCTL_TRP);
else /* Meson GXBB */
writel(timings.rp, PCTL_TRP);
writel(timings.cke + 1, PCTL_TCKESR);
writel(timings.al, PCTL_TAL);
writel(timings.cwl, PCTL_TCWL);
writel(timings.cl, PCTL_TCL);
writel(timings.ras, PCTL_TRAS);
writel(timings.rc, PCTL_TRC);
writel(timings.rcd, PCTL_TRCD);
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
writel(timings.rrd, PCTL_TRRD);
} else {
writel(timings.rrd | ((timings.rrd + 2) * 0x10000), PCTL_TRRD);
writel((timings.tccdl << 16) | 4, PCTL_TCCD);
}
writel(timings.rtp, PCTL_TRTP);
writel(timings.wr, PCTL_TWR);
writel(timings.wtr, PCTL_TWTR);
writel(timings.exsr, PCTL_TEXSR);
writel(timings.xp, PCTL_TXP);
writel(timings.dqs, PCTL_TDQS);
writel(timings.rtw, PCTL_TRTW);
writel(timings.cksre, PCTL_TCKSRE);
writel(timings.cksrx, PCTL_TCKSRX);
writel(timings.mod, PCTL_TMOD);
writel(timings.cke, PCTL_TCKE);
writel(timings.zqcs, PCTL_TZQCS);
writel(timings.zqcl, PCTL_TZQCL);
writel(timings.xpdll, PCTL_TXPDLL);
writel(timings.zqcsi, PCTL_TZQCSI);
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
/* GXBB: Enter config state */
writel(PCTL0_SCFG, PCTL_SCFG);
writel(PCTL_SCTL_CFG_STATE, PCTL_SCTL);
}
}
void meson_dram_set_dfi_timings(void)
{
#ifdef CONFIG_MESON_GXL
writel(0xab0a560a, PCTL_ZQCFG);
#endif
WAIT_FOR(PCTL_STAT);
writel(PCTL0_PPCFG, PCTL_PPCFG);
writel(PCTL0_DFISTCFG0, PCTL_DFISTCFG0);
writel(PCTL0_DFISTCFG1, PCTL_DFISTCFG1);
writel(PCTL0_DFITCTRLDELAY, PCTL_DFITCTRLDELAY);
writel(PCTL0_DFITPHYWRDATA, PCTL_DFITPHYWRDATA);
writel(PCTL0_DFITPHYWRLTA, PCTL_DFITPHYWRLAT);
writel(PCTL0_DFITRDDATAEN, PCTL_DFITRDDATAEN);
writel(PCTL0_DFITPHYRDLAT, PCTL_DFITPHYRDLAT);
writel(PCTL0_DFITDRAMCLKDIS, PCTL_DFITDRAMCLKDIS);
writel(PCTL0_DFITDRAMCLKEN, PCTL_DFITDRAMCLKEN);
writel(PCTL0_DFITCTRLUPDMIN, PCTL_DFITCTRLUPDMIN);
#if defined(CONFIG_MESON_GXL)
writel(PCTL0_DFITCTRLUPDMAX, PCTL_DFITCTRLUPDMAX);
writel(PCTL0_DFIUPDCFG, PCTL_DFIUPDCFG);
#endif
writel(PCTL0_DFILPCFG0, PCTL_DFILPCFG0);
#if defined(CONFIG_MESON_GXL)
writel(PCTL0_DFITPHYUPDTYPE0, PCTL_DFITPHYUPDTYPE0);
#endif
writel(PCTL0_DFITPHYUPDTYPE1, PCTL_DFITPHYUPDTYPE1);
writel(PCTL0_DFIODTCFG, PCTL_DFIODTCFG);
writel(PCTL0_DFIODTCFG1, PCTL_DFIODTCFG1);
#if defined(CONFIG_MESON_GXBB)
writel(PCTL0_CMDTSTATEN, PCTL_CMDTSTATEN);
#endif
}
uint meson_dram_phy_finalise_init(void)
{
writel(PUB_ZQ0PR, DDR0_PUB_ZQ0PR);
writel(PUB_ZQ1PR, DDR0_PUB_ZQ1PR);
writel(PUB_ZQ2PR, DDR0_PUB_ZQ2PR);
#if defined(CONFIG_MESON_GXBB)
writel(PUB_ZQ3PR, DDR0_PUB_ZQ3PR);
#endif
writel(PUB_PIR_INIT | PUB_PIR_ZCAL, DDR0_PUB_PIR);
WAIT_FOR(DDR0_PUB_PGSR0);
/*
* Is this needed?
* TODO: test without
*/
writel(readl(DDR0_PUB_ZQCR) | (1 << 2) | (1 << 27), DDR0_PUB_ZQCR);
udelay(10);
writel(readl(DDR0_PUB_ZQCR) & ~((1 << 2) | (1 << 27)), DDR0_PUB_ZQCR);
udelay(30);
#if defined(CONFIG_MESON_GXL) && defined(CONFIG_DRAM_16BIT_RANK)
clrsetbits_32(DDR0_PUB_DX2GCR0, 0xb0001, 0xb0000); /* Make it neat somehow? */
clrsetbits_32(DDR0_PUB_DX3GCR0, 0xb0001, 0xb0000);
#endif
writel(PUB_ACBDLR0, DDR0_PUB_ACBDLR0);
#if defined(CONFIG_MESON_GXL)
writel(PUB_ACBDLR3, DDR0_PUB_ACBDLR3);
#endif
#if defined(CONFIG_MESON_GXL) && defined(CONFIG_DRAM_2T_MODE) && defined(CONFIG_DRAM_DDR3)
writel(0x10101010, DDR0_PUB_ACBDLR1);
writel(0x10101010, DDR0_PUB_ACBDLR7);
writel(0x20202020, DDR0_PUB_ACBDLR8);
writel(0x30303030, DDR0_PUB_ACBDLR9);
writel(0x3f003f, DDR0_PUB_ACBDLR2);
writel(0, DDR0_PUB_ACBDLR6);
#endif
#if defined(CONFIG_MESON_GXL) && defined(CONFIG_DRAM_DDR3)
clrsetbits_32(DDR0_PUB_DXCCR, (3 << 5) | (3 << 7) |
(3 << 9) | (3 << 11), (1 << 12) | (1 << 9));
#endif
writel(PUB_PIR_FINAL_STEP, DDR0_PUB_PIR);
udelay(1000);
for (u32 pgsr0 = readl(DDR0_PUB_PGSR0); (pgsr0 != 0xc0000fff) &&
(pgsr0 != 0x80000fff); pgsr0 = readl(DDR0_PUB_PGSR0)) {
udelay(20);
debug("Waiting for PGSR0, currently 0x%x\n", pgsr0);
/* Check for errors */
if (pgsr0 & PUB_PGSR0_ZCERR)
pr_err("%s: impedance calibration error\n", __func__);
if (pgsr0 & PUB_PGSR0_WLERR)
pr_err("%s: write leveling error\n", __func__);
if (pgsr0 & PUB_PGSR0_QSGERR)
pr_err("%s: DQS gate training error\n", __func__);
if (pgsr0 & PUB_PGSR0_WLAERR)
pr_err("%s: WL Adj error\n", __func__);
if (pgsr0 & PUB_PGSR0_RDERR)
pr_err("%s: read bit deskew error", __func__);
if (pgsr0 & PUB_PGSR0_WDERR)
pr_err("%s: write bit deskew error", __func__);
if (pgsr0 & PUB_PGSR0_REERR)
pr_err("%s: read eye training error", __func__);
if (pgsr0 & PUB_PGSR0_WEERR)
pr_err("%s: write eye training error", __func__);
}
debug("Wait done for PGSR0, currently 0x%x\n", readl(DDR0_PUB_PGSR0));
return 0;
}
void meson_dram_dmc_set_addrmap(void)
{
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
/* GXBB address map */
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS) ||
IS_ENABLED(CONFIG_DRAM_ONE_RANK)) {
writel(11 | 31 << 5 | 0 << 10 | 14 << 15 | 15 << 20 | 16 << 25,
DDR0_ADDRMAP_1);
writel(30 | 12 << 5 | 13 << 10 | 29 << 15 | 0 << 20 | 0 << 25,
DDR0_ADDRMAP_4);
} else if (IS_ENABLED(CONFIG_DRAM_TWO_DIFF_RANKS)) {
writel(11 | 31 << 5 | 0 << 10 | 14 << 15 | 15 << 20 | 16 << 25,
DDR0_ADDRMAP_1);
writel(0 | 12 << 5 | 13 << 10 | 29 << 15 | 0 << 20 | 30 << 25,
DDR0_ADDRMAP_4);
}
} else if (IS_ENABLED(CONFIG_MESON_GXL) && IS_ENABLED(CONFIG_DRAM_DDR3)) {
/* This applies for GXL + DDR3 RAM (e.g. LePotato) */
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS) ||
IS_ENABLED(CONFIG_DRAM_ONE_RANK)) {
writel(11 | 30 << 5 | 0 << 10 | 15 << 15 | 16 << 20 | 17 << 25,
DDR0_ADDRMAP_1);
writel(18 | 19 << 5 | 20 << 10 | 21 << 15 | 22 << 20 | 23 << 25,
DDR0_ADDRMAP_2);
writel(24 | 25 << 5 | 26 << 10 | 27 << 15 | 28 << 20 | 29 << 25,
DDR0_ADDRMAP_3);
writel(30 | 12 << 5 | 13 << 10 | 14 << 15 | 0 << 20 | 31 << 25,
DDR0_ADDRMAP_4);
writel(5 | 6 << 5 | 7 << 10 | 8 << 15 | 9 << 20 | 10 << 25,
DDR1_ADDRMAP_0);
writel(11 | 30 << 5 | 0 << 10 | 15 << 15 | 16 << 20 | 17 << 25,
DDR1_ADDRMAP_1);
writel(18 | 19 << 5 | 20 << 10 | 21 << 15 | 22 << 20 | 23 << 25,
DDR1_ADDRMAP_2);
writel(24 | 25 << 5 | 26 << 10 | 27 << 15 | 28 << 20 | 29 << 25,
DDR1_ADDRMAP_3);
writel(30 | 12 << 5 | 13 << 10 | 14 << 15 | 0 << 20 | 31 << 25,
DDR1_ADDRMAP_4);
}
} else if (IS_ENABLED(CONFIG_MESON_GXL) && IS_ENABLED(CONFIG_DRAM_DDR4)) {
/* This applies for GXL + DDR4 RAM (e.g. LaFrite) */
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS) ||
IS_ENABLED(CONFIG_DRAM_ONE_RANK)) {
writel(6 | 7 << 5 | 8 << 10 | 9 << 15 | 10 << 20 | 11 << 25,
DDR0_ADDRMAP_0);
writel(12 | 0 << 5 | 0 << 10 | 15 << 15 | 16 << 20 | 17 << 25,
DDR0_ADDRMAP_1);
writel(18 | 19 << 5 | 20 << 10 | 21 << 15 | 22 << 20 | 23 << 25,
DDR0_ADDRMAP_2);
writel(24 | 25 << 5 | 26 << 10 | 27 << 15 | 28 << 20 | 29 << 25,
DDR0_ADDRMAP_3);
writel(30 | 13 << 5 | 14 << 10 | 5 << 15 | 0 << 20 | 31 << 25,
DDR0_ADDRMAP_4);
writel(6 | 7 << 5 | 8 << 10 | 9 << 15 | 10 << 20 | 11 << 25,
DDR1_ADDRMAP_0);
writel(12 | 0 << 5 | 0 << 10 | 15 << 15 | 16 << 20 | 17 << 25,
DDR1_ADDRMAP_1);
writel(18 | 19 << 5 | 20 << 10 | 21 << 15 | 22 << 20 | 23 << 25,
DDR1_ADDRMAP_2);
writel(24 | 25 << 5 | 26 << 10 | 27 << 15 | 28 << 20 | 29 << 25,
DDR1_ADDRMAP_3);
writel(30 | 13 << 5 | 14 << 10 | 5 << 15 | 0 << 20 | 31 << 25,
DDR1_ADDRMAP_4);
} else if (IS_ENABLED(CONFIG_DRAM_16BIT_RANK)) {
writel(0 | 6 << 5 | 7 << 10 | 8 << 15 | 9 << 20 | 10 << 25,
DDR0_ADDRMAP_0);
writel(11 | 0 << 5 | 0 << 10 | 14 << 15 | 15 << 20 | 16 << 25,
DDR0_ADDRMAP_1);
writel(17 | 18 << 5 | 19 << 10 | 20 << 15 | 21 << 20 | 22 << 25,
DDR0_ADDRMAP_2);
writel(23 | 24 << 5 | 25 << 10 | 26 << 15 | 27 << 20 | 28 << 25,
DDR0_ADDRMAP_3);
writel(29 | 12 << 5 | 13 << 10 | 5 << 15 | 0 << 20 | 30 << 25,
DDR0_ADDRMAP_4);
writel(0 | 6 << 5 | 7 << 10 | 8 << 15 | 9 << 20 | 10 << 25,
DDR1_ADDRMAP_0);
writel(11 | 0 << 5 | 0 << 10 | 14 << 15 | 15 << 20 | 16 << 25,
DDR1_ADDRMAP_1);
writel(17 | 18 << 5 | 19 << 10 | 20 << 15 | 21 << 20 | 22 << 25,
DDR1_ADDRMAP_2);
writel(23 | 24 << 5 | 25 << 10 | 26 << 15 | 27 << 20 | 28 << 25,
DDR1_ADDRMAP_3);
writel(29 | 12 << 5 | 13 << 10 | 5 << 15 | 0 << 20 | 30 << 25,
DDR1_ADDRMAP_4);
}
}
}
void meson_dram_dmc_init(void)
{
u32 ddr_size_register = 0;
printf("DMC version: 0x%x\n", readl(DMC_VERSION));
for (int i = CONFIG_DRAM_SIZE >> DMC_DRAM_SIZE_SHIFT;
!((i >>= 1) & 1); ddr_size_register++)
;
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS) || IS_ENABLED(CONFIG_DRAM_ONE_RANK))
writel(DMC_CTRL | ddr_size_register |
(ddr_size_register << 3),
DMC_DDR_CTRL);
else
writel(DMC_CTRL | ddr_size_register |
(5 << 3),
DMC_DDR_CTRL);
meson_dram_dmc_set_addrmap();
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
writel(0x440620, DMC_PCTL_LP_CTRL);
writel(BIT(13) | BIT(5), DDR0_APD_CTRL);
writel(0x5, DDR0_CLK_CTRL);
writel(0x11, DMC_AXI0_QOS_CTRL1);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel(BIT(13), DDR0_APD_CTRL);
}
writel(0x0, DMC_SEC_RANGE_CTRL);
writel(0x80000000, DMC_SEC_CTRL);
writel(0x55555555, DMC_SEC_AXI_PORT_CTRL);
writel(0x55555555, DMC_DEV_SEC_READ_CTRL);
writel(0x55555555, DMC_DEV_SEC_WRITE_CTRL);
writel(0x15, DMC_GE2D_SEC_CTRL);
writel(0x5, DMC_PARSER_SEC_CTRL);
DMC_ENABLE_REGION(DMC_VPU);
DMC_ENABLE_REGION(DMC_VDEC);
DMC_ENABLE_REGION(DMC_HCODEC);
DMC_ENABLE_REGION(DMC_HEVC);
writel(0xffff, DMC_REQ_CTRL);
dmb();
isb();
debug("dram: memory controller init done\n");
}
int dram_init(void)
{
uint ret;
debug("SPL: initialising dram\n");
meson_dram_pll_init();
meson_dram_phy_prepare();
meson_dram_phy_init();
meson_dram_prepare_pctl();
meson_dram_set_memory_timings();
meson_dram_set_dfi_timings();
ret = meson_dram_phy_finalise_init();
if (ret < 0)
return ret;
meson_dram_phy_setup_ranks();
meson_dram_finalise_init();
meson_dram_dmc_init();
/* Write size */
clrsetbits_32(GX_SEC_AO_SEC_GP_CFG0, GX_AO_MEM_SIZE_MASK,
CONFIG_DRAM_SIZE << GX_AO_MEM_SIZE_SHIFT);
debug("SPL: dram init done\n");
return 0;
}

View File

@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <init.h>
#include <asm/unaligned.h>
#include <linux/libfdt.h>
#include <config.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/dram-gx.h>
#include <asm/arch/gx.h>
#include <asm/arch/clock-gx.h>
#include <asm/arch/dram-settings-gx.h>
#include <linux/delay.h>
/* Meson GXBB specific DRAM init */
void meson_dram_prepare_pctl(void)
{
writel(PCTL0_1US_PCK, PCTL_TOGCNT1U);
writel(PCTL0_100NS_PCK, PCTL_TOGCNT100N);
writel(PCTL0_INIT_US, PCTL_TINIT);
writel(PCTL0_RSTH_US, PCTL_TRSTH);
writel(PCTL0_MCFG | (CONFIG_DRAM_2T_MODE ? 8 : 0),
PCTL_MCFG);
writel(PCTL0_MCFG1, PCTL_MCFG1);
udelay(500);
WAIT_FOR(PCTL_DFISTSTAT0);
/* Ask the DRAM to kindly power on and wait until it is ready */
writel(PCTL_POWCTL_POWERON, PCTL_POWCTL);
WAIT_FOR(PCTL_POWSTAT);
}
void meson_dram_phy_init(void)
{
/* Some unknown magic done by bl2 */
writel(0x49494949, DDR0_PUB_IOVCR0);
writel(0x49494949, DDR0_PUB_IOVCR1);
writel(PUB_ODTCR, DDR0_PUB_ODTCR);
writel(PUB_MR0, DDR0_PUB_MR0);
writel(PUB_MR1, DDR0_PUB_MR1);
writel(PUB_MR2, DDR0_PUB_MR2);
writel(PUB_MR3, DDR0_PUB_MR3);
/* Configure DRAM timing parameters (DTPR) */
writel(PUB_DTPR0, DDR0_PUB_DTPR0);
writel(PUB_DTPR1, DDR0_PUB_DTPR1);
writel(PUB_PGCR1, DDR0_PUB_PGCR1);
writel(PUB_DTPR2, DDR0_PUB_DTPR2);
writel(PUB_DTPR3, DDR0_PUB_DTPR3);
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS))
writel(PUB_PGCR2 | (1 << 28), DDR0_PUB_PGCR2);
else
writel(PUB_PGCR2, DDR0_PUB_PGCR2);
writel(PUB_PGCR3, DDR0_PUB_PGCR3);
writel(PUB_DXCCR, DDR0_PUB_DXCCR);
writel(PUB_DTCR, DDR0_PUB_DTCR);
/* Wait for DLL lock */
WAIT_FOR(DDR0_PUB_PGSR0);
writel(0, DDR0_PUB_ACIOCR1);
writel(0, DDR0_PUB_ACIOCR2);
writel(0, DDR0_PUB_ACIOCR3);
writel(0, DDR0_PUB_ACIOCR4);
writel(0, DDR0_PUB_ACIOCR5);
writel(0, DDR0_PUB_DX0GCR1);
writel(0, DDR0_PUB_DX0GCR2);
writel((1 << 10) | (2 << 12), DDR0_PUB_DX0GCR3);
writel(0, DDR0_PUB_DX1GCR1);
writel(0, DDR0_PUB_DX1GCR2);
writel((1 << 10) | (2 << 12), DDR0_PUB_DX1GCR3);
writel(0, DDR0_PUB_DX2GCR1);
writel(0, DDR0_PUB_DX2GCR2);
writel((1 << 10) | (2 << 12), DDR0_PUB_DX2GCR3);
writel(0, DDR0_PUB_DX3GCR1);
writel(0, DDR0_PUB_DX3GCR2);
writel((1 << 10) | (2 << 12), DDR0_PUB_DX3GCR3);
writel(PUB_DCR, DDR0_PUB_DCR);
writel(PUB_DTAR, DDR0_PUB_DTAR0);
writel(PUB_DTAR | 0x8, DDR0_PUB_DTAR1);
writel(PUB_DTAR | 0x10, DDR0_PUB_DTAR2);
writel(PUB_DTAR | 0x18, DDR0_PUB_DTAR3);
writel(PUB_DSGCR, DDR0_PUB_DSGCR);
/* Wait for the SDRAM to initialise */
WAIT_FOR(DDR0_PUB_PGSR0);
}
void meson_dram_phy_setup_ranks(void)
{
if (IS_ENABLED(CONFIG_DRAM_ONE_RANK) || IS_ENABLED(CONFIG_DRAM_TWO_DIFF_RANKS)) {
uint i = 0, j = 0;
writel((readl(DDR0_PUB_DX0LCDLR0) >> 8) |
(readl(DDR0_PUB_DX0LCDLR0) & 0xffffff00),
DDR0_PUB_DX0LCDLR0);
i = ((readl(DDR0_PUB_DX2GTR) >> 3) & (7 << 0));
j = ((readl(DDR0_PUB_DX2GTR) >> 14) & (3 << 0));
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX2GTR);
writel((readl(DDR0_PUB_DX2LCDLR2) >> 8) |
(readl(DDR0_PUB_DX2LCDLR2) & 0xffffff00),
DDR0_PUB_DX2LCDLR2);
writel((readl(DDR0_PUB_DX3LCDLR0) >> 8) |
(readl(DDR0_PUB_DX3LCDLR0) & 0xffffff00),
DDR0_PUB_DX3LCDLR0);
i = (readl(DDR0_PUB_DX3GTR) >> 3) & (7 << 0);
j = (readl(DDR0_PUB_DX3GTR) >> 14) & (3 << 0);
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX3GTR);
writel((readl(DDR0_PUB_DX3LCDLR2) >> 8) |
(readl(DDR0_PUB_DX3LCDLR2) & 0xffffff00),
DDR0_PUB_DX3LCDLR2);
writel((readl(DDR0_PUB_DX0LCDLR0) << 8) |
(readl(DDR0_PUB_DX0LCDLR0) & 0xffff00ff),
DDR0_PUB_DX0LCDLR0);
i = (readl(DDR0_PUB_DX0GTR) << 0) & (7 << 0);
j = (readl(DDR0_PUB_DX0GTR) >> 12) & (3 << 0);
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX0GTR);
writel((readl(DDR0_PUB_DX0LCDLR2) << 8) |
(readl(DDR0_PUB_DX0LCDLR2) & 0xffff00ff),
DDR0_PUB_DX0LCDLR2);
writel((readl(DDR0_PUB_DX1LCDLR0) << 8) |
(readl(DDR0_PUB_DX1LCDLR0) & 0xffff00ff),
DDR0_PUB_DX1LCDLR0);
i = (readl(DDR0_PUB_DX1GTR) << 0) & (7 << 0);
j = (readl(DDR0_PUB_DX1GTR) >> 12) & (3 << 0);
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX0GTR);
writel((readl(DDR0_PUB_DX1LCDLR2) >> 8) |
(readl(DDR0_PUB_DX1LCDLR2) & 0xffffff00),
DDR0_PUB_DX1LCDLR2);
}
writel((~(1 << 28)) & PUB_PGCR2, DDR0_PUB_PGCR2);
if (IS_ENABLED(CONFIG_DRAM_2T_MODE) && (PUB_DCR & 7) == 3)
writel(0x1f, DDR0_PUB_ACLCDLR);
}
void meson_dram_finalise_init(void)
{
WAIT_FOR(PCTL_CMDTSTAT);
writel(PCTL_SCTL_GO_STATE, PCTL_SCTL);
while (readl(PCTL_STAT) != PCTL_STAT_ACCESS)
;
writel(0x880019d, DMC_REFR_CTRL1);
writel(0x20100000 | (CONFIG_DRAM_CLK / 20) |
(timings.refi << 8), DMC_REFR_CTRL2);
clrbits_32(DDR0_PUB_ZQCR, 4);
}

View File

@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <init.h>
#include <asm/unaligned.h>
#include <linux/libfdt.h>
#include <config.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/dram-gx.h>
#include <asm/arch/gx.h>
#include <asm/arch/clock-gx.h>
#include <asm/arch/dram-settings-gx.h>
#include <linux/delay.h>
/* Meson GXL specific DRAM init */
void meson_dram_prepare_pctl(void)
{
writel(CONFIG_DRAM_2T_MODE ? 8 : 0, PCTL_MCFG);
setbits_32(PCTL_MCFG, PCTL0_MCFG);
udelay(500);
WAIT_FOR(PCTL_DFISTSTAT0);
/* Enter config state */
writel(PCTL0_SCFG, PCTL_SCFG);
writel(PCTL_SCTL_CFG_STATE, PCTL_SCTL);
WAIT_FOR(PCTL_STAT);
writel(0x581, DDR0_PUB_PIR);
WAIT_FOR(DDR0_PUB_PGSR0);
}
void meson_dram_phy_init(void)
{
/* Some unknown magic done by bl2 */
writel(0x190c3500, DDR0_PUB_PTR3);
writel(0x12c493e0, DDR0_PUB_PTR4);
writel(0x1f090909, DDR0_PUB_IOVCR0);
writel(0x109, DDR0_PUB_IOVCR1);
writel(0xe09093c, DDR0_PUB_DX0GCR4);
writel(0xe09093c, DDR0_PUB_DX1GCR4);
writel(0xe09093c, DDR0_PUB_DX2GCR4);
writel(0xe09093c, DDR0_PUB_DX3GCR4);
writel(PUB_ODTCR, DDR0_PUB_ODTCR);
writel(PUB_MR0, DDR0_PUB_MR0);
writel(PUB_MR1, DDR0_PUB_MR1);
writel(PUB_MR2, DDR0_PUB_MR2);
writel(PUB_MR3, DDR0_PUB_MR3);
writel(PUB_MR4, DDR0_PUB_MR4);
writel(PUB_MR5, DDR0_PUB_MR5);
writel(PUB_MR6, DDR0_PUB_MR6);
/* Configure DRAM timing parameters (DTPR) */
writel(timings.odt | (1 << 2), DDR0_PUB_MR11);
writel(PUB_DTPR0, DDR0_PUB_DTPR0);
writel(PUB_DTPR1, DDR0_PUB_DTPR1);
writel(PUB_DTPR2, DDR0_PUB_DTPR2);
writel(PUB_DTPR3, DDR0_PUB_DTPR3);
writel(PUB_DTPR4, DDR0_PUB_DTPR4);
writel(PUB_DTPR5, DDR0_PUB_DTPR5);
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS))
writel(PUB_PGCR2 | (1 << 28), DDR0_PUB_PGCR2);
else
writel(PUB_PGCR2, DDR0_PUB_PGCR2);
writel(PUB_PGCR3, DDR0_PUB_PGCR3);
writel(PUB_DXCCR, DDR0_PUB_DXCCR);
writel(PUB_DTCR, DDR0_PUB_DTCR);
writel(PUB_DTCR1, DDR0_PUB_DTCR1);
writel(PUB_PGCR1, DDR0_PUB_PGCR1);
writel(0, DDR0_PUB_ACIOCR1);
writel(0, DDR0_PUB_ACIOCR2);
writel(0, DDR0_PUB_ACIOCR3);
writel(0, DDR0_PUB_ACIOCR4);
writel(0, DDR0_PUB_ACIOCR5);
writel(0, DDR0_PUB_DX0GCR1);
writel(0, DDR0_PUB_DX0GCR2);
writel(0, DDR0_PUB_DX1GCR1);
writel(0, DDR0_PUB_DX1GCR2);
writel(0, DDR0_PUB_DX2GCR1);
writel(0, DDR0_PUB_DX2GCR2);
writel(0, DDR0_PUB_DX3GCR1);
writel(0, DDR0_PUB_DX3GCR2);
if (IS_ENABLED(CONFIG_DRAM_16BIT_RANK)) {
writel(0, DDR0_PUB_DX2GCR0);
writel(0, DDR0_PUB_DX3GCR0);
}
writel(0x73, DDR0_PUB_PIR);
WAIT_FOR(DDR0_PUB_PGSR0);
writel(PUB_DCR | (CONFIG_DRAM_2T_MODE ? 1 << 28 : 0), DDR0_PUB_DCR);
writel(0xfc00172, DDR0_PUB_VTCR1);
writel(PUB_DSGCR & ~(0x800004), DDR0_PUB_DSGCR);
/* Wait for the SDRAM to initialise */
WAIT_FOR(DDR0_PUB_PGSR0);
}
void meson_dram_phy_setup_ranks(void)
{
if (IS_ENABLED(CONFIG_DRAM_2T_MODE)) {
writel(0x3f003f, DDR0_PUB_ACBDLR2);
if (PUB_ACLCDLR <= 62) {
writel(((PUB_ACLCDLR - 24) + (readl(DDR0_PUB_ACMDLR0) & ~(0xe00))) |
(((PUB_ACLCDLR - 24) + (readl(DDR0_PUB_ACMDLR0) & ~(0xe00)))
* 0xffff), DDR0_PUB_ACBDLR2);
}
}
writel((PUB_ACLCDLR - 24) + (readl(DDR0_PUB_ACMDLR0) & ~(0xe00)), DDR0_PUB_ACLCDLR);
if (IS_ENABLED(CONFIG_DRAM_DQS_CORR)) {
/* DQS correction stuff(?) */
clrbits_32(DDR0_PUB_ACLCDLR, 0xe00);
if (!readl(DDR0_PUB_ACLCDLR))
writel(1, DDR0_PUB_ACLCDLR);
writel(readl(DDR0_PUB_ACLCDLR) & ~(0xe00), DDR0_PUB_ACLCDLR);
clrbits_32(DDR0_PUB_ACBDLR0, 0xe00);
if (!readl(DDR0_PUB_ACBDLR0))
writel(1, DDR0_PUB_ACBDLR0);
writel(readl(DDR0_PUB_ACBDLR0) & ~(0xc0), DDR0_PUB_ACBDLR0);
DQSCORR_DX(DDR0_PUB_DX0LCDLR0);
DQSCORR_DX(DDR0_PUB_DX1LCDLR0);
DQSCORR_DX(DDR0_PUB_DX2LCDLR0);
DQSCORR_DX(DDR0_PUB_DX3LCDLR0);
}
}
void meson_dram_finalise_init(void)
{
writel((0x3f << 12) | 0xf8, DDR0_PUB_PGCR6);
writel(PCTL_SCTL_GO_STATE, PCTL_SCTL);
while ((readl(PCTL_STAT) & 7) != PCTL_STAT_ACCESS)
;
writel(0xfffc << 16, DDR0_PUB_DX0GCR3);
writel(0xfffc << 16, DDR0_PUB_DX1GCR3);
writel(0xfffc << 16, DDR0_PUB_DX2GCR3);
writel(0xfffc << 16, DDR0_PUB_DX3GCR3);
writel(0, DDR0_PUB_RANKIDR);
writel(PUB_DSGCR | 0x800004, DDR0_PUB_DSGCR);
setbits_32(DDR0_PUB_ZQCR, 4);
writel(0x20100000 | ((CONFIG_DRAM_CLK / 20) - 1) |
(timings.refi << 8), DMC_REFR_CTRL2);
writel(0xf08f, DMC_REFR_CTRL1);
}

View File

@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <hang.h>
#include <image.h>
#include <spl.h>
#include <vsprintf.h>
#include <asm/io.h>
#include <asm/arch/boot.h>
#include <asm/arch/clock-gx.h>
#include <asm/arch/gx.h>
#include <linux/delay.h>
/* Meson GX SPL code */
inline void cpu_pll_switch_to(int mode)
{
u32 reg;
reg = readl(GX_HIU_BASE + HHI_SYS_CPU_CLK_CNTL0);
while (reg & HHI_SCC_CNTL0_BUSY)
reg = readl(GX_HIU_BASE + HHI_SYS_CPU_CLK_CNTL0);
reg |= HHI_SCC_CNTL0_DYN_ENABLE;
if (mode == 1) {
/* Switch to System PLL */
reg |= HHI_SCC_CNTL0_FINAL_MUX_SEL;
} else {
if (reg & HHI_SCC_CNTL0_FINAL_DYN_MUX_SEL) {
reg = (reg & ~(HHI_SCC_CNTL0_FINAL_DYN_MUX_SEL |
HHI_SCC_CNTL0_MUX0_DIVN_TCNT |
HHI_SCC_CNTL0_POSTMUX0 | HHI_SCC_CNTL0_PREMUX0));
} else {
reg = (reg & ~(HHI_SCC_CNTL0_FINAL_DYN_MUX_SEL |
HHI_SCC_CNTL0_MUX1_DIVN_TCNT |
(HHI_SCC_CNTL0_POSTMUX1 | HHI_SCC_CNTL0_PREMUX1))) |
HHI_SCC_CNTL0_FINAL_DYN_MUX_SEL;
}
/* Select dynamic mux */
reg = reg & ~(HHI_SCC_CNTL0_FINAL_MUX_SEL) /*final_mux_sel*/;
}
writel(reg, GX_HIU_BASE + HHI_SYS_CPU_CLK_CNTL0);
}
int meson_pll_init(void)
{
clrbits_32(GX_HIU_BASE + HHI_MPEG_CLK_CNTL, 1 << 8);
cpu_pll_switch_to(0);
setbits_32(GX_HIU_BASE + HHI_MPLL_CNTL6, 1 << 26);
udelay(100);
while (!((readl(GX_HIU_BASE + HHI_SYS_PLL_CNTL) >> 31) & 1)) {
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
setbits_32(GX_HIU_BASE + HHI_SYS_PLL_CNTL, 1 << 29);
writel(0x5ac80000, GX_HIU_BASE + HHI_SYS_PLL_CNTL2);
writel(0x8e452015, GX_HIU_BASE + HHI_SYS_PLL_CNTL3);
writel(0x401d40c, GX_HIU_BASE + HHI_SYS_PLL_CNTL4);
writel(0x870, GX_HIU_BASE + HHI_SYS_PLL_CNTL5);
writel((1 << 30) | (1 << 29) |
((0 << 16) | (1 << 9) |
(1536 / 24)), /* 1.5 GHz */
GX_HIU_BASE + HHI_SYS_PLL_CNTL);
clrbits_32(GX_HIU_BASE + HHI_SYS_PLL_CNTL, 1 << 29);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel(0xc4258100, GX_HIU_BASE + HHI_SYS_PLL_CNTL1);
writel(0xb7400000, GX_HIU_BASE + HHI_SYS_PLL_CNTL2);
writel(0xa59a288, GX_HIU_BASE + HHI_SYS_PLL_CNTL3);
writel(0x40002d, GX_HIU_BASE + HHI_SYS_PLL_CNTL4);
writel(0x7c700007, GX_HIU_BASE + HHI_SYS_PLL_CNTL5);
writel((1 << 30) | ((1 << 9) |
(1200 / 24)), /* 1.2 GHz */
GX_HIU_BASE + HHI_SYS_PLL_CNTL);
}
udelay(20);
}
cpu_pll_switch_to(1); /* Hook the CPU to the PLL divider output */
if (IS_ENABLED(CONFIG_MESON_GXBB))
writel(0x10007, GX_HIU_BASE + HHI_MPLL_CNTL4);
else if (IS_ENABLED(CONFIG_MESON_GXL))
writel(0x10006, GX_HIU_BASE + HHI_MPLL_CNTL4);
setbits_32(GX_HIU_BASE + HHI_MPLL_CNTL, 1 << 29);
udelay(200);
writel(0x59C80000, GX_HIU_BASE + HHI_MPLL_CNTL2);
writel(0xCA45B822, GX_HIU_BASE + HHI_MPLL_CNTL3);
if (IS_ENABLED(CONFIG_MESON_GXBB))
writel(0xB5500E1A, GX_HIU_BASE + HHI_MPLL_CNTL5);
else if (IS_ENABLED(CONFIG_MESON_GXL))
writel(0x95520E1A, GX_HIU_BASE + HHI_MPLL_CNTL5);
writel(0xFC454545, GX_HIU_BASE + HHI_MPLL_CNTL6);
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
writel((1 << 30) | (1 << 29) | (3 << 9) | (250 << 0), GX_HIU_BASE + HHI_MPLL_CNTL);
clrbits_32(GX_HIU_BASE + HHI_MPLL_CNTL, 1 << 29);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel((1 << 30) | (3 << 9) | (250 << 0), GX_HIU_BASE + HHI_MPLL_CNTL);
}
udelay(800);
setbits_32(GX_HIU_BASE + HHI_MPLL_CNTL4, 1 << 14);
while (!((readl(GX_HIU_BASE + HHI_MPLL_CNTL) >> 31) & 1)) {
if ((readl(GX_HIU_BASE + HHI_MPLL_CNTL) & (1 << 31)) != 0)
break;
setbits_32(GX_HIU_BASE + HHI_MPLL_CNTL, 1 << 29);
udelay(1000);
clrbits_32(GX_HIU_BASE + HHI_MPLL_CNTL, 1 << 29);
udelay(1000);
}
if (IS_ENABLED(CONFIG_MESON_GXBB)) {
writel(0xFFF << 16, GX_HIU_BASE + HHI_MPLL_CNTL10);
writel(((7 << 16) | (1 << 15) | (1 << 14) | (4681 << 0)),
GX_HIU_BASE + HHI_MPLL_CNTL7);
writel(((readl(GX_HIU_BASE + HHI_MPEG_CLK_CNTL) & (~((0x7 << 12) | (1 << 7) |
(0x7F << 0)))) | ((5 << 12) | (1 << 7) | (2 << 0))),
GX_HIU_BASE + HHI_MPEG_CLK_CNTL);
setbits_32(GX_HIU_BASE + HHI_MPEG_CLK_CNTL, 1 << 8);
writel(((5 << 16) | (1 << 15) | (1 << 14) | (12524 << 0)),
GX_HIU_BASE + HHI_MPLL_CNTL8);
} else if (IS_ENABLED(CONFIG_MESON_GXL)) {
writel((1 << 12) | 3, GX_HIU_BASE + HHI_MPLL_CNTL10);
writel(0x5edb7, GX_HIU_BASE + HHI_MPLL_CNTL7);
clrbits_32(GX_HIU_BASE + HHI_MPEG_CLK_CNTL,
(3 << 13) | (1 << 12) | (15 << 4) | 15);
setbits_32(GX_HIU_BASE + HHI_MPEG_CLK_CNTL,
(1 << 14) | (1 << 12) | (1 << 8) | (2 << 6) | (1 << 1));
writel((4 << 16) | (7 << 13) | (1 << 8) | (5 << 4) | 10,
GX_HIU_BASE + HHI_MPLL_CNTL8);
}
udelay(200);
/* TODO: Some error handling and timeouts... */
return 0;
}
#if CONFIG_IS_ENABLED(MMC) && !CONFIG_IS_ENABLED(DM_MMC)
int board_mmc_init(struct bd_info *bis)
{
int mmc_device;
switch (meson_get_boot_device()) {
case BOOT_DEVICE_SD:
mmc_device = 0;
break;
case BOOT_DEVICE_EMMC:
mmc_device = 1;
break;
default:
return -1;
}
if (!meson_mmc_init(mmc_device))
return -1;
return 0;
}
#endif

View File

@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <image.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/gx.h>
#include <linux/delay.h>
#if CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS)
/*
* This is only needed for GXBB because on GXL SCP firmware loading
* has been moved to BL31.
*/
inline void send_scp(void *addr, size_t size, const uint8_t *sha2,
uint32_t sha2_length)
{
int i;
puts("Trying to send the SCP firmware\n");
writel(size, GX_MB_SRAM_BASE);
udelay(500);
writel(GX_MB_CMD_DATA_LEN, GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4);
while (readl(GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4))
;
udelay(500);
memcpy((void *)GX_MB_SRAM_BASE, (const void *)sha2, sha2_length);
writel(GX_MB_CMD_SHA, GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4);
while (readl(GX_SEC_HIU_MAILBOX_STAT_0 + 3 * 3 * 4))
;
udelay(500);
for (i = 0; i < size; i += 1024) {
if (size >= i + 1024)
memcpy((void *)GX_MB_SRAM_BASE,
(const void *)(unsigned long)(addr + i), 1024);
else if (size > i)
memcpy((void *)GX_MB_SRAM_BASE,
(const void *)(unsigned long)(addr + i), (size - i));
writel(GX_MB_CMD_DATA, GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4);
while (readl(GX_SEC_HIU_MAILBOX_STAT_0 + 3 * 3 * 4))
;
}
writel(GX_MB_CMD_OP_SHA, GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4);
while (readl(GX_SEC_HIU_MAILBOX_STAT_0 + 3 * 3 * 4))
;
udelay(500);
/* We transferred all of the SCP firmware. Running it */
writel(GX_MB_CMD_END, GX_SEC_HIU_MAILBOX_SET_0 + 3 * 3 * 4);
}
void board_fit_image_post_process(const void *fit, int node, void **image, size_t *size)
{
const char *name = fit_get_name(fit, node, NULL);
int noffset = 0, value_len;
u8 *value;
if (strcmp("scp", name) && strcmp("bl301", name))
return;
fdt_for_each_subnode(noffset, fit, node) {
if (strncmp(fit_get_name(fit, noffset, NULL),
FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME)))
continue;
if (fit_image_hash_get_value(fit, noffset, &value, &value_len))
continue;
/* Send the SCP firmware to the SCP */
send_scp(*image, *size, value, value_len);
break;
}
}
#endif
void meson_power_init(void)
{
/* TODO: Support more voltages */
/* Init PWM B */
clrsetbits_32(GX_PWM_MISC_REG_AB, 0x7f << 16, (1 << 23) | (1 << 1));
/* Set voltage */
if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1120MV))
writel(0x02001a, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1100MV))
writel(0x040018, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1000MV))
writel(0x0e000e, GX_PWM_PWM_B);
clrbits_32(GX_PIN_MUX_REG7, 1 << 22);
clrsetbits_32(GX_PIN_MUX_REG3, 1 << 22, 1 << 21);
/* Init PWM D */
clrsetbits_32(GX_PWM_MISC_REG_CD, 0x7f << 16, (1 << 23) | (1 << 1));
/* Set voltage */
if (CONFIG_IS_ENABLED(MESON_GX_VDDEE_1100MV))
writel(0x040018, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VDDEE_1000MV))
writel(0x0e000e, GX_PWM_PWM_B);
clrbits_32(GX_PIN_MUX_REG7, 1 << 23);
setbits_32(GX_PIN_MUX_REG3, 1 << 20);
}

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/gx.h>
void meson_power_init_gxl(void)
{
/* TODO: Support more voltages */
/* Init PWM B */
clrsetbits_32(GX_PWM_MISC_REG_AB, 0x7f << 16, (1 << 23) | (1 << 1));
/* Set voltage */
if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1120MV))
writel(0x02001a, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1100MV))
writel(0x040018, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VCCK_1000MV))
writel(0x0e000e, GX_PWM_PWM_B);
clrbits_32(GX_PIN_MUX_REG1, 1 << 10);
clrsetbits_32(GX_PIN_MUX_REG2, 1 << 5, 1 << 11);
/* Init PWM D */
clrsetbits_32(GX_PWM_MISC_REG_CD, 0x7f << 16, (1 << 23) | (1 << 1));
/* Set voltage */
if (CONFIG_IS_ENABLED(MESON_GX_VDDEE_1100MV))
writel(0x040018, GX_PWM_PWM_B);
else if (CONFIG_IS_ENABLED(MESON_GX_VDDEE_1000MV))
writel(0x0e000e, GX_PWM_PWM_B);
clrbits_32(GX_PIN_MUX_REG1, (1 << 9) | (1 << 11));
setbits_32(GX_PIN_MUX_REG2, 1 << 12);
}

123
arch/arm/mach-meson/spl.c Normal file
View File

@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
* Copyright (C) 2023, Ferass El Hafidi <funderscore@postmarketos.org>
*/
#include <spl.h>
#include <hang.h>
#include <asm/io.h>
#include <asm/spl.h>
#include <asm/arch/boot.h>
#include <vsprintf.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <atf_common.h>
#include <image.h>
#include <asm/arch/gx.h>
#include <linux/delay.h>
#include <asm/arch/clock-gx.h>
u32 spl_boot_device(void)
{
int boot_device = meson_get_boot_device();
switch (boot_device) {
case BOOT_DEVICE_EMMC:
return BOOT_DEVICE_MMC2;
case BOOT_DEVICE_SD:
return BOOT_DEVICE_MMC1;
/*
* TODO: Get USB DFU to work
* Right now we just panic when booted from USB.
*/
case BOOT_DEVICE_USB:
if (CONFIG_IS_ENABLED(YMODEM_SUPPORT))
return BOOT_DEVICE_UART;
else
return BOOT_DEVICE_DFU;
}
panic("Unknown device %d\n", boot_device);
return BOOT_DEVICE_NONE; /* Never reached */
}
__weak struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
{
return (void *)CONFIG_TEXT_BASE + 0x4000000;
}
__weak void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len)
{
/* HACK: use same fit load buffer address as for mmc raw */
return spl_get_load_buffer(0, fit_size);
}
__weak bool spl_load_simple_fit_skip_processing(void)
{
return false;
}
/* To be defined in dram-${GENERATION}.c */
__weak int dram_init(void)
{
return 0;
}
/* Placeholder functions to be defined in SoC-specific spl-... file */
__weak void meson_power_init(void)
{
}
__weak int meson_pll_init(void)
{
return 0;
}
void board_init_f(ulong dummy)
{
int ret;
/* Restart execution at EL3 */
if (current_el() != 3) {
struct pt_regs regs = {0};
static struct entry_point_info spl_ep_info;
SET_PARAM_HEAD(&spl_ep_info, ATF_PARAM_BL31, ATF_VERSION_1, 0);
spl_ep_info.pc = CONFIG_SPL_TEXT_BASE;
spl_ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS);
regs.regs[0] = 0xc0000000;
regs.regs[1] = (unsigned long)&spl_ep_info;
smc_call(&regs);
}
meson_power_init();
ret = meson_pll_init();
if (ret) {
debug("meson_pll_init() failed: %d\n", ret);
return;
}
ret = dram_init();
if (ret) {
debug("dram_init() failed: %d\n", ret);
hang();
}
if (CONFIG_IS_ENABLED(OF_CONTROL)) {
ret = spl_early_init();
if (ret) {
debug("spl_early_init() failed: %d\n", ret);
hang();
}
}
spl_init();
icache_enable();
preloader_console_init();
#if !CONFIG_IS_ENABLED(WDT_MESON_GXBB)
/* Disable watchdog */
clrbits_32(GX_WDT_CTRL_REG, (1 << 18) | (1 << 25));
#endif
}

View File

@@ -0,0 +1,38 @@
#
# U-Boot SPL fragment for odroid-c2
#
CONFIG_SPL=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SPL_TEXT_BASE=0xd9001000
CONFIG_SPL_STACK=0xd9013000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0xd900c000
CONFIG_SPL_HAVE_INIT_STACK=y
CONFIG_SPL_BSS_MAX_SIZE=0x1000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_SPL_SHA256=y
# CONFIG_SPL_SHA1 is not set
# Enable MMC and serial drivers
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_MMC=y
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x100
# CONFIG_SYS_MMCSD_FS_BOOT is not set
# Image things
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_SPL_MAX_SIZE=0xb000
CONFIG_SPL_PAD_TO=0x1fe00
CONFIG_SPL_ATF=y
CONFIG_SPL_OF_CONTROL=y
# DRAM configuration
CONFIG_DRAM_SIZE=2048
CONFIG_DRAM_2T_MODE=y
CONFIG_DRAM_TWO_IDENTICAL_RANKS=y

View File

@@ -0,0 +1,39 @@
#
# U-Boot SPL fragment for videostrong-kii-pro
#
CONFIG_SPL=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SPL_TEXT_BASE=0xd9001000
CONFIG_SPL_STACK=0xd9013000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0xd900c000
CONFIG_SPL_HAVE_INIT_STACK=y
CONFIG_SPL_BSS_MAX_SIZE=0x1000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_SPL_SHA256=y
# CONFIG_SPL_SHA1 is not set
# Enable MMC and serial drivers
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_MMC=y
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x100
# CONFIG_SYS_MMCSD_FS_BOOT is not set
# Image things
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_SPL_MAX_SIZE=0xb000
CONFIG_SPL_PAD_TO=0x1fe00
CONFIG_SPL_ATF=y
CONFIG_SPL_OF_CONTROL=y
# DRAM configuration
CONFIG_DRAM_SIZE=2048
CONFIG_DRAM_2T_MODE=y
CONFIG_DRAM_TWO_DIFF_RANKS=y

View File

@@ -0,0 +1,36 @@
#
# U-Boot SPL fragment for libretech-cc (1 GB variant)
#
CONFIG_SPL=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SPL_TEXT_BASE=0xd9001000
CONFIG_SPL_STACK=0xd9013000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0xd900c000
CONFIG_SPL_HAVE_INIT_STACK=y
CONFIG_SPL_BSS_MAX_SIZE=0x1000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_SPL_SHA256=y
# CONFIG_SPL_SHA1 is not set
# Enable MMC and serial drivers
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_MMC=y
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x100
# CONFIG_SYS_MMCSD_FS_BOOT is not set
# Image things
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_MAX_SIZE=0xb000
CONFIG_SPL_PAD_TO=0x1fe00
CONFIG_SPL_ATF=y
CONFIG_SPL_OF_CONTROL=y
# DRAM configuration
CONFIG_DRAM_2T_MODE=y
CONFIG_DRAM_DQS_CORR=y

View File

@@ -0,0 +1,38 @@
#
# U-Boot SPL fragment for libretech-cc (2 GB variant)
#
CONFIG_SPL=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SPL_TEXT_BASE=0xd9001000
CONFIG_SPL_STACK=0xd9013000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0xd900c000
CONFIG_SPL_HAVE_INIT_STACK=y
CONFIG_SPL_BSS_MAX_SIZE=0x1000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_SPL_SHA256=y
# CONFIG_SPL_SHA1 is not set
# Enable MMC and serial drivers
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_MMC=y
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x100
# CONFIG_SYS_MMCSD_FS_BOOT is not set
# Image things
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_MAX_SIZE=0xb000
CONFIG_SPL_PAD_TO=0x1fe00
CONFIG_SPL_ATF=y
CONFIG_SPL_OF_CONTROL=y
# DRAM configuration
CONFIG_DRAM_SIZE=2048
CONFIG_DRAM_2T_MODE=y
CONFIG_DRAM_DQS_CORR=y
CONFIG_DRAM_TWO_IDENTICAL_RANKS=y

View File

@@ -12,20 +12,6 @@
#include <asm/io.h>
#include <asm/arch/eth.h>
struct efi_fw_image fw_images[] = {
{
.fw_name = u"AML_A311D_CC_BOOT",
.image_index = 1,
},
};
struct efi_capsule_update_info update_info = {
.dfu_string = "sf 0:0=u-boot-bin raw 0 0x10000",
.num_images = ARRAY_SIZE(fw_images),
.images = fw_images,
};
#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO)
void set_dfu_alt_info(char *interface, char *devstr)
{

View File

@@ -20,19 +20,6 @@
#define EFUSE_MAC_OFFSET 52
#define EFUSE_MAC_SIZE 6
struct efi_fw_image fw_images[] = {
{
.fw_name = u"AML_S805X_AC_BOOT",
.image_index = 1,
},
};
struct efi_capsule_update_info update_info = {
.dfu_string = "sf 0:0=u-boot-bin raw 0 0x10000",
.num_images = ARRAY_SIZE(fw_images),
.images = fw_images,
};
#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO)
void set_dfu_alt_info(char *interface, char *devstr)
{

View File

@@ -12,20 +12,6 @@
#include <asm/io.h>
#include <asm/arch/eth.h>
struct efi_fw_image fw_images[] = {
{
.fw_name = u"AML_S905D3_CC_BOOT",
.image_index = 1,
},
};
struct efi_capsule_update_info update_info = {
.dfu_string = "sf 0:0=u-boot-bin raw 0 0x10000",
.num_images = ARRAY_SIZE(fw_images),
.images = fw_images,
};
#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO)
void set_dfu_alt_info(char *interface, char *devstr)
{

View File

@@ -185,6 +185,7 @@ static const table_entry_t uimage_type[] = {
{ IH_TYPE_STARFIVE_SPL, "sfspl", "StarFive SPL Image" },
{ IH_TYPE_TFA_BL31, "tfa-bl31", "TFA BL31 Image", },
{ IH_TYPE_STM32IMAGE_V2, "stm32imagev2", "STMicroelectronics STM32 Image V2.0" },
{ IH_TYPE_AMLIMAGE, "amlimage", "Amlogic Boot Image" },
{ -1, "", "", },
};

View File

@@ -41,6 +41,7 @@ config SPL_SIZE_LIMIT
default 0x11000 if ARCH_MX6 && !MX6_OCRAM_256KB
default 0x31000 if ARCH_MX6 && MX6_OCRAM_256KB
default 0x30000 if ARCH_MVEBU && ARMADA_32BIT
default 0xb000 if ARCH_MESON && MESON_GX
default 0x0
help
Specifies the maximum length of the U-Boot SPL image.

View File

@@ -78,6 +78,7 @@ Boot Documentation
boot-flow
pre-generated-fip
spl
Board Documentation
-------------------

View File

@@ -98,6 +98,13 @@ The repo also provides the following files used with GXBB boards:
The repo also supports the open-source 'gxlimg' signing tool that can be used to sign
U-Boot binaries for GXL/GXM/G12A/G12B/SM1 boards: https://github.com/repk/gxlimg
The following binaries can be replaced with open-source implementations:
- bl2.bin (GXBB and GXL only)
- bl31.img (GXBB, GXL, AXG and G12A only)
Refer to `Experimental U-Boot SPL Support`_ if you wish to replace them.
Licensing
---------
@@ -129,3 +136,5 @@ clarified. The current Amlogic distribution licence is below:
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.. _`Experimental U-Boot SPL Support`: spl.rst

77
doc/board/amlogic/spl.rst Normal file
View File

@@ -0,0 +1,77 @@
.. SPDX-License-Identifier: GPL-2.0+
Experimental U-Boot SPL Support
===============================
There's some experimental support for some Amlogic SoCs, in U-Boot SPL. It
replaces the proprietary bl2.bin blob used for DRAM init. Currently Meson GX
SoCs (GXBB, GXL) are supported.
A subset of Amlogic boards have SPL enabled. These boards have been tested and
are known to work to an extent.
Building Arm Trusted Firmware (TF-A)
------------------------------------
This U-Boot SPL port requires the BL31 stage of mainline Arm Trusted
Firmware-A firmware. It provides an open source implementation of secure
software for Armv8-A. Build it with:
.. code-block:: bash
$ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
$ cd trusted-firmware-a
$ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=your_soc AML_STDPARAMS=1
Replace ``your_soc`` with the SoC target you wish to build for. For GXBB it's
``gxbb`` and for GXL it's ``gxl``.
Building a bl30_new.bin binary
------------------------------
``bl30_new.bin`` has both ``bl30.bin`` and ``bl301.bin`` binary blobs
bundled. The former is the proper system control processor firmware and the
latter is a "plug-in" for board-specific DVFS/suspend-resume parameters. For
more info you may wish to read this page: `Pre-Generated FIP File Repo`_.
To build using the FIP file repo, simply issue the following commands:
.. code-block:: bash
$ cd amlogic-boot-fip/your_board
$ make bl30_new.bin
.. _`Pre-Generated FIP File Repo`: pre-generated-fip.rst
U-Boot compilation
------------------
U-Boot SPL is not enabled by default, instead there are config fragments that
can be used to enable it, with per-board configuration:
- ``spl-libretech-cc-1gb.config``: 1 GB LePotato board
- ``spl-libretech-cc-2gb.config``: 2 GB LePotato board
- ``spl-odroid-c2.config``: ODROID-C2
- ``spl-videostrong-kii-pro.config``: Videostrong KII Pro
Pick one of them then:
.. code-block:: bash
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ export BL31=path/to/tf-a/bl31.bin # Upstream TF-A BL31 binary
$ export SCP=path/to/bl30_new.bin # bl30_new.bin binary
$ make <yourboardname>_defconfig spl-<yourboardname>.config
$ make
Write to SD:
.. code-block:: bash
$ DEV=/dev/boot_device
$ dd if=u-boot-meson-with-spl.bin of=$DEV conv=fsync,notrunc bs=512 seek=1

View File

@@ -16,6 +16,7 @@
#include <linux/log2.h>
#include "meson_gx_mmc.h"
#if CONFIG_IS_ENABLED(DM_MMC)
bool meson_gx_mmc_is_compatible(struct udevice *dev,
enum meson_gx_mmc_compatible family)
{
@@ -23,6 +24,7 @@ bool meson_gx_mmc_is_compatible(struct udevice *dev,
return compat == family;
}
#endif
static inline void *get_regbase(const struct mmc *mmc)
{
@@ -67,10 +69,14 @@ static void meson_mmc_config_clock(struct mmc *mmc)
* Other SoCs use CLK_CO_PHASE_180 by default.
* It needs to find what is a proper value about each SoCs.
*/
#if CONFIG_IS_ENABLED(DM_MMC)
if (meson_gx_mmc_is_compatible(mmc->dev, MMC_COMPATIBLE_SM1))
meson_mmc_clk |= CLK_CO_PHASE_270;
else
meson_mmc_clk |= CLK_CO_PHASE_180;
#else /* U-Boot SPL on GX SoCs */
meson_mmc_clk |= CLK_CO_PHASE_180;
#endif
/* 180 phase tx clock */
meson_mmc_clk |= CLK_TX_PHASE_000;
@@ -82,9 +88,14 @@ static void meson_mmc_config_clock(struct mmc *mmc)
meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK);
}
#if CONFIG_IS_ENABLED(DM_MMC)
static int meson_dm_mmc_set_ios(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else /* U-Boot SPL */
static int meson_legacy_mmc_set_ios(struct mmc *mmc)
{
#endif
uint32_t meson_mmc_cfg;
meson_mmc_config_clock(mmc);
@@ -193,10 +204,16 @@ static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd)
}
}
#if CONFIG_IS_ENABLED(DM_MMC)
static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else /* U-Boot SPL */
static int meson_legacy_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
#endif
struct meson_mmc_plat *pdata = mmc->priv;
uint32_t status;
ulong start;
@@ -235,6 +252,59 @@ static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
return ret;
}
#if !CONFIG_IS_ENABLED(DM_MMC) /* Non-DM MMC driver for use in U-Boot SPL */
struct meson_mmc_plat mmc_plat[2];
static int meson_legacy_mmc_init(struct mmc *mmc)
{
/* reset all status bits */
meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
/* disable interrupts */
meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN);
return 0;
}
static const struct mmc_ops meson_mmc_ops = {
.send_cmd = meson_legacy_mmc_send_cmd,
.set_ios = meson_legacy_mmc_set_ios,
.init = meson_legacy_mmc_init,
};
struct mmc *meson_mmc_init(int mmc_no)
{
struct meson_mmc_plat *pdata = &mmc_plat[mmc_no];
struct mmc_config *cfg = &pdata->cfg;
cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
MMC_VDD_31_32 | MMC_VDD_165_195;
cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT;
cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV);
cfg->f_max = 6000000; /* 6 MHz */
cfg->b_max = 127; /* max 128 - 1 block */
cfg->name = "Meson SD/eMMC";
cfg->ops = &meson_mmc_ops;
if (mmc_no == 0) /* MMC1: SD card */
pdata->regbase = (void *)0xd0072000;
else if (mmc_no == 1) /* MMC2: eMMC */
pdata->regbase = (void *)0xd0074000;
#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
/* Enable power if needed */
ret = mmc_pwrseq_get_power(dev, cfg);
if (!ret) {
ret = pwrseq_set_power(cfg->pwr_dev, true);
if (ret)
return ret;
}
#endif
return mmc_create(cfg, pdata);
}
#else /* DM-based driver for use in U-Boot proper */
static const struct dm_mmc_ops meson_dm_mmc_ops = {
.send_cmd = meson_dm_mmc_send_cmd,
.set_ios = meson_dm_mmc_set_ios,
@@ -278,10 +348,16 @@ static int meson_mmc_probe(struct udevice *dev)
cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
MMC_MODE_HS_52MHz | MMC_MODE_HS;
cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV);
cfg->f_max = 100000000; /* 100 MHz */
cfg->f_max = 40000000; /* 40 MHz */
cfg->b_max = 511; /* max 512 - 1 blocks */
cfg->name = dev->name;
if (IS_ENABLED(CONFIG_SPL_BUILD)) {
cfg->host_caps &= ~(MMC_MODE_HS_52MHz | MMC_MODE_HS);
cfg->f_max = 6000000; /* 6 MHz */
cfg->b_max = 127; /* max 128 - 1 block */
}
mmc->priv = pdata;
upriv->mmc = mmc;
@@ -336,3 +412,4 @@ U_BOOT_DRIVER(meson_mmc) = {
.of_to_plat = meson_mmc_of_to_plat,
.plat_auto = sizeof(struct meson_mmc_plat),
};
#endif /* CONFIG_IS_ENABLED(DM_MMC) */

View File

@@ -129,6 +129,7 @@ serial_initfunc(pxa_serial_initialize);
serial_initfunc(smh_serial_initialize);
serial_initfunc(sh_serial_initialize);
serial_initfunc(mtk_serial_initialize);
serial_initfunc(meson_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -167,6 +168,7 @@ int serial_initialize(void)
smh_serial_initialize();
sh_serial_initialize();
mtk_serial_initialize();
meson_serial_initialize();
serial_assign(default_serial_console()->name);

View File

@@ -3,9 +3,11 @@
* (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
*/
#if CONFIG_IS_ENABLED(DM_SERIAL)
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#endif
#include <errno.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
@@ -25,6 +27,15 @@ struct meson_serial_plat {
struct meson_uart *reg;
};
#if !CONFIG_IS_ENABLED(DM_SERIAL)
/* UART base address */
#if defined(CONFIG_MESON_GX)
#define AML_UART_BASE 0xc81004c0
#else /* G12A, AXG, ... */
#define AML_UART_BASE 0xff803000
#endif
#endif
/* AML_UART_STATUS bits */
#define AML_UART_PARITY_ERR BIT(16)
#define AML_UART_FRAME_ERR BIT(17)
@@ -51,6 +62,7 @@ struct meson_serial_plat {
#define AML_UART_REG5_USE_NEW_BAUD BIT(23) /* default 1 (use new baud rate register) */
#define AML_UART_REG5_BAUD_MASK 0x7fffff
#if CONFIG_IS_ENABLED(DM_SERIAL)
static u32 meson_calc_baud_divisor(ulong src_rate, u32 baud)
{
/*
@@ -245,6 +257,111 @@ U_BOOT_DRIVER(serial_meson) = {
.plat_auto = sizeof(struct meson_serial_plat),
};
#else
static int meson_serial_init(void)
{
struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
u32 val;
val = readl(&uart->control);
val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
writel(val, &uart->control);
val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
writel(val, &uart->control);
val |= (AML_UART_RX_EN | AML_UART_TX_EN);
writel(val, &uart->control);
return 0;
}
static int meson_serial_stop(void)
{
return 0;
}
static void meson_serial_setbrg(void)
{
}
static void meson_serial_putc(const char ch)
{
struct meson_uart *uart = (struct meson_uart *)AML_UART_BASE;
/* On '\n' also do '\r' */
if (ch == '\n')
meson_serial_putc('\r');
while (readl(&uart->status) & AML_UART_TX_FULL)
;
writel(ch, &uart->wfifo);
}
static void meson_serial_puts(const char *s)
{
while (*s)
meson_serial_putc(*s++);
}
static int meson_serial_getc(void)
{
struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
uint32_t status = readl(&uart->status);
if (status & AML_UART_RX_EMPTY)
return -EAGAIN;
if (status & AML_UART_ERR) {
u32 val = readl(&uart->control);
/* Clear error */
val |= AML_UART_CLR_ERR;
writel(val, &uart->control);
val &= ~AML_UART_CLR_ERR;
writel(val, &uart->control);
/* Remove spurious byte from fifo */
readl(&uart->rfifo);
return -EIO;
}
return readl(&uart->rfifo) & 0xff;
}
static int meson_serial_tstc(void)
{
struct meson_uart *const uart = (struct meson_uart *)AML_UART_BASE;
uint32_t status = readl(&uart->status);
if (status & AML_UART_RX_EMPTY)
return 0;
return 1;
}
struct serial_device meson_serial_device = {
.name = "meson_serial",
.start = meson_serial_init,
.stop = meson_serial_stop,
.setbrg = meson_serial_setbrg,
.getc = meson_serial_getc,
.tstc = meson_serial_tstc,
.putc = meson_serial_putc,
.puts = meson_serial_puts,
};
void meson_serial_initialize(void)
{
serial_register(&meson_serial_device);
}
__weak struct serial_device *default_serial_console(void)
{
return &meson_serial_device;
}
#endif
#ifdef CONFIG_DEBUG_UART_MESON
#include <debug_uart.h>

View File

@@ -234,6 +234,7 @@ enum image_type_t {
IH_TYPE_STARFIVE_SPL, /* StarFive SPL image */
IH_TYPE_TFA_BL31, /* TFA BL31 image */
IH_TYPE_STM32IMAGE_V2, /* STMicroelectronics STM32 Image V2.0 */
IH_TYPE_AMLIMAGE, /* Amlogic Boot Image */
IH_TYPE_COUNT, /* Number of image types */
};

View File

@@ -110,6 +110,7 @@ ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
# common objs for dumpimage and mkimage
dumpimage-mkimage-objs := aisimage.o \
amlimage.o \
atmelimage.o \
$(FIT_OBJS-y) \
$(FIT_SIG_OBJS-y) \

255
tools/amlimage.c Normal file
View File

@@ -0,0 +1,255 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright Contributors to the U-Boot project.
#include "imagetool.h"
#include <u-boot/sha256.h>
/*
* Image contain data in the following order:
* Nonce 16 byte
* Header 64 byte
* Digest 32 byte
* Padding align up to 4K
* Payload
*/
#define HEADER_MAGIC 0x4c4d4140 /* @AML */
#define HEADER_OFFSET 0x10 /* 16 */
#define HEADER_SIZE 0x40 /* 64 */
#define PAYLOAD_OFFSET 0x1000 /* 4096 */
struct amlimage_header {
uint32_t magic;
uint32_t total_size;
uint8_t header_size;
uint8_t root_key_index;
uint8_t version_major;
uint8_t version_minor;
uint32_t padding1;
uint32_t digest_type;
uint32_t digest_offset;
uint32_t digest_size;
uint32_t data_offset;
uint32_t key_type;
uint32_t key_offset;
uint32_t key_size;
uint32_t data_size;
uint32_t payload_type;
uint32_t payload_offset;
uint32_t payload_size;
uint32_t padding2;
} __packed;
struct amlimage_variant {
const char *name;
const struct amlimage_header hdr;
};
#define VARIANT(name, major, minor, size) \
{ name, { .magic = HEADER_MAGIC, .header_size = HEADER_SIZE, \
.version_major = major, .version_minor = minor, \
.payload_size = size, } }
static const struct amlimage_variant variants[] = {
VARIANT("gxbb", 1, 0, 0xb000),
VARIANT("gxl", 1, 1, 0xb000),
VARIANT("gxm", 1, 1, 0xb000),
VARIANT("axg", 1, 1, 0xb000),
VARIANT("g12a", 1, 1, 0xf000),
VARIANT("g12b", 1, 1, 0xf000),
VARIANT("sm1", 1, 1, 0xf000),
};
static const struct amlimage_variant *amlimage_get_variant(const char *name)
{
if (!name)
return NULL;
for (int i = 0; i < ARRAY_SIZE(variants); i++)
if (!strcmp(name, variants[i].name))
return &variants[i];
return NULL;
}
static int amlimage_check_params(struct image_tool_params *params)
{
const struct amlimage_variant *variant =
amlimage_get_variant(params->imagename);
int datafile_size;
if (params->lflag || params->iflag)
return EXIT_SUCCESS;
if (!variant) {
fprintf(stderr, "%s: unsupported image name: %s\n",
params->cmdname, params->imagename);
exit(EXIT_FAILURE);
}
datafile_size = imagetool_get_filesize(params, params->datafile);
if (datafile_size < 0) {
exit(EXIT_FAILURE);
} else if (datafile_size > variant->hdr.payload_size) {
fprintf(stderr, "%s: datafile is too large (%#x > %#x)\n",
params->cmdname, datafile_size,
variant->hdr.payload_size);
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
static int amlimage_verify_header(unsigned char *buf, int size,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = (void *)buf + HEADER_OFFSET;
if (size >= HEADER_OFFSET + HEADER_SIZE + SHA256_SUM_LEN &&
hdr->magic == HEADER_MAGIC && hdr->header_size == HEADER_SIZE &&
hdr->version_major == 1 && hdr->version_minor <= 1)
return 0;
return -1;
}
static void amlimage_print_header(const void *buf,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = buf + HEADER_OFFSET;
uint8_t digest[SHA256_SUM_LEN];
sha256_context ctx;
bool valid;
printf("Amlogic Boot Image %" PRIu8 ".%" PRIu8 "\n",
hdr->version_major, hdr->version_minor);
printf("Total size: %" PRIu32 "\n", hdr->total_size);
printf("Digest %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->digest_type, hdr->digest_size, hdr->digest_offset);
printf("Key %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->key_type, hdr->key_size, hdr->key_offset);
printf("Payload %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->payload_type, hdr->payload_size, hdr->payload_offset);
if (hdr->digest_type == 0) {
/* sha256 digest (normal boot) */
sha256_starts(&ctx);
/* Header and data is used as input for sha256 digest */
sha256_update(&ctx, (void *)hdr, hdr->header_size);
sha256_update(&ctx, (void *)hdr + hdr->data_offset, hdr->data_size);
sha256_finish(&ctx, digest);
valid = !memcmp((void *)hdr + hdr->digest_offset,
digest, SHA256_SUM_LEN);
printf("Data: %" PRIu32 " @ 0x%" PRIx32 " - %s\n",
hdr->data_size, hdr->data_offset, valid ? "OK" : "BAD");
} else {
/* RSA (secure boot) */
printf("Data: %" PRIu32 " @ 0x%" PRIx32 " - Secure Boot\n",
hdr->data_size, hdr->data_offset);
}
}
static void amlimage_set_header(void *buf, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
struct amlimage_header *hdr = buf + HEADER_OFFSET;
sha256_context ctx;
/* Use header size as initial size */
hdr->total_size = hdr->header_size;
/* Use sha256 digest (normal boot) */
hdr->digest_type = 0;
/* The sha256 digest is stored directly following the header */
hdr->digest_offset = hdr->total_size;
/* Unknown if this is used as block size instead of digest size */
hdr->digest_size = 512;
hdr->total_size += hdr->digest_size;
/* Use key as padding so that payload ends up 4K aligned in TZRAM */
hdr->key_type = 0;
hdr->key_offset = hdr->total_size;
hdr->key_size = PAYLOAD_OFFSET - HEADER_OFFSET - hdr->key_offset;
hdr->total_size += hdr->key_size;
/* With padding above payload will have a 0x1000 offset in TZRAM */
hdr->payload_type = 0;
hdr->payload_offset = hdr->total_size;
/* Payload size has already been copied from the variant header */
hdr->total_size += hdr->payload_size;
/* Set the data range to be used as input for sha256 digest */
hdr->data_offset = hdr->digest_offset + SHA256_SUM_LEN;
hdr->data_size = hdr->total_size - hdr->data_offset;
sha256_starts(&ctx);
/* Header and data is used as input for sha256 digest */
sha256_update(&ctx, (void *)hdr, hdr->header_size);
sha256_update(&ctx, (void *)hdr + hdr->data_offset, hdr->data_size);
/* Write sha256 digest to the 32 bytes directly following the header */
sha256_finish(&ctx, (void *)hdr + hdr->digest_offset);
}
static int amlimage_extract_subimage(void *buf,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = buf + HEADER_OFFSET;
/* Save payload as the subimage */
return imagetool_save_subimage(params->outfile,
(ulong)hdr + hdr->payload_offset,
hdr->payload_size);
}
static int amlimage_check_image_type(uint8_t type)
{
if (type == IH_TYPE_AMLIMAGE)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
static int amlimage_vrec_header(struct image_tool_params *params,
struct image_type_params *tparams)
{
const struct amlimage_variant *variant =
amlimage_get_variant(params->imagename);
const struct amlimage_header *hdr = &variant->hdr;
/* Use payload offset as header size, datafile will be appended */
tparams->header_size = PAYLOAD_OFFSET;
tparams->hdr = calloc(1, tparams->header_size);
if (!tparams->hdr) {
fprintf(stderr, "%s: Can't alloc header: %s\n",
params->cmdname, strerror(errno));
exit(EXIT_FAILURE);
}
/* Start with a copy of the variant header */
memcpy(tparams->hdr + HEADER_OFFSET, hdr, hdr->header_size);
/* Pad up to payload size of the variant header */
return hdr->payload_size - params->file_size;
}
/*
* amlimage parameters
*/
U_BOOT_IMAGE_TYPE(
amlimage,
"Amlogic Boot Image",
0,
NULL,
amlimage_check_params,
amlimage_verify_header,
amlimage_print_header,
amlimage_set_header,
amlimage_extract_subimage,
amlimage_check_image_type,
NULL,
amlimage_vrec_header
);