From 18c1654567dca70d848a4da1af93ea86632a45ba Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 26 Nov 2025 12:17:03 +0000 Subject: [PATCH 01/13] tools: mkimage: Add Amlogic Boot Image type Add support for creating an Amlogic Boot Image that pass CHK in BL1 on Amlogic AArch64 SoCs. Images can optionally be signed for secure boot scenario, however creation of signed images has not been implemented. Example of how to use it: # Create an amlogic boot image tools/mkimage -T amlimage -n gxbb -d u-boot-spl.bin u-boot-amlogic.bin # List boot image header information tools/mkimage -l u-boot-amlogic.bin # Extract amlogic boot image payload tools/dumpimage -T amlimage -o bl2-payload.bin u-boot-amlogic.bin Or with binman using something like: binman { u-boot-amlogic { filename = "u-boot-amlogic.bin"; pad-byte = <0xff>; mkimage { filename = "bl2.bin"; args = "-n", "gxbb", "-T", "amlimage"; u-boot-spl { }; }; }; }; Reviewed-by: Neil Armstrong Signed-off-by: Jonas Karlman [Ferass: check digest type in _print_header, version in _verify_image] Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-1-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- MAINTAINERS | 1 + boot/image.c | 1 + include/image.h | 1 + tools/Makefile | 1 + tools/amlimage.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 tools/amlimage.c 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/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/include/image.h b/include/image.h index d543c6cf254..ae844ec7e02 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 + +/* + * 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 +); From 3eee9c1f61fc4ec0b7823477fbdac31d136fc729 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:04 +0000 Subject: [PATCH 02/13] mmc: meson_gx_mmc: add minimal non-DM driver Add a minimal non-DM MMC driver for use in size-constrained environments. Signed-off-by: Ferass El Hafidi Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251126-spl-gx-v5-2-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/gx.h | 5 ++ drivers/mmc/meson_gx_mmc.c | 77 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/arch/arm/include/asm/arch-meson/gx.h b/arch/arm/include/asm/arch-meson/gx.h index 26ec5d0bc34..8cfc6b00329 100644 --- a/arch/arm/include/asm/arch-meson/gx.h +++ b/arch/arm/include/asm/arch-meson/gx.h @@ -41,4 +41,9 @@ #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) +/* Non-DM MMC init */ +#if CONFIG_IS_ENABLED(MMC) && !CONFIG_IS_ENABLED(DM_MMC) +struct mmc *meson_mmc_init(int mmc_no); +#endif + #endif /* __GX_H__ */ diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index 5852b24c6d2..d1558ebe3a2 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -16,6 +16,7 @@ #include #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, @@ -282,6 +352,12 @@ static int meson_mmc_probe(struct udevice *dev) 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) */ From ec958be7cc76b4f305fd78d55a20502d7c8b35b3 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:05 +0000 Subject: [PATCH 03/13] serial: serial_meson: add minimal non-DM driver It is very limited and minimal, only implements putc/puts. This minimal driver is intended to be used in SPL, and other size-constrained situations. Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-3-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- drivers/serial/serial.c | 2 + drivers/serial/serial_meson.c | 119 +++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 1 deletion(-) 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 */ +#if CONFIG_IS_ENABLED(DM_SERIAL) #include -#include #include +#endif +#include #include #include #include @@ -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 From f39f6eeaa8c19053405788479b61a1e3b17ec150 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:06 +0000 Subject: [PATCH 04/13] arm: meson: initial u-boot SPL support for GX SoCs Add initial boilerplate for U-Boot SPL support on Amlogic. Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-4-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/clock-gx.h | 14 ++ arch/arm/include/asm/arch-meson/gx.h | 36 +++++ arch/arm/mach-meson/Kconfig | 42 +++++- arch/arm/mach-meson/Makefile | 7 + arch/arm/mach-meson/board-common.c | 11 ++ arch/arm/mach-meson/spl-gx.c | 168 +++++++++++++++++++++ arch/arm/mach-meson/spl-gxbb.c | 113 ++++++++++++++ arch/arm/mach-meson/spl-gxl.c | 39 +++++ arch/arm/mach-meson/spl.c | 123 +++++++++++++++ 9 files changed, 552 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-meson/spl-gx.c create mode 100644 arch/arm/mach-meson/spl-gxbb.c create mode 100644 arch/arm/mach-meson/spl-gxl.c create mode 100644 arch/arm/mach-meson/spl.c 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/gx.h b/arch/arm/include/asm/arch-meson/gx.h index 8cfc6b00329..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,9 +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..8d1bf91e98b 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,42 @@ config SYS_BOARD Based on this option board// will be used. +if MESON_GX && SPL +config SPL_SYS_MALLOC_F_LEN + default 0x2000 + +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..798b20df78a 100644 --- a/arch/arm/mach-meson/Makefile +++ b/arch/arm/mach-meson/Makefile @@ -4,6 +4,13 @@ obj-y += board-common.o sm.o board-info.o obj-$(CONFIG_MESON_GX) += board-gx.o +ifeq ($(CONFIG_SPL_BUILD),y) +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..c243c46c0fc 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) { @@ -150,5 +152,14 @@ int board_late_init(void) 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/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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + */ +#include +#include +#include +#include +#include + +#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 + */ +#include +#include +#include + +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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +} From 17d80a3b326ea94cab687236cfeac5fc7c2bca2e Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:07 +0000 Subject: [PATCH 05/13] arm: meson: spl: add support for SPL DRAM init Supports both GXBB and GXL SoCs. Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-5-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/dram-gx.h | 341 ++++++++++++++ arch/arm/include/asm/arch-meson/dram-gxbb.h | 168 +++++++ arch/arm/include/asm/arch-meson/dram-gxl.h | 193 ++++++++ .../include/asm/arch-meson/dram-settings-gx.h | 296 +++++++++++++ .../include/asm/arch-meson/dram-timings-gx.h | 117 +++++ arch/arm/mach-meson/Kconfig | 70 +++ arch/arm/mach-meson/Makefile | 3 + arch/arm/mach-meson/dram-gx.c | 419 ++++++++++++++++++ arch/arm/mach-meson/dram-gxbb.c | 174 ++++++++ arch/arm/mach-meson/dram-gxl.c | 167 +++++++ 10 files changed, 1948 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/dram-gx.h create mode 100644 arch/arm/include/asm/arch-meson/dram-gxbb.h create mode 100644 arch/arm/include/asm/arch-meson/dram-gxl.h create mode 100644 arch/arm/include/asm/arch-meson/dram-settings-gx.h create mode 100644 arch/arm/include/asm/arch-meson/dram-timings-gx.h create mode 100644 arch/arm/mach-meson/dram-gx.c create mode 100644 arch/arm/mach-meson/dram-gxbb.c create mode 100644 arch/arm/mach-meson/dram-gxl.c 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 + */ +#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 +#elif defined(CONFIG_MESON_GXL) +# include +#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 + */ +#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 + */ +#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 + */ +#ifndef DRAM_SETTINGS_GX_H +#define DRAM_SETTINGS_GX_H +#include +#include + +/* + * 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 + */ +#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/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 8d1bf91e98b..ef86129b535 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -99,6 +99,76 @@ 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 diff --git a/arch/arm/mach-meson/Makefile b/arch/arm/mach-meson/Makefile index 798b20df78a..5b57d63e02d 100644 --- a/arch/arm/mach-meson/Makefile +++ b/arch/arm/mach-meson/Makefile @@ -5,6 +5,9 @@ obj-y += board-common.o sm.o board-info.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 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} + From 3d0a06aaecc7b380e2588072bf6cfc3bf1ae8832 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:08 +0000 Subject: [PATCH 06/13] arm: dts: meson: add meson-gxbb-u-boot.dtsi Add a common GXBB DTSI, similar to the meson-gxl-u-boot.dtsi file, which GXBB devicetrees can include. Signed-off-by: Ferass El Hafidi Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251126-spl-gx-v5-6-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/dts/meson-gxbb-kii-pro-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-p200-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-p201-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-u-boot.dtsi | 7 +++++++ arch/arm/dts/meson-gxbb-wetek-hub-u-boot.dtsi | 2 +- arch/arm/dts/meson-gxbb-wetek-play2-u-boot.dtsi | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 arch/arm/dts/meson-gxbb-u-boot.dtsi 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 */ -#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 */ -#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 */ -#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 */ -#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 */ -#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..c35158d7e9e --- /dev/null +++ b/arch/arm/dts/meson-gxbb-u-boot.dtsi @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#include "meson-gx-u-boot.dtsi" 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 */ -#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 */ -#include "meson-gx-u-boot.dtsi" +#include "meson-gxbb-u-boot.dtsi" ðmac { snps,reset-gpio = <&gpio GPIOZ_14 0>; From 236e4b1cc4eb491dea31e112cf4e880ebcce05f5 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:09 +0000 Subject: [PATCH 07/13] arm: dts: meson-gx-u-boot: add binman configuration for U-Boot SPL Add binman configuration to meson-gx-u-boot.dtsi to automate building bootable images using amlimage. Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-7-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/dts/meson-gx-u-boot.dtsi | 125 ++++++++++++++++++++++++++++ arch/arm/dts/meson-gxbb-u-boot.dtsi | 20 +++++ arch/arm/dts/meson-gxl-u-boot.dtsi | 20 +++++ 3 files changed, 165 insertions(+) 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 + * Copyright (c) 2023 Ferass El Hafidi */ / { @@ -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 = ; + fit,align = <512>; + offset = ; + + images { + u-boot { + description = "U-Boot"; + type = "standalone"; + os = "u-boot"; + arch = "arm64"; + compression = "none"; + load = ; + entry = ; + + 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-u-boot.dtsi b/arch/arm/dts/meson-gxbb-u-boot.dtsi index c35158d7e9e..a4dc1c136f1 100644 --- a/arch/arm/dts/meson-gxbb-u-boot.dtsi +++ b/arch/arm/dts/meson-gxbb-u-boot.dtsi @@ -5,3 +5,23 @@ */ #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-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 From 773aaf8f8cc94a882a89373920f7986a9669f0e7 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:10 +0000 Subject: [PATCH 08/13] board: amlogic: add kconfig fragments for SPL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add kconfig fragments for building SPL binaries for: · ODROID-C2 · Videostrong KII Pro · Libre Computer LePotato (1 GB and 2 GB variants) Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-8-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- board/amlogic/p200/spl-odroid-c2.config | 38 ++++++++++++++++++ .../p200/spl-videostrong-kii-pro.config | 39 +++++++++++++++++++ .../amlogic/p212/spl-libretech-cc-1gb.config | 36 +++++++++++++++++ .../amlogic/p212/spl-libretech-cc-2gb.config | 38 ++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 board/amlogic/p200/spl-odroid-c2.config create mode 100644 board/amlogic/p200/spl-videostrong-kii-pro.config create mode 100644 board/amlogic/p212/spl-libretech-cc-1gb.config create mode 100644 board/amlogic/p212/spl-libretech-cc-2gb.config 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 From dcf8a2738b0e00a7caaf193a6cc69d3cf0ec3999 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:11 +0000 Subject: [PATCH 09/13] spl: meson: set SPL max size for GX SoCs Enforce the max size for U-Boot SPL at the Kconfig level, to prevent the build system from producing an image too large for the bootROM to load. Signed-off-by: Ferass El Hafidi Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251126-spl-gx-v5-9-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- common/spl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index a4327167164..6ec9dd923a2 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. From 8f2169faf6e4ae1d0506779c6630104dfff7feea Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Wed, 26 Nov 2025 12:17:12 +0000 Subject: [PATCH 10/13] doc: board: amlogic: add u-boot-spl documentation Add building and usage instructions for SPL. Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251126-spl-gx-v5-10-6cbffb2451ca@postmarketos.org Signed-off-by: Neil Armstrong --- doc/board/amlogic/index.rst | 1 + doc/board/amlogic/pre-generated-fip.rst | 9 +++ doc/board/amlogic/spl.rst | 77 +++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 doc/board/amlogic/spl.rst 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 _defconfig spl-.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 + From 8fa0db145f6b38341ac939c1e768ca37446bbaf8 Mon Sep 17 00:00:00 2001 From: Nick Xie Date: Tue, 9 Dec 2025 13:57:50 +0800 Subject: [PATCH 11/13] mmc: meson_gx_mmc: reduce maximum frequency Reduce the maximum frequency to 40MHz to be compatible with more eMMC. And the Amlogic vendor U-Boot also use the maximum frequency of 40MHz. Signed-off-by: Nick Xie Link: https://patch.msgid.link/20251209055750.43594-1-nick@khadas.com Signed-off-by: Neil Armstrong --- drivers/mmc/meson_gx_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index d1558ebe3a2..76af3873e15 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -348,7 +348,7 @@ 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; From 1bb973b4db6c07b7765b92e93e596907e8b8b469 Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Thu, 11 Dec 2025 15:37:00 +0000 Subject: [PATCH 12/13] arm: meson: add support for EFI capsule updates Previously, few Amlogic devices supported EFI capsule updates. Generally only the Libre Computer ones with SPI flash supported it, thanks to board-specific code. This commit commonises capsule update support across supported Amlogic boards. Similar to Qualcomm's support for it, the dfu string and firmware name is automatically generated at runtime depending on which device we are booted from. Right now this supports flashing to the eMMC/SD and SPI flash. As usual, the capsule UUID is automatically generated. You can get it by enabling CONFIG_CMD_EFIDEBUG and running: => efidebug capsule esrt ======================================== ESRT: fw_resource_count=1 ESRT: fw_resource_count_max=1 ESRT: fw_resource_version=1 [entry 0]============================== ESRT: fw_class=796180D4-AAB2-50F1-B16A-53DFF9CA89B2 ESRT: fw_type=unknown ESRT: fw_version=0 ESRT: lowest_supported_fw_version=0 ESRT: capsule_flags=0 ESRT: last_attempt_version=0 ESRT: last_attempt_status=success ======================================== Reviewed-by: Evgeny Bachinin Reviewed-by: Neil Armstrong Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251211-meson-capsule-v4-1-59f126ba4115@postmarketos.org Signed-off-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/boot.h | 2 + arch/arm/mach-meson/Makefile | 2 +- arch/arm/mach-meson/board-common.c | 5 +++ arch/arm/mach-meson/capsule.c | 61 ++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-meson/capsule.c 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/mach-meson/Makefile b/arch/arm/mach-meson/Makefile index 5b57d63e02d..08a24d4b24f 100644 --- a/arch/arm/mach-meson/Makefile +++ b/arch/arm/mach-meson/Makefile @@ -2,7 +2,7 @@ # # Copyright (c) 2016 Beniamino Galvani -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 diff --git a/arch/arm/mach-meson/board-common.c b/arch/arm/mach-meson/board-common.c index c243c46c0fc..a5afc2d75c0 100644 --- a/arch/arm/mach-meson/board-common.c +++ b/arch/arm/mach-meson/board-common.c @@ -147,6 +147,11 @@ 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(); } 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 + */ + +#include +#include +#include +#include + +/* + * 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; +} From 6e844dd4df6765e5e772b5606a675c16fe98d9ac Mon Sep 17 00:00:00 2001 From: Ferass El Hafidi Date: Thu, 11 Dec 2025 15:37:01 +0000 Subject: [PATCH 13/13] board: libre-computer: use common Amlogic EFI capsule support Remove the board-specific capsule support code, as we now support EFI capsules across multiple Amlogic boards without the need for that. Signed-off-by: Ferass El Hafidi Link: https://patch.msgid.link/20251211-meson-capsule-v4-2-59f126ba4115@postmarketos.org Signed-off-by: Neil Armstrong --- board/libre-computer/aml-a311d-cc/aml-a311d-cc.c | 14 -------------- board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 13 ------------- board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c | 14 -------------- 3 files changed, 41 deletions(-) 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 #include -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 #include -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) {