diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 432b1c10..07332791 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -69,6 +69,19 @@ struct mm_region *mem_map = sunxi_mem_map; phys_addr_t board_get_usable_ram_top(phys_size_t total_size) { + /* + * The A523/T527 can report DRAM spanning the 4 GiB boundary. Relocating + * U-Boot immediately below 0x1_0000_0000 is not reliable on Avaota A1: + * relocated command text becomes zero/corrupt and triggers synchronous + * aborts. Keep U-Boot itself in the first 256 MiB of DRAM while retaining + * the full gd->ram_size for the OS device tree and Linux. + */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && gd->ram_top > 0x50000000ULL) { + printf("LYNX_RAM_TOP_SAFE: detected_top=0x%llx usable_top=0x50000000\n", + (unsigned long long)gd->ram_top); + return 0x50000000ULL; + } + /* Some devices (like the EMAC) have a 32-bit DMA limit. */ if (gd->ram_top > (1ULL << 32)) return 1ULL << 32; @@ -221,6 +234,26 @@ static int spl_board_load_image(struct spl_image_info *spl_image, return 0; } SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image); + +void board_boot_order(u32 *spl_boot_list) +{ + u32 boot_device = spl_boot_device(); + + spl_boot_list[0] = boot_device; + + /* + * A failed cold eMMC read must remain recoverable without another + * board-specific FEL key sequence. Returning through the standard + * sunxi BOOT_DEVICE_BOARD method hands control back to BootROM FEL. + * Keep every other sunxi platform's one-device boot order unchanged. + */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && + boot_device != BOOT_DEVICE_BOARD) { + printf("LYNX_RECOVERY_FEL: armed after boot device %u\n", + boot_device); + spl_boot_list[1] = BOOT_DEVICE_BOARD; + } +} #endif /* CONFIG_XPL_BUILD */ #define SUNXI_INVALID_BOOT_SOURCE -1 diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index cc16709d..8e8a7af5 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -45,9 +45,12 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image, struct blk_desc *bd = mmc_get_blk_desc(mmc); struct spl_load_info load; + printf("LYNX_MMC_DIAG: read sector=0x%lx blksz=%lu\n", + sector, bd->blksz); spl_load_init(&load, h_spl_load_read, bd, bd->blksz); ret = spl_load(spl_image, bootdev, &load, 0, sector << bd->log2blksz); if (ret) { + printf("LYNX_MMC_DIAG: raw/FIT load failed ret=%d\n", ret); puts("mmc_load_image_raw_sector: mmc block read error\n"); log_debug("(error=%d)\n", ret); return ret; @@ -413,6 +416,31 @@ int spl_mmc_load(struct spl_image_info *spl_image, case MMCSD_MODE_RAW: debug("spl: mmc boot mode: raw\n"); + /* + * A523/T527 reports raw boot mode even when BootROM fetched SPL from + * eMMC Boot0. The controller still accesses Boot0, but the legacy + * block descriptor is cached as hwpart 0. A no-op CMD6 value of zero + * does not clear the controller/card boot-access state reliably, so + * force a real Boot1 -> user transition before every raw FIT read. + */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && IS_MMC(mmc)) { + printf("LYNX_MMC_FORCE_USER: mode=%u before_part_config=0x%02x cached_hwpart=%u\n", + boot_mode, mmc->part_config, + mmc_get_blk_desc(mmc)->hwpart); + ret = mmc_switch_part(mmc, EMMC_HWPART_BOOT1); + printf("LYNX_MMC_FORCE_USER: boot1_ret=%d cached_hwpart=%u\n", + ret, mmc_get_blk_desc(mmc)->hwpart); + if (ret) + return ret; + ret = mmc_switch_part(mmc, EMMC_HWPART_DEFAULT); + printf("LYNX_MMC_FORCE_USER: user_ret=%d after_part_config=0x%02x cached_hwpart=%u\n", + ret, mmc->part_config, + mmc_get_blk_desc(mmc)->hwpart); + if (ret) + return ret; + part = EMMC_HWPART_DEFAULT; + } + if (!spl_start_uboot()) { ret = mmc_load_image_raw_os(spl_image, bootdev, mmc); if (!ret) @@ -424,6 +452,10 @@ int spl_mmc_load(struct spl_image_info *spl_image, raw_sect = spl_mmc_get_uboot_raw_sector(mmc, raw_sect); #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + printf("LYNX_MMC_DIAG: mode=%u part=%d base=0x%lx offset=0x%lx final=0x%lx\n", + boot_mode, part, raw_sect, + spl_mmc_raw_uboot_offset(part), + raw_sect + spl_mmc_raw_uboot_offset(part)); ret = mmc_load_image_raw_sector(spl_image, bootdev, mmc, raw_sect + spl_mmc_raw_uboot_offset(part)); diff --git a/configs/avaota-a1_defconfig b/configs/avaota-a1_defconfig index a1f89927..1d1e49ac 100644 --- a/configs/avaota-a1_defconfig +++ b/configs/avaota-a1_defconfig @@ -1,7 +1,10 @@ CONFIG_ARM=y +CONFIG_EXPERT=y +CONFIG_SKIP_RELOCATE=y CONFIG_ARCH_SUNXI=y CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun55i-t527-avaota-a1" CONFIG_SPL=y +CONFIG_SPL_FIT_PRINT=y CONFIG_DRAM_SUNXI_DX_ODT=0x07070707 CONFIG_DRAM_SUNXI_DX_DRI=0x0d0d0d0d CONFIG_DRAM_SUNXI_CA_DRI=0x0e0e @@ -22,6 +25,8 @@ CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_SLAVE=0x7f CONFIG_SYS_I2C_SPEED=400000 CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_BOOTDELAY=5 +CONFIG_PREBOOT="" CONFIG_SUN8I_EMAC=y CONFIG_PHY_REALTEK=y CONFIG_REGULATOR_AXP=y @@ -31,3 +36,4 @@ CONFIG_AXP_DCDC2_VOLT=920 CONFIG_AXP_DCDC3_VOLT=1160 CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_KEYBOARD is not set diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2e565560..11b1538f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -551,9 +551,23 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, do { cur = (blocks_todo > b_max) ? b_max : blocks_todo; if (mmc_read_blocks(mmc, dst, start, cur) != cur) { + /* + * The A523 MMC2 controller is reset by its driver after a data + * timeout. Retry the same small request once after that reset; + * never loop indefinitely or mask a persistent media failure. + */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && b_max == 128) { +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) + printf("LYNX_MMC_READ_RETRY: start=0x" LBAF + " blocks=0x" LBAF "\n", start, cur); +#endif + if (mmc_read_blocks(mmc, dst, start, cur) == cur) + goto read_ok; + } pr_debug("%s: Failed to read blocks\n", __func__); return 0; } + read_ok: blocks_todo -= cur; start += cur; dst += cur * mmc->read_bl_len; diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index e28c81af..dfc07873 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -50,6 +50,61 @@ struct sunxi_mmc_priv { struct mmc_config cfg; }; +static bool sunxi_mmc_is_a523_mmc2(struct sunxi_mmc_priv *priv) +{ + return IS_ENABLED(CONFIG_MACH_SUN55I_A523) && priv->mmc_no == 2; +} + +/* Match the vendor timing-mode-4 defaults for legacy/SDR operation. */ +static void sunxi_mmc_a523_tm4_set_timing(struct sunxi_mmc_priv *priv, + unsigned int hz) +{ + u32 val; + + if (!sunxi_mmc_is_a523_mmc2(priv)) + return; + + /* Controller v0x50500 must use 1x mode, not generic sunxi 2x mode. */ + clrbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW); + + /* Tina TM4_OUT_PH180: both output-delay phase bits are set. */ + val = readl(&priv->reg->drv_dl); + val &= ~(0x3 << 16); + val |= 0x3 << 16; + /* Tina enables the TM4 drive-delay circuit above identification rate. */ + if (hz <= 400000) + val &= ~BIT(7); + else + val |= BIT(7); + writel(val, &priv->reg->drv_dl); + + /* Tina sdly=0 with software delay control enabled. */ + val = readl(&priv->reg->samp_dl); + val &= ~0x3f; + val |= SUNXI_MMC_CAL_DL_SW_EN; + writel(val, &priv->reg->samp_dl); +} + +static void sunxi_mmc_a523_tm4_core_init(struct sunxi_mmc_priv *priv) +{ + if (!sunxi_mmc_is_a523_mmc2(priv)) + return; + + /* Values used by Tina's v0x50500 timing-mode-4 host driver. */ + writel(0xffffffff, &priv->reg->timeout); + writel(SUNXI_MMC_THLDC_READ_THLD(512) | + SUNXI_MMC_THLDC_WRITE_EN | SUNXI_MMC_THLDC_READ_EN, + &priv->reg->thldc); + writel(3, &priv->reg->csdc); + writel(0xdeb, &priv->reg->dbgc); + + printf("LYNX_MMC_TM4_INIT: mmc=%u timeout=0x%08x thldc=0x%08x " + "csdc=0x%08x dbgc=0x%08x\n", + priv->mmc_no, readl(&priv->reg->timeout), + readl(&priv->reg->thldc), readl(&priv->reg->csdc), + readl(&priv->reg->dbgc)); +} + /* * All A64 and later MMC controllers feature auto-calibration. This would * normally be detected via the compatible string, but we need something @@ -74,6 +129,16 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) new_mode = false; + /* + * A523/T527 MMC2 is timing-mode-4 hardware. The vendor TM4 driver + * explicitly clears NTSR bit 31 for controller version >= 0x50300 to + * disable 2x mode. Keeping the generic sunxi new mode enabled causes + * cold-boot CMD18 reads to complete with DATA_CRC_ERROR. + */ + if (sunxi_mmc_is_a523_mmc2(priv)) { + new_mode = false; + } + if (hz <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; pll_hz = 24000000; @@ -172,6 +237,7 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_M(div) | val, priv->mclkreg); + sunxi_mmc_a523_tm4_set_timing(priv, hz); debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n", priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div); @@ -259,6 +325,15 @@ static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv, else writel(0x0, &priv->reg->width); + if (sunxi_mmc_is_a523_mmc2(priv)) + printf("LYNX_MMC_IOS: mmc=%u width=%u clock=%u mclk=0x%08x " + "ntsr=0x%08x drv_dl=0x%08x samp_dl=0x%08x " + "width_reg=0x%08x\n", + priv->mmc_no, mmc->bus_width, mmc->clock, + readl(priv->mclkreg), readl(&priv->reg->ntsr), + readl(&priv->reg->drv_dl), readl(&priv->reg->samp_dl), + readl(&priv->reg->width)); + return 0; } @@ -456,6 +531,14 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv, } out: if (error < 0) { + printf("LYNX_MMC_HW_DIAG: mmc=%u cmd=%u arg=0x%08x err=%d " + "blocks=%u blocksize=%u width=%u clock=%u " + "rint=0x%08x status=0x%08x gctrl=0x%08x clkcr=0x%08x\n", + priv->mmc_no, cmd->cmdidx, cmd->cmdarg, error, + data ? data->blocks : 0, data ? data->blocksize : 0, + mmc->bus_width, mmc->clock, + readl(&priv->reg->rint), readl(&priv->reg->status), + readl(&priv->reg->gctrl), readl(&priv->reg->clkcr)); writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); mmc_update_clk(priv); } @@ -466,18 +549,29 @@ out: return error; } -static void sunxi_mmc_reset(void *regs) +static void sunxi_mmc_reset(struct sunxi_mmc_priv *priv) { + void *regs = priv->reg; + /* Reset controller */ writel(SUNXI_MMC_GCTRL_RESET, regs + SUNXI_MMC_GCTRL); udelay(1000); if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) { - /* Reset card */ - writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST); - udelay(10); - writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST); - udelay(300); + if (sunxi_mmc_is_a523_mmc2(priv)) { + /* Exact reset sequence and settling delays from Tina TM4. */ + writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST); + writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST); + udelay(1000); + writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST); + udelay(1000); + } else { + /* Reset card */ + writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST); + udelay(10); + writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST); + udelay(300); + } /* Setup FIFO R/W threshold. Needed on H616. */ writel(SUNXI_MMC_THLDC_READ_THLD(512) | @@ -533,7 +627,8 @@ static int sunxi_mmc_core_init(struct mmc *mmc) { struct sunxi_mmc_priv *priv = mmc->priv; - sunxi_mmc_reset(priv->reg); + sunxi_mmc_reset(priv); + sunxi_mmc_a523_tm4_core_init(priv); return 0; } @@ -577,14 +672,31 @@ struct mmc *sunxi_mmc_init(int sdc_no) if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) || IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_MACH_SUN55I_A523)) && - (sdc_no == 2)) - cfg->host_caps = MMC_MODE_8BIT; + (sdc_no == 2)) { + /* Keep the A523 eMMC in 4-bit mode until its 8-bit timing is tuned. */ + if (!IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + cfg->host_caps = MMC_MODE_8BIT; + } cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; cfg->f_min = 400000; - cfg->f_max = 52000000; + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && sdc_no == 2) { + /* + * MMC2 data reads show CRC errors at 52 MHz on Avaota A1 before + * the A523 sampling delay is tuned. SPL has no device tree, so + * the board's max-frequency property cannot constrain this path. + * Keep each request small as well: a 65535-block CMD18 exceeds the + * controller's data timeout while loading the kernel from FAT. + */ + cfg->f_max = 25000000; + cfg->b_max = 128; + printf("LYNX_MMC_SAFE_IO: mmc=%d f_max=%u b_max=%u\n", + sdc_no, cfg->f_max, cfg->b_max); + } else { + cfg->f_max = 52000000; + } if (mmc_resource_init(sdc_no) != 0) return NULL; @@ -709,6 +821,20 @@ static int sunxi_mmc_probe(struct udevice *dev) priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000; priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4; + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523) && priv->mmc_no == 2) { + /* + * Keep MMC2 below the fixed 120 ms data-completion timeout. This + * path is used by U-Boot proper; the legacy setup above only covers + * SPL. At 25 MHz, 128 blocks (64 KiB) leave ample timeout margin. + */ + cfg->f_max = min(cfg->f_max, 25000000U); + cfg->b_max = 128; + cfg->host_caps &= ~MMC_MODE_8BIT; + cfg->host_caps |= MMC_MODE_4BIT; + printf("LYNX_MMC_SAFE_IO_DM: mmc=%u f_max=%u b_max=%u " + "force_width=4\n", priv->mmc_no, cfg->f_max, cfg->b_max); + } + ret = clk_get_by_name(dev, "ahb", &gate_clk); if (!ret) clk_enable(&gate_clk); @@ -727,7 +853,8 @@ static int sunxi_mmc_probe(struct udevice *dev) upriv->mmc = &plat->mmc; - sunxi_mmc_reset(priv->reg); + sunxi_mmc_reset(priv); + sunxi_mmc_a523_tm4_core_init(priv); return 0; } diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h index 71865160..a4c225ef 100644 --- a/drivers/mmc/sunxi_mmc.h +++ b/drivers/mmc/sunxi_mmc.h @@ -34,7 +34,7 @@ struct sunxi_mmc { u32 cbcr; /* 0x48 CIU byte count */ u32 bbcr; /* 0x4c BIU byte count */ u32 dbgc; /* 0x50 debug enable */ - u32 res0; /* 0x54 reserved */ + u32 csdc; /* 0x54 CRC status detect control */ u32 a12a; /* 0x58 Auto command 12 argument */ u32 ntsr; /* 0x5c New timing set register */ u32 res1[6]; @@ -49,9 +49,11 @@ struct sunxi_mmc { u32 res2[26]; #if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2) u32 thldc; /* 0x100 Threshold control */ - u32 res3[16]; - u32 samp_dl; - u32 res4[46]; + u32 res3[15]; + u32 drv_dl; /* 0x140 Drive Delay Control */ + u32 samp_dl; /* 0x144 Sample Delay Control */ + u32 ds_dl; /* 0x148 Data Strobe Delay Control */ + u32 res4[45]; #endif u32 fifo; /* 0x100 / 0x200 FIFO access address */ }; diff --git a/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts b/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts index 054d0357..5b9aa86d 100644 --- a/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts +++ b/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts @@ -127,10 +127,13 @@ }; &mmc2 { - bus-width = <8>; + bus-width = <4>; cap-mmc-hw-reset; - mmc-ddr-1_8v; - mmc-hs200-1_8v; + /* + * Keep eMMC in conservative SDR timing until A523/T527 MMC2 TM4 + * 8-bit sampling delay calibration is implemented and validated. + */ + max-frequency = <25000000>; non-removable; vmmc-supply = <®_cldo3>; vqmmc-supply = <®_cldo1>;