diff options
| author | Tom Rini <[email protected]> | 2025-12-19 10:30:26 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-12-19 10:30:26 -0600 |
| commit | adbbf5982d26801224b10cd847dc468f8b5e4095 (patch) | |
| tree | edb0eb14bfb2b16e7b92141a64f0d122259eb660 | |
| parent | 930eff5416ea98ebd09cec73f5d06a7033b4d52e (diff) | |
| parent | 6e844dd4df6765e5e772b5606a675c16fe98d9ac (diff) | |
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
48 files changed, 3449 insertions, 52 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index c9853f40992..27ce73d83f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/arch/arm/dts/meson-gx-u-boot.dtsi b/arch/arm/dts/meson-gx-u-boot.dtsi index 9e0620f395e..cef7f90fcd4 100644 --- a/arch/arm/dts/meson-gx-u-boot.dtsi +++ b/arch/arm/dts/meson-gx-u-boot.dtsi @@ -2,6 +2,7 @@ /* * Copyright (c) 2019 BayLibre, SAS. * Author: Maxime Jourdan <[email protected]> + * Copyright (c) 2023 Ferass El Hafidi <[email protected]> */ / { @@ -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 diff --git a/arch/arm/dts/meson-gxbb-kii-pro-u-boot.dtsi b/arch/arm/dts/meson-gxbb-kii-pro-u-boot.dtsi index 191c5192c68..4a027b9022b 100644 --- a/arch/arm/dts/meson-gxbb-kii-pro-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-kii-pro-u-boot.dtsi @@ -4,7 +4,7 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" ðmac { snps,reset-gpio = <&gpio GPIOZ_14 0>; diff --git a/arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi b/arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi index 2a245bbe7f2..53d5c0113fc 100644 --- a/arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi @@ -4,7 +4,7 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" ðmac { snps,reset-gpio = <&gpio GPIOZ_14 0>; diff --git a/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi b/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi index 5a2be8171e1..1bd000eaa86 100644 --- a/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi @@ -4,7 +4,7 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" / { smbios { diff --git a/arch/arm/dts/meson-gxbb-p200-u-boot.dtsi b/arch/arm/dts/meson-gxbb-p200-u-boot.dtsi index c35158d7e9e..1bef64dc01d 100644 --- a/arch/arm/dts/meson-gxbb-p200-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-p200-u-boot.dtsi @@ -4,4 +4,4 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" diff --git a/arch/arm/dts/meson-gxbb-p201-u-boot.dtsi b/arch/arm/dts/meson-gxbb-p201-u-boot.dtsi index c35158d7e9e..1bef64dc01d 100644 --- a/arch/arm/dts/meson-gxbb-p201-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-p201-u-boot.dtsi @@ -4,4 +4,4 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" diff --git a/arch/arm/dts/meson-gxbb-u-boot.dtsi b/arch/arm/dts/meson-gxbb-u-boot.dtsi new file mode 100644 index 00000000000..a4dc1c136f1 --- /dev/null +++ b/arch/arm/dts/meson-gxbb-u-boot.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong <[email protected]> + */ + +#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 diff --git a/arch/arm/dts/meson-gxbb-wetek-hub-u-boot.dtsi b/arch/arm/dts/meson-gxbb-wetek-hub-u-boot.dtsi index 3743053eb9c..cd2e9b5099e 100644 --- a/arch/arm/dts/meson-gxbb-wetek-hub-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-wetek-hub-u-boot.dtsi @@ -4,7 +4,7 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" ðmac { snps,reset-gpio = <&gpio GPIOZ_14 0>; diff --git a/arch/arm/dts/meson-gxbb-wetek-play2-u-boot.dtsi b/arch/arm/dts/meson-gxbb-wetek-play2-u-boot.dtsi index 3743053eb9c..cd2e9b5099e 100644 --- a/arch/arm/dts/meson-gxbb-wetek-play2-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-wetek-play2-u-boot.dtsi @@ -4,7 +4,7 @@ * Author: Neil Armstrong <[email protected]> */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" ðmac { snps,reset-gpio = <&gpio GPIOZ_14 0>; diff --git a/arch/arm/dts/meson-gxl-u-boot.dtsi b/arch/arm/dts/meson-gxl-u-boot.dtsi index c35158d7e9e..3f1bbc1038f 100644 --- a/arch/arm/dts/meson-gxl-u-boot.dtsi +++ b/arch/arm/dts/meson-gxl-u-boot.dtsi @@ -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 diff --git a/arch/arm/include/asm/arch-meson/boot.h b/arch/arm/include/asm/arch-meson/boot.h index a11dfde719e..e66b45983fe 100644 --- a/arch/arm/include/asm/arch-meson/boot.h +++ b/arch/arm/include/asm/arch-meson/boot.h @@ -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 * diff --git a/arch/arm/include/asm/arch-meson/clock-gx.h b/arch/arm/include/asm/arch-meson/clock-gx.h index 13a2e7688fc..72e4bac7aad 100644 --- a/arch/arm/include/asm/arch-meson/clock-gx.h +++ b/arch/arm/include/asm/arch-meson/clock-gx.h @@ -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 diff --git a/arch/arm/include/asm/arch-meson/dram-gx.h b/arch/arm/include/asm/arch-meson/dram-gx.h new file mode 100644 index 00000000000..177e0ac1a65 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/dram-gx.h @@ -0,0 +1,341 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2015, Amlogic, Inc. All rights reserved. + * Copyright (C) 2023, Ferass El Hafidi <[email protected]> + */ +#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 diff --git a/arch/arm/include/asm/arch-meson/dram-gxbb.h b/arch/arm/include/asm/arch-meson/dram-gxbb.h new file mode 100644 index 00000000000..b04f66d6336 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/dram-gxbb.h @@ -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 <[email protected]> + */ +#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 diff --git a/arch/arm/include/asm/arch-meson/dram-gxl.h b/arch/arm/include/asm/arch-meson/dram-gxl.h new file mode 100644 index 00000000000..c52ef37c1bf --- /dev/null +++ b/arch/arm/include/asm/arch-meson/dram-gxl.h @@ -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 <[email protected]> + */ +#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 diff --git a/arch/arm/include/asm/arch-meson/dram-settings-gx.h b/arch/arm/include/asm/arch-meson/dram-settings-gx.h new file mode 100644 index 00000000000..b4ced2eda67 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/dram-settings-gx.h @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023-2024, Ferass El Hafidi <[email protected]> + */ +#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 */ diff --git a/arch/arm/include/asm/arch-meson/dram-timings-gx.h b/arch/arm/include/asm/arch-meson/dram-timings-gx.h new file mode 100644 index 00000000000..144b727e998 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/dram-timings-gx.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2024, Ferass El Hafidi <[email protected]> + */ +#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 diff --git a/arch/arm/include/asm/arch-meson/gx.h b/arch/arm/include/asm/arch-meson/gx.h index 26ec5d0bc34..b4cb2a5ddbc 100644 --- a/arch/arm/include/asm/arch-meson/gx.h +++ b/arch/arm/include/asm/arch-meson/gx.h @@ -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__ */ diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 7570f48e25f..ef86129b535 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -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 diff --git a/arch/arm/mach-meson/Makefile b/arch/arm/mach-meson/Makefile index 535b0878b91..08a24d4b24f 100644 --- a/arch/arm/mach-meson/Makefile +++ b/arch/arm/mach-meson/Makefile @@ -2,8 +2,18 @@ # # Copyright (c) 2016 Beniamino Galvani <[email protected]> -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 diff --git a/arch/arm/mach-meson/board-common.c b/arch/arm/mach-meson/board-common.c index 39774c43049..a5afc2d75c0 100644 --- a/arch/arm/mach-meson/board-common.c +++ b/arch/arm/mach-meson/board-common.c @@ -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 } diff --git a/arch/arm/mach-meson/capsule.c b/arch/arm/mach-meson/capsule.c new file mode 100644 index 00000000000..6e968a59c2c --- /dev/null +++ b/arch/arm/mach-meson/capsule.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025, Ferass El Hafidi <[email protected]> + */ + +#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; +} diff --git a/arch/arm/mach-meson/dram-gx.c b/arch/arm/mach-meson/dram-gx.c new file mode 100644 index 00000000000..049beda6ef3 --- /dev/null +++ b/arch/arm/mach-meson/dram-gx.c @@ -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 <[email protected]> + */ +#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; +} diff --git a/arch/arm/mach-meson/dram-gxbb.c b/arch/arm/mach-meson/dram-gxbb.c new file mode 100644 index 00000000000..9cfe3bac071 --- /dev/null +++ b/arch/arm/mach-meson/dram-gxbb.c @@ -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 <[email protected]> + */ +#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); +} diff --git a/arch/arm/mach-meson/dram-gxl.c b/arch/arm/mach-meson/dram-gxl.c new file mode 100644 index 00000000000..60c41632582 --- /dev/null +++ b/arch/arm/mach-meson/dram-gxl.c @@ -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 <[email protected]> + */ +#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); +} + diff --git a/arch/arm/mach-meson/spl-gx.c b/arch/arm/mach-meson/spl-gx.c new file mode 100644 index 00000000000..a7d2b672421 --- /dev/null +++ b/arch/arm/mach-meson/spl-gx.c @@ -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 <[email protected]> + */ +#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 diff --git a/arch/arm/mach-meson/spl-gxbb.c b/arch/arm/mach-meson/spl-gxbb.c new file mode 100644 index 00000000000..954254bd9ad --- /dev/null +++ b/arch/arm/mach-meson/spl-gxbb.c @@ -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 <[email protected]> + */ +#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); +} diff --git a/arch/arm/mach-meson/spl-gxl.c b/arch/arm/mach-meson/spl-gxl.c new file mode 100644 index 00000000000..07fff695be8 --- /dev/null +++ b/arch/arm/mach-meson/spl-gxl.c @@ -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 <[email protected]> + */ +#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); +} diff --git a/arch/arm/mach-meson/spl.c b/arch/arm/mach-meson/spl.c new file mode 100644 index 00000000000..28a63f39d36 --- /dev/null +++ b/arch/arm/mach-meson/spl.c @@ -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 <[email protected]> + */ +#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(®s); + } + + 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 +} diff --git a/board/amlogic/p200/spl-odroid-c2.config b/board/amlogic/p200/spl-odroid-c2.config new file mode 100644 index 00000000000..f3497c54153 --- /dev/null +++ b/board/amlogic/p200/spl-odroid-c2.config @@ -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 diff --git a/board/amlogic/p200/spl-videostrong-kii-pro.config b/board/amlogic/p200/spl-videostrong-kii-pro.config new file mode 100644 index 00000000000..62df2333717 --- /dev/null +++ b/board/amlogic/p200/spl-videostrong-kii-pro.config @@ -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 + diff --git a/board/amlogic/p212/spl-libretech-cc-1gb.config b/board/amlogic/p212/spl-libretech-cc-1gb.config new file mode 100644 index 00000000000..be414c8770e --- /dev/null +++ b/board/amlogic/p212/spl-libretech-cc-1gb.config @@ -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 diff --git a/board/amlogic/p212/spl-libretech-cc-2gb.config b/board/amlogic/p212/spl-libretech-cc-2gb.config new file mode 100644 index 00000000000..9f7b81fd6e9 --- /dev/null +++ b/board/amlogic/p212/spl-libretech-cc-2gb.config @@ -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 diff --git a/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c index b3b78bfd0ea..760dc740004 100644 --- a/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c +++ b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c @@ -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) { diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c index daece299848..966fd287878 100644 --- a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -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) { diff --git a/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c index 09a69b090ab..760dc740004 100644 --- a/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c +++ b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c @@ -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) { diff --git a/boot/image.c b/boot/image.c index abac2c7034b..dd96f712b6f 100644 --- a/boot/image.c +++ b/boot/image.c @@ -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, "", "", }, }; diff --git a/common/spl/Kconfig b/common/spl/Kconfig index d413b54aa70..9e0402f6827 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -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. diff --git a/doc/board/amlogic/index.rst b/doc/board/amlogic/index.rst index dcd935224ac..23380ac33f2 100644 --- a/doc/board/amlogic/index.rst +++ b/doc/board/amlogic/index.rst @@ -78,6 +78,7 @@ Boot Documentation boot-flow pre-generated-fip + spl Board Documentation ------------------- diff --git a/doc/board/amlogic/pre-generated-fip.rst b/doc/board/amlogic/pre-generated-fip.rst index 6a43d776d43..d820bd09115 100644 --- a/doc/board/amlogic/pre-generated-fip.rst +++ b/doc/board/amlogic/pre-generated-fip.rst @@ -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 diff --git a/doc/board/amlogic/spl.rst b/doc/board/amlogic/spl.rst new file mode 100644 index 00000000000..0495cd1ee9f --- /dev/null +++ b/doc/board/amlogic/spl.rst @@ -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 + diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index 5852b24c6d2..76af3873e15 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -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) */ diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index e10ca6eef76..c0b1eb30561 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -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); diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c index bb79b972957..cc71381f87e 100644 --- a/drivers/serial/serial_meson.c +++ b/drivers/serial/serial_meson.c @@ -3,9 +3,11 @@ * (C) Copyright 2016 Beniamino Galvani <[email protected]> */ +#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> diff --git a/include/image.h b/include/image.h index 8841dea06c9..34efac6056d 100644 --- a/include/image.h +++ b/include/image.h @@ -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 */ }; diff --git a/tools/Makefile b/tools/Makefile index ae6a3052646..982e35f5881 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -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) \ diff --git a/tools/amlimage.c b/tools/amlimage.c new file mode 100644 index 00000000000..ecb06bc535b --- /dev/null +++ b/tools/amlimage.c @@ -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 +); |
