/* * (C) Copyright 2009 * Marvell Semiconductor * Written-by: Prafulla Wadaskar * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #ifdef CONFIG_SYS_MVEBU_DDR_A38X #include "../../../drivers/ddr/marvell/axp/xor.h" #include "../../../drivers/ddr/marvell/axp/xor_regs.h" #endif #ifdef CONFIG_SYS_MVEBU_DDR_AXP #include "../../../drivers/ddr/marvell/axp/xor.h" #include "../../../drivers/ddr/marvell/axp/xor_regs.h" #endif DECLARE_GLOBAL_DATA_PTR; struct sdram_bank { u32 win_bar; u32 win_sz; }; struct sdram_addr_dec { struct sdram_bank sdram_bank[4]; }; #define REG_CPUCS_WIN_ENABLE (1 << 0) #define REG_CPUCS_WIN_WR_PROTECT (1 << 1) #define REG_CPUCS_WIN_WIN0_CS(x) (((x) & 0x3) << 2) #define REG_CPUCS_WIN_SIZE(x) (((x) & 0xff) << 24) #define SDRAM_SIZE_MAX 0xc0000000 #define SCRUB_MAGIC 0xbeefdead #define SCRB_XOR_UNIT 0 #define SCRB_XOR_CHAN 1 #define SCRB_XOR_WIN 0 #define XEBARX_BASE_OFFS 16 /* * mvebu_sdram_bar - reads SDRAM Base Address Register */ u32 mvebu_sdram_bar(enum memory_bank bank) { struct sdram_addr_dec *base = (struct sdram_addr_dec *)MVEBU_SDRAM_BASE; u32 result = 0; u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); if ((!enable) || (bank > BANK3)) return 0; result = readl(&base->sdram_bank[bank].win_bar); return result; } /* * mvebu_sdram_bs_set - writes SDRAM Bank size */ static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size) { struct sdram_addr_dec *base = (struct sdram_addr_dec *)MVEBU_SDRAM_BASE; /* Read current register value */ u32 reg = readl(&base->sdram_bank[bank].win_sz); /* Clear window size */ reg &= ~REG_CPUCS_WIN_SIZE(0xFF); /* Set new window size */ reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24); writel(reg, &base->sdram_bank[bank].win_sz); } /* * mvebu_sdram_bs - reads SDRAM Bank size */ u32 mvebu_sdram_bs(enum memory_bank bank) { struct sdram_addr_dec *base = (struct sdram_addr_dec *)MVEBU_SDRAM_BASE; u32 result = 0; u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); if ((!enable) || (bank > BANK3)) return 0; result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz); result += 0x01000000; return result; } void mvebu_sdram_size_adjust(enum memory_bank bank) { u32 size; /* probe currently equipped RAM size */ size = get_ram_size((void *)mvebu_sdram_bar(bank), mvebu_sdram_bs(bank)); /* adjust SDRAM window size accordingly */ mvebu_sdram_bs_set(bank, size); } #if defined(CONFIG_SYS_MVEBU_DDR_A38X) || defined(CONFIG_SYS_MVEBU_DDR_AXP) static u32 xor_ctrl_save; static u32 xor_base_save; static u32 xor_mask_save; static void mv_xor_init2(u32 cs) { u32 reg, base, size, base2; u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 }; xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN)); xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN)); xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN)); /* Enable Window x for each CS */ reg = 0x1; reg |= (0x3 << 16); reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg); base = 0; size = mvebu_sdram_bs(cs) - 1; if (size) { base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) | bank_attr[cs]; reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), base2); base += size + 1; size = (size / (64 << 10)) << 16; /* Window x - size - 256 MB */ reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size); } mv_xor_hal_init(0); return; } static void mv_xor_finish2(void) { reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), xor_ctrl_save); reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), xor_base_save); reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), xor_mask_save); } static void dram_ecc_scrubbing(void) { int cs; u32 size, temp; u32 total_mem = 0; u64 total; u32 start_addr; /* * The DDR training code from the bin_hdr / SPL already * scrubbed the DDR till 0x1000000. And the main U-Boot * is loaded to an address < 0x1000000. So we need to * skip this range to not re-scrub this area again. */ temp = reg_read(REG_SDRAM_CONFIG_ADDR); temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS); reg_write(REG_SDRAM_CONFIG_ADDR, temp); for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) { size = mvebu_sdram_bs(cs) - 1; if (size == 0) continue; total = (u64)size + 1; total_mem += (u32)(total / (1 << 30)); start_addr = 0; mv_xor_init2(cs); /* Skip first 16 MiB */ if (0 == cs) { start_addr = 0x1000000; size -= start_addr; } mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size, SCRUB_MAGIC, SCRUB_MAGIC); /* Wait for previous transfer completion */ while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE) ; mv_xor_finish2(); } temp = reg_read(REG_SDRAM_CONFIG_ADDR); temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS); reg_write(REG_SDRAM_CONFIG_ADDR, temp); } static int ecc_enabled(void) { if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) return 1; return 0; } #else static void dram_ecc_scrubbing(void) { } static int ecc_enabled(void) { return 0; } #endif int dram_init(void) { u64 size = 0; int i; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { /* * It is assumed that all memory banks are consecutive * and without gaps. * If the gap is found, ram_size will be reported for * consecutive memory only */ if (mvebu_sdram_bar(i) != size) break; /* * Don't report more than 3GiB of SDRAM, otherwise there is no * address space left for the internal registers etc. */ size += mvebu_sdram_bs(i); if (size > SDRAM_SIZE_MAX) size = SDRAM_SIZE_MAX; } for (; i < CONFIG_NR_DRAM_BANKS; i++) { /* If above loop terminated prematurely, we need to set * remaining banks' start address & size as 0. Otherwise other * u-boot functions and Linux kernel gets wrong values which * could result in crash */ gd->bd->bi_dram[i].start = 0; gd->bd->bi_dram[i].size = 0; } if (ecc_enabled()) dram_ecc_scrubbing(); gd->ram_size = size; return 0; } /* * If this function is not defined here, * board.c alters dram bank zero configuration defined above. */ void dram_init_banksize(void) { u64 size = 0; int i; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { gd->bd->bi_dram[i].start = mvebu_sdram_bar(i); gd->bd->bi_dram[i].size = mvebu_sdram_bs(i); /* Clip the banksize to 1GiB if it exceeds the max size */ size += gd->bd->bi_dram[i].size; if (size > SDRAM_SIZE_MAX) mvebu_sdram_bs_set(i, 0x40000000); } } void board_add_ram_info(int use_default) { if (ecc_enabled()) printf(" (ECC"); else printf(" (ECC not"); printf(" enabled)"); }