ddr: altera: Add DDR2 support to Gen5 driver

Add DDR2 support to Gen5 DRAM driver. As the DDR2 macro names generated
by Quartus are named differently than the DDR3 ones, use anon unions to
store them in the same structures, without growing their size.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Ley Foon Tan <ley.foon.tan@intel.com>
Cc: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
This commit is contained in:
Marek Vasut 2019-10-18 00:22:31 +02:00
parent cf89ef8d10
commit 9a5a90ad9b
6 changed files with 243 additions and 70 deletions

View file

@ -146,24 +146,51 @@ struct socfpga_sdram_rw_mgr_config {
u8 lfsr_wr_rd_dm_bank_0_nop;
u8 lfsr_wr_rd_dm_bank_0_wait;
u8 lfsr_wr_rd_dm_bank_0_wl_1;
union {
u8 mrs0_dll_reset;
u8 mr_dll_reset;
};
union {
u8 mrs0_dll_reset_mirr;
u8 emr_ocd_enable;
};
union {
u8 mrs0_user;
u8 mr_user;
};
union {
u8 mrs0_user_mirr;
u8 mr_calib;
};
union {
u8 mrs1;
u8 mrs1_mirr;
u8 emr;
};
union {
u8 mrs2;
u8 mrs2_mirr;
u8 emr2;
};
union {
u8 mrs3;
u8 emr3;
};
u8 mrs1_mirr;
u8 mrs2_mirr;
u8 mrs3_mirr;
u8 precharge_all;
u8 read_b2b;
u8 read_b2b_wait1;
u8 read_b2b_wait2;
union {
u8 refresh;
u8 refresh_all;
};
u8 rreturn;
u8 sgle_read;
union {
u8 zqcl;
u8 nop;
};
u8 true_mem_data_mask_width;
u8 mem_address_mirroring;
@ -199,6 +226,7 @@ struct socfpga_sdram_io_config {
struct socfpga_sdram_misc_config {
u32 reg_file_init_seq_signature;
u16 afi_clk_freq;
u8 afi_rate_ratio;
u8 calib_lfifo_offset;
u8 calib_vfifo_offset;

File diff suppressed because one or more lines are too long

View file

@ -80,13 +80,15 @@ static const struct socfpga_sdram_config sdram_config = {
SDR_CTRLGRP_DRAMODT_READ_LSB) |
(CONFIG_HPS_SDR_CTRLCFG_DRAMODT_WRITE <<
SDR_CTRLGRP_DRAMODT_WRITE_LSB),
#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE == 2) /* DDR3 */
.extratime1 =
(CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR <<
SDR_CTRLGRP_EXTRATIME1_RD_TO_WR_LSB) |
(CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC <<
SDR_CTRLGRP_EXTRATIME1_RD_TO_WR_BC_LSB) |
(CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP <<
(CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP <<
SDR_CTRLGRP_EXTRATIME1_RD_TO_WR_DIFF_LSB),
#endif
.dram_addrw =
(CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS <<
SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB) |
@ -190,7 +192,6 @@ static const struct socfpga_sdram_rw_mgr_config rw_mgr_config = {
.activate_0_and_1 = RW_MGR_ACTIVATE_0_AND_1,
.activate_0_and_1_wait1 = RW_MGR_ACTIVATE_0_AND_1_WAIT1,
.activate_0_and_1_wait2 = RW_MGR_ACTIVATE_0_AND_1_WAIT2,
.activate_1 = RW_MGR_ACTIVATE_1,
.clear_dqs_enable = RW_MGR_CLEAR_DQS_ENABLE,
.guaranteed_read = RW_MGR_GUARANTEED_READ,
.guaranteed_read_cont = RW_MGR_GUARANTEED_READ_CONT,
@ -199,11 +200,41 @@ static const struct socfpga_sdram_rw_mgr_config rw_mgr_config = {
.guaranteed_write_wait1 = RW_MGR_GUARANTEED_WRITE_WAIT1,
.guaranteed_write_wait2 = RW_MGR_GUARANTEED_WRITE_WAIT2,
.guaranteed_write_wait3 = RW_MGR_GUARANTEED_WRITE_WAIT3,
.idle = RW_MGR_IDLE,
.idle_loop1 = RW_MGR_IDLE_LOOP1,
.idle_loop2 = RW_MGR_IDLE_LOOP2,
#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE == 1) /* DDR2 */
.emr = RW_MGR_EMR,
.emr2 = RW_MGR_EMR2,
.emr3 = RW_MGR_EMR3,
.init_reset_0_cke_0 = RW_MGR_INIT_CKE_0,
.nop = RW_MGR_NOP,
.refresh = RW_MGR_REFRESH,
.mr_calib = RW_MGR_MR_CALIB,
.mr_user = RW_MGR_MR_USER,
.mr_dll_reset = RW_MGR_MR_DLL_RESET,
.emr_ocd_enable = RW_MGR_EMR_OCD_ENABLE,
#elif (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE == 2) /* DDR3 */
.activate_1 = RW_MGR_ACTIVATE_1,
.idle = RW_MGR_IDLE,
.init_reset_0_cke_0 = RW_MGR_INIT_RESET_0_CKE_0,
.init_reset_1_cke_0 = RW_MGR_INIT_RESET_1_CKE_0,
.mrs1 = RW_MGR_MRS1,
.mrs1_mirr = RW_MGR_MRS1_MIRR,
.mrs2 = RW_MGR_MRS2,
.mrs2_mirr = RW_MGR_MRS2_MIRR,
.mrs3 = RW_MGR_MRS3,
.mrs3_mirr = RW_MGR_MRS3_MIRR,
.refresh_all = RW_MGR_REFRESH_ALL,
.rreturn = RW_MGR_RETURN,
.sgle_read = RW_MGR_SGLE_READ,
.zqcl = RW_MGR_ZQCL,
.mrs0_dll_reset = RW_MGR_MRS0_DLL_RESET,
.mrs0_dll_reset_mirr = RW_MGR_MRS0_DLL_RESET_MIRR,
.mrs0_user = RW_MGR_MRS0_USER,
.mrs0_user_mirr = RW_MGR_MRS0_USER_MIRR,
#else
#error LPDDR2 and other DRAM types are not yet supported
#endif
.lfsr_wr_rd_bank_0 = RW_MGR_LFSR_WR_RD_BANK_0,
.lfsr_wr_rd_bank_0_data = RW_MGR_LFSR_WR_RD_BANK_0_DATA,
.lfsr_wr_rd_bank_0_dqs = RW_MGR_LFSR_WR_RD_BANK_0_DQS,
@ -216,24 +247,10 @@ static const struct socfpga_sdram_rw_mgr_config rw_mgr_config = {
.lfsr_wr_rd_dm_bank_0_nop = RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
.lfsr_wr_rd_dm_bank_0_wait = RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT,
.lfsr_wr_rd_dm_bank_0_wl_1 = RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1,
.mrs0_dll_reset = RW_MGR_MRS0_DLL_RESET,
.mrs0_dll_reset_mirr = RW_MGR_MRS0_DLL_RESET_MIRR,
.mrs0_user = RW_MGR_MRS0_USER,
.mrs0_user_mirr = RW_MGR_MRS0_USER_MIRR,
.mrs1 = RW_MGR_MRS1,
.mrs1_mirr = RW_MGR_MRS1_MIRR,
.mrs2 = RW_MGR_MRS2,
.mrs2_mirr = RW_MGR_MRS2_MIRR,
.mrs3 = RW_MGR_MRS3,
.mrs3_mirr = RW_MGR_MRS3_MIRR,
.precharge_all = RW_MGR_PRECHARGE_ALL,
.read_b2b = RW_MGR_READ_B2B,
.read_b2b_wait1 = RW_MGR_READ_B2B_WAIT1,
.read_b2b_wait2 = RW_MGR_READ_B2B_WAIT2,
.refresh_all = RW_MGR_REFRESH_ALL,
.rreturn = RW_MGR_RETURN,
.sgle_read = RW_MGR_SGLE_READ,
.zqcl = RW_MGR_ZQCL,
.true_mem_data_mask_width = RW_MGR_TRUE_MEM_DATA_MASK_WIDTH,
.mem_address_mirroring = RW_MGR_MEM_ADDRESS_MIRRORING,
@ -270,6 +287,9 @@ static const struct socfpga_sdram_io_config io_config = {
};
static const struct socfpga_sdram_misc_config misc_config = {
#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE == 1) /* DDR2 */
.afi_clk_freq = AFI_CLK_FREQ,
#endif
.afi_rate_ratio = AFI_RATE_RATIO,
.calib_lfifo_offset = CALIB_LFIFO_OFFSET,
.calib_vfifo_offset = CALIB_VFIFO_OFFSET,

View file

@ -434,8 +434,10 @@ static void sdr_load_regs(struct socfpga_sdr_ctrl *sdr_ctrl,
debug("Configuring DRAMODT\n");
writel(cfg->dram_odt, &sdr_ctrl->dram_odt);
if (dram_is_ddr(3)) {
debug("Configuring EXTRATIME1\n");
writel(cfg->extratime1, &sdr_ctrl->extratime1);
}
}
/**

View file

@ -7,6 +7,7 @@
#include <asm/io.h>
#include <asm/arch/sdram.h>
#include <errno.h>
#include <hang.h>
#include "sequencer.h"
static const struct socfpga_sdr_rw_load_manager *sdr_rw_load_mgr_regs =
@ -54,6 +55,21 @@ static const struct socfpga_sdr_ctrl *sdr_ctrl =
#define SKIP_DELAY_LOOP_VALUE_OR_ZERO(non_skip_value) \
((non_skip_value) & seq->skip_delay_mask)
bool dram_is_ddr(const u8 ddr)
{
const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config();
const u8 type = (cfg->ctrl_cfg >> SDR_CTRLGRP_CTRLCFG_MEMTYPE_LSB) &
SDR_CTRLGRP_CTRLCFG_MEMTYPE_MASK;
if (ddr == 2 && type == 1) /* DDR2 */
return true;
if (ddr == 3 && type == 2) /* DDR3 */
return true;
return false;
}
static void set_failing_group_stage(struct socfpga_sdrseq *seq,
u32 group, u32 stage, u32 substage)
{
@ -164,6 +180,8 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
*/
odt_mask_0 = 0x3 & ~(1 << rank);
odt_mask_1 = 0x3;
if (dram_is_ddr(2))
odt_mask_1 &= ~(1 << rank);
} else {
/*
* - Single-Slot , Dual-Rank (2 CS per DIMM)
@ -176,10 +194,11 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
}
break;
case 4: /* 4 Ranks */
/* Read:
/*
* DDR3 Read, DDR2 Read/Write:
* ----------+-----------------------+
* | ODT |
* Read From +-----------------------+
* +-----------------------+
* Rank | 3 | 2 | 1 | 0 |
* ----------+-----+-----+-----+-----+
* 0 | 0 | 1 | 0 | 0 |
@ -188,7 +207,7 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
* 3 | 0 | 0 | 1 | 0 |
* ----------+-----+-----+-----+-----+
*
* Write:
* DDR3 Write:
* ----------+-----------------------+
* | ODT |
* Write To +-----------------------+
@ -203,18 +222,30 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
switch (rank) {
case 0:
odt_mask_0 = 0x4;
if (dram_is_ddr(2))
odt_mask_1 = 0x4;
else if (dram_is_ddr(3))
odt_mask_1 = 0x5;
break;
case 1:
odt_mask_0 = 0x8;
if (dram_is_ddr(2))
odt_mask_1 = 0x8;
else if (dram_is_ddr(3))
odt_mask_1 = 0xA;
break;
case 2:
odt_mask_0 = 0x1;
if (dram_is_ddr(2))
odt_mask_1 = 0x1;
else if (dram_is_ddr(3))
odt_mask_1 = 0x5;
break;
case 3:
odt_mask_0 = 0x2;
if (dram_is_ddr(2))
odt_mask_1 = 0x2;
else if (dram_is_ddr(3))
odt_mask_1 = 0xA;
break;
}
@ -839,6 +870,12 @@ static void delay_for_n_mem_clocks(struct socfpga_sdrseq *seq,
debug("%s:%d clocks=%u ... end\n", __func__, __LINE__, clocks);
}
static void delay_for_n_ns(struct socfpga_sdrseq *seq, const u32 ns)
{
delay_for_n_mem_clocks(seq, (ns * seq->misccfg->afi_clk_freq *
seq->misccfg->afi_rate_ratio) / 1000);
}
/**
* rw_mgr_mem_init_load_regs() - Load instruction registers
* @cntr0: Counter 0 value
@ -872,14 +909,59 @@ static void rw_mgr_mem_init_load_regs(struct socfpga_sdrseq *seq,
}
/**
* rw_mgr_mem_load_user() - Load user calibration values
* rw_mgr_mem_load_user_ddr2() - Load user calibration values for DDR2
* @handoff: Indicate whether this is initialization or handoff phase
*
* Load user calibration values and optionally precharge the banks.
*/
static void rw_mgr_mem_load_user_ddr2(struct socfpga_sdrseq *seq,
const int handoff)
{
u32 grpaddr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
RW_MGR_RUN_SINGLE_GROUP_OFFSET;
u32 r;
for (r = 0; r < seq->rwcfg->mem_number_of_ranks; r++) {
/* set rank */
set_rank_and_odt_mask(seq, r, RW_MGR_ODT_MODE_OFF);
/* precharge all banks ... */
writel(seq->rwcfg->precharge_all, grpaddr);
writel(seq->rwcfg->emr2, grpaddr);
writel(seq->rwcfg->emr3, grpaddr);
writel(seq->rwcfg->emr, grpaddr);
if (handoff) {
writel(seq->rwcfg->mr_user, grpaddr);
continue;
}
writel(seq->rwcfg->mr_dll_reset, grpaddr);
writel(seq->rwcfg->precharge_all, grpaddr);
writel(seq->rwcfg->refresh, grpaddr);
delay_for_n_ns(seq, 200);
writel(seq->rwcfg->refresh, grpaddr);
delay_for_n_ns(seq, 200);
writel(seq->rwcfg->mr_calib, grpaddr);
writel(/*seq->rwcfg->*/0x0b, grpaddr); // EMR_OCD_ENABLE
writel(seq->rwcfg->emr, grpaddr);
delay_for_n_mem_clocks(seq, 200);
}
}
/**
* rw_mgr_mem_load_user_ddr3() - Load user calibration values
* @fin1: Final instruction 1
* @fin2: Final instruction 2
* @precharge: If 1, precharge the banks at the end
*
* Load user calibration values and optionally precharge the banks.
*/
static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
static void rw_mgr_mem_load_user_ddr3(struct socfpga_sdrseq *seq,
const u32 fin1, const u32 fin2,
const int precharge)
{
@ -935,6 +1017,25 @@ static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
}
}
/**
* rw_mgr_mem_load_user() - Load user calibration values
* @fin1: Final instruction 1
* @fin2: Final instruction 2
* @precharge: If 1, precharge the banks at the end
*
* Load user calibration values and optionally precharge the banks.
*/
static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
const u32 fin1, const u32 fin2,
const int precharge)
{
if (dram_is_ddr(2))
rw_mgr_mem_load_user_ddr2(seq, precharge);
else if (dram_is_ddr(3))
rw_mgr_mem_load_user_ddr3(seq, fin1, fin2, precharge);
else
hang();
}
/**
* rw_mgr_mem_initialize() - Initialize RW Manager
*
@ -945,8 +1046,10 @@ static void rw_mgr_mem_initialize(struct socfpga_sdrseq *seq)
debug("%s:%d\n", __func__, __LINE__);
/* The reset / cke part of initialization is broadcasted to all ranks */
if (dram_is_ddr(3)) {
writel(RW_MGR_RANK_ALL, SDR_PHYGRP_RWMGRGRP_ADDRESS |
RW_MGR_SET_CS_AND_ODT_MASK_OFFSET);
}
/*
* Here's how you load register for a loop
@ -979,6 +1082,15 @@ static void rw_mgr_mem_initialize(struct socfpga_sdrseq *seq)
/* Indicate that memory is stable. */
writel(1, &phy_mgr_cfg->reset_mem_stbl);
if (dram_is_ddr(2)) {
writel(seq->rwcfg->nop, SDR_PHYGRP_RWMGRGRP_ADDRESS |
RW_MGR_RUN_SINGLE_GROUP_OFFSET);
/* Bring up clock enable. */
/* tXRP < 400 ck cycles */
delay_for_n_ns(seq, 400);
} else if (dram_is_ddr(3)) {
/*
* transition the RESET to high
* Wait for 500us
@ -987,21 +1099,21 @@ static void rw_mgr_mem_initialize(struct socfpga_sdrseq *seq)
/*
* 500us @ 266MHz (3.75 ns) ~ 134000 clock cycles
* If a and b are the number of iteration in 2 nested loops
* it takes the following number of cycles to complete the operation
* number_of_cycles = ((2 + n) * a + 2) * b
* it takes the following number of cycles to complete the
* operation number_of_cycles = ((2 + n) * a + 2) * b
* where n is the number of instruction in the inner loop
* One possible solution is n = 2 , a = 131 , b = 256 => a = 83,
* b = FF
* One possible solution is
* n = 2 , a = 131 , b = 256 => a = 83, b = FF
*/
rw_mgr_mem_init_load_regs(seq, seq->misccfg->treset_cntr0_val,
seq->misccfg->treset_cntr1_val,
seq->misccfg->treset_cntr2_val,
seq->rwcfg->init_reset_1_cke_0);
/* Bring up clock enable. */
/* tXRP < 250 ck cycles */
delay_for_n_mem_clocks(seq, 250);
}
rw_mgr_mem_load_user(seq, seq->rwcfg->mrs0_dll_reset_mirr,
seq->rwcfg->mrs0_dll_reset, 0);
@ -3769,16 +3881,26 @@ static void initialize_tracking(struct socfpga_sdrseq *seq)
&sdr_reg_file->delays);
/* mux delay */
writel((seq->rwcfg->idle << 24) | (seq->rwcfg->activate_1 << 16) |
(seq->rwcfg->sgle_read << 8) | (seq->rwcfg->precharge_all << 0),
if (dram_is_ddr(2)) {
writel(0, &sdr_reg_file->trk_rw_mgr_addr);
} else if (dram_is_ddr(3)) {
writel((seq->rwcfg->idle << 24) |
(seq->rwcfg->activate_1 << 16) |
(seq->rwcfg->sgle_read << 8) |
(seq->rwcfg->precharge_all << 0),
&sdr_reg_file->trk_rw_mgr_addr);
}
writel(seq->rwcfg->mem_if_read_dqs_width,
&sdr_reg_file->trk_read_dqs_width);
/* trefi [7:0] */
if (dram_is_ddr(2)) {
writel(1000 << 0, &sdr_reg_file->trk_rfsh);
} else if (dram_is_ddr(3)) {
writel((seq->rwcfg->refresh_all << 24) | (1000 << 0),
&sdr_reg_file->trk_rfsh);
}
}
int sdram_calibration_full(struct socfpga_sdr *sdr)

View file

@ -279,5 +279,6 @@ struct socfpga_sdrseq {
};
int sdram_calibration_full(struct socfpga_sdr *sdr);
bool dram_is_ddr(const u8 ddr);
#endif /* _SEQUENCER_H_ */