diff options
Diffstat (limited to 'roms/u-boot/arch/arm/mach-mvebu/dram.c')
-rw-r--r-- | roms/u-boot/arch/arm/mach-mvebu/dram.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-mvebu/dram.c b/roms/u-boot/arch/arm/mach-mvebu/dram.c new file mode 100644 index 000000000..349e0cc4c --- /dev/null +++ b/roms/u-boot/arch/arm/mach-mvebu/dram.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + */ + +#include <config.h> +#include <common.h> +#include <init.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> + +#if defined(CONFIG_ARCH_MVEBU) +/* Use common XOR definitions for A3x and 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) + +#ifndef MVEBU_SDRAM_SIZE_MAX +#define MVEBU_SDRAM_SIZE_MAX 0xc0000000 +#endif + +#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_ARCH_MVEBU) +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); + if (size == 0) + continue; + + total = (u64)size; + 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 - 1, + 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; +} + +/* Return the width of the DRAM bus, or 0 for unknown. */ +static int bus_width(void) +{ + int full_width = 0; + + if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_WIDTH_OFFS)) + full_width = 1; + + switch (mvebu_soc_family()) { + case MVEBU_SOC_AXP: + return full_width ? 64 : 32; + break; + case MVEBU_SOC_A375: + case MVEBU_SOC_A38X: + case MVEBU_SOC_MSYS: + return full_width ? 32 : 16; + default: + return 0; + } +} + +static int cycle_mode(void) +{ + int val = reg_read(REG_DUNIT_CTRL_LOW_ADDR); + + return (val >> REG_DUNIT_CTRL_LOW_2T_OFFS) & REG_DUNIT_CTRL_LOW_2T_MASK; +} + +#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 > MVEBU_SDRAM_SIZE_MAX) + size = MVEBU_SDRAM_SIZE_MAX; + } + + 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. + */ +int 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 > MVEBU_SDRAM_SIZE_MAX) + mvebu_sdram_bs_set(i, 0x40000000); + } + + return 0; +} + +#if defined(CONFIG_ARCH_MVEBU) +void board_add_ram_info(int use_default) +{ + struct sar_freq_modes sar_freq; + int mode; + int width; + + get_sar_freq(&sar_freq); + printf(" (%d MHz, ", sar_freq.d_clk); + + width = bus_width(); + if (width) + printf("%d-bit, ", width); + + mode = cycle_mode(); + /* Mode 0 = Single cycle + * Mode 1 = Two cycles (2T) + * Mode 2 = Three cycles (3T) + */ + if (mode == 1) + printf("2T, "); + if (mode == 2) + printf("3T, "); + + if (ecc_enabled()) + printf("ECC"); + else + printf("ECC not"); + printf(" enabled)"); +} +#endif |