mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-19 11:24:42 +00:00

This syncs drivers/ddr/marvell/a38x/ with the master branch of repository
https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
up to the commit "mv_ddr: a3700: Use the right size for memset to not overflow"
d5acc10c287e40cc2feeb28710b92e45c93c702c
This patch was created by following steps:
1. Replace all a38x files in U-Boot tree by files from upstream github
Marvell mv-ddr-marvell repository.
2. Run following command to omit portions not relevant for a38x, ddr3, and ddr4:
files=drivers/ddr/marvell/a38x/*
unifdef -m -UMV_DDR -UMV_DDR_ATF -UCONFIG_APN806 \
-UCONFIG_MC_STATIC -UCONFIG_MC_STATIC_PRINT -UCONFIG_PHY_STATIC \
-UCONFIG_PHY_STATIC_PRINT -UCONFIG_CUSTOMER_BOARD_SUPPORT \
-UCONFIG_A3700 -UA3900 -UA80X0 -UA70X0 -DCONFIG_ARMADA_38X -UCONFIG_ARMADA_39X \
-UCONFIG_64BIT $files
3. Manually change license to SPDX-License-Identifier
(upstream license in upstream github repository contains long license
texts and U-Boot is using just SPDX-License-Identifier.
After applying this patch, a38x, ddr3, and ddr4 code in upstream Marvell github
repository and in U-Boot would be fully identical. So in future applying
above steps could be used to sync code again.
The only change in this patch are:
1. Some fixes with include files.
2. Some function return and basic type defines changes in
mv_ddr_plat.c (to correct Marvell bug).
3. Remove of dead code in newly copied files (as a result of the
filter script stripping out everything other than a38x, dd3, and ddr4).
Reference:
"ddr: marvell: a38x: Sync code with Marvell mv-ddr-marvell repository"
107c3391b9
Signed-off-by: Tony Dinh <mibodhi@gmail.com>
Reviewed-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Stefan Roese <sr@denx.de>
674 lines
20 KiB
C
674 lines
20 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) Marvell International Ltd. and its affiliates
|
|
*/
|
|
|
|
#if defined(CONFIG_DDR4)
|
|
|
|
/* DDR4 MPR/PDA Interface */
|
|
#include "ddr3_init.h"
|
|
#include "mv_ddr4_mpr_pda_if.h"
|
|
#include "mv_ddr4_training.h"
|
|
#include "mv_ddr_training_db.h"
|
|
#include "mv_ddr_common.h"
|
|
#include "mv_ddr_regs.h"
|
|
|
|
static u8 dram_to_mc_dq_map[MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
|
|
static int dq_map_enable;
|
|
|
|
static u32 mv_ddr4_tx_odt_get(void)
|
|
{
|
|
u16 odt = 0xffff, rtt = 0xffff;
|
|
|
|
if (g_odt_config & 0xe0000)
|
|
rtt = mv_ddr4_rtt_nom_to_odt(g_rtt_nom);
|
|
else if (g_odt_config & 0x10000)
|
|
rtt = mv_ddr4_rtt_wr_to_odt(g_rtt_wr);
|
|
else
|
|
return odt;
|
|
|
|
return (odt * rtt) / (odt + rtt);
|
|
}
|
|
|
|
/*
|
|
* mode registers initialization function
|
|
* replaces all MR writes in DDR3 init function
|
|
*/
|
|
int mv_ddr4_mode_regs_init(u8 dev_num)
|
|
{
|
|
int status;
|
|
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
|
|
enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
|
|
u32 if_id;
|
|
u32 cl, cwl;
|
|
u32 val, mask;
|
|
u32 t_wr, t_ckclk;
|
|
/* design GL params to be set outside */
|
|
u32 dic = 0;
|
|
u32 ron = 30; /* znri */
|
|
u32 rodt = mv_ddr4_tx_odt_get(); /* effective rtt */
|
|
/* vref percentage presented as 100 x percentage value (e.g., 6000 = 100 x 60%) */
|
|
u32 vref = ((ron + rodt / 2) * 10000) / (ron + rodt);
|
|
u32 range = (vref >= 6000) ? 0 : 1; /* if vref is >= 60%, use upper range */
|
|
u32 tap;
|
|
u32 refresh_mode;
|
|
|
|
if (range == 0)
|
|
tap = (vref - 6000) / 65;
|
|
else
|
|
tap = (vref - 4500) / 65;
|
|
|
|
for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
|
|
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
|
|
cl = tm->interface_params[if_id].cas_l;
|
|
cwl = tm->interface_params[if_id].cas_wl;
|
|
t_ckclk = MEGA / mv_ddr_freq_get(tm->interface_params[if_id].memory_freq);
|
|
t_wr = time_to_nclk(mv_ddr_speed_bin_timing_get(tm->interface_params[if_id].speed_bin_index,
|
|
SPEED_BIN_TWR), t_ckclk) - 1;
|
|
|
|
/* TODO: replace hard-coded values with appropriate defines */
|
|
/* DDR4 MR0 */
|
|
/*
|
|
* [6:4,2] bits to be taken from S@R frequency and speed bin
|
|
* rtt_nom to be taken from the algorithm definition
|
|
* dic to be taken fro the algorithm definition -
|
|
* set to 0x1 (for driver rzq/5 = 48 ohm) or
|
|
* set to 0x0 (for driver rzq/7 = 34 ohm)
|
|
*/
|
|
/* set dll reset, 0x1900[8] to 0x1 */
|
|
/* set tm, 0x1900[7] to 0x0 */
|
|
/* set rbt, 0x1900[3] to 0x0 */
|
|
/* set bl, 0x1900[1:0] to 0x0 */
|
|
val = ((cl_mask_table[cl] & 0x1) << 2) |
|
|
(((cl_mask_table[cl] & 0xe) >> 1) << 4) |
|
|
(twr_mask_table[t_wr + 1] << 9) |
|
|
(0x1 << 8) | (0x0 << 7) | (0x0 << 3) | 0x0;
|
|
mask = (0x1 << 2) | (0x7 << 4) | (0x7 << 9) |
|
|
(0x1 << 8) | (0x1 << 7) | (0x1 << 3) | 0x3;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR0_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR1 */
|
|
/* set rtt nom to 0 if rtt park is activated (not zero) */
|
|
if ((g_rtt_park >> 6) != 0x0)
|
|
g_rtt_nom = 0;
|
|
/* set tdqs, 0x1904[11] to 0x0 */
|
|
/* set al, 0x1904[4:3] to 0x0 */
|
|
/* dic, 0x1904[2:1] */
|
|
/* dll enable */
|
|
val = g_rtt_nom | (0x0 << 11) | (0x0 << 3) | (dic << 1) | 0x1;
|
|
mask = (0x7 << 8) | (0x1 << 11) | (0x3 << 3) | (0x3 << 1) | 0x1;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR1_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR2 */
|
|
/* set rtt wr, 0x1908[10,9] to 0x0 */
|
|
/* set wr crc, 0x1908[12] to 0x0 */
|
|
/* cwl */
|
|
val = g_rtt_wr | (0x0 << 12) | (cwl_mask_table[cwl] << 3);
|
|
mask = (0x3 << 9) | (0x1 << 12) | (0x7 << 3);
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR2_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR3 */
|
|
/* set fgrm, 0x190C[8:6] to 0x0 */
|
|
/* set gd, 0x190C[3] to 0x0 */
|
|
refresh_mode = (tm->interface_params[if_id].interface_temp == MV_DDR_TEMP_HIGH) ? 1 : 0;
|
|
|
|
val = (refresh_mode << 6) | (0x0 << 3);
|
|
mask = (0x7 << 6) | (0x1 << 3);
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR3_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR4 */
|
|
/*
|
|
* set wp, 0x1910[12] to 0x0
|
|
* set rp, 0x1910[11] to 0x0
|
|
* set rp training, 0x1910[10] to 0x0
|
|
* set sra, 0x1910[9] to 0x0
|
|
* set cs2cmd, 0x1910[8:6] to 0x0
|
|
* set mpd, 0x1910[1] to 0x0
|
|
*/
|
|
mask = (0x1 << 12) | (0x1 << 11) | (0x1 << 10) | (0x1 << 9) | (0x7 << 6) | (0x1 << 1);
|
|
val = (0x0 << 12) | (0x1 << 11) | (0x0 << 10) | (0x0 << 9) | (0x0 << 6) | (0x0 << 1);
|
|
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR4_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR5 */
|
|
/*
|
|
* set rdbi, 0x1914[12] to 0x0 during init sequence (may be enabled with
|
|
* op cmd mrs - bug in z1, to be fixed in a0)
|
|
* set wdbi, 0x1914[11] to 0x0
|
|
* set dm, 0x1914[10] to 0x1
|
|
* set ca_pl, 0x1914[2:0] to 0x0
|
|
* set odt input buffer during power down mode, 0x1914[5] to 0x1
|
|
*/
|
|
mask = (0x1 << 12) | (0x1 << 11) | (0x1 << 10) | (0x7 << 6) | (0x1 << 5) | 0x7;
|
|
val = (0x0 << 12) | (0x0 << 11) | (0x1 << 10) | g_rtt_park | (0x1 << 5) | 0x0;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR5_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* DDR4 MR6 */
|
|
/*
|
|
* set t_ccd_l, 0x1918[12:10] to 0x0, 0x2, or 0x4 (z1 supports only even
|
|
* values, to be fixed in a0)
|
|
* set vdq te, 0x1918[7] to 0x0
|
|
* set vdq tv, 0x1918[5:0] to vref training value
|
|
*/
|
|
mask = (0x7 << 10) | (0x1 << 7) | (0x1 << 6) | 0x3f;
|
|
val = (0x2 << 10) | (0x0 << 7) | (range << 6) | tap;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR6_REG,
|
|
val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* enter mpr read mode */
|
|
static int mv_ddr4_mpr_read_mode_enable(u8 dev_num, u32 mpr_num, u32 page_num,
|
|
enum mv_ddr4_mpr_read_format read_format)
|
|
{
|
|
/*
|
|
* enable MPR page 2 mpr mode in DDR4 MR3
|
|
* read_format: 0 for serial, 1 for parallel, and 2 for staggered
|
|
* TODO: add support for cs, multicast or unicast, and if id
|
|
*/
|
|
int status;
|
|
u32 val, mask, if_id = 0;
|
|
|
|
if (page_num != 0) {
|
|
/* serial is the only read format if the page is other than 0 */
|
|
read_format = MV_DDR4_MPR_READ_SERIAL;
|
|
}
|
|
|
|
val = (page_num << 0) | (0x1 << 2) | (read_format << 11);
|
|
mask = (0x3 << 0) | (0x1 << 2) | (0x3 << 11);
|
|
|
|
/* cs0 */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, DDR4_MR3_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* op cmd: cs0, cs1 are on, cs2, cs3 are off */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, SDRAM_OP_REG,
|
|
(0x9 | (0xc << 8)) , (0x1f | (0xf << 8)));
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK) {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_mpr_read_mode_enable: DDR3 poll failed(MPR3)\n"));
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* exit mpr read or write mode */
|
|
static int mv_ddr4_mpr_mode_disable(u8 dev_num)
|
|
{
|
|
/* TODO: add support for cs, multicast or unicast, and if id */
|
|
int status;
|
|
u32 val, mask, if_id = 0;
|
|
|
|
/* exit mpr */
|
|
val = 0x0 << 2;
|
|
mask = 0x1 << 2;
|
|
/* cs0 */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, DDR4_MR3_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* op cmd: cs0, cs1 are on, cs2, cs3 are off */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, SDRAM_OP_REG,
|
|
(0x9 | (0xc << 8)) , (0x1f | (0xf << 8)));
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK) {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_mpr_mode_disable: DDR3 poll failed(MPR3)\n"));
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* translate dq read value per dram dq pin */
|
|
static int mv_ddr4_dq_decode(u8 dev_num, u32 *data)
|
|
{
|
|
u32 subphy_num, dq_num;
|
|
u32 dq_val = 0, raw_data, idx;
|
|
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
|
|
u32 subphy_max = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
|
|
|
|
/* suppose the third word is stable */
|
|
raw_data = data[2];
|
|
|
|
/* skip ecc supbhy; TODO: check to add support for ecc */
|
|
if (subphy_max % 2)
|
|
subphy_max -= 1;
|
|
|
|
for (subphy_num = 0; subphy_num < subphy_max; subphy_num++) {
|
|
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy_num);
|
|
for (dq_num = 0; dq_num < BUS_WIDTH_IN_BITS; dq_num++) {
|
|
idx = (dram_to_mc_dq_map[subphy_num][dq_num] + (subphy_num * BUS_WIDTH_IN_BITS));
|
|
dq_val |= (((raw_data & (1 << idx)) >> idx) << ((subphy_num * BUS_WIDTH_IN_BITS) + dq_num));
|
|
}
|
|
}
|
|
|
|
/* update burst words[0..7] with correct mapping */
|
|
for (idx = 0; idx < EXT_ACCESS_BURST_LENGTH; idx++)
|
|
data[idx] = dq_val;
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/*
|
|
* read mpr value per requested format and type
|
|
* note: for parallel decoded read, data is presented as stored in mpr on dram side,
|
|
* for all others, data to be presneted "as is" (i.e. per dq order from high to low
|
|
* and bus pins connectivity).
|
|
*/
|
|
int mv_ddr4_mpr_read(u8 dev_num, u32 mpr_num, u32 page_num,
|
|
enum mv_ddr4_mpr_read_format read_format,
|
|
enum mv_ddr4_mpr_read_type read_type,
|
|
u32 *data)
|
|
{
|
|
/* TODO: add support for multiple if_id, dev num, and cs */
|
|
u32 word_idx, if_id = 0;
|
|
volatile unsigned long *addr = NULL;
|
|
|
|
/* enter mpr read mode */
|
|
mv_ddr4_mpr_read_mode_enable(dev_num, mpr_num, page_num, read_format);
|
|
|
|
/* set pattern type*/
|
|
ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, DDR4_MPR_WR_REG,
|
|
mpr_num << 8, 0x3 << 8);
|
|
|
|
for (word_idx = 0; word_idx < EXT_ACCESS_BURST_LENGTH; word_idx++) {
|
|
data[word_idx] = *addr;
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("mv_ddr4_mpr_read: addr 0x%08lx, data 0x%08x\n",
|
|
(unsigned long)addr, data[word_idx]));
|
|
addr++;
|
|
}
|
|
|
|
/* exit mpr read mode */
|
|
mv_ddr4_mpr_mode_disable(dev_num);
|
|
|
|
/* decode mpr read value (only parallel mode supported) */
|
|
if ((read_type == MV_DDR4_MPR_READ_DECODED) && (read_format == MV_DDR4_MPR_READ_PARALLEL)) {
|
|
if (dq_map_enable == 1) {
|
|
mv_ddr4_dq_decode(dev_num, data);
|
|
} else {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_mpr_read: run mv_ddr4_dq_pins_mapping()\n"));
|
|
return MV_FAIL;
|
|
}
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* enter mpr write mode */
|
|
static int mv_ddr4_mpr_write_mode_enable(u8 dev_num, u32 mpr_location, u32 page_num, u32 data)
|
|
{
|
|
/*
|
|
* enable MPR page 2 mpr mode in DDR4 MR3
|
|
* TODO: add support for cs, multicast or unicast, and if id
|
|
*/
|
|
int status;
|
|
u32 if_id = 0, val = 0, mask;
|
|
|
|
val = (page_num << 0) | (0x1 << 2);
|
|
mask = (0x3 << 0) | (0x1 << 2);
|
|
/* cs0 */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, DDR4_MR3_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* cs0 */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, DDR4_MPR_WR_REG,
|
|
(mpr_location << 8) | data, 0x3ff);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* op cmd: cs0, cs1 are on, cs2, cs3 are off */
|
|
status = ddr3_tip_if_write(dev_num, ACCESS_TYPE_UNICAST, if_id, SDRAM_OP_REG,
|
|
(0x13 | 0xc << 8) , (0x1f | (0xf << 8)));
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK) {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_mpr_write_mode_enable: DDR3 poll failed(MPR3)\n"));
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* write mpr value */
|
|
int mv_ddr4_mpr_write(u8 dev_num, u32 mpr_location, u32 mpr_num, u32 page_num, u32 data)
|
|
{
|
|
/* enter mpr write mode */
|
|
mv_ddr4_mpr_write_mode_enable(dev_num, mpr_location, page_num, data);
|
|
|
|
/* TODO: implement this function */
|
|
|
|
/* TODO: exit mpr write mode */
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/*
|
|
* map physical on-board connection of dram dq pins to ddr4 controller pins
|
|
* note: supports only 32b width
|
|
* TODO: add support for 64-bit bus width and ecc subphy
|
|
*/
|
|
int mv_ddr4_dq_pins_mapping(u8 dev_num)
|
|
{
|
|
static int run_once;
|
|
u8 dq_val[MAX_BUS_NUM][BUS_WIDTH_IN_BITS] = { {0} };
|
|
u32 mpr_pattern[MV_DDR4_MPR_READ_PATTERN_NUM][EXT_ACCESS_BURST_LENGTH] = { {0} };
|
|
u32 subphy_num, dq_num, mpr_type;
|
|
u8 subphy_pattern[3];
|
|
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
|
|
u32 subphy_max = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
|
|
|
|
if (run_once)
|
|
return MV_OK;
|
|
else
|
|
run_once++;
|
|
|
|
/* clear dq mapping */
|
|
memset(dram_to_mc_dq_map, 0, sizeof(dram_to_mc_dq_map));
|
|
|
|
/* stage 1: read page 0 mpr0..2 raw patterns */
|
|
for (mpr_type = 0; mpr_type < MV_DDR4_MPR_READ_PATTERN_NUM; mpr_type++)
|
|
mv_ddr4_mpr_read(dev_num, mpr_type, 0, MV_DDR4_MPR_READ_PARALLEL,
|
|
MV_DDR4_MPR_READ_RAW, mpr_pattern[mpr_type]);
|
|
|
|
/* stage 2: map every dq for each subphy to 3-bit value, create local database */
|
|
/* skip ecc supbhy; TODO: check to add support for ecc */
|
|
if (subphy_max % 2)
|
|
subphy_max -= 1;
|
|
|
|
for (subphy_num = 0; subphy_num < subphy_max; subphy_num++) {
|
|
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy_num);
|
|
/* extract pattern for each subphy */
|
|
for (mpr_type = 0; mpr_type < MV_DDR4_MPR_READ_PATTERN_NUM; mpr_type++)
|
|
subphy_pattern[mpr_type] = ((mpr_pattern[mpr_type][2] >> (subphy_num * 8)) & 0xff);
|
|
|
|
for (dq_num = 0; dq_num < BUS_WIDTH_IN_BITS; dq_num++)
|
|
for (mpr_type = 0; mpr_type < MV_DDR4_MPR_READ_PATTERN_NUM; mpr_type++)
|
|
dq_val[subphy_num][dq_num] += (((subphy_pattern[mpr_type] >> dq_num) & 1) *
|
|
(1 << mpr_type));
|
|
}
|
|
|
|
/* stage 3: map dram dq to mc dq and update database */
|
|
for (subphy_num = 0; subphy_num < subphy_max; subphy_num++) {
|
|
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy_num);
|
|
for (dq_num = 0; dq_num < BUS_WIDTH_IN_BITS; dq_num++)
|
|
dram_to_mc_dq_map[subphy_num][7 - dq_val[subphy_num][dq_num]] = dq_num;
|
|
}
|
|
|
|
/* set dq_map_enable */
|
|
dq_map_enable = 1;
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* enter to or exit from dram vref training mode */
|
|
int mv_ddr4_vref_training_mode_ctrl(u8 dev_num, u8 if_id, enum hws_access_type access_type, int enable)
|
|
{
|
|
int status;
|
|
u32 val, mask;
|
|
|
|
/* DDR4 MR6 */
|
|
/*
|
|
* set t_ccd_l, 0x1918[12:10] to 0x0, 0x2, or 0x4 (z1 supports only even
|
|
* values, to be fixed in a0)
|
|
* set vdq te, 0x1918[7] to 0x0
|
|
* set vdq tv, 0x1918[5:0] to vref training value
|
|
*/
|
|
|
|
val = (((enable == 1) ? 1 : 0) << 7);
|
|
mask = (0x1 << 7);
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR6_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* write DDR4 MR6 cs configuration; only cs0, cs1 supported */
|
|
if (effective_cs == 0)
|
|
val = 0xe;
|
|
else
|
|
val = 0xd;
|
|
val <<= 8;
|
|
/* write DDR4 MR6 command */
|
|
val |= 0x12;
|
|
mask = (0xf << 8) | 0x1f;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, SDRAM_OP_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK) {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_vref_training_mode_ctrl: Polling command failed\n"));
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* set dram vref tap value */
|
|
int mv_ddr4_vref_tap_set(u8 dev_num, u8 if_id, enum hws_access_type access_type,
|
|
u32 taps_num, enum mv_ddr4_vref_tap_state state)
|
|
{
|
|
int status;
|
|
u32 range, vdq_tv;
|
|
|
|
/* disable and then enable the training with a new range */
|
|
if ((state == MV_DDR4_VREF_TAP_BUSY) && ((taps_num + MV_DDR4_VREF_STEP_SIZE) >= 23) &&
|
|
(taps_num < 23))
|
|
state = MV_DDR4_VREF_TAP_FLIP;
|
|
|
|
if (taps_num < 23) {
|
|
range = 1;
|
|
vdq_tv = taps_num;
|
|
} else {
|
|
range = 0;
|
|
vdq_tv = taps_num - 23;
|
|
}
|
|
|
|
if ((state == MV_DDR4_VREF_TAP_FLIP) | (state == MV_DDR4_VREF_TAP_START)) {
|
|
/* 0 to disable */
|
|
status = mv_ddr4_vref_set(dev_num, if_id, access_type, range, vdq_tv, 0);
|
|
if (status != MV_OK)
|
|
return status;
|
|
/* 1 to enable */
|
|
status = (mv_ddr4_vref_set(dev_num, if_id, access_type, range, vdq_tv, 1));
|
|
if (status != MV_OK)
|
|
return status;
|
|
} else if (state == MV_DDR4_VREF_TAP_END) {
|
|
/* 1 to enable */
|
|
status = (mv_ddr4_vref_set(dev_num, if_id, access_type, range, vdq_tv, 1));
|
|
if (status != MV_OK)
|
|
return status;
|
|
/* 0 to disable */
|
|
status = mv_ddr4_vref_set(dev_num, if_id, access_type, range, vdq_tv, 0);
|
|
if (status != MV_OK)
|
|
return status;
|
|
} else {
|
|
/* 1 to enable */
|
|
status = (mv_ddr4_vref_set(dev_num, if_id, access_type, range, vdq_tv, 1));
|
|
if (status != MV_OK)
|
|
return status;
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* set dram vref value */
|
|
int mv_ddr4_vref_set(u8 dev_num, u8 if_id, enum hws_access_type access_type,
|
|
u32 range, u32 vdq_tv, u8 vdq_training_ena)
|
|
{
|
|
int status;
|
|
u32 read_data;
|
|
u32 val, mask;
|
|
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("mv_ddr4_vref_set: range %d, vdq_tv %d\n", range, vdq_tv));
|
|
|
|
/* DDR4 MR6 */
|
|
/*
|
|
* set t_ccd_l, 0x1918[12:10] to 0x0, 0x2, or 0x4 (z1 supports only even
|
|
* values, to be fixed in a0)
|
|
* set vdq te, 0x1918[7] to 0x0
|
|
* set vdq tr, 0x1918[6] to 0x0 to disable or 0x1 to enable
|
|
* set vdq tv, 0x1918[5:0] to vref training value
|
|
*/
|
|
val = (vdq_training_ena << 7) | (range << 6) | vdq_tv;
|
|
mask = (0x0 << 7) | (0x1 << 6) | 0x3f;
|
|
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR6_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
ddr3_tip_if_read(dev_num, access_type, if_id, DDR4_MR6_REG, &read_data, 0xffffffff);
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_INFO, ("mv_ddr4_vref_set: MR6 = 0x%x\n", read_data));
|
|
|
|
/* write DDR4 MR6 cs configuration; only cs0, cs1 supported */
|
|
if (effective_cs == 0)
|
|
val = 0xe;
|
|
else
|
|
val = 0xd;
|
|
val <<= 8;
|
|
/* write DDR4 MR6 command */
|
|
val |= 0x12;
|
|
mask = (0xf << 8) | 0x1f;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, SDRAM_OP_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1F, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK) {
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_vref_set: Polling command failed\n"));
|
|
}
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* pda - load pattern to odpg */
|
|
int mv_ddr4_pda_pattern_odpg_load(u32 dev_num, enum hws_access_type access_type,
|
|
u32 if_id, u32 subphy_mask, u32 cs_num)
|
|
{
|
|
int status;
|
|
u32 pattern_len_count = 0;
|
|
u32 data_low[KILLER_PATTERN_LENGTH] = {0};
|
|
u32 data_high[KILLER_PATTERN_LENGTH] = {0};
|
|
u32 val, mask, subphy_num;
|
|
|
|
/*
|
|
* set 0x1630[10:5] bits to 0x3 (0x1 for 16-bit bus width)
|
|
* set 0x1630[14:11] bits to 0x3 (0x1 for 16-bit bus width)
|
|
*/
|
|
val = (cs_num << 26) | (0x1 << 25) | (0x3 << 11) | (0x3 << 5) | 0x1;
|
|
mask = (0x3 << 26) | (0x1 << 25) | (0x3f << 11) | (0x3f << 5) | 0x1;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, ODPG_DATA_CTRL_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (subphy_mask != 0xf) {
|
|
for (subphy_num = 0; subphy_num < 4; subphy_num++)
|
|
if (((subphy_mask >> subphy_num) & 0x1) == 0)
|
|
data_low[0] = (data_low[0] | (0xff << (subphy_num * 8)));
|
|
} else
|
|
data_low[0] = 0;
|
|
|
|
for (pattern_len_count = 0; pattern_len_count < 4; pattern_len_count++) {
|
|
data_low[pattern_len_count] = data_low[0];
|
|
data_high[pattern_len_count] = data_low[0];
|
|
}
|
|
|
|
for (pattern_len_count = 0; pattern_len_count < 4 ; pattern_len_count++) {
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, ODPG_DATA_WR_DATA_LOW_REG,
|
|
data_low[pattern_len_count], MASK_ALL_BITS);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, ODPG_DATA_WR_DATA_HIGH_REG,
|
|
data_high[pattern_len_count], MASK_ALL_BITS);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, ODPG_DATA_WR_ADDR_REG,
|
|
pattern_len_count, MASK_ALL_BITS);
|
|
if (status != MV_OK)
|
|
return status;
|
|
}
|
|
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, ODPG_DATA_BUFFER_OFFS_REG,
|
|
0x0, MASK_ALL_BITS);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
return MV_OK;
|
|
}
|
|
|
|
/* enable or disable pda */
|
|
int mv_ddr4_pda_ctrl(u8 dev_num, u8 if_id, u8 cs_num, int enable)
|
|
{
|
|
/*
|
|
* if enable is 0, exit
|
|
* mrs to be directed to all dram devices
|
|
* a calling function responsible to change odpg to 0x0
|
|
*/
|
|
|
|
int status;
|
|
enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
|
|
u32 val, mask;
|
|
|
|
/* per dram addressability enable */
|
|
val = ((enable == 1) ? 1 : 0);
|
|
val <<= 4;
|
|
mask = 0x1 << 4;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, DDR4_MR3_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
/* write DDR4 MR3 cs configuration; only cs0, cs1 supported */
|
|
if (cs_num == 0)
|
|
val = 0xe;
|
|
else
|
|
val = 0xd;
|
|
val <<= 8;
|
|
/* write DDR4 MR3 command */
|
|
val |= 0x9;
|
|
mask = (0xf << 8) | 0x1f;
|
|
status = ddr3_tip_if_write(dev_num, access_type, if_id, SDRAM_OP_REG, val, mask);
|
|
if (status != MV_OK)
|
|
return status;
|
|
|
|
if (enable == 0) {
|
|
/* check odpg access is done */
|
|
if (mv_ddr_is_odpg_done(MAX_POLLING_ITERATIONS) != MV_OK)
|
|
return MV_FAIL;
|
|
}
|
|
|
|
if (ddr3_tip_if_polling(dev_num, ACCESS_TYPE_UNICAST, if_id, 0, 0x1f, SDRAM_OP_REG,
|
|
MAX_POLLING_ITERATIONS) != MV_OK)
|
|
DEBUG_TRAINING_IP(DEBUG_LEVEL_ERROR, ("mv_ddr4_pda_ctrl: Polling command failed\n"));
|
|
|
|
return MV_OK;
|
|
}
|
|
#endif /* CONFIG_DDR4 */
|