diff options
Diffstat (limited to 'drivers/ddr/fsl/util.c')
| -rw-r--r-- | drivers/ddr/fsl/util.c | 271 | 
1 files changed, 271 insertions, 0 deletions
| diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c new file mode 100644 index 000000000..0658261d8 --- /dev/null +++ b/drivers/ddr/fsl/util.c @@ -0,0 +1,271 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#ifdef CONFIG_PPC +#include <asm/fsl_law.h> +#endif +#include <div64.h> + +#include <fsl_ddr.h> +#include <fsl_immap.h> +#include <asm/io.h> + +/* To avoid 64-bit full-divides, we factor this here */ +#define ULL_2E12 2000000000000ULL +#define UL_5POW12 244140625UL +#define UL_2POW13 (1UL << 13) + +#define ULL_8FS 0xFFFFFFFFULL + +/* + * Round up mclk_ps to nearest 1 ps in memory controller code + * if the error is 0.5ps or more. + * + * If an imprecise data rate is too high due to rounding error + * propagation, compute a suitably rounded mclk_ps to compute + * a working memory controller configuration. + */ +unsigned int get_memory_clk_period_ps(void) +{ +	unsigned int data_rate = get_ddr_freq(0); +	unsigned int result; + +	/* Round to nearest 10ps, being careful about 64-bit multiply/divide */ +	unsigned long long rem, mclk_ps = ULL_2E12; + +	/* Now perform the big divide, the result fits in 32-bits */ +	rem = do_div(mclk_ps, data_rate); +	result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps; + +	return result; +} + +/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */ +unsigned int picos_to_mclk(unsigned int picos) +{ +	unsigned long long clks, clks_rem; +	unsigned long data_rate = get_ddr_freq(0); + +	/* Short circuit for zero picos */ +	if (!picos) +		return 0; + +	/* First multiply the time by the data rate (32x32 => 64) */ +	clks = picos * (unsigned long long)data_rate; +	/* +	 * Now divide by 5^12 and track the 32-bit remainder, then divide +	 * by 2*(2^12) using shifts (and updating the remainder). +	 */ +	clks_rem = do_div(clks, UL_5POW12); +	clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12; +	clks >>= 13; + +	/* If we had a remainder greater than the 1ps error, then round up */ +	if (clks_rem > data_rate) +		clks++; + +	/* Clamp to the maximum representable value */ +	if (clks > ULL_8FS) +		clks = ULL_8FS; +	return (unsigned int) clks; +} + +unsigned int mclk_to_picos(unsigned int mclk) +{ +	return get_memory_clk_period_ps() * mclk; +} + +#ifdef CONFIG_PPC +void +__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, +			   unsigned int law_memctl, +			   unsigned int ctrl_num) +{ +	unsigned long long base = memctl_common_params->base_address; +	unsigned long long size = memctl_common_params->total_mem; + +	/* +	 * If no DIMMs on this controller, do not proceed any further. +	 */ +	if (!memctl_common_params->ndimms_present) { +		return; +	} + +#if !defined(CONFIG_PHYS_64BIT) +	if (base >= CONFIG_MAX_MEM_MAPPED) +		return; +	if ((base + size) >= CONFIG_MAX_MEM_MAPPED) +		size = CONFIG_MAX_MEM_MAPPED - base; +#endif +	if (set_ddr_laws(base, size, law_memctl) < 0) { +		printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num, +			law_memctl); +		return ; +	} +	debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n", +		base, size, law_memctl); +} + +__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void +fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, +			 unsigned int memctl_interleaved, +			 unsigned int ctrl_num); +#endif + +void fsl_ddr_set_intl3r(const unsigned int granule_size) +{ +#ifdef CONFIG_E6500 +	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +	*mcintl3r = 0x80000000 | (granule_size & 0x1f); +	debug("Enable MCINTL3R with granule size 0x%x\n", granule_size); +#endif +} + +u32 fsl_ddr_get_intl3r(void) +{ +	u32 val = 0; +#ifdef CONFIG_E6500 +	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +	val = *mcintl3r; +#endif +	return val; +} + +void board_add_ram_info(int use_default) +{ +	struct ccsr_ddr __iomem *ddr = +		(struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR); + +#if	defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3) +	u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +#endif +#if (CONFIG_NUM_DDR_CONTROLLERS > 1) +	uint32_t cs0_config = in_be32(&ddr->cs0_config); +#endif +	uint32_t sdram_cfg = in_be32(&ddr->sdram_cfg); +	int cas_lat; + +#if CONFIG_NUM_DDR_CONTROLLERS >= 2 +	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) { +		ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR; +		sdram_cfg = in_be32(&ddr->sdram_cfg); +	} +#endif +#if CONFIG_NUM_DDR_CONTROLLERS >= 3 +	if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) { +		ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR; +		sdram_cfg = in_be32(&ddr->sdram_cfg); +	} +#endif +	puts(" (DDR"); +	switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >> +		SDRAM_CFG_SDRAM_TYPE_SHIFT) { +	case SDRAM_TYPE_DDR1: +		puts("1"); +		break; +	case SDRAM_TYPE_DDR2: +		puts("2"); +		break; +	case SDRAM_TYPE_DDR3: +		puts("3"); +		break; +	default: +		puts("?"); +		break; +	} + +	if (sdram_cfg & SDRAM_CFG_32_BE) +		puts(", 32-bit"); +	else if (sdram_cfg & SDRAM_CFG_16_BE) +		puts(", 16-bit"); +	else +		puts(", 64-bit"); + +	/* Calculate CAS latency based on timing cfg values */ +	cas_lat = ((in_be32(&ddr->timing_cfg_1) >> 16) & 0xf) + 1; +	if ((in_be32(&ddr->timing_cfg_3) >> 12) & 1) +		cas_lat += (8 << 1); +	printf(", CL=%d", cas_lat >> 1); +	if (cas_lat & 0x1) +		puts(".5"); + +	if (sdram_cfg & SDRAM_CFG_ECC_EN) +		puts(", ECC on)"); +	else +		puts(", ECC off)"); + +#if (CONFIG_NUM_DDR_CONTROLLERS == 3) +#ifdef CONFIG_E6500 +	if (*mcintl3r & 0x80000000) { +		puts("\n"); +		puts("       DDR Controller Interleaving Mode: "); +		switch (*mcintl3r & 0x1f) { +		case FSL_DDR_3WAY_1KB_INTERLEAVING: +			puts("3-way 1KB"); +			break; +		case FSL_DDR_3WAY_4KB_INTERLEAVING: +			puts("3-way 4KB"); +			break; +		case FSL_DDR_3WAY_8KB_INTERLEAVING: +			puts("3-way 8KB"); +			break; +		default: +			puts("3-way UNKNOWN"); +			break; +		} +	} +#endif +#endif +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) +	if (cs0_config & 0x20000000) { +		puts("\n"); +		puts("       DDR Controller Interleaving Mode: "); + +		switch ((cs0_config >> 24) & 0xf) { +		case FSL_DDR_CACHE_LINE_INTERLEAVING: +			puts("cache line"); +			break; +		case FSL_DDR_PAGE_INTERLEAVING: +			puts("page"); +			break; +		case FSL_DDR_BANK_INTERLEAVING: +			puts("bank"); +			break; +		case FSL_DDR_SUPERBANK_INTERLEAVING: +			puts("super-bank"); +			break; +		default: +			puts("invalid"); +			break; +		} +	} +#endif + +	if ((sdram_cfg >> 8) & 0x7f) { +		puts("\n"); +		puts("       DDR Chip-Select Interleaving Mode: "); +		switch(sdram_cfg >> 8 & 0x7f) { +		case FSL_DDR_CS0_CS1_CS2_CS3: +			puts("CS0+CS1+CS2+CS3"); +			break; +		case FSL_DDR_CS0_CS1: +			puts("CS0+CS1"); +			break; +		case FSL_DDR_CS2_CS3: +			puts("CS2+CS3"); +			break; +		case FSL_DDR_CS0_CS1_AND_CS2_CS3: +			puts("CS0+CS1 and CS2+CS3"); +			break; +		default: +			puts("invalid"); +			break; +		} +	} +} |