2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2017-05-16 18:46:35 +00:00
|
|
|
/*
|
|
|
|
* ti816x_emif4.c
|
|
|
|
*
|
|
|
|
* TI816x emif4 configuration file
|
|
|
|
*
|
|
|
|
* Copyright (C) 2017, Konsulko Group
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <asm/arch/cpu.h>
|
|
|
|
#include <asm/arch/ddr_defs.h>
|
|
|
|
#include <asm/arch/hardware.h>
|
|
|
|
#include <asm/arch/clock.h>
|
|
|
|
#include <asm/arch/sys_proto.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/emif.h>
|
2020-05-10 17:40:11 +00:00
|
|
|
#include <linux/delay.h>
|
2017-05-16 18:46:35 +00:00
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
* Init DDR3 on TI816X EVM
|
|
|
|
*********************************************************************/
|
|
|
|
static void ddr_init_settings(const struct cmd_control *ctrl, int emif)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* setup use_rank_delays to 1. This is only necessary when
|
|
|
|
* multiple ranks are in use. Though the EVM does not have
|
|
|
|
* multiple ranks, this is a good value to set.
|
|
|
|
*/
|
|
|
|
writel(1, DDRPHY_CONFIG_BASE + 0x134); // DATA0_REG_PHY_USE_RANK0_DELAYS
|
|
|
|
writel(1, DDRPHY_CONFIG_BASE + 0x1d8); // DATA1_REG_PHY_USE_RANK0_DELAYS
|
|
|
|
writel(1, DDRPHY_CONFIG_BASE + 0x27c); // DATA2_REG_PHY_USE_RANK0_DELAYS
|
|
|
|
writel(1, DDRPHY_CONFIG_BASE + 0x320); // DATA3_REG_PHY_USE_RANK0_DELAYS
|
|
|
|
|
|
|
|
config_cmd_ctrl(ctrl, emif);
|
|
|
|
|
|
|
|
/* for ddr3 this needs to be set to 1 */
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x0F8); /* init mode */
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x104);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x19C);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x1A8);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x240);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x24C);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x2E4);
|
|
|
|
writel(0x1, DDRPHY_CONFIG_BASE + 0x2F0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This represents the initial value for the leveling process. The
|
|
|
|
* value is a ratio - so 0x100 represents one cycle. The real delay
|
|
|
|
* is determined through the leveling process.
|
|
|
|
*
|
|
|
|
* During the leveling process, 0x20 is subtracted from the value, so
|
|
|
|
* we have added that to the value we want to set. We also set the
|
|
|
|
* values such that byte3 completes leveling after byte2 and byte1
|
|
|
|
* after byte0.
|
|
|
|
*/
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x0F0); /* data0 writelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x0F4); /* */
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x194); /* data1 writelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x198); /* */
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x238); /* data2 writelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x23c); /* */
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x2dc); /* data3 writelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x2e0); /* */
|
|
|
|
|
|
|
|
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x0FC); /* data0 gatelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x100);
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x1A0); /* data1 gatelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x1A4);
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x244); /* data2 gatelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x248);
|
|
|
|
writel((0x20 << 10) | 0x20, DDRPHY_CONFIG_BASE + 0x2E8); /* data3 gatelvl init ratio */
|
|
|
|
writel(0x0, DDRPHY_CONFIG_BASE + 0x2EC);
|
|
|
|
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x00C); /* cmd0 io config - output impedance of pad */
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x010); /* cmd0 io clk config - output impedance of pad */
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x040); /* cmd1 io config - output impedance of pad */
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x044); /* cmd1 io clk config - output impedance of pad */
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x074); /* cmd2 io config - output impedance of pad */
|
|
|
|
writel(0x5, DDRPHY_CONFIG_BASE + 0x078); /* cmd2 io clk config - output impedance of pad */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x0A8); /* data0 io config - output impedance of pad */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x0AC); /* data0 io clk config - output impedance of pad */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x14C); /* data1 io config - output impedance of pa */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x150); /* data1 io clk config - output impedance of pad */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x1F0); /* data2 io config - output impedance of pa */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x1F4); /* data2 io clk config - output impedance of pad */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x294); /* data3 io config - output impedance of pa */
|
|
|
|
writel(0x4, DDRPHY_CONFIG_BASE + 0x298); /* data3 io clk config - output impedance of pad */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ddr3_sw_levelling(const struct ddr_data *data, int emif)
|
|
|
|
{
|
|
|
|
/* Set the correct value to DDR_VTP_CTRL_0 */
|
|
|
|
writel(0x6, (DDRPHY_CONFIG_BASE + 0x358));
|
|
|
|
|
|
|
|
writel(data->datafwsratio0, (DDRPHY_CONFIG_BASE + 0x108));
|
|
|
|
writel(data->datafwsratio0, (DDRPHY_CONFIG_BASE + 0x1AC));
|
|
|
|
writel(data->datafwsratio0, (DDRPHY_CONFIG_BASE + 0x250));
|
|
|
|
writel(data->datafwsratio0, (DDRPHY_CONFIG_BASE + 0x2F4));
|
|
|
|
|
|
|
|
writel(data->datawdsratio0, (DDRPHY_CONFIG_BASE + 0x0DC));
|
|
|
|
writel(data->datawdsratio0, (DDRPHY_CONFIG_BASE + 0x180));
|
|
|
|
writel(data->datawdsratio0, (DDRPHY_CONFIG_BASE + 0x224));
|
|
|
|
writel(data->datawdsratio0, (DDRPHY_CONFIG_BASE + 0x2C8));
|
|
|
|
|
|
|
|
writel(data->datawrsratio0, (DDRPHY_CONFIG_BASE + 0x120));
|
|
|
|
writel(data->datawrsratio0, (DDRPHY_CONFIG_BASE + 0x1C4));
|
|
|
|
writel(data->datawrsratio0, (DDRPHY_CONFIG_BASE + 0x268));
|
|
|
|
writel(data->datawrsratio0, (DDRPHY_CONFIG_BASE + 0x30C));
|
|
|
|
|
|
|
|
writel(data->datardsratio0, (DDRPHY_CONFIG_BASE + 0x0C8));
|
|
|
|
writel(data->datardsratio0, (DDRPHY_CONFIG_BASE + 0x16C));
|
|
|
|
writel(data->datardsratio0, (DDRPHY_CONFIG_BASE + 0x210));
|
|
|
|
writel(data->datardsratio0, (DDRPHY_CONFIG_BASE + 0x2B4));
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dmm_lisa_map_regs *hw_lisa_map_regs =
|
|
|
|
(struct dmm_lisa_map_regs *)DMM_BASE;
|
|
|
|
|
|
|
|
#define DMM_PAT_BASE_ADDR (DMM_BASE + 0x420)
|
|
|
|
void config_dmm(const struct dmm_lisa_map_regs *regs)
|
|
|
|
{
|
|
|
|
writel(0, &hw_lisa_map_regs->dmm_lisa_map_3);
|
|
|
|
writel(0, &hw_lisa_map_regs->dmm_lisa_map_2);
|
|
|
|
writel(0, &hw_lisa_map_regs->dmm_lisa_map_1);
|
|
|
|
writel(0, &hw_lisa_map_regs->dmm_lisa_map_0);
|
|
|
|
|
|
|
|
writel(regs->dmm_lisa_map_3, &hw_lisa_map_regs->dmm_lisa_map_3);
|
|
|
|
writel(regs->dmm_lisa_map_2, &hw_lisa_map_regs->dmm_lisa_map_2);
|
|
|
|
writel(regs->dmm_lisa_map_1, &hw_lisa_map_regs->dmm_lisa_map_1);
|
|
|
|
writel(regs->dmm_lisa_map_0, &hw_lisa_map_regs->dmm_lisa_map_0);
|
|
|
|
|
|
|
|
/* Enable Tiled Access */
|
|
|
|
writel(0x80000000, DMM_PAT_BASE_ADDR);
|
|
|
|
}
|
|
|
|
|
|
|
|
void config_ddr(const struct ddr_data *data, const struct cmd_control *ctrl,
|
|
|
|
const struct emif_regs *regs,
|
|
|
|
const struct dmm_lisa_map_regs *lisa_regs, int nrs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
enable_emif_clocks();
|
|
|
|
|
|
|
|
for (i = 0; i < nrs; i++)
|
|
|
|
ddr_init_settings(ctrl, i);
|
|
|
|
|
|
|
|
enable_dmm_clocks();
|
|
|
|
|
|
|
|
/* Program the DMM to for non-interleaved configuration */
|
|
|
|
config_dmm(lisa_regs);
|
|
|
|
|
|
|
|
/* Program EMIF CFG Registers */
|
|
|
|
for (i = 0; i < nrs; i++) {
|
|
|
|
set_sdram_timings(regs, i);
|
|
|
|
config_sdram(regs, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
udelay(1000);
|
|
|
|
for (i = 0; i < nrs; i++)
|
|
|
|
ddr3_sw_levelling(data, i);
|
|
|
|
|
|
|
|
udelay(50000); /* Some delay needed */
|
|
|
|
}
|