Commit 2fef96a3 authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #745 from rockchip-linux/support-rk3399-dram

Support rk3399 dram
parents be7b4af3 4c127e68
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <debug.h>
#include <mmio.h>
#include <plat_private.h>
#include "dfs.h"
#include "dram.h"
#include "dram_spec_timing.h"
#include "string.h"
#include "soc.h"
#include "pmu.h"
#include <delay_timer.h>
#define CTL_TRAINING (1)
#define PI_TRAINING (!CTL_TRAINING)
#define EN_READ_GATE_TRAINING (1)
#define EN_CA_TRAINING (0)
#define EN_WRITE_LEVELING (0)
#define EN_READ_LEVELING (0)
#define EN_WDQ_LEVELING (0)
#define ENPER_CS_TRAINING_FREQ (933)
struct pll_div {
unsigned int mhz;
unsigned int refdiv;
unsigned int fbdiv;
unsigned int postdiv1;
unsigned int postdiv2;
unsigned int frac;
unsigned int freq;
};
static const struct pll_div dpll_rates_table[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1},
{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1},
{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2},
};
struct rk3399_dram_status {
uint32_t current_index;
uint32_t index_freq[2];
uint32_t low_power_stat;
struct timing_related_config timing_config;
struct drv_odt_lp_config drv_odt_lp_cfg;
};
static struct rk3399_dram_status rk3399_dram_status;
static struct ddr_dts_config_timing dts_parameter = {
.available = 0
};
static struct rk3399_sdram_default_config ddr3_default_config = {
.bl = 8,
.ap = 0,
.dramds = 40,
.dramodt = 120,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config ddr3_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 933,
.dram_side_drv = 40,
.dram_side_dq_odt = 120,
.dram_side_ca_odt = 120,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 40,
.phy_side_dq_drv = 40,
.phy_side_odt = 240,
};
static struct rk3399_sdram_default_config lpddr3_default_config = {
.bl = 8,
.ap = 0,
.dramds = 34,
.dramodt = 240,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config lpddr3_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 666,
.dram_side_drv = 40,
.dram_side_dq_odt = 120,
.dram_side_ca_odt = 120,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 40,
.phy_side_dq_drv = 40,
.phy_side_odt = 240,
};
static struct rk3399_sdram_default_config lpddr4_default_config = {
.bl = 16,
.ap = 0,
.dramds = 40,
.dramodt = 240,
.caodt = 240,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config lpddr4_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 933,
.dram_side_drv = 60,
.dram_side_dq_odt = 40,
.dram_side_ca_odt = 40,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 80,
.phy_side_dq_drv = 80,
.phy_side_odt = 60,
};
uint32_t dcf_code[] = {
#include "dcf_code.inc"
};
#define DCF_START_ADDR (SRAM_BASE + 0x1400)
#define DCF_PARAM_ADDR (SRAM_BASE + 0x1000)
/* DCF_PAMET */
#define PARAM_DRAM_FREQ (0)
#define PARAM_DPLL_CON0 (4)
#define PARAM_DPLL_CON1 (8)
#define PARAM_DPLL_CON2 (0xc)
#define PARAM_DPLL_CON3 (0x10)
#define PARAM_DPLL_CON4 (0x14)
#define PARAM_DPLL_CON5 (0x18)
/* equal to fn<<4 */
#define PARAM_FREQ_SELECT (0x1c)
static uint32_t get_cs_die_capability(struct rk3399_sdram_params *sdram_config,
uint8_t channel, uint8_t cs)
{
struct rk3399_sdram_channel *ch = &sdram_config->ch[channel];
uint32_t bandwidth;
uint32_t die_bandwidth;
uint32_t die;
uint32_t cs_cap;
uint32_t row;
row = cs == 0 ? ch->cs0_row : ch->cs1_row;
bandwidth = 8 * (1 << ch->bw);
die_bandwidth = 8 * (1 << ch->dbw);
die = bandwidth / die_bandwidth;
cs_cap = (1 << (row + ((1 << ch->bk) / 4 + 1) + ch->col +
(bandwidth / 16)));
if (ch->row_3_4)
cs_cap = cs_cap * 3 / 4;
return (cs_cap / die);
}
static void drv_odt_lp_cfg_init(uint32_t dram_type,
struct ddr_dts_config_timing *dts_timing,
struct drv_odt_lp_config *drv_config)
{
if ((dts_timing) && (dts_timing->available)) {
drv_config->ddr3_speed_bin = dts_timing->ddr3_speed_bin;
drv_config->pd_idle = dts_timing->pd_idle;
drv_config->sr_idle = dts_timing->sr_idle;
drv_config->sr_mc_gate_idle = dts_timing->sr_mc_gate_idle;
drv_config->srpd_lite_idle = dts_timing->srpd_lite_idle;
drv_config->standby_idle = dts_timing->standby_idle;
drv_config->ddr3_dll_dis_freq = dts_timing->ddr3_dll_dis_freq;
drv_config->phy_dll_dis_freq = dts_timing->phy_dll_dis_freq;
}
switch (dram_type) {
case DDR3:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->ddr3_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->ddr3_drv;
drv_config->dram_side_dq_odt = dts_timing->ddr3_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_ddr3_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_ddr3_ca_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_ddr3_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_ddr3_odt;
} else {
memcpy(drv_config, &ddr3_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
case LPDDR3:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->lpddr3_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->lpddr3_drv;
drv_config->dram_side_dq_odt = dts_timing->lpddr3_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_lpddr3_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_lpddr3_ca_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_lpddr3_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_lpddr3_odt;
} else {
memcpy(drv_config, &lpddr3_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
case LPDDR4:
default:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->lpddr4_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->lpddr4_drv;
drv_config->dram_side_dq_odt =
dts_timing->lpddr4_dq_odt;
drv_config->dram_side_ca_odt =
dts_timing->lpddr4_ca_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_lpddr4_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_lpddr4_ck_cs_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_lpddr4_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_lpddr4_odt;
} else {
memcpy(drv_config, &lpddr4_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
}
switch (drv_config->phy_side_ca_drv) {
case 240:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_34_3;
break;
};
switch (drv_config->phy_side_ck_cs_drv) {
case 240:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_34_3;
break;
}
switch (drv_config->phy_side_dq_drv) {
case 240:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_34_3;
break;
}
switch (drv_config->phy_side_odt) {
case 240:
drv_config->phy_side_odt = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_odt = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_odt = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_odt = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_odt = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_odt = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_odt = PHY_DRV_ODT_34_3;
break;
}
}
static void sdram_timing_cfg_init(struct timing_related_config *ptiming_config,
struct rk3399_sdram_params *sdram_params,
struct drv_odt_lp_config *drv_config)
{
uint32_t i, j;
for (i = 0; i < sdram_params->num_channels; i++) {
ptiming_config->dram_info[i].speed_rate =
drv_config->ddr3_speed_bin;
ptiming_config->dram_info[i].cs_cnt = sdram_params->ch[i].rank;
for (j = 0; j < sdram_params->ch[i].rank; j++) {
ptiming_config->dram_info[i].per_die_capability[j] =
get_cs_die_capability(sdram_params, i, j);
}
}
ptiming_config->dram_type = sdram_params->dramtype;
ptiming_config->ch_cnt = sdram_params->num_channels;
switch (sdram_params->dramtype) {
case DDR3:
ptiming_config->bl = ddr3_default_config.bl;
ptiming_config->ap = ddr3_default_config.ap;
break;
case LPDDR3:
ptiming_config->bl = lpddr3_default_config.bl;
ptiming_config->ap = lpddr3_default_config.ap;
break;
case LPDDR4:
ptiming_config->bl = lpddr4_default_config.bl;
ptiming_config->ap = lpddr4_default_config.ap;
ptiming_config->rdbi = 0;
ptiming_config->wdbi = 0;
break;
}
ptiming_config->dramds = drv_config->dram_side_drv;
ptiming_config->dramodt = drv_config->dram_side_dq_odt;
ptiming_config->caodt = drv_config->dram_side_ca_odt;
}
struct lat_adj_pair {
uint32_t cl;
uint32_t rdlat_adj;
uint32_t cwl;
uint32_t wrlat_adj;
};
const struct lat_adj_pair ddr3_lat_adj[] = {
{6, 5, 5, 4},
{8, 7, 6, 5},
{10, 9, 7, 6},
{11, 9, 8, 7},
{13, 0xb, 9, 8},
{14, 0xb, 0xa, 9}
};
const struct lat_adj_pair lpddr3_lat_adj[] = {
{3, 2, 1, 0},
{6, 5, 3, 2},
{8, 7, 4, 3},
{9, 8, 5, 4},
{10, 9, 6, 5},
{11, 9, 6, 5},
{12, 0xa, 6, 5},
{14, 0xc, 8, 7},
{16, 0xd, 8, 7}
};
const struct lat_adj_pair lpddr4_lat_adj[] = {
{6, 5, 4, 2},
{10, 9, 6, 4},
{14, 0xc, 8, 6},
{20, 0x11, 0xa, 8},
{24, 0x15, 0xc, 0xa},
{28, 0x18, 0xe, 0xc},
{32, 0x1b, 0x10, 0xe},
{36, 0x1e, 0x12, 0x10}
};
static uint32_t get_rdlat_adj(uint32_t dram_type, uint32_t cl)
{
const struct lat_adj_pair *p;
uint32_t cnt;
uint32_t i;
if (dram_type == DDR3) {
p = ddr3_lat_adj;
cnt = ARRAY_SIZE(ddr3_lat_adj);
} else if (dram_type == LPDDR3) {
p = lpddr3_lat_adj;
cnt = ARRAY_SIZE(lpddr3_lat_adj);
} else {
p = lpddr4_lat_adj;
cnt = ARRAY_SIZE(lpddr4_lat_adj);
}
for (i = 0; i < cnt; i++) {
if (cl == p[i].cl)
return p[i].rdlat_adj;
}
/* fail */
return 0xff;
}
static uint32_t get_wrlat_adj(uint32_t dram_type, uint32_t cwl)
{
const struct lat_adj_pair *p;
uint32_t cnt;
uint32_t i;
if (dram_type == DDR3) {
p = ddr3_lat_adj;
cnt = ARRAY_SIZE(ddr3_lat_adj);
} else if (dram_type == LPDDR3) {
p = lpddr3_lat_adj;
cnt = ARRAY_SIZE(lpddr3_lat_adj);
} else {
p = lpddr4_lat_adj;
cnt = ARRAY_SIZE(lpddr4_lat_adj);
}
for (i = 0; i < cnt; i++) {
if (cwl == p[i].cwl)
return p[i].wrlat_adj;
}
/* fail */
return 0xff;
}
#define PI_REGS_DIMM_SUPPORT (0)
#define PI_ADD_LATENCY (0)
#define PI_DOUBLEFREEK (1)
#define PI_PAD_DELAY_PS_VALUE (1000)
#define PI_IE_ENABLE_VALUE (3000)
#define PI_TSEL_ENABLE_VALUE (700)
static uint32_t get_pi_rdlat_adj(struct dram_timing_t *pdram_timing)
{
/*[DLLSUBTYPE2] == "STD_DENALI_HS" */
uint32_t rdlat, delay_adder, ie_enable, hs_offset, tsel_adder,
extra_adder, tsel_enable;
ie_enable = PI_IE_ENABLE_VALUE;
tsel_enable = PI_TSEL_ENABLE_VALUE;
rdlat = pdram_timing->cl + PI_ADD_LATENCY;
delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
hs_offset = 0;
tsel_adder = 0;
extra_adder = 0;
/* rdlat = rdlat - (PREAMBLE_SUPPORT & 0x1); */
tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
tsel_adder++;
delay_adder = delay_adder - 1;
if (tsel_adder > delay_adder)
extra_adder = tsel_adder - delay_adder;
else
extra_adder = 0;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
if (delay_adder > (rdlat - 1 - hs_offset)) {
rdlat = rdlat - tsel_adder;
} else {
if ((rdlat - delay_adder) < 2)
rdlat = 2;
else
rdlat = rdlat - delay_adder - extra_adder;
}
return rdlat;
}
static uint32_t get_pi_wrlat(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp;
if (timing_config->dram_type == LPDDR3) {
tmp = pdram_timing->cl;
if (tmp >= 14)
tmp = 8;
else if (tmp >= 10)
tmp = 6;
else if (tmp == 9)
tmp = 5;
else if (tmp == 8)
tmp = 4;
else if (tmp == 6)
tmp = 3;
else
tmp = 1;
} else {
tmp = 1;
}
return tmp;
}
static uint32_t get_pi_wrlat_adj(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
return get_pi_wrlat(pdram_timing, timing_config) + PI_ADD_LATENCY - 1;
}
static uint32_t get_pi_tdfi_phy_rdlat(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
/* [DLLSUBTYPE2] == "STD_DENALI_HS" */
uint32_t cas_lat, delay_adder, ie_enable, hs_offset, ie_delay_adder;
uint32_t mem_delay_ps, round_trip_ps;
uint32_t phy_internal_delay, lpddr_adder, dfi_adder, rdlat_delay;
ie_enable = PI_IE_ENABLE_VALUE;
delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
delay_adder = delay_adder - 1;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
if (delay_adder > (cas_lat - 1 - hs_offset)) {
ie_delay_adder = 0;
} else {
ie_delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
ie_delay_adder++;
}
if (timing_config->dram_type == DDR3) {
mem_delay_ps = 0;
} else if (timing_config->dram_type == LPDDR4) {
mem_delay_ps = 3600;
} else if (timing_config->dram_type == LPDDR3) {
mem_delay_ps = 5500;
} else {
printf("get_pi_tdfi_phy_rdlat:dramtype unsupport\n");
return 0;
}
round_trip_ps = 1100 + 500 + mem_delay_ps + 500 + 600;
delay_adder = round_trip_ps / (1000000 / pdram_timing->mhz);
if ((round_trip_ps % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
phy_internal_delay = 5 + 2 + 4;
lpddr_adder = mem_delay_ps / (1000000 / pdram_timing->mhz);
if ((mem_delay_ps % (1000000 / pdram_timing->mhz)) != 0)
lpddr_adder++;
dfi_adder = 0;
phy_internal_delay = phy_internal_delay + 2;
rdlat_delay = delay_adder + phy_internal_delay +
ie_delay_adder + lpddr_adder + dfi_adder;
rdlat_delay = rdlat_delay + 2;
return rdlat_delay;
}
static uint32_t get_pi_todtoff_min(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp, todtoff_min_ps;
if (timing_config->dram_type == LPDDR3)
todtoff_min_ps = 2500;
else if (timing_config->dram_type == LPDDR4)
todtoff_min_ps = 1500;
else
todtoff_min_ps = 0;
/* todtoff_min */
tmp = todtoff_min_ps / (1000000 / pdram_timing->mhz);
if ((todtoff_min_ps % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
return tmp;
}
static uint32_t get_pi_todtoff_max(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp, todtoff_max_ps;
if ((timing_config->dram_type == LPDDR4)
|| (timing_config->dram_type == LPDDR3))
todtoff_max_ps = 3500;
else
todtoff_max_ps = 0;
/* todtoff_max */
tmp = todtoff_max_ps / (1000000 / pdram_timing->mhz);
if ((todtoff_max_ps % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
return tmp;
}
static void gen_rk3399_ctl_params_f0(struct timing_related_config
*timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t i;
uint32_t tmp, tmp1;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == DDR3) {
tmp = ((700000 + 10) * timing_config->freq +
999) / 1000;
tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
pdram_timing->tmod + pdram_timing->tzqinit;
mmio_write_32(CTL_REG(i, 5), tmp);
mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff,
pdram_timing->tdllk);
mmio_write_32(CTL_REG(i, 32),
(pdram_timing->tmod << 8) |
pdram_timing->tmrd);
mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
(pdram_timing->txsr -
pdram_timing->trcd) << 16);
} else if (timing_config->dram_type == LPDDR4) {
mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1 +
pdram_timing->tinit3);
mmio_write_32(CTL_REG(i, 32),
(pdram_timing->tmrd << 8) |
pdram_timing->tmrd);
mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
pdram_timing->txsr << 16);
} else {
mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1);
mmio_write_32(CTL_REG(i, 7), pdram_timing->tinit4);
mmio_write_32(CTL_REG(i, 32),
(pdram_timing->tmrd << 8) |
pdram_timing->tmrd);
mmio_clrsetbits_32(CTL_REG(i, 59), 0xffff << 16,
pdram_timing->txsr << 16);
}
mmio_write_32(CTL_REG(i, 6), pdram_timing->tinit3);
mmio_write_32(CTL_REG(i, 8), pdram_timing->tinit5);
mmio_clrsetbits_32(CTL_REG(i, 23), (0x7f << 16),
((pdram_timing->cl * 2) << 16));
mmio_clrsetbits_32(CTL_REG(i, 23), (0x1f << 24),
(pdram_timing->cwl << 24));
mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f, pdram_timing->al);
mmio_clrsetbits_32(CTL_REG(i, 26), 0xffff << 16,
(pdram_timing->trc << 24) |
(pdram_timing->trrd << 16));
mmio_write_32(CTL_REG(i, 27),
(pdram_timing->tfaw << 24) |
(pdram_timing->trppb << 16) |
(pdram_timing->twtr << 8) |
pdram_timing->tras_min);
mmio_clrsetbits_32(CTL_REG(i, 31), 0xff << 24,
max(4, pdram_timing->trtp) << 24);
mmio_write_32(CTL_REG(i, 33), (pdram_timing->tcke << 24) |
pdram_timing->tras_max);
mmio_clrsetbits_32(CTL_REG(i, 34), 0xff,
max(1, pdram_timing->tckesr));
mmio_clrsetbits_32(CTL_REG(i, 39),
(0x3f << 16) | (0xff << 8),
(pdram_timing->twr << 16) |
(pdram_timing->trcd << 8));
mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 16,
pdram_timing->tmrz << 16);
tmp = pdram_timing->tdal ? pdram_timing->tdal :
(pdram_timing->twr + pdram_timing->trp);
mmio_clrsetbits_32(CTL_REG(i, 44), 0xff, tmp);
mmio_clrsetbits_32(CTL_REG(i, 45), 0xff, pdram_timing->trp);
mmio_write_32(CTL_REG(i, 48),
((pdram_timing->trefi - 8) << 16) |
pdram_timing->trfc);
mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff, pdram_timing->txp);
mmio_clrsetbits_32(CTL_REG(i, 53), 0xffff << 16,
pdram_timing->txpdll << 16);
mmio_clrsetbits_32(CTL_REG(i, 55), 0xf << 24,
pdram_timing->tcscke << 24);
mmio_clrsetbits_32(CTL_REG(i, 55), 0xff, pdram_timing->tmrri);
mmio_write_32(CTL_REG(i, 56),
(pdram_timing->tzqcke << 24) |
(pdram_timing->tmrwckel << 16) |
(pdram_timing->tckehcs << 8) |
pdram_timing->tckelcs);
mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff, pdram_timing->txsnr);
mmio_clrsetbits_32(CTL_REG(i, 62), 0xffff << 16,
(pdram_timing->tckehcmd << 24) |
(pdram_timing->tckelcmd << 16));
mmio_write_32(CTL_REG(i, 63),
(pdram_timing->tckelpd << 24) |
(pdram_timing->tescke << 16) |
(pdram_timing->tsr << 8) |
pdram_timing->tckckel);
mmio_clrsetbits_32(CTL_REG(i, 64), 0xfff,
(pdram_timing->tcmdcke << 8) |
pdram_timing->tcsckeh);
mmio_clrsetbits_32(CTL_REG(i, 92), 0xffff << 8,
(pdram_timing->tcksrx << 16) |
(pdram_timing->tcksre << 8));
mmio_clrsetbits_32(CTL_REG(i, 108), 0x1 << 24,
(timing_config->dllbp << 24));
mmio_clrsetbits_32(CTL_REG(i, 122), 0x3ff << 16,
(pdram_timing->tvrcg_enable << 16));
mmio_write_32(CTL_REG(i, 123), (pdram_timing->tfc_long << 16) |
pdram_timing->tvrcg_disable);
mmio_write_32(CTL_REG(i, 124),
(pdram_timing->tvref_long << 16) |
(pdram_timing->tckfspx << 8) |
pdram_timing->tckfspe);
mmio_write_32(CTL_REG(i, 133), (pdram_timing->mr[1] << 16) |
pdram_timing->mr[0]);
mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff,
pdram_timing->mr[2]);
mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff,
pdram_timing->mr[3]);
mmio_clrsetbits_32(CTL_REG(i, 139), 0xff << 24,
pdram_timing->mr11 << 24);
mmio_write_32(CTL_REG(i, 147),
(pdram_timing->mr[1] << 16) |
pdram_timing->mr[0]);
mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff,
pdram_timing->mr[2]);
mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff,
pdram_timing->mr[3]);
mmio_clrsetbits_32(CTL_REG(i, 153), 0xff << 24,
pdram_timing->mr11 << 24);
if (timing_config->dram_type == LPDDR4) {
mmio_clrsetbits_32(CTL_REG(i, 140), 0xffff << 16,
pdram_timing->mr12 << 16);
mmio_clrsetbits_32(CTL_REG(i, 142), 0xffff << 16,
pdram_timing->mr14 << 16);
mmio_clrsetbits_32(CTL_REG(i, 145), 0xffff << 16,
pdram_timing->mr22 << 16);
mmio_clrsetbits_32(CTL_REG(i, 154), 0xffff << 16,
pdram_timing->mr12 << 16);
mmio_clrsetbits_32(CTL_REG(i, 156), 0xffff << 16,
pdram_timing->mr14 << 16);
mmio_clrsetbits_32(CTL_REG(i, 159), 0xffff << 16,
pdram_timing->mr22 << 16);
}
mmio_clrsetbits_32(CTL_REG(i, 179), 0xfff << 8,
pdram_timing->tzqinit << 8);
mmio_write_32(CTL_REG(i, 180), (pdram_timing->tzqcs << 16) |
(pdram_timing->tzqinit / 2));
mmio_write_32(CTL_REG(i, 181), (pdram_timing->tzqlat << 16) |
pdram_timing->tzqcal);
mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 8,
pdram_timing->todton << 8);
if (timing_config->odt) {
mmio_setbits_32(CTL_REG(i, 213), 1 << 16);
if (timing_config->freq < 400)
tmp = 4 << 24;
else
tmp = 8 << 24;
} else {
mmio_clrbits_32(CTL_REG(i, 213), 1 << 16);
tmp = 2 << 24;
}
mmio_clrsetbits_32(CTL_REG(i, 216), 0x1f << 24, tmp);
mmio_clrsetbits_32(CTL_REG(i, 221), (0x3 << 16) | (0xf << 8),
(pdram_timing->tdqsck << 16) |
(pdram_timing->tdqsck_max << 8));
tmp =
(get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl)
<< 8) | get_rdlat_adj(timing_config->dram_type,
pdram_timing->cl);
mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff, tmp);
mmio_clrsetbits_32(CTL_REG(i, 82), 0xffff << 16,
(4 * pdram_timing->trefi) << 16);
mmio_clrsetbits_32(CTL_REG(i, 83), 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = 0;
}
mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 16,
(tmp & 0x3f) << 16);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble = cl+TDQSCK_MIN -1 */
tmp = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config) - 1;
/* todtoff_max */
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 8,
(tmp & 0x3f) << 8);
mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 16,
(get_pi_tdfi_phy_rdlat(pdram_timing,
timing_config) &
0xff) << 16);
mmio_clrsetbits_32(CTL_REG(i, 277), 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
mmio_clrsetbits_32(CTL_REG(i, 282), 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
mmio_write_32(CTL_REG(i, 283), 20 * pdram_timing->trefi);
/* CTL_308 TDFI_CALVL_CAPTURE_F0:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff << 16, tmp << 16);
/* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */
tmp = tmp + 18;
mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff, tmp);
/* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */
tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
if (tmp1 == 0)
tmp = 0;
else if (tmp1 < 5)
tmp = tmp1 - 1;
else
tmp = tmp1 - 5;
} else {
tmp = tmp1 - 2;
}
mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 8, tmp << 8);
/* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */
if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
(pdram_timing->cl >= 5))
tmp = pdram_timing->cl - 5;
else
tmp = pdram_timing->cl - 2;
mmio_clrsetbits_32(CTL_REG(i, 314), 0xff, tmp);
}
}
static void gen_rk3399_ctl_params_f1(struct timing_related_config
*timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t i;
uint32_t tmp, tmp1;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == DDR3) {
tmp =
((700000 + 10) * timing_config->freq + 999) / 1000;
tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
pdram_timing->tmod + pdram_timing->tzqinit;
mmio_write_32(CTL_REG(i, 9), tmp);
mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff << 16,
pdram_timing->tdllk << 16);
mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
(pdram_timing->tmod << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
(pdram_timing->txsr -
pdram_timing->trcd) << 16);
} else if (timing_config->dram_type == LPDDR4) {
mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1 +
pdram_timing->tinit3);
mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
(pdram_timing->tmrd << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
pdram_timing->txsr << 16);
} else {
mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1);
mmio_write_32(CTL_REG(i, 11), pdram_timing->tinit4);
mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
(pdram_timing->tmrd << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff << 16,
pdram_timing->txsr << 16);
}
mmio_write_32(CTL_REG(i, 10), pdram_timing->tinit3);
mmio_write_32(CTL_REG(i, 12), pdram_timing->tinit5);
mmio_clrsetbits_32(CTL_REG(i, 24), (0x7f << 8),
((pdram_timing->cl * 2) << 8));
mmio_clrsetbits_32(CTL_REG(i, 24), (0x1f << 16),
(pdram_timing->cwl << 16));
mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f << 24,
pdram_timing->al << 24);
mmio_clrsetbits_32(CTL_REG(i, 28), 0xffffff00,
(pdram_timing->tras_min << 24) |
(pdram_timing->trc << 16) |
(pdram_timing->trrd << 8));
mmio_clrsetbits_32(CTL_REG(i, 29), 0xffffff,
(pdram_timing->tfaw << 16) |
(pdram_timing->trppb << 8) |
pdram_timing->twtr);
mmio_write_32(CTL_REG(i, 35), (pdram_timing->tcke << 24) |
pdram_timing->tras_max);
mmio_clrsetbits_32(CTL_REG(i, 36), 0xff,
max(1, pdram_timing->tckesr));
mmio_clrsetbits_32(CTL_REG(i, 39), (0xff << 24),
(pdram_timing->trcd << 24));
mmio_clrsetbits_32(CTL_REG(i, 40), 0x3f, pdram_timing->twr);
mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 24,
pdram_timing->tmrz << 24);
tmp = pdram_timing->tdal ? pdram_timing->tdal :
(pdram_timing->twr + pdram_timing->trp);
mmio_clrsetbits_32(CTL_REG(i, 44), 0xff << 8, tmp << 8);
mmio_clrsetbits_32(CTL_REG(i, 45), 0xff << 8,
pdram_timing->trp << 8);
mmio_write_32(CTL_REG(i, 49),
((pdram_timing->trefi - 8) << 16) |
pdram_timing->trfc);
mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff << 16,
pdram_timing->txp << 16);
mmio_clrsetbits_32(CTL_REG(i, 54), 0xffff,
pdram_timing->txpdll);
mmio_clrsetbits_32(CTL_REG(i, 55), 0xff << 8,
pdram_timing->tmrri << 8);
mmio_write_32(CTL_REG(i, 57), (pdram_timing->tmrwckel << 24) |
(pdram_timing->tckehcs << 16) |
(pdram_timing->tckelcs << 8) |
pdram_timing->tcscke);
mmio_clrsetbits_32(CTL_REG(i, 58), 0xf, pdram_timing->tzqcke);
mmio_clrsetbits_32(CTL_REG(i, 61), 0xffff, pdram_timing->txsnr);
mmio_clrsetbits_32(CTL_REG(i, 64), 0xffff << 16,
(pdram_timing->tckehcmd << 24) |
(pdram_timing->tckelcmd << 16));
mmio_write_32(CTL_REG(i, 65), (pdram_timing->tckelpd << 24) |
(pdram_timing->tescke << 16) |
(pdram_timing->tsr << 8) |
pdram_timing->tckckel);
mmio_clrsetbits_32(CTL_REG(i, 66), 0xfff,
(pdram_timing->tcmdcke << 8) |
pdram_timing->tcsckeh);
mmio_clrsetbits_32(CTL_REG(i, 92), (0xff << 24),
(pdram_timing->tcksre << 24));
mmio_clrsetbits_32(CTL_REG(i, 93), 0xff,
pdram_timing->tcksrx);
mmio_clrsetbits_32(CTL_REG(i, 108), (0x1 << 25),
(timing_config->dllbp << 25));
mmio_write_32(CTL_REG(i, 125),
(pdram_timing->tvrcg_disable << 16) |
pdram_timing->tvrcg_enable);
mmio_write_32(CTL_REG(i, 126), (pdram_timing->tckfspx << 24) |
(pdram_timing->tckfspe << 16) |
pdram_timing->tfc_long);
mmio_clrsetbits_32(CTL_REG(i, 127), 0xffff,
pdram_timing->tvref_long);
mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff << 16,
pdram_timing->mr[0] << 16);
mmio_write_32(CTL_REG(i, 135), (pdram_timing->mr[2] << 16) |
pdram_timing->mr[1]);
mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff << 16,
pdram_timing->mr[3] << 16);
mmio_clrsetbits_32(CTL_REG(i, 140), 0xff, pdram_timing->mr11);
mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff << 16,
pdram_timing->mr[0] << 16);
mmio_write_32(CTL_REG(i, 149), (pdram_timing->mr[2] << 16) |
pdram_timing->mr[1]);
mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff << 16,
pdram_timing->mr[3] << 16);
mmio_clrsetbits_32(CTL_REG(i, 154), 0xff, pdram_timing->mr11);
if (timing_config->dram_type == LPDDR4) {
mmio_clrsetbits_32(CTL_REG(i, 141), 0xffff,
pdram_timing->mr12);
mmio_clrsetbits_32(CTL_REG(i, 143), 0xffff,
pdram_timing->mr14);
mmio_clrsetbits_32(CTL_REG(i, 146), 0xffff,
pdram_timing->mr22);
mmio_clrsetbits_32(CTL_REG(i, 155), 0xffff,
pdram_timing->mr12);
mmio_clrsetbits_32(CTL_REG(i, 157), 0xffff,
pdram_timing->mr14);
mmio_clrsetbits_32(CTL_REG(i, 160), 0xffff,
pdram_timing->mr22);
}
mmio_write_32(CTL_REG(i, 182),
((pdram_timing->tzqinit / 2) << 16) |
pdram_timing->tzqinit);
mmio_write_32(CTL_REG(i, 183), (pdram_timing->tzqcal << 16) |
pdram_timing->tzqcs);
mmio_clrsetbits_32(CTL_REG(i, 184), 0x3f, pdram_timing->tzqlat);
mmio_clrsetbits_32(CTL_REG(i, 188), 0xfff,
pdram_timing->tzqreset);
mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 16,
pdram_timing->todton << 16);
if (timing_config->odt) {
mmio_setbits_32(CTL_REG(i, 213), (1 << 24));
if (timing_config->freq < 400)
tmp = 4 << 24;
else
tmp = 8 << 24;
} else {
mmio_clrbits_32(CTL_REG(i, 213), (1 << 24));
tmp = 2 << 24;
}
mmio_clrsetbits_32(CTL_REG(i, 217), 0x1f << 24, tmp);
mmio_clrsetbits_32(CTL_REG(i, 221), 0xf << 24,
(pdram_timing->tdqsck_max << 24));
mmio_clrsetbits_32(CTL_REG(i, 222), 0x3, pdram_timing->tdqsck);
mmio_clrsetbits_32(CTL_REG(i, 291), 0xffff,
(get_wrlat_adj(timing_config->dram_type,
pdram_timing->cwl) << 8) |
get_rdlat_adj(timing_config->dram_type,
pdram_timing->cl));
mmio_clrsetbits_32(CTL_REG(i, 84), 0xffff,
(4 * pdram_timing->trefi) & 0xffff);
mmio_clrsetbits_32(CTL_REG(i, 84), 0xffff << 16,
((2 * pdram_timing->trefi) & 0xffff) << 16);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = 0;
}
mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 24,
(tmp & 0x3f) << 24);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
tmp = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config);
tmp--;
/* todtoff_max */
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 16,
(tmp & 0x3f) << 16);
mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 24,
(get_pi_tdfi_phy_rdlat(pdram_timing,
timing_config) &
0xff) << 24);
mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff << 16,
((2 * pdram_timing->trefi) & 0xffff) << 16);
mmio_clrsetbits_32(CTL_REG(i, 289), 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
mmio_write_32(CTL_REG(i, 290), 20 * pdram_timing->trefi);
/* CTL_309 TDFI_CALVL_CAPTURE_F1:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff << 16, tmp << 16);
/* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */
tmp = tmp + 18;
mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff, tmp);
/* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */
tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
if (tmp1 == 0)
tmp = 0;
else if (tmp1 < 5)
tmp = tmp1 - 1;
else
tmp = tmp1 - 5;
} else {
tmp = tmp1 - 2;
}
mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 24, tmp << 24);
/* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */
if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
(pdram_timing->cl >= 5))
tmp = pdram_timing->cl - 5;
else
tmp = pdram_timing->cl - 2;
mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 16, tmp << 16);
}
}
static void gen_rk3399_ctl_params(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
if (fn == 0)
gen_rk3399_ctl_params_f0(timing_config, pdram_timing);
else
gen_rk3399_ctl_params_f1(timing_config, pdram_timing);
#if CTL_TRAINING
uint32_t i, tmp0, tmp1;
tmp0 = tmp1 = 0;
#if EN_READ_GATE_TRAINING
tmp1 = 1;
#endif
#if EN_CA_TRAINING
tmp0 |= (1 << 8);
#endif
#if EN_WRITE_LEVELING
tmp0 |= (1 << 16);
#endif
#if EN_READ_LEVELING
tmp0 |= (1 << 24);
#endif
for (i = 0; i < timing_config->ch_cnt; i++) {
if (tmp0 | tmp1)
mmio_setbits_32(CTL_REG(i, 305), 1 << 16);
if (tmp0)
mmio_setbits_32(CTL_REG(i, 70), tmp0);
if (tmp1)
mmio_setbits_32(CTL_REG(i, 71), tmp1);
}
#endif
}
static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t tmp, tmp1, tmp2;
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
/* PI_02 PI_TDFI_PHYMSTR_MAX_F0:RW:0:32 */
tmp = 4 * pdram_timing->trefi;
mmio_write_32(PI_REG(i, 2), tmp);
/* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */
tmp = 2 * pdram_timing->trefi;
mmio_clrsetbits_32(PI_REG(i, 3), 0xffff, tmp);
/* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */
mmio_clrsetbits_32(PI_REG(i, 7), 0xffff << 16, tmp << 16);
/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F0:RW:0:8 */
if (timing_config->dram_type == LPDDR4)
tmp = 2;
else
tmp = 0;
tmp = (pdram_timing->bl / 2) + 4 +
(get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 42), 0xff, tmp);
/* PI_43 PI_WRLAT_F0:RW:0:5 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 43), 0x1f, tmp);
}
/* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */
mmio_clrsetbits_32(PI_REG(i, 43), 0x3f << 8,
PI_ADD_LATENCY << 8);
/* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */
mmio_clrsetbits_32(PI_REG(i, 43), 0x7f << 16,
(pdram_timing->cl * 2) << 16);
/* PI_46 PI_TREF_F0:RW:16:16 */
mmio_clrsetbits_32(PI_REG(i, 46), 0xffff << 16,
pdram_timing->trefi << 16);
/* PI_46 PI_TRFC_F0:RW:0:10 */
mmio_clrsetbits_32(PI_REG(i, 46), 0x3ff, pdram_timing->trfc);
/* PI_66 PI_TODTL_2CMD_F0:RW:24:8 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_todtoff_max(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 66), 0xff << 24,
tmp << 24);
}
/* PI_72 PI_WR_TO_ODTH_F0:RW:16:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp1 = get_pi_wrlat(pdram_timing, timing_config);
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = 0;
}
mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 16, tmp << 16);
/* PI_73 PI_RD_TO_ODTH_F0:RW:8:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
tmp1 = pdram_timing->cl;
tmp1 += get_pi_todtoff_min(pdram_timing, timing_config);
tmp1--;
/* todtoff_max */
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 8, tmp << 8);
/* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */
tmp = get_pi_rdlat_adj(pdram_timing);
mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 16, tmp << 16);
/* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */
tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 16, tmp << 16);
/* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */
tmp1 = tmp;
if (tmp1 == 0)
tmp = 0;
else if (tmp1 < 5)
tmp = tmp1 - 1;
else
tmp = tmp1 - 5;
mmio_clrsetbits_32(PI_REG(i, 91), 0xff << 16, tmp << 16);
/* PI_95 PI_TDFI_CALVL_CAPTURE_F0:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff << 16, tmp << 16);
/* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */
mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff, tmp + 18);
/* PI_102 PI_TMRZ_F0:RW:8:5 */
mmio_clrsetbits_32(PI_REG(i, 102), 0x1f << 8,
pdram_timing->tmrz << 8);
/* PI_111 PI_TDFI_CALVL_STROBE_F0:RW:8:4 */
tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
/* pi_tdfi_calvl_strobe=tds_train+5 */
tmp = tmp1 + 5;
mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 8, tmp << 8);
/* PI_116 PI_TCKEHDQS_F0:RW:16:6 */
tmp = 10000 / (1000000 / pdram_timing->mhz);
if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
if (pdram_timing->mhz <= 100)
tmp = tmp + 1;
else
tmp = tmp + 8;
mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 16, tmp << 16);
/* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */
mmio_clrsetbits_32(PI_REG(i, 125), 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 133), 0xffff, pdram_timing->mr[1]);
/* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */
mmio_clrsetbits_32(PI_REG(i, 140), 0xffff << 16,
pdram_timing->mr[1] << 16);
/* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 148), 0xffff, pdram_timing->mr[1]);
/* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 126), 0xffff, pdram_timing->mr[2]);
/* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */
mmio_clrsetbits_32(PI_REG(i, 133), 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 141), 0xffff, pdram_timing->mr[2]);
/* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */
mmio_clrsetbits_32(PI_REG(i, 148), 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_156 PI_TFC_F0:RW:0:10 */
mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff, pdram_timing->trfc);
/* PI_158 PI_TWR_F0:RW:24:6 */
mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 24,
pdram_timing->twr << 24);
/* PI_158 PI_TWTR_F0:RW:16:6 */
mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 16,
pdram_timing->twtr << 16);
/* PI_158 PI_TRCD_F0:RW:8:8 */
mmio_clrsetbits_32(PI_REG(i, 158), 0xff << 8,
pdram_timing->trcd << 8);
/* PI_158 PI_TRP_F0:RW:0:8 */
mmio_clrsetbits_32(PI_REG(i, 158), 0xff, pdram_timing->trp);
/* PI_157 PI_TRTP_F0:RW:24:8 */
mmio_clrsetbits_32(PI_REG(i, 157), 0xff << 24,
pdram_timing->trtp << 24);
/* PI_159 PI_TRAS_MIN_F0:RW:24:8 */
mmio_clrsetbits_32(PI_REG(i, 159), 0xff << 24,
pdram_timing->tras_min << 24);
/* PI_159 PI_TRAS_MAX_F0:RW:0:17 */
tmp = pdram_timing->tras_max * 99 / 100;
mmio_clrsetbits_32(PI_REG(i, 159), 0x1ffff, tmp);
/* PI_160 PI_TMRD_F0:RW:16:6 */
mmio_clrsetbits_32(PI_REG(i, 160), 0x3f << 16,
pdram_timing->tmrd << 16);
/*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */
mmio_clrsetbits_32(PI_REG(i, 160), 0xf,
pdram_timing->tdqsck_max);
/* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */
mmio_clrsetbits_32(PI_REG(i, 187), 0xffff << 8,
(2 * pdram_timing->trefi) << 8);
/* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */
mmio_clrsetbits_32(PI_REG(i, 188), 0xffffffff,
20 * pdram_timing->trefi);
}
}
static void gen_rk3399_pi_params_f1(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t tmp, tmp1, tmp2;
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
/* PI_04 PI_TDFI_PHYMSTR_MAX_F1:RW:0:32 */
tmp = 4 * pdram_timing->trefi;
mmio_write_32(PI_REG(i, 4), tmp);
/* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */
tmp = 2 * pdram_timing->trefi;
mmio_clrsetbits_32(PI_REG(i, 5), 0xffff, tmp);
/* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */
mmio_clrsetbits_32(PI_REG(i, 12), 0xffff, tmp);
/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F1:RW:8:8 */
if (timing_config->dram_type == LPDDR4)
tmp = 2;
else
tmp = 0;
tmp = (pdram_timing->bl / 2) + 4 +
(get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 42), 0xff << 8, tmp << 8);
/* PI_43 PI_WRLAT_F1:RW:24:5 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 43), 0x1f << 24,
tmp << 24);
}
/* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */
mmio_clrsetbits_32(PI_REG(i, 44), 0x3f, PI_ADD_LATENCY);
/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */
mmio_clrsetbits_32(PI_REG(i, 44), 0x7f << 8,
pdram_timing->cl * 2);
/* PI_47 PI_TREF_F1:RW:16:16 */
mmio_clrsetbits_32(PI_REG(i, 47), 0xffff << 16,
pdram_timing->trefi << 16);
/* PI_47 PI_TRFC_F1:RW:0:10 */
mmio_clrsetbits_32(PI_REG(i, 47), 0x3ff, pdram_timing->trfc);
/* PI_67 PI_TODTL_2CMD_F1:RW:8:8 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_todtoff_max(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 67), 0xff << 8, tmp << 8);
}
/* PI_72 PI_WR_TO_ODTH_F1:RW:24:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp1 = get_pi_wrlat(pdram_timing, timing_config);
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = 0;
}
mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 24, tmp << 24);
/* PI_73 PI_RD_TO_ODTH_F1:RW:16:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
tmp1 = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config);
tmp1--;
/* todtoff_max */
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3)
tmp = pdram_timing->cl - pdram_timing->cwl;
mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 16, tmp << 16);
/*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */
tmp = get_pi_rdlat_adj(pdram_timing);
mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 24, tmp << 24);
/* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */
tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 24, tmp << 24);
/* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */
tmp1 = tmp;
if (tmp1 == 0)
tmp = 0;
else if (tmp1 < 5)
tmp = tmp1 - 1;
else
tmp = tmp1 - 5;
mmio_clrsetbits_32(PI_REG(i, 91), 0xff << 24, tmp << 24);
/*PI_96 PI_TDFI_CALVL_CAPTURE_F1:RW:16:10 */
/* tadr=20ns */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff << 16, tmp << 16);
/* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */
tmp = tmp + 18;
mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff, tmp);
/*PI_103 PI_TMRZ_F1:RW:0:5 */
mmio_clrsetbits_32(PI_REG(i, 103), 0x1f, pdram_timing->tmrz);
/*PI_111 PI_TDFI_CALVL_STROBE_F1:RW:16:4 */
/* tds_train=ceil(2/ns) */
tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
/* pi_tdfi_calvl_strobe=tds_train+5 */
tmp = tmp1 + 5;
mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 16,
tmp << 16);
/* PI_116 PI_TCKEHDQS_F1:RW:24:6 */
tmp = 10000 / (1000000 / pdram_timing->mhz);
if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
if (pdram_timing->mhz <= 100)
tmp = tmp + 1;
else
tmp = tmp + 8;
mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 24,
tmp << 24);
/* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 128), 0xffff, pdram_timing->mr[1]);
/* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */
mmio_clrsetbits_32(PI_REG(i, 135), 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 143), 0xffff, pdram_timing->mr[1]);
/* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */
mmio_clrsetbits_32(PI_REG(i, 150), 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */
mmio_clrsetbits_32(PI_REG(i, 128), 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 136), 0xffff, pdram_timing->mr[2]);
/* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */
mmio_clrsetbits_32(PI_REG(i, 143), 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */
mmio_clrsetbits_32(PI_REG(i, 151), 0xffff, pdram_timing->mr[2]);
/* PI_156 PI_TFC_F1:RW:16:10 */
mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff << 16,
pdram_timing->trfc << 16);
/* PI_162 PI_TWR_F1:RW:8:6 */
mmio_clrsetbits_32(PI_REG(i, 162), 0x3f << 8,
pdram_timing->twr << 8);
/* PI_162 PI_TWTR_F1:RW:0:6 */
mmio_clrsetbits_32(PI_REG(i, 162), 0x3f, pdram_timing->twtr);
/* PI_161 PI_TRCD_F1:RW:24:8 */
mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 24,
pdram_timing->trcd << 24);
/* PI_161 PI_TRP_F1:RW:16:8 */
mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 16,
pdram_timing->trp << 16);
/* PI_161 PI_TRTP_F1:RW:8:8 */
mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 8,
pdram_timing->trtp << 8);
/* PI_163 PI_TRAS_MIN_F1:RW:24:8 */
mmio_clrsetbits_32(PI_REG(i, 163), 0xff << 24,
pdram_timing->tras_min << 24);
/* PI_163 PI_TRAS_MAX_F1:RW:0:17 */
mmio_clrsetbits_32(PI_REG(i, 163), 0x1ffff,
pdram_timing->tras_max * 99 / 100);
/* PI_164 PI_TMRD_F1:RW:16:6 */
mmio_clrsetbits_32(PI_REG(i, 164), 0x3f << 16,
pdram_timing->tmrd << 16);
/* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */
mmio_clrsetbits_32(PI_REG(i, 164), 0xf,
pdram_timing->tdqsck_max);
/* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */
mmio_clrsetbits_32(PI_REG(i, 189), 0xffff,
2 * pdram_timing->trefi);
/* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */
mmio_clrsetbits_32(PI_REG(i, 190), 0xffffffff,
20 * pdram_timing->trefi);
}
}
static void gen_rk3399_pi_params(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
if (fn == 0)
gen_rk3399_pi_params_f0(timing_config, pdram_timing);
else
gen_rk3399_pi_params_f1(timing_config, pdram_timing);
#if PI_TRAINING
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
#if EN_READ_GATE_TRAINING
mmio_clrsetbits_32(PI_REG(i, 80), 3 << 24, 2 << 24);
#endif
#if EN_CA_TRAINING
mmio_clrsetbits_32(PI_REG(i, 100), 3 << 8, 2 << 8);
#endif
#if EN_WRITE_LEVELING
mmio_clrsetbits_32(PI_REG(i, 60), 3 << 8, 2 << 8);
#endif
#if EN_READ_LEVELING
mmio_clrsetbits_32(PI_REG(i, 80), 3 << 16, 2 << 16);
#endif
#if EN_WDQ_LEVELING
mmio_clrsetbits_32(PI_REG(i, 124), 3 << 16, 2 << 16);
#endif
}
#endif
}
static void gen_rk3399_set_odt(uint32_t odt_en)
{
uint32_t drv_odt_val;
uint32_t i;
for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 16;
mmio_clrsetbits_32(PHY_REG(i, 5), 0x7 << 16, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 133), 0x7 << 16, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 261), 0x7 << 16, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 389), 0x7 << 16, drv_odt_val);
drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24;
mmio_clrsetbits_32(PHY_REG(i, 6), 0x7 << 24, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 134), 0x7 << 24, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 262), 0x7 << 24, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 390), 0x7 << 24, drv_odt_val);
}
}
static void gen_rk3399_set_ds_odt(struct timing_related_config *timing_config,
struct drv_odt_lp_config *drv_config)
{
uint32_t i, drv_odt_val;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == LPDDR4)
drv_odt_val = drv_config->phy_side_odt |
(PHY_DRV_ODT_Hi_Z << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
else if (timing_config->dram_type == LPDDR3)
drv_odt_val = PHY_DRV_ODT_Hi_Z |
(drv_config->phy_side_odt << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
else
drv_odt_val = drv_config->phy_side_odt |
(drv_config->phy_side_odt << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
/* DQ drv odt set */
mmio_clrsetbits_32(PHY_REG(i, 6), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 134), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 262), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 390), 0xffffff, drv_odt_val);
/* DQS drv odt set */
mmio_clrsetbits_32(PHY_REG(i, 7), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 135), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 263), 0xffffff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 391), 0xffffff, drv_odt_val);
gen_rk3399_set_odt(timing_config->odt);
/* CA drv set */
drv_odt_val = drv_config->phy_side_ca_drv |
(drv_config->phy_side_ca_drv << 4);
mmio_clrsetbits_32(PHY_REG(i, 544), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 672), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 800), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 928), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 937), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 935), 0xff, drv_odt_val);
drv_odt_val = drv_config->phy_side_ck_cs_drv |
(drv_config->phy_side_ck_cs_drv << 4);
mmio_clrsetbits_32(PHY_REG(i, 929), 0xff, drv_odt_val);
mmio_clrsetbits_32(PHY_REG(i, 939), 0xff, drv_odt_val);
}
}
static void gen_rk3399_phy_params(struct timing_related_config *timing_config,
struct drv_odt_lp_config *drv_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
uint32_t tmp, i, div, j;
uint32_t mem_delay_ps, pad_delay_ps, total_delay_ps, delay_frac_ps;
uint32_t trpre_min_ps, gate_delay_ps, gate_delay_frac_ps;
uint32_t ie_enable, tsel_enable, cas_lat, rddata_en_ie_dly, tsel_adder;
uint32_t extra_adder, delta, hs_offset;
for (i = 0; i < timing_config->ch_cnt; i++) {
pad_delay_ps = PI_PAD_DELAY_PS_VALUE;
ie_enable = PI_IE_ENABLE_VALUE;
tsel_enable = PI_TSEL_ENABLE_VALUE;
mmio_clrsetbits_32(PHY_REG(i, 896), (0x3 << 8) | 1, fn << 8);
/* PHY_LOW_FREQ_SEL */
/* DENALI_PHY_913 1bit offset_0 */
if (timing_config->freq > 400)
mmio_clrbits_32(PHY_REG(i, 913), 1);
else
mmio_setbits_32(PHY_REG(i, 913), 1);
/* PHY_RPTR_UPDATE_x */
/* DENALI_PHY_87/215/343/471 4bit offset_16 */
tmp = 2500 / (1000000 / pdram_timing->mhz) + 3;
if ((2500 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
mmio_clrsetbits_32(PHY_REG(i, 87), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 215), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 343), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 471), 0xf << 16, tmp << 16);
/* PHY_PLL_CTRL */
/* DENALI_PHY_911 13bits offset_0 */
/* PHY_LP4_BOOT_PLL_CTRL */
/* DENALI_PHY_919 13bits offset_0 */
if (pdram_timing->mhz <= 150)
tmp = 3;
else if (pdram_timing->mhz <= 300)
tmp = 2;
else if (pdram_timing->mhz <= 600)
tmp = 1;
else
tmp = 0;
tmp = (1 << 12) | (tmp << 9) | (2 << 7) | (1 << 1);
mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff, tmp);
mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff, tmp);
/* PHY_PLL_CTRL_CA */
/* DENALI_PHY_911 13bits offset_16 */
/* PHY_LP4_BOOT_PLL_CTRL_CA */
/* DENALI_PHY_919 13bits offset_16 */
if (pdram_timing->mhz <= 150)
tmp = 3;
else if (pdram_timing->mhz <= 300)
tmp = 2;
else if (pdram_timing->mhz <= 600)
tmp = 1;
else
tmp = 0;
tmp = (tmp << 9) | (2 << 7) | (1 << 5) | (1 << 1);
mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff << 16, tmp << 16);
/* PHY_TCKSRE_WAIT */
/* DENALI_PHY_922 4bits offset_24 */
if (pdram_timing->mhz <= 400)
tmp = 1;
else if (pdram_timing->mhz <= 800)
tmp = 3;
else if (pdram_timing->mhz <= 1000)
tmp = 4;
else
tmp = 5;
mmio_clrsetbits_32(PHY_REG(i, 922), 0xf << 24, tmp << 24);
/* PHY_CAL_CLK_SELECT_0:RW8:3 */
div = pdram_timing->mhz / (2 * 20);
for (j = 2, tmp = 1; j <= 128; j <<= 1, tmp++) {
if (div < j)
break;
}
mmio_clrsetbits_32(PHY_REG(i, 947), 0x7 << 8, tmp << 8);
mmio_setbits_32(PHY_REG(i, 927), (1 << 22));
if (timing_config->dram_type == DDR3) {
mem_delay_ps = 0;
trpre_min_ps = 1000;
} else if (timing_config->dram_type == LPDDR4) {
mem_delay_ps = 1500;
trpre_min_ps = 900;
} else if (timing_config->dram_type == LPDDR3) {
mem_delay_ps = 2500;
trpre_min_ps = 900;
} else {
ERROR("gen_rk3399_phy_params:dramtype unsupport\n");
return;
}
total_delay_ps = mem_delay_ps + pad_delay_ps;
delay_frac_ps = 1000 * total_delay_ps /
(1000000 / pdram_timing->mhz);
gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2);
gate_delay_frac_ps = gate_delay_ps % 1000;
tmp = gate_delay_frac_ps * 0x200 / 1000;
/* PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY */
/* DENALI_PHY_2/130/258/386 10bits offset_0 */
mmio_clrsetbits_32(PHY_REG(i, 2), 0x2ff, tmp);
mmio_clrsetbits_32(PHY_REG(i, 130), 0x2ff, tmp);
mmio_clrsetbits_32(PHY_REG(i, 258), 0x2ff, tmp);
mmio_clrsetbits_32(PHY_REG(i, 386), 0x2ff, tmp);
/* PHY_RDDQS_GATE_SLAVE_DELAY */
/* DENALI_PHY_77/205/333/461 10bits offset_16 */
mmio_clrsetbits_32(PHY_REG(i, 77), 0x2ff << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 205), 0x2ff << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 333), 0x2ff << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 461), 0x2ff << 16, tmp << 16);
tmp = gate_delay_ps / 1000;
/* PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST */
/* DENALI_PHY_10/138/266/394 4bit offset_0 */
mmio_clrsetbits_32(PHY_REG(i, 10), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 138), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 266), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
/* PHY_RDDQS_LATENCY_ADJUST */
/* DENALI_PHY_78/206/334/462 4bits offset_0 */
mmio_clrsetbits_32(PHY_REG(i, 78), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 206), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 334), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 462), 0xf, tmp);
/* PHY_GTLVL_LAT_ADJ_START */
/* DENALI_PHY_80/208/336/464 4bits offset_16 */
tmp = delay_frac_ps / 1000;
mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 464), 0xf << 16, tmp << 16);
cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
rddata_en_ie_dly = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
rddata_en_ie_dly++;
rddata_en_ie_dly = rddata_en_ie_dly - 1;
tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
tsel_adder++;
if (rddata_en_ie_dly > tsel_adder)
extra_adder = rddata_en_ie_dly - tsel_adder;
else
extra_adder = 0;
delta = cas_lat - rddata_en_ie_dly;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset))
tmp = 0;
else if ((delta == 2) || (delta == 1))
tmp = rddata_en_ie_dly - 0 - extra_adder;
else
tmp = extra_adder;
/* PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY */
/* DENALI_PHY_9/137/265/393 4bit offset_16 */
mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 16, tmp << 16);
mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 16, tmp << 16);
/* PHY_RDDATA_EN_TSEL_DLY */
/* DENALI_PHY_86/214/342/470 4bit offset_0 */
mmio_clrsetbits_32(PHY_REG(i, 86), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 214), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 342), 0xf, tmp);
mmio_clrsetbits_32(PHY_REG(i, 470), 0xf, tmp);
if (tsel_adder > rddata_en_ie_dly)
extra_adder = tsel_adder - rddata_en_ie_dly;
else
extra_adder = 0;
if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset))
tmp = tsel_adder;
else
tmp = rddata_en_ie_dly - 0 + extra_adder;
/* PHY_LP4_BOOT_RDDATA_EN_DLY */
/* DENALI_PHY_9/137/265/393 4bit offset_8 */
mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 8, tmp << 8);
mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 8, tmp << 8);
mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 8, tmp << 8);
mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 8, tmp << 8);
/* PHY_RDDATA_EN_DLY */
/* DENALI_PHY_85/213/341/469 4bit offset_24 */
mmio_clrsetbits_32(PHY_REG(i, 85), 0xf << 24, tmp << 24);
mmio_clrsetbits_32(PHY_REG(i, 213), 0xf << 24, tmp << 24);
mmio_clrsetbits_32(PHY_REG(i, 341), 0xf << 24, tmp << 24);
mmio_clrsetbits_32(PHY_REG(i, 469), 0xf << 24, tmp << 24);
if (pdram_timing->mhz <= ENPER_CS_TRAINING_FREQ) {
/*
* Note:Per-CS Training is not compatible at speeds
* under 533 MHz. If the PHY is running at a speed
* less than 533MHz, all phy_per_cs_training_en_X
* parameters must be cleared to 0.
*/
/*DENALI_PHY_84/212/340/468 1bit offset_16 */
mmio_clrbits_32(PHY_REG(i, 84), 0x1 << 16);
mmio_clrbits_32(PHY_REG(i, 212), 0x1 << 16);
mmio_clrbits_32(PHY_REG(i, 340), 0x1 << 16);
mmio_clrbits_32(PHY_REG(i, 468), 0x1 << 16);
} else {
mmio_setbits_32(PHY_REG(i, 84), 0x1 << 16);
mmio_setbits_32(PHY_REG(i, 212), 0x1 << 16);
mmio_setbits_32(PHY_REG(i, 340), 0x1 << 16);
mmio_setbits_32(PHY_REG(i, 468), 0x1 << 16);
}
}
}
static int to_get_clk_index(unsigned int mhz)
{
int pll_cnt, i;
pll_cnt = ARRAY_SIZE(dpll_rates_table);
/* Assumming rate_table is in descending order */
for (i = 0; i < pll_cnt; i++) {
if (mhz >= dpll_rates_table[i].mhz)
break;
}
/* if mhz lower than lowest frequency in table, use lowest frequency */
if (i == pll_cnt)
i = pll_cnt - 1;
return i;
}
uint32_t rkclk_prepare_pll_timing(unsigned int mhz)
{
unsigned int refdiv, postdiv1, fbdiv, postdiv2;
int index;
index = to_get_clk_index(mhz);
refdiv = dpll_rates_table[index].refdiv;
fbdiv = dpll_rates_table[index].fbdiv;
postdiv1 = dpll_rates_table[index].postdiv1;
postdiv2 = dpll_rates_table[index].postdiv2;
mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(fbdiv));
mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON1,
POSTDIV2(postdiv2) | POSTDIV1(postdiv1) | REFDIV(refdiv));
return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
}
uint32_t ddr_get_rate(void)
{
uint32_t refdiv, postdiv1, fbdiv, postdiv2;
refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f;
fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
postdiv1 =
(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7;
postdiv2 =
(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7;
return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000;
}
/*
* return: bit12: channel 1, external self-refresh
* bit11: channel 1, stdby_mode
* bit10: channel 1, self-refresh with controller and memory clock gate
* bit9: channel 1, self-refresh
* bit8: channel 1, power-down
*
* bit4: channel 1, external self-refresh
* bit3: channel 0, stdby_mode
* bit2: channel 0, self-refresh with controller and memory clock gate
* bit1: channel 0, self-refresh
* bit0: channel 0, power-down
*/
uint32_t exit_low_power(void)
{
uint32_t low_power = 0;
uint32_t channel_mask;
uint32_t tmp, i;
channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
0x3;
for (i = 0; i < 2; i++) {
if (!(channel_mask & (1 << i)))
continue;
/* exit stdby mode */
mmio_write_32(CIC_BASE + CIC_CTRL1,
(1 << (i + 16)) | (0 << i));
/* exit external self-refresh */
tmp = i ? 12 : 8;
low_power |= ((mmio_read_32(PMU_BASE + PMU_SFT_CON) >> tmp) &
0x1) << (4 + 8 * i);
mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp);
while (!(mmio_read_32(PMU_BASE + PMU_DDR_SREF_ST) & (1 << i)))
;
/* exit auto low-power */
mmio_clrbits_32(CTL_REG(i, 101), 0x7);
/* lp_cmd to exit */
if (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
0x40) {
while (mmio_read_32(CTL_REG(i, 200)) & 0x1)
;
mmio_clrsetbits_32(CTL_REG(i, 93), 0xff << 24,
0x69 << 24);
while (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
0x40)
;
}
}
return low_power;
}
void resume_low_power(uint32_t low_power)
{
uint32_t channel_mask;
uint32_t tmp, i, val;
channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
0x3;
for (i = 0; i < 2; i++) {
if (!(channel_mask & (1 << i)))
continue;
/* resume external self-refresh */
tmp = i ? 12 : 8;
val = (low_power >> (4 + 8 * i)) & 0x1;
mmio_setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp);
/* resume auto low-power */
val = (low_power >> (8 * i)) & 0x7;
mmio_setbits_32(CTL_REG(i, 101), val);
/* resume stdby mode */
val = (low_power >> (3 + 8 * i)) & 0x1;
mmio_write_32(CIC_BASE + CIC_CTRL1,
(1 << (i + 16)) | (val << i));
}
}
static void wait_dcf_done(void)
{
while ((mmio_read_32(DCF_BASE + DCF_DCF_ISR) & (DCF_DONE)) == 0)
continue;
}
void clr_dcf_irq(void)
{
/* clear dcf irq status */
mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
}
static void enable_dcf(uint32_t dcf_addr)
{
/* config DCF start addr */
mmio_write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr);
/* wait dcf done */
while (mmio_read_32(DCF_BASE + DCF_DCF_CTRL) & 1)
continue;
/* clear dcf irq status */
mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
/* DCF start */
mmio_setbits_32(DCF_BASE + DCF_DCF_CTRL, DCF_START);
}
void dcf_code_init(void)
{
memcpy((void *)DCF_START_ADDR, (void *)dcf_code, sizeof(dcf_code));
/* set dcf master secure */
mmio_write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0));
mmio_write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000);
}
static void dcf_start(uint32_t freq, uint32_t index)
{
mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
(0x1 << (1 + 16)) | (1 << 1));
mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
(0x1 << (0 + 16)) | (1 << 0));
mmio_write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4);
mmio_write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq);
rkclk_prepare_pll_timing(freq);
udelay(10);
mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
(0x1 << (1 + 16)) | (0 << 1));
mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
(0x1 << (0 + 16)) | (0 << 0));
udelay(10);
enable_dcf(DCF_START_ADDR);
}
static void dram_low_power_config(struct drv_odt_lp_config *lp_config)
{
uint32_t tmp, tmp1, i;
uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
uint32_t *low_power = &rk3399_dram_status.low_power_stat;
if (dram_type == LPDDR4)
tmp = (lp_config->srpd_lite_idle << 16) |
lp_config->pd_idle;
else
tmp = lp_config->pd_idle;
if (dram_type == DDR3)
tmp1 = (2 << 16) | (0x7 << 8) | 7;
else
tmp1 = (3 << 16) | (0x7 << 8) | 7;
*low_power = 0;
for (i = 0; i < ch_cnt; i++) {
mmio_write_32(CTL_REG(i, 102), tmp);
mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff,
(lp_config->sr_mc_gate_idle << 8) |
lp_config->sr_idle);
mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp1);
*low_power |= (7 << (8 * i));
}
/* standby idle */
mmio_write_32(CIC_BASE + CIC_IDLE_TH, lp_config->standby_idle);
mmio_write_32(CIC_BASE + CIC_CG_WAIT_TH, 0x640008);
if (ch_cnt == 2) {
mmio_write_32(GRF_BASE + GRF_DDRC1_CON1,
(((0x1<<4) | (0x1<<5) | (0x1<<6) |
(0x1<<7)) << 16) |
((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
if (lp_config->standby_idle) {
tmp = 0x002a002a;
*low_power |= (1 << 11);
} else
tmp = 0;
mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
}
mmio_write_32(GRF_BASE + GRF_DDRC0_CON1,
(((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
if (lp_config->standby_idle) {
tmp = 0x00150015;
*low_power |= (1 << 3);
} else
tmp = 0;
mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
}
static void dram_related_init(struct ddr_dts_config_timing *dts_timing)
{
uint32_t trefi0, trefi1;
uint32_t i;
dcf_code_init();
/* get sdram config for os reg */
drv_odt_lp_cfg_init(sdram_config.dramtype, dts_timing,
&rk3399_dram_status.drv_odt_lp_cfg);
sdram_timing_cfg_init(&rk3399_dram_status.timing_config,
&sdram_config,
&rk3399_dram_status.drv_odt_lp_cfg);
trefi0 = ((mmio_read_32(CTL_REG(0, 48)) >> 16) & 0xffff) + 8;
trefi1 = ((mmio_read_32(CTL_REG(0, 49)) >> 16) & 0xffff) + 8;
rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39;
rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39;
rk3399_dram_status.current_index =
(mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3;
if (rk3399_dram_status.timing_config.dram_type == DDR3) {
rk3399_dram_status.index_freq[0] /= 2;
rk3399_dram_status.index_freq[1] /= 2;
}
rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1)
& 0x1] = 0;
/* disable all training by ctl and pi */
for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
mmio_clrbits_32(CTL_REG(i, 70), (1 << 24) |
(1 << 16) | (1 << 8) | 1);
mmio_clrbits_32(CTL_REG(i, 71), 1);
mmio_clrbits_32(PI_REG(i, 60), 0x3 << 8);
mmio_clrbits_32(PI_REG(i, 80), (0x3 << 24) | (0x3 << 16));
mmio_clrbits_32(PI_REG(i, 100), 0x3 << 8);
mmio_clrbits_32(PI_REG(i, 124), 0x3 << 16);
}
/* init drv odt */
if (rk3399_dram_status.index_freq[rk3399_dram_status.current_index] <
rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq)
rk3399_dram_status.timing_config.odt = 0;
else
rk3399_dram_status.timing_config.odt = 1;
gen_rk3399_set_ds_odt(&rk3399_dram_status.timing_config,
&rk3399_dram_status.drv_odt_lp_cfg);
dram_low_power_config(&rk3399_dram_status.drv_odt_lp_cfg);
}
static uint32_t prepare_ddr_timing(uint32_t mhz)
{
uint32_t index;
struct dram_timing_t dram_timing;
rk3399_dram_status.timing_config.freq = mhz;
if (mhz < rk3399_dram_status.drv_odt_lp_cfg.ddr3_dll_dis_freq)
rk3399_dram_status.timing_config.dllbp = 1;
else
rk3399_dram_status.timing_config.dllbp = 0;
if (mhz < rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq) {
rk3399_dram_status.timing_config.odt = 0;
} else {
rk3399_dram_status.timing_config.odt = 1;
gen_rk3399_set_odt(1);
}
index = (rk3399_dram_status.current_index + 1) & 0x1;
if (rk3399_dram_status.index_freq[index] == mhz)
goto out;
/*
* checking if having available gate traiing timing for
* target freq.
*/
dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing);
gen_rk3399_ctl_params(&rk3399_dram_status.timing_config,
&dram_timing, index);
gen_rk3399_pi_params(&rk3399_dram_status.timing_config,
&dram_timing, index);
gen_rk3399_phy_params(&rk3399_dram_status.timing_config,
&rk3399_dram_status.drv_odt_lp_cfg,
&dram_timing, index);
rk3399_dram_status.index_freq[index] = mhz;
out:
return index;
}
void print_dram_status_info(void)
{
uint32_t *p;
uint32_t i;
p = (uint32_t *) &rk3399_dram_status.timing_config;
INFO("rk3399_dram_status.timing_config:\n");
for (i = 0; i < sizeof(struct timing_related_config) / 4; i++)
tf_printf("%u\n", p[i]);
p = (uint32_t *) &rk3399_dram_status.drv_odt_lp_cfg;
INFO("rk3399_dram_status.drv_odt_lp_cfg:\n");
for (i = 0; i < sizeof(struct drv_odt_lp_config) / 4; i++)
tf_printf("%u\n", p[i]);
}
uint32_t ddr_set_rate(uint32_t hz)
{
uint32_t low_power, index;
uint32_t mhz = hz / (1000 * 1000);
if (mhz ==
rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
goto out;
index = to_get_clk_index(mhz);
mhz = dpll_rates_table[index].mhz;
low_power = exit_low_power();
index = prepare_ddr_timing(mhz);
if (index > 1)
goto out;
dcf_start(mhz, index);
wait_dcf_done();
if (rk3399_dram_status.timing_config.odt == 0)
gen_rk3399_set_odt(0);
rk3399_dram_status.current_index = index;
if (mhz < dts_parameter.auto_pd_dis_freq)
low_power |= rk3399_dram_status.low_power_stat;
resume_low_power(low_power);
out:
return mhz;
}
uint32_t ddr_round_rate(uint32_t hz)
{
int index;
uint32_t mhz = hz / (1000 * 1000);
index = to_get_clk_index(mhz);
return dpll_rates_table[index].mhz * 1000 * 1000;
}
uint32_t dts_timing_receive(uint32_t timing, uint32_t index)
{
uint32_t *p = (uint32_t *) &dts_parameter;
static uint32_t receive_nums;
if (index < (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
p[index] = (uint32_t)timing;
receive_nums++;
} else {
dts_parameter.available = 0;
return -1;
}
/* receive all parameter */
if (receive_nums == (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
dts_parameter.available = 1;
receive_nums = 0;
}
return index;
}
void ddr_dfs_init(void)
{
dram_related_init(&dts_parameter);
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SOC_ROCKCHIP_RK3399_DFS_H__
#define __SOC_ROCKCHIP_RK3399_DFS_H__
struct rk3399_sdram_default_config {
unsigned char bl;
/* 1:auto precharge, 0:never auto precharge */
unsigned char ap;
/* dram driver strength */
unsigned char dramds;
/* dram ODT, if odt=0, this parameter invalid */
unsigned char dramodt;
/* ca ODT, if odt=0, this parameter invalid
* only used by LPDDR4
*/
unsigned char caodt;
unsigned char burst_ref_cnt;
/* zqcs period, unit(s) */
unsigned char zqcsi;
};
struct ddr_dts_config_timing {
unsigned int ddr3_speed_bin;
unsigned int pd_idle;
unsigned int sr_idle;
unsigned int sr_mc_gate_idle;
unsigned int srpd_lite_idle;
unsigned int standby_idle;
unsigned int auto_pd_dis_freq;
unsigned int ddr3_dll_dis_freq;
unsigned int phy_dll_dis_freq;
unsigned int ddr3_odt_dis_freq;
unsigned int ddr3_drv;
unsigned int ddr3_odt;
unsigned int phy_ddr3_ca_drv;
unsigned int phy_ddr3_dq_drv;
unsigned int phy_ddr3_odt;
unsigned int lpddr3_odt_dis_freq;
unsigned int lpddr3_drv;
unsigned int lpddr3_odt;
unsigned int phy_lpddr3_ca_drv;
unsigned int phy_lpddr3_dq_drv;
unsigned int phy_lpddr3_odt;
unsigned int lpddr4_odt_dis_freq;
unsigned int lpddr4_drv;
unsigned int lpddr4_dq_odt;
unsigned int lpddr4_ca_odt;
unsigned int phy_lpddr4_ca_drv;
unsigned int phy_lpddr4_ck_cs_drv;
unsigned int phy_lpddr4_dq_drv;
unsigned int phy_lpddr4_odt;
uint32_t available;
};
struct drv_odt_lp_config {
uint32_t ddr3_speed_bin;
uint32_t pd_idle;
uint32_t sr_idle;
uint32_t sr_mc_gate_idle;
uint32_t srpd_lite_idle;
uint32_t standby_idle;
uint32_t ddr3_dll_dis_freq;/* for ddr3 only */
uint32_t phy_dll_dis_freq;
uint32_t odt_dis_freq;
uint32_t dram_side_drv;
uint32_t dram_side_dq_odt;
uint32_t dram_side_ca_odt;
uint32_t phy_side_ca_drv;
uint32_t phy_side_ck_cs_drv;
uint32_t phy_side_dq_drv;
uint32_t phy_side_odt;
};
void ddr_dfs_init(void);
uint32_t ddr_set_rate(uint32_t hz);
uint32_t ddr_round_rate(uint32_t hz);
uint32_t ddr_get_rate(void);
void clr_dcf_irq(void);
uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
#endif
......@@ -28,2540 +28,49 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <debug.h>
#include <mmio.h>
#include <dram.h>
#include <plat_private.h>
#include "dram.h"
#include "dram_spec_timing.h"
#include "string.h"
#include "soc.h"
#include "pmu.h"
#include <soc.h>
#include <rk3399_def.h>
#include <delay_timer.h>
__sramdata struct rk3399_sdram_params sdram_config;
#define CTL_TRAINING (1)
#define PI_TRAINING (!CTL_TRAINING)
#define EN_READ_GATE_TRAINING (1)
#define EN_CA_TRAINING (0)
#define EN_WRITE_LEVELING (0)
#define EN_READ_LEVELING (0)
#define EN_WDQ_LEVELING (0)
#define ENPER_CS_TRAINING_FREQ (933)
struct pll_div {
unsigned int mhz;
unsigned int refdiv;
unsigned int fbdiv;
unsigned int postdiv1;
unsigned int postdiv2;
unsigned int frac;
unsigned int freq;
};
static const struct pll_div dpll_rates_table[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1},
{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1},
{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1},
{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2},
};
static struct rk3399_ddr_cic_regs *const rk3399_ddr_cic = (void *)CIC_BASE;
static struct rk3399_ddr_pctl_regs *const rk3399_ddr_pctl[2] = {
(void *)DDRC0_BASE, (void *)DDRC1_BASE
};
static struct rk3399_ddr_pi_regs *const rk3399_ddr_pi[2] = {
(void *)DDRC0_PI_BASE, (void *)DDRC1_PI_BASE
};
static struct rk3399_ddr_publ_regs *const rk3399_ddr_publ[2] = {
(void *)DDRC0_PHY_BASE, (void *)DDRC1_PHY_BASE
};
struct rk3399_dram_status {
uint32_t current_index;
uint32_t index_freq[2];
uint32_t low_power_stat;
struct timing_related_config timing_config;
struct drv_odt_lp_config drv_odt_lp_cfg;
};
static struct rk3399_dram_status rk3399_dram_status;
static struct ddr_dts_config_timing dts_parameter = {
.available = 0
};
static struct rk3399_sdram_default_config ddr3_default_config = {
.bl = 8,
.ap = 0,
.dramds = 40,
.dramodt = 120,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config ddr3_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 933,
.dram_side_drv = 40,
.dram_side_dq_odt = 120,
.dram_side_ca_odt = 120,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 40,
.phy_side_dq_drv = 40,
.phy_side_odt = 240,
};
static struct rk3399_sdram_default_config lpddr3_default_config = {
.bl = 8,
.ap = 0,
.dramds = 34,
.dramodt = 240,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config lpddr3_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 666,
.dram_side_drv = 40,
.dram_side_dq_odt = 120,
.dram_side_ca_odt = 120,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 40,
.phy_side_dq_drv = 40,
.phy_side_odt = 240,
};
static struct rk3399_sdram_default_config lpddr4_default_config = {
.bl = 16,
.ap = 0,
.dramds = 40,
.dramodt = 240,
.caodt = 240,
.burst_ref_cnt = 1,
.zqcsi = 0
};
static struct drv_odt_lp_config lpddr4_drv_odt_default_config = {
.ddr3_speed_bin = DDR3_DEFAULT,
.pd_idle = 0,
.sr_idle = 0,
.sr_mc_gate_idle = 0,
.srpd_lite_idle = 0,
.standby_idle = 0,
.ddr3_dll_dis_freq = 300,
.phy_dll_dis_freq = 125,
.odt_dis_freq = 933,
.dram_side_drv = 60,
.dram_side_dq_odt = 40,
.dram_side_ca_odt = 40,
.phy_side_ca_drv = 40,
.phy_side_ck_cs_drv = 80,
.phy_side_dq_drv = 80,
.phy_side_odt = 60,
};
uint32_t dcf_code[] = {
#include "dcf_code.inc"
};
#define write_32(addr, value)\
mmio_write_32((uintptr_t)(addr), (uint32_t)(value))
#define read_32(addr) \
mmio_read_32((uintptr_t)(addr))
#define clrbits_32(addr, clear)\
mmio_clrbits_32((uintptr_t)(addr), (uint32_t)(clear))
#define setbits_32(addr, set)\
mmio_setbits_32((uintptr_t)(addr), (uint32_t)(set))
#define clrsetbits_32(addr, clear, set)\
mmio_clrsetbits_32((uintptr_t)(addr), (uint32_t)(clear),\
(uint32_t)(set))
#define DCF_START_ADDR (SRAM_BASE + 0x1400)
#define DCF_PARAM_ADDR (SRAM_BASE + 0x1000)
/* DCF_PAMET */
#define PARAM_DRAM_FREQ (0)
#define PARAM_DPLL_CON0 (4)
#define PARAM_DPLL_CON1 (8)
#define PARAM_DPLL_CON2 (0xc)
#define PARAM_DPLL_CON3 (0x10)
#define PARAM_DPLL_CON4 (0x14)
#define PARAM_DPLL_CON5 (0x18)
/* equal to fn<<4 */
#define PARAM_FREQ_SELECT (0x1c)
static unsigned int get_cs_die_capability(struct rk3399_sdram_config
*psdram_config, unsigned int channel,
unsigned int cs)
{
unsigned int die;
unsigned int cs_cap;
unsigned int row[2];
row[0] = psdram_config->ch[channel].cs0_row;
row[1] = psdram_config->ch[channel].cs1_row;
die = psdram_config->ch[channel].bus_width /
psdram_config->ch[channel].each_die_bus_width;
cs_cap = (1 << (row[cs] +
(psdram_config->ch[channel].bank / 4 + 1) +
psdram_config->ch[channel].col +
(psdram_config->ch[channel].bus_width / 16)));
if (psdram_config->ch[channel].each_die_6gb_or_12gb)
cs_cap = cs_cap * 3 / 4;
return (cs_cap / die);
}
static void sdram_config_init(struct rk3399_sdram_config *psdram_config)
void dram_init(void)
{
uint32_t os_reg2_val, i;
os_reg2_val = read_32(PMUGRF_BASE + PMUGRF_OSREG(2));
for (i = 0; i < READ_CH_CNT(os_reg2_val); i++) {
psdram_config->ch[i].bank = 1 << READ_BK_INFO(os_reg2_val, i);
psdram_config->ch[i].bus_width =
8 * (1 << READ_BW_INFO(os_reg2_val, i));
psdram_config->ch[i].col = READ_COL_INFO(os_reg2_val, i);
psdram_config->ch[i].cs0_row =
READ_CS0_ROW_INFO(os_reg2_val, i);
psdram_config->ch[i].cs1_row =
READ_CS1_ROW_INFO(os_reg2_val, i);
psdram_config->ch[i].cs_cnt = READ_CS_INFO(os_reg2_val, i);
psdram_config->ch[i].each_die_6gb_or_12gb =
READ_CH_ROW_INFO(os_reg2_val, i);
psdram_config->ch[i].each_die_bus_width =
8 * (1 << READ_DIE_BW_INFO(os_reg2_val, i));
}
psdram_config->dramtype = READ_DRAMTYPE_INFO(os_reg2_val);
psdram_config->channal_num = READ_CH_CNT(os_reg2_val);
}
static void drv_odt_lp_cfg_init(uint32_t dram_type,
struct ddr_dts_config_timing *dts_timing,
struct drv_odt_lp_config *drv_config)
{
if ((dts_timing) && (dts_timing->available)) {
drv_config->ddr3_speed_bin = dts_timing->ddr3_speed_bin;
drv_config->pd_idle = dts_timing->pd_idle;
drv_config->sr_idle = dts_timing->sr_idle;
drv_config->sr_mc_gate_idle = dts_timing->sr_mc_gate_idle;
drv_config->srpd_lite_idle = dts_timing->srpd_lite_idle;
drv_config->standby_idle = dts_timing->standby_idle;
drv_config->ddr3_dll_dis_freq = dts_timing->ddr3_dll_dis_freq;
drv_config->phy_dll_dis_freq = dts_timing->phy_dll_dis_freq;
}
switch (dram_type) {
case DDR3:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->ddr3_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->ddr3_drv;
drv_config->dram_side_dq_odt = dts_timing->ddr3_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_ddr3_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_ddr3_ca_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_ddr3_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_ddr3_odt;
} else {
memcpy(drv_config, &ddr3_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
case LPDDR3:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->lpddr3_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->lpddr3_drv;
drv_config->dram_side_dq_odt = dts_timing->lpddr3_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_lpddr3_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_lpddr3_ca_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_lpddr3_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_lpddr3_odt;
} else {
memcpy(drv_config, &lpddr3_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
case LPDDR4:
default:
if ((dts_timing) && (dts_timing->available)) {
drv_config->odt_dis_freq =
dts_timing->lpddr4_odt_dis_freq;
drv_config->dram_side_drv = dts_timing->lpddr4_drv;
drv_config->dram_side_dq_odt =
dts_timing->lpddr4_dq_odt;
drv_config->dram_side_ca_odt =
dts_timing->lpddr4_ca_odt;
drv_config->phy_side_ca_drv =
dts_timing->phy_lpddr4_ca_drv;
drv_config->phy_side_ck_cs_drv =
dts_timing->phy_lpddr4_ck_cs_drv;
drv_config->phy_side_dq_drv =
dts_timing->phy_lpddr4_dq_drv;
drv_config->phy_side_odt = dts_timing->phy_lpddr4_odt;
} else {
memcpy(drv_config, &lpddr4_drv_odt_default_config,
sizeof(struct drv_odt_lp_config));
}
break;
}
switch (drv_config->phy_side_ca_drv) {
case 240:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_ca_drv = PHY_DRV_ODT_34_3;
break;
};
switch (drv_config->phy_side_ck_cs_drv) {
case 240:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_34_3;
break;
}
switch (drv_config->phy_side_dq_drv) {
case 240:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_dq_drv = PHY_DRV_ODT_34_3;
break;
}
switch (drv_config->phy_side_odt) {
case 240:
drv_config->phy_side_odt = PHY_DRV_ODT_240;
break;
case 120:
drv_config->phy_side_odt = PHY_DRV_ODT_120;
break;
case 80:
drv_config->phy_side_odt = PHY_DRV_ODT_80;
break;
case 60:
drv_config->phy_side_odt = PHY_DRV_ODT_60;
break;
case 48:
drv_config->phy_side_odt = PHY_DRV_ODT_48;
break;
case 40:
drv_config->phy_side_odt = PHY_DRV_ODT_40;
break;
default:
drv_config->phy_side_odt = PHY_DRV_ODT_34_3;
break;
}
}
static void sdram_timing_cfg_init(struct timing_related_config *ptiming_config,
struct rk3399_sdram_config *psdram_config,
struct drv_odt_lp_config *drv_config)
{
uint32_t i, j;
for (i = 0; i < psdram_config->channal_num; i++) {
ptiming_config->dram_info[i].speed_rate =
drv_config->ddr3_speed_bin;
ptiming_config->dram_info[i].cs_cnt =
psdram_config->ch[i].cs_cnt;
for (j = 0; j < psdram_config->ch[i].cs_cnt; j++) {
ptiming_config->dram_info[i].per_die_capability[j] =
get_cs_die_capability(psdram_config, i, j);
}
}
ptiming_config->dram_type = psdram_config->dramtype;
ptiming_config->ch_cnt = psdram_config->channal_num;
switch (psdram_config->dramtype) {
case DDR3:
ptiming_config->bl = ddr3_default_config.bl;
ptiming_config->ap = ddr3_default_config.ap;
break;
case LPDDR3:
ptiming_config->bl = lpddr3_default_config.bl;
ptiming_config->ap = lpddr3_default_config.ap;
break;
case LPDDR4:
ptiming_config->bl = lpddr4_default_config.bl;
ptiming_config->ap = lpddr4_default_config.ap;
ptiming_config->rdbi = 0;
ptiming_config->wdbi = 0;
break;
}
ptiming_config->dramds = drv_config->dram_side_drv;
ptiming_config->dramodt = drv_config->dram_side_dq_odt;
ptiming_config->caodt = drv_config->dram_side_ca_odt;
}
struct lat_adj_pair {
uint32_t cl;
uint32_t rdlat_adj;
uint32_t cwl;
uint32_t wrlat_adj;
};
const struct lat_adj_pair ddr3_lat_adj[] = {
{6, 5, 5, 4},
{8, 7, 6, 5},
{10, 9, 7, 6},
{11, 9, 8, 7},
{13, 0xb, 9, 8},
{14, 0xb, 0xa, 9}
};
const struct lat_adj_pair lpddr3_lat_adj[] = {
{3, 2, 1, 0},
{6, 5, 3, 2},
{8, 7, 4, 3},
{9, 8, 5, 4},
{10, 9, 6, 5},
{11, 9, 6, 5},
{12, 0xa, 6, 5},
{14, 0xc, 8, 7},
{16, 0xd, 8, 7}
};
const struct lat_adj_pair lpddr4_lat_adj[] = {
{6, 5, 4, 2},
{10, 9, 6, 4},
{14, 0xc, 8, 6},
{20, 0x11, 0xa, 8},
{24, 0x15, 0xc, 0xa},
{28, 0x18, 0xe, 0xc},
{32, 0x1b, 0x10, 0xe},
{36, 0x1e, 0x12, 0x10}
};
static uint32_t get_rdlat_adj(uint32_t dram_type, uint32_t cl)
{
const struct lat_adj_pair *p;
uint32_t cnt;
uint32_t i;
if (dram_type == DDR3) {
p = ddr3_lat_adj;
cnt = ARRAY_SIZE(ddr3_lat_adj);
} else if (dram_type == LPDDR3) {
p = lpddr3_lat_adj;
cnt = ARRAY_SIZE(lpddr3_lat_adj);
} else {
p = lpddr4_lat_adj;
cnt = ARRAY_SIZE(lpddr4_lat_adj);
}
for (i = 0; i < cnt; i++) {
if (cl == p[i].cl)
return p[i].rdlat_adj;
}
/* fail */
return 0xff;
}
static uint32_t get_wrlat_adj(uint32_t dram_type, uint32_t cwl)
{
const struct lat_adj_pair *p;
uint32_t cnt;
uint32_t i;
if (dram_type == DDR3) {
p = ddr3_lat_adj;
cnt = ARRAY_SIZE(ddr3_lat_adj);
} else if (dram_type == LPDDR3) {
p = lpddr3_lat_adj;
cnt = ARRAY_SIZE(lpddr3_lat_adj);
} else {
p = lpddr4_lat_adj;
cnt = ARRAY_SIZE(lpddr4_lat_adj);
}
for (i = 0; i < cnt; i++) {
if (cwl == p[i].cwl)
return p[i].wrlat_adj;
}
/* fail */
return 0xff;
}
#define PI_REGS_DIMM_SUPPORT (0)
#define PI_ADD_LATENCY (0)
#define PI_DOUBLEFREEK (1)
#define PI_PAD_DELAY_PS_VALUE (1000)
#define PI_IE_ENABLE_VALUE (3000)
#define PI_TSEL_ENABLE_VALUE (700)
static uint32_t get_pi_rdlat_adj(struct dram_timing_t *pdram_timing)
{
/*[DLLSUBTYPE2] == "STD_DENALI_HS" */
uint32_t rdlat, delay_adder, ie_enable, hs_offset, tsel_adder,
extra_adder, tsel_enable;
ie_enable = PI_IE_ENABLE_VALUE;
tsel_enable = PI_TSEL_ENABLE_VALUE;
rdlat = pdram_timing->cl + PI_ADD_LATENCY;
delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
hs_offset = 0;
tsel_adder = 0;
extra_adder = 0;
/* rdlat = rdlat - (PREAMBLE_SUPPORT & 0x1); */
tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
tsel_adder++;
delay_adder = delay_adder - 1;
if (tsel_adder > delay_adder)
extra_adder = tsel_adder - delay_adder;
else
extra_adder = 0;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
os_reg2_val = mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2));
sdram_config.dramtype = SYS_REG_DEC_DDRTYPE(os_reg2_val);
sdram_config.num_channels = SYS_REG_DEC_NUM_CH(os_reg2_val);
sdram_config.stride = (mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(4)) >>
10) & 0x1f;
if (delay_adder > (rdlat - 1 - hs_offset)) {
rdlat = rdlat - tsel_adder;
} else {
if ((rdlat - delay_adder) < 2)
rdlat = 2;
else
rdlat = rdlat - delay_adder - extra_adder;
}
return rdlat;
}
static uint32_t get_pi_wrlat(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp;
if (timing_config->dram_type == LPDDR3) {
tmp = pdram_timing->cl;
if (tmp >= 14)
tmp = 8;
else if (tmp >= 10)
tmp = 6;
else if (tmp == 9)
tmp = 5;
else if (tmp == 8)
tmp = 4;
else if (tmp == 6)
tmp = 3;
else
tmp = 1;
} else {
tmp = 1;
}
return tmp;
}
static uint32_t get_pi_wrlat_adj(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
return get_pi_wrlat(pdram_timing, timing_config) + PI_ADD_LATENCY - 1;
}
static uint32_t get_pi_tdfi_phy_rdlat(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
/* [DLLSUBTYPE2] == "STD_DENALI_HS" */
uint32_t cas_lat, delay_adder, ie_enable, hs_offset, ie_delay_adder;
uint32_t mem_delay_ps, round_trip_ps;
uint32_t phy_internal_delay, lpddr_adder, dfi_adder, rdlat_delay;
ie_enable = PI_IE_ENABLE_VALUE;
delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
delay_adder = delay_adder - 1;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
if (delay_adder > (cas_lat - 1 - hs_offset)) {
ie_delay_adder = 0;
} else {
ie_delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
ie_delay_adder++;
}
if (timing_config->dram_type == DDR3) {
mem_delay_ps = 0;
} else if (timing_config->dram_type == LPDDR4) {
mem_delay_ps = 3600;
} else if (timing_config->dram_type == LPDDR3) {
mem_delay_ps = 5500;
} else {
printf("get_pi_tdfi_phy_rdlat:dramtype unsupport\n");
return 0;
}
round_trip_ps = 1100 + 500 + mem_delay_ps + 500 + 600;
delay_adder = round_trip_ps / (1000000 / pdram_timing->mhz);
if ((round_trip_ps % (1000000 / pdram_timing->mhz)) != 0)
delay_adder++;
phy_internal_delay = 5 + 2 + 4;
lpddr_adder = mem_delay_ps / (1000000 / pdram_timing->mhz);
if ((mem_delay_ps % (1000000 / pdram_timing->mhz)) != 0)
lpddr_adder++;
dfi_adder = 0;
phy_internal_delay = phy_internal_delay + 2;
rdlat_delay = delay_adder + phy_internal_delay +
ie_delay_adder + lpddr_adder + dfi_adder;
rdlat_delay = rdlat_delay + 2;
return rdlat_delay;
}
static uint32_t get_pi_todtoff_min(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp, todtoff_min_ps;
if (timing_config->dram_type == LPDDR3)
todtoff_min_ps = 2500;
else if (timing_config->dram_type == LPDDR4)
todtoff_min_ps = 1500;
else
todtoff_min_ps = 0;
/* todtoff_min */
tmp = todtoff_min_ps / (1000000 / pdram_timing->mhz);
if ((todtoff_min_ps % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
return tmp;
}
static uint32_t get_pi_todtoff_max(struct dram_timing_t *pdram_timing,
struct timing_related_config *timing_config)
{
uint32_t tmp, todtoff_max_ps;
if ((timing_config->dram_type == LPDDR4)
|| (timing_config->dram_type == LPDDR3))
todtoff_max_ps = 3500;
else
todtoff_max_ps = 0;
/* todtoff_max */
tmp = todtoff_max_ps / (1000000 / pdram_timing->mhz);
if ((todtoff_max_ps % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
return tmp;
}
static void gen_rk3399_ctl_params_f0(struct timing_related_config
*timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t i;
uint32_t tmp, tmp1;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == DDR3) {
tmp = ((700000 + 10) * timing_config->freq +
999) / 1000;
tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
pdram_timing->tmod + pdram_timing->tzqinit;
write_32(&rk3399_ddr_pctl[i]->denali_ctl[5], tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[22],
0xffff, pdram_timing->tdllk);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[32],
(pdram_timing->tmod << 8) |
pdram_timing->tmrd);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59],
0xffff << 16,
(pdram_timing->txsr -
pdram_timing->trcd) << 16);
} else if (timing_config->dram_type == LPDDR4) {
write_32(&rk3399_ddr_pctl[i]->denali_ctl[5],
pdram_timing->tinit1 + pdram_timing->tinit3);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[32],
(pdram_timing->tmrd << 8) |
pdram_timing->tmrd);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59],
0xffff << 16, pdram_timing->txsr << 16);
} else {
write_32(&rk3399_ddr_pctl[i]->denali_ctl[5],
pdram_timing->tinit1);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[7],
pdram_timing->tinit4);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[32],
(pdram_timing->tmrd << 8) |
pdram_timing->tmrd);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[59],
0xffff << 16, pdram_timing->txsr << 16);
}
write_32(&rk3399_ddr_pctl[i]->denali_ctl[6],
pdram_timing->tinit3);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[8],
pdram_timing->tinit5);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[23], (0x7f << 16),
((pdram_timing->cl * 2) << 16));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[23], (0x1f << 24),
(pdram_timing->cwl << 24));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], 0x3f,
pdram_timing->al);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[26], 0xffff << 16,
(pdram_timing->trc << 24) |
(pdram_timing->trrd << 16));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[27],
(pdram_timing->tfaw << 24) |
(pdram_timing->trppb << 16) |
(pdram_timing->twtr << 8) | pdram_timing->tras_min);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[31], 0xff << 24,
max(4, pdram_timing->trtp) << 24);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[33],
(pdram_timing->tcke << 24) | pdram_timing->tras_max);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34], 0xff,
max(1, pdram_timing->tckesr));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[39],
(0x3f << 16) | (0xff << 8),
(pdram_timing->twr << 16) |
(pdram_timing->trcd << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[42], 0x1f << 16,
pdram_timing->tmrz << 16);
tmp = pdram_timing->tdal ? pdram_timing->tdal :
(pdram_timing->twr + pdram_timing->trp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[44], 0xff, tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[45], 0xff,
pdram_timing->trp);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[48],
((pdram_timing->trefi - 8) << 16) |
pdram_timing->trfc);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[52], 0xffff,
pdram_timing->txp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[53], 0xffff << 16,
pdram_timing->txpdll << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xf << 24,
pdram_timing->tcscke << 24);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xff,
pdram_timing->tmrri);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[56],
(pdram_timing->tzqcke << 24) |
(pdram_timing->tmrwckel << 16) |
(pdram_timing->tckehcs << 8) | pdram_timing->tckelcs);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60], 0xffff,
pdram_timing->txsnr);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[62], 0xffff << 16,
(pdram_timing->tckehcmd << 24) |
(pdram_timing->tckelcmd << 16));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[63],
(pdram_timing->tckelpd << 24) |
(pdram_timing->tescke << 16) |
(pdram_timing->tsr << 8) | pdram_timing->tckckel);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[64], 0xfff,
(pdram_timing->tcmdcke << 8) |
pdram_timing->tcsckeh);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[92],
(0xffff << 8),
(pdram_timing->tcksrx << 16) |
(pdram_timing->tcksre << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[108], (0x1 << 24),
(timing_config->dllbp << 24));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[122],
(0x3FF << 16),
(pdram_timing->tvrcg_enable << 16));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[123],
(pdram_timing->tfc_long << 16) |
pdram_timing->tvrcg_disable);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[124],
(pdram_timing->tvref_long << 16) |
(pdram_timing->tckfspx << 8) |
pdram_timing->tckfspe);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[133],
(pdram_timing->mr[1] << 16) | pdram_timing->mr[0]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[134], 0xffff,
pdram_timing->mr[2]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[138], 0xffff,
pdram_timing->mr[3]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[139], 0xff << 24,
pdram_timing->mr11 << 24);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[147],
(pdram_timing->mr[1] << 16) | pdram_timing->mr[0]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[148], 0xffff,
pdram_timing->mr[2]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[152], 0xffff,
pdram_timing->mr[3]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[153], 0xff << 24,
pdram_timing->mr11 << 24);
if (timing_config->dram_type == LPDDR4) {
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[140],
0xffff << 16, pdram_timing->mr12 << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[142],
0xffff << 16, pdram_timing->mr14 << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[145],
0xffff << 16, pdram_timing->mr22 << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[154],
0xffff << 16, pdram_timing->mr12 << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[156],
0xffff << 16, pdram_timing->mr14 << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[159],
0xffff << 16, pdram_timing->mr22 << 16);
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[179], 0xfff << 8,
pdram_timing->tzqinit << 8);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[180],
(pdram_timing->tzqcs << 16) |
(pdram_timing->tzqinit / 2));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[181],
(pdram_timing->tzqlat << 16) | pdram_timing->tzqcal);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[212], 0xff << 8,
pdram_timing->todton << 8);
if (timing_config->odt) {
setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213],
1 << 16);
if (timing_config->freq < 400)
tmp = 4 << 24;
else
tmp = 8 << 24;
} else {
clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213],
1 << 16);
tmp = 2 << 24;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[216],
0x1f << 24, tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[221],
(0x3 << 16) | (0xf << 8),
(pdram_timing->tdqsck << 16) |
(pdram_timing->tdqsck_max << 8));
tmp =
(get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl)
<< 8) | get_rdlat_adj(timing_config->dram_type,
pdram_timing->cl);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[284], 0xffff,
tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[82], 0xffff << 16,
(4 * pdram_timing->trefi) << 16);
for (i = 0; i < 2; i++) {
struct rk3399_sdram_channel *ch = &sdram_config.ch[i];
struct rk3399_msch_timings *noc = &ch->noc_timings;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[83], 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = 0;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[214], 0x3f << 16,
(tmp & 0x3f) << 16);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble= cl+TDQSCK_MIN-1 */
tmp = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config) - 1;
/* todtoff_max */
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[215], 0x3f << 8,
(tmp & 0x3f) << 8);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[275], 0xff << 16,
(get_pi_tdfi_phy_rdlat
(pdram_timing, timing_config)
& 0xff) << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[277], 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[282], 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[283],
20 * pdram_timing->trefi);
/* CTL_308 TDFI_CALVL_CAPTURE_F0:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[308], 0x3ff << 16,
tmp << 16);
/* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */
tmp = tmp + 18;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[308], 0x3ff,
tmp);
/* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */
tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
if (tmp1 < 5) {
if (tmp1 == 0)
tmp = 0;
else
tmp = tmp1 - 1;
} else {
tmp = tmp1 - 5;
}
} else {
tmp = tmp1 - 2;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 8,
tmp << 8);
/* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */
if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
(pdram_timing->cl >= 5))
tmp = pdram_timing->cl - 5;
else
tmp = pdram_timing->cl - 2;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff,
tmp);
}
}
static void gen_rk3399_ctl_params_f1(struct timing_related_config
*timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t i;
uint32_t tmp, tmp1;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == DDR3) {
tmp =
((700000 + 10) * timing_config->freq +
999) / 1000;
tmp +=
pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
pdram_timing->tmod + pdram_timing->tzqinit;
write_32(&rk3399_ddr_pctl[i]->denali_ctl[9], tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[22],
0xffff << 16, pdram_timing->tdllk << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34],
0xffffff00,
(pdram_timing->tmod << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60],
0xffff << 16,
(pdram_timing->txsr -
pdram_timing->trcd) << 16);
} else if (timing_config->dram_type == LPDDR4) {
write_32(&rk3399_ddr_pctl[i]->denali_ctl[9],
pdram_timing->tinit1 + pdram_timing->tinit3);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34],
0xffffff00,
(pdram_timing->tmrd << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60],
0xffff << 16, pdram_timing->txsr << 16);
} else {
write_32(&rk3399_ddr_pctl[i]->denali_ctl[9],
pdram_timing->tinit1);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[11],
pdram_timing->tinit4);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[34],
0xffffff00,
(pdram_timing->tmrd << 24) |
(pdram_timing->tmrd << 16) |
(pdram_timing->trtp << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[60],
0xffff << 16, pdram_timing->txsr << 16);
}
write_32(&rk3399_ddr_pctl[i]->denali_ctl[10],
pdram_timing->tinit3);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[12],
pdram_timing->tinit5);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], (0x7f << 8),
((pdram_timing->cl * 2) << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], (0x1f << 16),
(pdram_timing->cwl << 16));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[24], 0x3f << 24,
pdram_timing->al << 24);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[28], 0xffffff00,
(pdram_timing->tras_min << 24) |
(pdram_timing->trc << 16) |
(pdram_timing->trrd << 8));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[29], 0xffffff,
(pdram_timing->tfaw << 16) |
(pdram_timing->trppb << 8) | pdram_timing->twtr);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[35],
(pdram_timing->tcke << 24) | pdram_timing->tras_max);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[36], 0xff,
max(1, pdram_timing->tckesr));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[39],
(0xff << 24), (pdram_timing->trcd << 24));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[40],
0x3f, pdram_timing->twr);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[42], 0x1f << 24,
pdram_timing->tmrz << 24);
tmp = pdram_timing->tdal ? pdram_timing->tdal :
(pdram_timing->twr + pdram_timing->trp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[44], 0xff << 8,
tmp << 8);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[45], 0xff << 8,
pdram_timing->trp << 8);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[49],
((pdram_timing->trefi - 8) << 16) |
pdram_timing->trfc);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[52], 0xffff << 16,
pdram_timing->txp << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[54], 0xffff,
pdram_timing->txpdll);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[55], 0xff << 8,
pdram_timing->tmrri << 8);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[57],
(pdram_timing->tmrwckel << 24) |
(pdram_timing->tckehcs << 16) |
(pdram_timing->tckelcs << 8) | pdram_timing->tcscke);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[58], 0xf,
pdram_timing->tzqcke);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[61], 0xffff,
pdram_timing->txsnr);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[64], 0xffff << 16,
(pdram_timing->tckehcmd << 24) |
(pdram_timing->tckelcmd << 16));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[65],
(pdram_timing->tckelpd << 24) |
(pdram_timing->tescke << 16) |
(pdram_timing->tsr << 8) | pdram_timing->tckckel);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[66], 0xfff,
(pdram_timing->tcmdcke << 8) |
pdram_timing->tcsckeh);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[92], (0xff << 24),
(pdram_timing->tcksre << 24));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[93], 0xff,
pdram_timing->tcksrx);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[108], (0x1 << 25),
(timing_config->dllbp << 25));
write_32(&rk3399_ddr_pctl[i]->denali_ctl[125],
(pdram_timing->tvrcg_disable << 16) |
pdram_timing->tvrcg_enable);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[126],
(pdram_timing->tckfspx << 24) |
(pdram_timing->tckfspe << 16) |
pdram_timing->tfc_long);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[127], 0xffff,
pdram_timing->tvref_long);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[134],
0xffff << 16, pdram_timing->mr[0] << 16);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[135],
(pdram_timing->mr[2] << 16) | pdram_timing->mr[1]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[138],
0xffff << 16, pdram_timing->mr[3] << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[140], 0xff,
pdram_timing->mr11);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[148],
0xffff << 16, pdram_timing->mr[0] << 16);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[149],
(pdram_timing->mr[2] << 16) | pdram_timing->mr[1]);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[152],
0xffff << 16, pdram_timing->mr[3] << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[154], 0xff,
pdram_timing->mr11);
if (timing_config->dram_type == LPDDR4) {
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[141],
0xffff, pdram_timing->mr12);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[143],
0xffff, pdram_timing->mr14);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[146],
0xffff, pdram_timing->mr22);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[155],
0xffff, pdram_timing->mr12);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[157],
0xffff, pdram_timing->mr14);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[160],
0xffff, pdram_timing->mr22);
}
write_32(&rk3399_ddr_pctl[i]->denali_ctl[182],
((pdram_timing->tzqinit / 2) << 16) |
pdram_timing->tzqinit);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[183],
(pdram_timing->tzqcal << 16) | pdram_timing->tzqcs);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[184], 0x3f,
pdram_timing->tzqlat);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[188], 0xfff,
pdram_timing->tzqreset);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[212], 0xff << 16,
pdram_timing->todton << 16);
if (timing_config->odt) {
setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213],
(1 << 24));
if (timing_config->freq < 400)
tmp = 4 << 24;
else
tmp = 8 << 24;
} else {
clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[213],
(1 << 24));
tmp = 2 << 24;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[217], 0x1f << 24,
tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[221], 0xf << 24,
(pdram_timing->tdqsck_max << 24));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[222], 0x3,
pdram_timing->tdqsck);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[291], 0xffff,
(get_wrlat_adj(timing_config->dram_type,
pdram_timing->cwl) << 8) |
get_rdlat_adj(timing_config->dram_type,
pdram_timing->cl));
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[84], 0xffff,
(4 * pdram_timing->trefi) & 0xffff);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[84], 0xffff << 16,
((2 * pdram_timing->trefi) & 0xffff) << 16);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = 0;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[214], 0x3f << 24,
(tmp & 0x3f) << 24);
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble= cl+TDQSCK_MIN-1 */
tmp = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config) - 1;
/* todtoff_max */
tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
} else {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[215], 0x3f << 16,
(tmp & 0x3f) << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[275], 0xff << 24,
(get_pi_tdfi_phy_rdlat
(pdram_timing, timing_config)
& 0xff) << 24);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[284],
0xffff << 16,
((2 * pdram_timing->trefi) & 0xffff) << 16);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[289], 0xffff,
(2 * pdram_timing->trefi) & 0xffff);
write_32(&rk3399_ddr_pctl[i]->denali_ctl[290],
20 * pdram_timing->trefi);
/* CTL_309 TDFI_CALVL_CAPTURE_F1:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[309], 0x3ff << 16,
tmp << 16);
/* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */
tmp = tmp + 18;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[309], 0x3ff,
tmp);
/* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */
tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
if (tmp1 < 5) {
if (tmp1 == 0)
tmp = 0;
else
tmp = tmp1 - 1;
} else {
tmp = tmp1 - 5;
}
} else {
tmp = tmp1 - 2;
}
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 24,
tmp << 24);
/* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */
if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
(pdram_timing->cl >= 5))
tmp = pdram_timing->cl - 5;
else
tmp = pdram_timing->cl - 2;
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[314], 0xff << 16,
tmp << 16);
}
}
static void gen_rk3399_ctl_params(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
if (fn == 0)
gen_rk3399_ctl_params_f0(timing_config, pdram_timing);
else
gen_rk3399_ctl_params_f1(timing_config, pdram_timing);
#if CTL_TRAINING
uint32_t i, tmp0, tmp1;
tmp0 = tmp1 = 0;
#if EN_READ_GATE_TRAINING
tmp1 = 1;
#endif
#if EN_CA_TRAINING
tmp0 |= (1 << 8);
#endif
#if EN_WRITE_LEVELING
tmp0 |= (1 << 16);
#endif
#if EN_READ_LEVELING
tmp0 |= (1 << 24);
#endif
for (i = 0; i < timing_config->ch_cnt; i++) {
if (tmp0 | tmp1)
setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[305],
1 << 16);
if (tmp0)
setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[70], tmp0);
if (tmp1)
setbits_32(&rk3399_ddr_pctl[i]->denali_ctl[71], tmp1);
}
#endif
}
static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t tmp, tmp1, tmp2;
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
/* PI_02 PI_TDFI_PHYMSTR_MAX_F0:RW:0:32 */
tmp = 4 * pdram_timing->trefi;
write_32(&rk3399_ddr_pi[i]->denali_pi[2], tmp);
/* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */
tmp = 2 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[3], 0xffff, tmp);
/* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[7], 0xffff << 16,
tmp << 16);
/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F0:RW:0:8 */
if (timing_config->dram_type == LPDDR4)
tmp = 2;
else
tmp = 0;
tmp = (pdram_timing->bl / 2) + 4 +
(get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[42], 0xff, tmp);
/* PI_43 PI_WRLAT_F0:RW:0:5 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x1f,
tmp);
}
/* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x3f << 8,
PI_ADD_LATENCY << 8);
/* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */
tmp = pdram_timing->cl * 2;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43], 0x7f << 16,
tmp << 16);
/* PI_46 PI_TREF_F0:RW:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[46], 0xffff << 16,
pdram_timing->trefi << 16);
/* PI_46 PI_TRFC_F0:RW:0:10 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[46], 0x3ff,
pdram_timing->trfc);
/* PI_66 PI_TODTL_2CMD_F0:RW:24:8 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_todtoff_max(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[66],
0xff << 24, tmp << 24);
}
/* PI_72 PI_WR_TO_ODTH_F0:RW:16:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
tmp1 = get_pi_wrlat(pdram_timing, timing_config);
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = 0;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[72], 0x3f << 16,
tmp << 16);
/* PI_73 PI_RD_TO_ODTH_F0:RW:8:6 */
if ((timing_config->dram_type == LPDDR3) ||
(timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble= cl+TDQSCK_MIN-1 */
tmp1 = pdram_timing->cl +
get_pi_todtoff_min(pdram_timing, timing_config) - 1;
/* todtoff_max */
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[73], 0x3f << 8,
tmp << 8);
/* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */
tmp = get_pi_rdlat_adj(pdram_timing);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[89], 0xff << 16,
tmp << 16);
/* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */
tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[90], 0xff << 16,
tmp << 16);
/* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */
tmp1 = tmp;
if (tmp1 < 5) {
if (tmp1 == 0)
tmp = 0;
else
tmp = tmp1 - 1;
} else {
tmp = tmp1 - 5;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[91], 0xff << 16,
tmp << 16);
/* PI_95 PI_TDFI_CALVL_CAPTURE_F0:RW:16:10 */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[95], 0x3ff << 16,
tmp << 16);
/* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */
tmp = tmp + 18;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[95], 0x3ff, tmp);
/* PI_102 PI_TMRZ_F0:RW:8:5 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[102], 0x1f << 8,
pdram_timing->tmrz << 8);
/* PI_111 PI_TDFI_CALVL_STROBE_F0:RW:8:4 */
tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
/* pi_tdfi_calvl_strobe=tds_train+5 */
tmp = tmp1 + 5;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[111], 0xf << 8,
tmp << 8);
/* PI_116 PI_TCKEHDQS_F0:RW:16:6 */
tmp = 10000 / (1000000 / pdram_timing->mhz);
if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
if (pdram_timing->mhz <= 100)
tmp = tmp + 1;
else
tmp = tmp + 8;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[116], 0x3f << 16,
tmp << 16);
/* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[125], 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[133], 0xffff,
pdram_timing->mr[1]);
/* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[140], 0xffff << 16,
pdram_timing->mr[1] << 16);
/* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[148], 0xffff,
pdram_timing->mr[1]);
/* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[126], 0xffff,
pdram_timing->mr[2]);
/* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[133], 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[141], 0xffff,
pdram_timing->mr[2]);
/* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[148], 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_156 PI_TFC_F0:RW:0:10 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[156], 0x3ff,
pdram_timing->trfc);
/* PI_158 PI_TWR_F0:RW:24:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0x3f << 24,
pdram_timing->twr << 24);
/* PI_158 PI_TWTR_F0:RW:16:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0x3f << 16,
pdram_timing->twtr << 16);
/* PI_158 PI_TRCD_F0:RW:8:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0xff << 8,
pdram_timing->trcd << 8);
/* PI_158 PI_TRP_F0:RW:0:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[158], 0xff,
pdram_timing->trp);
/* PI_157 PI_TRTP_F0:RW:24:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[157], 0xff << 24,
pdram_timing->trtp << 24);
/* PI_159 PI_TRAS_MIN_F0:RW:24:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[159], 0xff << 24,
pdram_timing->tras_min << 24);
/* PI_159 PI_TRAS_MAX_F0:RW:0:17 */
tmp = pdram_timing->tras_max * 99 / 100;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[159], 0x1ffff, tmp);
/* PI_160 PI_TMRD_F0:RW:16:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[160], 0x3f << 16,
pdram_timing->tmrd << 16);
/*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[160], 0xf,
pdram_timing->tdqsck_max);
/* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */
tmp = 2 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[187], 0xffff << 8,
tmp << 8);
/* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */
tmp = 20 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[188], 0xffffffff,
tmp);
}
}
static void gen_rk3399_pi_params_f1(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing)
{
uint32_t tmp, tmp1, tmp2;
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
/* PI_04 PI_TDFI_PHYMSTR_MAX_F1:RW:0:32 */
tmp = 4 * pdram_timing->trefi;
write_32(&rk3399_ddr_pi[i]->denali_pi[4], tmp);
/* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */
tmp = 2 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[5], 0xffff, tmp);
/* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[12], 0xffff, tmp);
/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F1:RW:8:8 */
if (timing_config->dram_type == LPDDR4)
tmp = 2;
else
tmp = 0;
tmp = (pdram_timing->bl / 2) + 4 +
(get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[42], 0xff << 8,
tmp << 8);
/* PI_43 PI_WRLAT_F1:RW:24:5 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_wrlat(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[43],
0x1f << 24, tmp << 24);
}
/* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[44], 0x3f,
PI_ADD_LATENCY);
/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */
tmp = pdram_timing->cl * 2;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[44], 0x7f << 8,
tmp << 8);
/* PI_47 PI_TREF_F1:RW:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[47], 0xffff << 16,
pdram_timing->trefi << 16);
/* PI_47 PI_TRFC_F1:RW:0:10 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[47], 0x3ff,
pdram_timing->trfc);
/* PI_67 PI_TODTL_2CMD_F1:RW:8:8 */
if (timing_config->dram_type == LPDDR3) {
tmp = get_pi_todtoff_max(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[67],
0xff << 8, tmp << 8);
}
/* PI_72 PI_WR_TO_ODTH_F1:RW:24:6 */
if ((timing_config->dram_type == LPDDR3)
|| (timing_config->dram_type == LPDDR4)) {
tmp1 = get_pi_wrlat(pdram_timing, timing_config);
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = 0;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[72], 0x3f << 24,
tmp << 24);
/* PI_73 PI_RD_TO_ODTH_F1:RW:16:6 */
if ((timing_config->dram_type == LPDDR3)
|| (timing_config->dram_type == LPDDR4)) {
/* min_rl_preamble= cl+TDQSCK_MIN-1 */
tmp1 =
pdram_timing->cl + get_pi_todtoff_min(pdram_timing,
timing_config)
- 1;
/* todtoff_max */
tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
if (tmp1 > tmp2)
tmp = tmp1 - tmp2;
else
tmp = 0;
} else if (timing_config->dram_type == DDR3) {
tmp = pdram_timing->cl - pdram_timing->cwl;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[73], 0x3f << 16,
tmp << 16);
/*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */
tmp = get_pi_rdlat_adj(pdram_timing);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[89], 0xff << 24,
tmp << 24);
/* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */
tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[90], 0xff << 24,
tmp << 24);
/* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */
tmp1 = tmp;
if (tmp1 < 5) {
if (tmp1 == 0)
tmp = 0;
else
tmp = tmp1 - 1;
} else {
tmp = tmp1 - 5;
}
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[91], 0xff << 24,
tmp << 24);
/*PI_96 PI_TDFI_CALVL_CAPTURE_F1:RW:16:10 */
/* tadr=20ns */
tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[96], 0x3ff << 16,
tmp << 16);
/* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */
tmp = tmp + 18;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[96], 0x3ff, tmp);
/*PI_103 PI_TMRZ_F1:RW:0:5 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[103], 0x1f,
pdram_timing->tmrz);
/*PI_111 PI_TDFI_CALVL_STROBE_F1:RW:16:4 */
/* tds_train=ceil(2/ns) */
tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
tmp1++;
/* pi_tdfi_calvl_strobe=tds_train+5 */
tmp = tmp1 + 5;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[111], 0xf << 16,
tmp << 16);
/* PI_116 PI_TCKEHDQS_F1:RW:24:6 */
tmp = 10000 / (1000000 / pdram_timing->mhz);
if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
if (pdram_timing->mhz <= 100)
tmp = tmp + 1;
else
tmp = tmp + 8;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[116], 0x3f << 24,
tmp << 24);
/* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[128], 0xffff,
pdram_timing->mr[1]);
/* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[135], 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[143], 0xffff,
pdram_timing->mr[1]);
/* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[150], 0xffff << 8,
pdram_timing->mr[1] << 8);
/* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[128], 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[136], 0xffff,
pdram_timing->mr[2]);
/* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[143], 0xffff << 16,
pdram_timing->mr[2] << 16);
/* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[151], 0xffff,
pdram_timing->mr[2]);
/* PI_156 PI_TFC_F1:RW:16:10 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[156], 0x3ff << 16,
pdram_timing->trfc << 16);
/* PI_162 PI_TWR_F1:RW:8:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[162], 0x3f << 8,
pdram_timing->twr << 8);
/* PI_162 PI_TWTR_F1:RW:0:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[162], 0x3f,
pdram_timing->twtr);
/* PI_161 PI_TRCD_F1:RW:24:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 24,
pdram_timing->trcd << 24);
/* PI_161 PI_TRP_F1:RW:16:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 16,
pdram_timing->trp << 16);
/* PI_161 PI_TRTP_F1:RW:8:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[161], 0xff << 8,
pdram_timing->trtp << 8);
/* PI_163 PI_TRAS_MIN_F1:RW:24:8 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[163], 0xff << 24,
pdram_timing->tras_min << 24);
/* PI_163 PI_TRAS_MAX_F1:RW:0:17 */
tmp = pdram_timing->tras_max * 99 / 100;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[163], 0x1ffff, tmp);
/* PI_164 PI_TMRD_F1:RW:16:6 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[164], 0x3f << 16,
pdram_timing->tmrd << 16);
/* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[164], 0xf,
pdram_timing->tdqsck_max);
/* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */
tmp = 2 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[189], 0xffff, tmp);
/* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */
tmp = 20 * pdram_timing->trefi;
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[190], 0xffffffff,
tmp);
}
}
static void gen_rk3399_pi_params(struct timing_related_config *timing_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
if (fn == 0)
gen_rk3399_pi_params_f0(timing_config, pdram_timing);
else
gen_rk3399_pi_params_f1(timing_config, pdram_timing);
#if PI_TRAINING
uint32_t i;
for (i = 0; i < timing_config->ch_cnt; i++) {
#if EN_READ_GATE_TRAINING
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[80], 3 << 24,
2 << 24);
#endif
#if EN_CA_TRAINING
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[100], 3 << 8,
2 << 8);
#endif
#if EN_WRITE_LEVELING
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[60], 3 << 8,
2 << 8);
#endif
#if EN_READ_LEVELING
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[80], 3 << 16,
2 << 16);
#endif
#if EN_WDQ_LEVELING
clrsetbits_32(&rk3399_ddr_pi[i]->denali_pi[124], 3 << 16,
2 << 16);
#endif
}
#endif
}
static void gen_rk3399_set_odt(uint32_t odt_en)
{
uint32_t drv_odt_val;
uint32_t i;
for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 16;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[5],
0x7 << 16, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[133],
0x7 << 16, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[261],
0x7 << 16, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[389],
0x7 << 16, drv_odt_val);
drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[6],
0x7 << 24, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[134],
0x7 << 24, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[262],
0x7 << 24, drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[390],
0x7 << 24, drv_odt_val);
}
}
static void gen_rk3399_set_ds_odt(struct timing_related_config *timing_config,
struct drv_odt_lp_config *drv_config)
{
uint32_t i, drv_odt_val;
for (i = 0; i < timing_config->ch_cnt; i++) {
if (timing_config->dram_type == LPDDR4)
drv_odt_val = drv_config->phy_side_odt |
(PHY_DRV_ODT_Hi_Z << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
else if (timing_config->dram_type == LPDDR3)
drv_odt_val = PHY_DRV_ODT_Hi_Z |
(drv_config->phy_side_odt << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
else
drv_odt_val = drv_config->phy_side_odt |
(drv_config->phy_side_odt << 4) |
(drv_config->phy_side_dq_drv << 8) |
(drv_config->phy_side_dq_drv << 12);
/* DQ drv odt set */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[6], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[134], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[262], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[390], 0xffffff,
drv_odt_val);
/* DQS drv odt set */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[7], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[135], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[263], 0xffffff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[391], 0xffffff,
drv_odt_val);
gen_rk3399_set_odt(timing_config->odt);
/* CA drv set */
drv_odt_val = drv_config->phy_side_ca_drv |
(drv_config->phy_side_ca_drv << 4);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[544], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[672], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[800], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[928], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[937], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[935], 0xff,
drv_odt_val);
drv_odt_val = drv_config->phy_side_ck_cs_drv |
(drv_config->phy_side_ck_cs_drv << 4);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[929], 0xff,
drv_odt_val);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[939], 0xff,
drv_odt_val);
}
}
static void gen_rk3399_phy_params(struct timing_related_config *timing_config,
struct drv_odt_lp_config *drv_config,
struct dram_timing_t *pdram_timing,
uint32_t fn)
{
uint32_t tmp, i, div, j;
uint32_t mem_delay_ps, pad_delay_ps, total_delay_ps, delay_frac_ps;
uint32_t trpre_min_ps, gate_delay_ps, gate_delay_frac_ps;
uint32_t ie_enable, tsel_enable, cas_lat, rddata_en_ie_dly, tsel_adder;
uint32_t extra_adder, delta, hs_offset;
for (i = 0; i < timing_config->ch_cnt; i++) {
pad_delay_ps = PI_PAD_DELAY_PS_VALUE;
ie_enable = PI_IE_ENABLE_VALUE;
tsel_enable = PI_TSEL_ENABLE_VALUE;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[896],
(0x3 << 8) | 1, fn << 8);
/* PHY_LOW_FREQ_SEL */
/* DENALI_PHY_913 1bit offset_0 */
if (timing_config->freq > 400)
clrbits_32(&rk3399_ddr_publ[i]->denali_phy[913], 1);
else
setbits_32(&rk3399_ddr_publ[i]->denali_phy[913], 1);
/* PHY_RPTR_UPDATE_x */
/* DENALI_PHY_87/215/343/471 4bit offset_16 */
tmp = 2500 / (1000000 / pdram_timing->mhz) + 3;
if ((2500 % (1000000 / pdram_timing->mhz)) != 0)
tmp++;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[87], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[215], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[343], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[471], 0xf << 16,
tmp << 16);
/* PHY_PLL_CTRL */
/* DENALI_PHY_911 13bits offset_0 */
/* PHY_LP4_BOOT_PLL_CTRL */
/* DENALI_PHY_919 13bits offset_0 */
if (pdram_timing->mhz <= 150)
tmp = 3;
else if (pdram_timing->mhz <= 300)
tmp = 2;
else if (pdram_timing->mhz <= 600)
tmp = 1;
else
tmp = 0;
tmp = (1 << 12) | (tmp << 9) | (2 << 7) | (1 << 1);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[911], 0x1fff,
tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[919], 0x1fff,
tmp);
/* PHY_PLL_CTRL_CA */
/* DENALI_PHY_911 13bits offset_16 */
/* PHY_LP4_BOOT_PLL_CTRL_CA */
/* DENALI_PHY_919 13bits offset_16 */
if (pdram_timing->mhz <= 150)
tmp = 3;
else if (pdram_timing->mhz <= 300)
tmp = 2;
else if (pdram_timing->mhz <= 600)
tmp = 1;
else
tmp = 0;
tmp = (tmp << 9) | (2 << 7) | (1 << 5) | (1 << 1);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[911],
0x1fff << 16, tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[919],
0x1fff << 16, tmp << 16);
/* PHY_TCKSRE_WAIT */
/* DENALI_PHY_922 4bits offset_24 */
if (pdram_timing->mhz <= 400)
tmp = 1;
else if (pdram_timing->mhz <= 800)
tmp = 3;
else if (pdram_timing->mhz <= 1000)
tmp = 4;
else
tmp = 5;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[922], 0xf << 24,
tmp << 24);
/* PHY_CAL_CLK_SELECT_0:RW8:3 */
div = pdram_timing->mhz / (2 * 20);
for (j = 2, tmp = 1; j <= 128; j <<= 1, tmp++) {
if (div < j)
break;
}
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[947], 0x7 << 8,
tmp << 8);
setbits_32(&rk3399_ddr_publ[i]->denali_phy[927], (1 << 22));
if (timing_config->dram_type == DDR3) {
mem_delay_ps = 0;
trpre_min_ps = 1000;
} else if (timing_config->dram_type == LPDDR4) {
mem_delay_ps = 1500;
trpre_min_ps = 900;
} else if (timing_config->dram_type == LPDDR3) {
mem_delay_ps = 2500;
trpre_min_ps = 900;
} else {
ERROR("gen_rk3399_phy_params:dramtype unsupport\n");
return;
}
total_delay_ps = mem_delay_ps + pad_delay_ps;
delay_frac_ps =
1000 * total_delay_ps / (1000000 / pdram_timing->mhz);
gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2);
gate_delay_frac_ps =
gate_delay_ps - gate_delay_ps / 1000 * 1000;
tmp = gate_delay_frac_ps * 0x200 / 1000;
/* PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY */
/* DENALI_PHY_2/130/258/386 10bits offset_0 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[2], 0x2ff, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[130], 0x2ff, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[258], 0x2ff, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[386], 0x2ff, tmp);
/* PHY_RDDQS_GATE_SLAVE_DELAY */
/* DENALI_PHY_77/205/333/461 10bits offset_16 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[77], 0x2ff << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[205], 0x2ff << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[333], 0x2ff << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[461], 0x2ff << 16,
tmp << 16);
tmp = gate_delay_ps / 1000;
/* PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST */
/* DENALI_PHY_10/138/266/394 4bit offset_0 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[10], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[138], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[266], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[394], 0xf, tmp);
/* PHY_RDDQS_LATENCY_ADJUST */
/* DENALI_PHY_78/206/334/462 4bits offset_0 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[78], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[206], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[334], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[462], 0xf, tmp);
/* PHY_GTLVL_LAT_ADJ_START */
/* DENALI_PHY_80/208/336/464 4bits offset_16 */
tmp = delay_frac_ps / 1000;
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[80], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[208], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[336], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[464], 0xf << 16,
tmp << 16);
cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
rddata_en_ie_dly = ie_enable / (1000000 / pdram_timing->mhz);
if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
rddata_en_ie_dly++;
rddata_en_ie_dly = rddata_en_ie_dly - 1;
tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
tsel_adder++;
if (rddata_en_ie_dly > tsel_adder)
extra_adder = rddata_en_ie_dly - tsel_adder;
else
extra_adder = 0;
delta = cas_lat - rddata_en_ie_dly;
if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
hs_offset = 2;
else
hs_offset = 1;
if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset)) {
tmp = 0;
} else {
if ((delta == 2) || (delta == 1))
tmp = rddata_en_ie_dly - 0 - extra_adder;
else
tmp = extra_adder;
}
/* PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY */
/* DENALI_PHY_9/137/265/393 4bit offset_16 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[9], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[137], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[265], 0xf << 16,
tmp << 16);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[393], 0xf << 16,
tmp << 16);
/* PHY_RDDATA_EN_TSEL_DLY */
/* DENALI_PHY_86/214/342/470 4bit offset_0 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[86], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[214], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[342], 0xf, tmp);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[470], 0xf, tmp);
if (tsel_adder > rddata_en_ie_dly)
extra_adder = tsel_adder - rddata_en_ie_dly;
else
extra_adder = 0;
if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset))
tmp = tsel_adder;
else
tmp = rddata_en_ie_dly - 0 + extra_adder;
/* PHY_LP4_BOOT_RDDATA_EN_DLY */
/* DENALI_PHY_9/137/265/393 4bit offset_8 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[9], 0xf << 8,
tmp << 8);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[137], 0xf << 8,
tmp << 8);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[265], 0xf << 8,
tmp << 8);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[393], 0xf << 8,
tmp << 8);
/* PHY_RDDATA_EN_DLY */
/* DENALI_PHY_85/213/341/469 4bit offset_24 */
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[85], 0xf << 24,
tmp << 24);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[213], 0xf << 24,
tmp << 24);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[341], 0xf << 24,
tmp << 24);
clrsetbits_32(&rk3399_ddr_publ[i]->denali_phy[469], 0xf << 24,
tmp << 24);
if (pdram_timing->mhz <= ENPER_CS_TRAINING_FREQ) {
/*
* Note:Per-CS Training is not compatible at speeds
* under 533 MHz. If the PHY is running at a speed
* less than 533MHz, all phy_per_cs_training_en_X
* parameters must be cleared to 0.
*/
/*DENALI_PHY_84/212/340/468 1bit offset_16 */
clrbits_32(&rk3399_ddr_publ[i]->denali_phy[84],
0x1 << 16);
clrbits_32(&rk3399_ddr_publ[i]->denali_phy[212],
0x1 << 16);
clrbits_32(&rk3399_ddr_publ[i]->denali_phy[340],
0x1 << 16);
clrbits_32(&rk3399_ddr_publ[i]->denali_phy[468],
0x1 << 16);
} else {
setbits_32(&rk3399_ddr_publ[i]->denali_phy[84],
0x1 << 16);
setbits_32(&rk3399_ddr_publ[i]->denali_phy[212],
0x1 << 16);
setbits_32(&rk3399_ddr_publ[i]->denali_phy[340],
0x1 << 16);
setbits_32(&rk3399_ddr_publ[i]->denali_phy[468],
0x1 << 16);
}
}
}
static int to_get_clk_index(unsigned int mhz)
{
int pll_cnt, i;
pll_cnt = ARRAY_SIZE(dpll_rates_table);
/* Assumming rate_table is in descending order */
for (i = 0; i < pll_cnt; i++) {
if (mhz >= dpll_rates_table[i].mhz)
break;
}
/* if mhz lower than lowest frequency in table, use lowest frequency */
if (i == pll_cnt)
i = pll_cnt - 1;
return i;
}
uint32_t rkclk_prepare_pll_timing(unsigned int mhz)
{
unsigned int refdiv, postdiv1, fbdiv, postdiv2;
int index;
index = to_get_clk_index(mhz);
refdiv = dpll_rates_table[index].refdiv;
fbdiv = dpll_rates_table[index].fbdiv;
postdiv1 = dpll_rates_table[index].postdiv1;
postdiv2 = dpll_rates_table[index].postdiv2;
write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(fbdiv));
write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON1, POSTDIV2(postdiv2) |
POSTDIV1(postdiv1) | REFDIV(refdiv));
return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
}
uint32_t ddr_get_rate(void)
{
uint32_t refdiv, postdiv1, fbdiv, postdiv2;
refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f;
fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
postdiv1 =
(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7;
postdiv2 =
(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7;
return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000;
}
/*
* return: bit12: channel 1, external self-refresh
* bit11: channel 1, stdby_mode
* bit10: channel 1, self-refresh with controller and memory clock gate
* bit9: channel 1, self-refresh
* bit8: channel 1, power-down
*
* bit4: channel 1, external self-refresh
* bit3: channel 0, stdby_mode
* bit2: channel 0, self-refresh with controller and memory clock gate
* bit1: channel 0, self-refresh
* bit0: channel 0, power-down
*/
uint32_t exit_low_power(void)
{
struct rk3399_ddr_pctl_regs *ddr_pctl_regs;
uint32_t low_power = 0;
uint32_t channel_mask;
uint32_t channel;
uint32_t tmp;
channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3;
for (channel = 0; channel < 2; channel++) {
ddr_pctl_regs = rk3399_ddr_pctl[channel];
if (!(channel_mask & (1 << channel)))
continue;
/* exit stdby mode */
write_32(&rk3399_ddr_cic->cic_ctrl1,
(1 << (channel + 16)) | (0 << channel));
/* exit external self-refresh */
tmp = channel ? 12 : 8;
low_power |= ((read_32(PMU_BASE + PMU_SFT_CON) >> tmp) & 0x1)
<< (4 + 8 * channel);
clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp);
while (!(read_32(PMU_BASE + PMU_DDR_SREF_ST) &
(1 << channel)))
;
/* exit auto low-power */
clrbits_32(&ddr_pctl_regs->denali_ctl[101], 0x7);
/* lp_cmd to exit */
if (((read_32(&ddr_pctl_regs->denali_ctl[100]) >> 24) &
0x7f) != 0x40) {
while (read_32(&ddr_pctl_regs->denali_ctl[200]) & 0x1)
;
clrsetbits_32(&ddr_pctl_regs->denali_ctl[93],
0xff << 24, 0x69 << 24);
while (((read_32(&ddr_pctl_regs->denali_ctl[100]) >>
24) & 0x7f) != 0x40)
;
}
}
return low_power;
}
void resume_low_power(uint32_t low_power)
{
struct rk3399_ddr_pctl_regs *ddr_pctl_regs;
uint32_t channel_mask;
uint32_t channel;
uint32_t tmp;
uint32_t val;
channel_mask = (read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3;
for (channel = 0; channel < 2; channel++) {
ddr_pctl_regs = rk3399_ddr_pctl[channel];
if (!(channel_mask & (1 << channel)))
if (!(SYS_REG_DEC_CHINFO(os_reg2_val, i)))
continue;
/* resume external self-refresh */
tmp = channel ? 12 : 8;
val = (low_power >> (4 + 8 * channel)) & 0x1;
setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp);
/* resume auto low-power */
val = (low_power >> (8 * channel)) & 0x7;
setbits_32(&ddr_pctl_regs->denali_ctl[101], val);
/* resume stdby mode */
val = (low_power >> (3 + 8 * channel)) & 0x1;
write_32(&rk3399_ddr_cic->cic_ctrl1,
(1 << (channel + 16)) | (val << channel));
ch->rank = SYS_REG_DEC_RANK(os_reg2_val, i);
ch->col = SYS_REG_DEC_COL(os_reg2_val, i);
ch->bk = SYS_REG_DEC_BK(os_reg2_val, i);
ch->bw = SYS_REG_DEC_BW(os_reg2_val, i);
ch->dbw = SYS_REG_DEC_DBW(os_reg2_val, i);
ch->row_3_4 = SYS_REG_DEC_ROW_3_4(os_reg2_val, i);
ch->cs0_row = SYS_REG_DEC_CS0_ROW(os_reg2_val, i);
ch->cs1_row = SYS_REG_DEC_CS1_ROW(os_reg2_val, i);
ch->ddrconfig = mmio_read_32(MSCH_BASE(i) + MSCH_DEVICECONF);
noc->ddrtiminga0.d32 = mmio_read_32(MSCH_BASE(i) +
MSCH_DDRTIMINGA0);
noc->ddrtimingb0.d32 = mmio_read_32(MSCH_BASE(i) +
MSCH_DDRTIMINGB0);
noc->ddrtimingc0.d32 = mmio_read_32(MSCH_BASE(i) +
MSCH_DDRTIMINGC0);
noc->devtodev0.d32 = mmio_read_32(MSCH_BASE(i) +
MSCH_DEVTODEV0);
noc->ddrmode.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRMODE);
noc->agingx0 = mmio_read_32(MSCH_BASE(i) + MSCH_AGINGX0);
}
}
static void wait_dcf_done(void)
{
while ((read_32(DCF_BASE + DCF_DCF_ISR) & (DCF_DONE)) == 0)
continue;
}
void clr_dcf_irq(void)
{
/* clear dcf irq status */
mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
}
static void enable_dcf(uint32_t dcf_addr)
{
/* config DCF start addr */
write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr);
/* wait dcf done */
while (read_32(DCF_BASE + DCF_DCF_CTRL) & 1)
continue;
/* clear dcf irq status */
write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
/* DCF start */
setbits_32(DCF_BASE + DCF_DCF_CTRL, DCF_START);
}
void dcf_code_init(void)
{
memcpy((void *)DCF_START_ADDR, (void *)dcf_code, sizeof(dcf_code));
/* set dcf master secure */
write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0));
write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000);
}
static void dcf_start(uint32_t freq, uint32_t index)
{
write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (1 << 1));
write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (1 << 0));
write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4);
write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq);
rkclk_prepare_pll_timing(freq);
udelay(10);
write_32(CRU_BASE + CRU_SOFTRST_CON(10), (0x1 << (1 + 16)) | (0 << 1));
write_32(CRU_BASE + CRU_SOFTRST_CON(11), (0x1 << (0 + 16)) | (0 << 0));
udelay(10);
enable_dcf(DCF_START_ADDR);
}
static void dram_low_power_config(struct drv_odt_lp_config *lp_config)
{
uint32_t tmp, tmp1, i;
uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
uint32_t *low_power = &rk3399_dram_status.low_power_stat;
if (dram_type == LPDDR4)
tmp = (lp_config->srpd_lite_idle << 16) |
lp_config->pd_idle;
else
tmp = lp_config->pd_idle;
if (dram_type == DDR3)
tmp1 = (2 << 16) | (0x7 << 8) | 7;
else
tmp1 = (3 << 16) | (0x7 << 8) | 7;
*low_power = 0;
for (i = 0; i < ch_cnt; i++) {
write_32(&rk3399_ddr_pctl[i]->denali_ctl[102], tmp);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[103], 0xffff,
(lp_config->sr_mc_gate_idle << 8) |
lp_config->sr_idle);
clrsetbits_32(&rk3399_ddr_pctl[i]->denali_ctl[101],
0x70f0f, tmp1);
*low_power |= (7 << (8 * i));
}
/* standby idle */
write_32(&rk3399_ddr_cic->cic_idle_th, lp_config->standby_idle);
write_32(&rk3399_ddr_cic->cic_cg_wait_th, 0x640008);
if (ch_cnt == 2) {
write_32(GRF_BASE + GRF_DDRC1_CON1,
(((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
if (lp_config->standby_idle) {
tmp = 0x002a002a;
*low_power |= (1 << 11);
} else {
tmp = 0;
}
write_32(&rk3399_ddr_cic->cic_ctrl1, tmp);
}
write_32(GRF_BASE + GRF_DDRC0_CON1,
(((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
if (lp_config->standby_idle) {
tmp = 0x00150015;
*low_power |= (1 << 3);
} else {
tmp = 0;
}
write_32(&rk3399_ddr_cic->cic_ctrl1, tmp);
}
static void dram_related_init(struct ddr_dts_config_timing *dts_timing)
{
uint32_t trefi0, trefi1;
uint32_t i;
struct rk3399_sdram_config sdram_config;
dcf_code_init();
/* get sdram config for os reg */
sdram_config_init(&sdram_config);
drv_odt_lp_cfg_init(sdram_config.dramtype, dts_timing,
&rk3399_dram_status.drv_odt_lp_cfg);
sdram_timing_cfg_init(&rk3399_dram_status.timing_config,
&sdram_config,
&rk3399_dram_status.drv_odt_lp_cfg);
trefi0 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[48]) >>
16) & 0xffff) + 8;
trefi1 = ((read_32(&rk3399_ddr_pctl[0]->denali_ctl[49]) >>
16) & 0xffff) + 8;
rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39;
rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39;
rk3399_dram_status.current_index =
(read_32(&rk3399_ddr_pctl[0]->denali_ctl[111])
>> 16) & 0x3;
if (rk3399_dram_status.timing_config.dram_type == DDR3) {
rk3399_dram_status.index_freq[0] /= 2;
rk3399_dram_status.index_freq[1] /= 2;
}
rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1)
& 0x1] = 0;
/* disable all training by ctl and pi */
for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[70], (1 << 24) |
(1 << 16) | (1 << 8) | 1);
clrbits_32(&rk3399_ddr_pctl[i]->denali_ctl[71], 1);
clrbits_32(&rk3399_ddr_pi[i]->denali_pi[60], 0x3 << 8);
clrbits_32(&rk3399_ddr_pi[i]->denali_pi[80], (0x3 << 24) |
(0x3 << 16));
clrbits_32(&rk3399_ddr_pi[i]->denali_pi[100], 0x3 << 8);
clrbits_32(&rk3399_ddr_pi[i]->denali_pi[124], 0x3 << 16);
}
/* init drv odt */
if (rk3399_dram_status.index_freq[rk3399_dram_status.current_index] <
rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq)
rk3399_dram_status.timing_config.odt = 0;
else
rk3399_dram_status.timing_config.odt = 1;
gen_rk3399_set_ds_odt(&rk3399_dram_status.timing_config,
&rk3399_dram_status.drv_odt_lp_cfg);
dram_low_power_config(&rk3399_dram_status.drv_odt_lp_cfg);
}
static uint32_t prepare_ddr_timing(uint32_t mhz)
{
uint32_t index;
struct dram_timing_t dram_timing;
rk3399_dram_status.timing_config.freq = mhz;
if (mhz < rk3399_dram_status.drv_odt_lp_cfg.ddr3_dll_dis_freq)
rk3399_dram_status.timing_config.dllbp = 1;
else
rk3399_dram_status.timing_config.dllbp = 0;
if (mhz < rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq) {
rk3399_dram_status.timing_config.odt = 0;
} else {
rk3399_dram_status.timing_config.odt = 1;
gen_rk3399_set_odt(1);
}
index = (rk3399_dram_status.current_index + 1) & 0x1;
if (rk3399_dram_status.index_freq[index] == mhz)
goto out;
/*
* checking if having available gate traiing timing for
* target freq.
*/
dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing);
gen_rk3399_ctl_params(&rk3399_dram_status.timing_config,
&dram_timing, index);
gen_rk3399_pi_params(&rk3399_dram_status.timing_config,
&dram_timing, index);
gen_rk3399_phy_params(&rk3399_dram_status.timing_config,
&rk3399_dram_status.drv_odt_lp_cfg,
&dram_timing, index);
rk3399_dram_status.index_freq[index] = mhz;
out:
return index;
}
void print_dram_status_info(void)
{
uint32_t *p;
uint32_t i;
p = (uint32_t *) &rk3399_dram_status.timing_config;
INFO("rk3399_dram_status.timing_config:\n");
for (i = 0; i < sizeof(struct timing_related_config) / 4; i++)
tf_printf("%u\n", p[i]);
p = (uint32_t *) &rk3399_dram_status.drv_odt_lp_cfg;
INFO("rk3399_dram_status.drv_odt_lp_cfg:\n");
for (i = 0; i < sizeof(struct drv_odt_lp_config) / 4; i++)
tf_printf("%u\n", p[i]);
}
uint32_t ddr_set_rate(uint32_t hz)
{
uint32_t low_power, index;
uint32_t mhz = hz / (1000 * 1000);
if (mhz ==
rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
goto out;
index = to_get_clk_index(mhz);
mhz = dpll_rates_table[index].mhz;
low_power = exit_low_power();
index = prepare_ddr_timing(mhz);
if (index > 1)
goto out;
dcf_start(mhz, index);
wait_dcf_done();
if (rk3399_dram_status.timing_config.odt == 0)
gen_rk3399_set_odt(0);
rk3399_dram_status.current_index = index;
if (mhz < dts_parameter.auto_pd_dis_freq)
low_power |= rk3399_dram_status.low_power_stat;
resume_low_power(low_power);
out:
return mhz;
}
uint32_t ddr_round_rate(uint32_t hz)
{
int index;
uint32_t mhz = hz / (1000 * 1000);
index = to_get_clk_index(mhz);
return dpll_rates_table[index].mhz * 1000 * 1000;
}
uint32_t dts_timing_receive(uint32_t timing, uint32_t index)
{
uint32_t *p = (uint32_t *) &dts_parameter;
static uint32_t receive_nums;
if (index < (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
p[index] = (uint32_t)timing;
receive_nums++;
} else {
dts_parameter.available = 0;
return -1;
}
/* receive all parameter */
if (receive_nums == (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
dts_parameter.available = 1;
receive_nums = 0;
}
return index;
}
void ddr_init(void)
{
dram_related_init(&dts_parameter);
}
......@@ -28,49 +28,131 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SOC_ROCKCHIP_RK3399_SDRAM_H__
#define __SOC_ROCKCHIP_RK3399_SDRAM_H__
struct rk3399_ddr_cic_regs {
uint32_t cic_ctrl0;
uint32_t cic_ctrl1;
uint32_t cic_idle_th;
uint32_t cic_cg_wait_th;
uint32_t cic_status0;
uint32_t cic_status1;
uint32_t cic_ctrl2;
uint32_t cic_ctrl3;
uint32_t cic_ctrl4;
};
#ifndef __SOC_ROCKCHIP_RK3399_DRAM_H__
#define __SOC_ROCKCHIP_RK3399_DRAM_H__
#include <plat_private.h>
#include <stdint.h>
#define CTL_BASE(ch) (0xffa80000 + (ch) * 0x8000)
#define CTL_REG(ch, n) (CTL_BASE(ch) + (n) * 0x4)
#define PI_OFFSET 0x800
#define PI_BASE(ch) (CTL_BASE(ch) + PI_OFFSET)
#define PI_REG(ch, n) (PI_BASE(ch) + (n) * 0x4)
#define PHY_OFFSET 0x2000
#define PHY_BASE(ch) (CTL_BASE(ch) + PHY_OFFSET)
#define PHY_REG(ch, n) (PHY_BASE(ch) + (n) * 0x4)
#define MSCH_BASE(ch) (0xffa84000 + (ch) * 0x8000)
#define MSCH_ID_COREID 0x0
#define MSCH_ID_REVISIONID 0x4
#define MSCH_DEVICECONF 0x8
#define MSCH_DEVICESIZE 0xc
#define MSCH_DDRTIMINGA0 0x10
#define MSCH_DDRTIMINGB0 0x14
#define MSCH_DDRTIMINGC0 0x18
#define MSCH_DEVTODEV0 0x1c
#define MSCH_DDRMODE 0x110
#define MSCH_AGINGX0 0x1000
#define CIC_CTRL0 0x0
#define CIC_CTRL1 0x4
#define CIC_IDLE_TH 0x8
#define CIC_CG_WAIT_TH 0xc
#define CIC_STATUS0 0x10
#define CIC_STATUS1 0x14
#define CIC_CTRL2 0x18
#define CIC_CTRL3 0x1c
#define CIC_CTRL4 0x20
/* DENALI_CTL_00 */
#define START (1)
#define START 1
/* DENALI_CTL_68 */
#define PWRUP_SREFRESH_EXIT (1 << 16)
/* DENALI_CTL_274 */
#define MEM_RST_VALID (1)
#define MEM_RST_VALID 1
#define PHY_DRV_ODT_Hi_Z 0x0
#define PHY_DRV_ODT_240 0x1
#define PHY_DRV_ODT_120 0x8
#define PHY_DRV_ODT_80 0x9
#define PHY_DRV_ODT_60 0xc
#define PHY_DRV_ODT_48 0xd
#define PHY_DRV_ODT_40 0xe
#define PHY_DRV_ODT_34_3 0xf
/*
* sys_reg bitfield struct
* [31] row_3_4_ch1
* [30] row_3_4_ch0
* [29:28] chinfo
* [27] rank_ch1
* [26:25] col_ch1
* [24] bk_ch1
* [23:22] cs0_row_ch1
* [21:20] cs1_row_ch1
* [19:18] bw_ch1
* [17:16] dbw_ch1;
* [15:13] ddrtype
* [12] channelnum
* [11] rank_ch0
* [10:9] col_ch0
* [8] bk_ch0
* [7:6] cs0_row_ch0
* [5:4] cs1_row_ch0
* [3:2] bw_ch0
* [1:0] dbw_ch0
*/
#define SYS_REG_ENC_ROW_3_4(n, ch) ((n) << (30 + (ch)))
#define SYS_REG_DEC_ROW_3_4(n, ch) (((n) >> (30 + (ch))) & 0x1)
#define SYS_REG_ENC_CHINFO(ch) (1 << (28 + (ch)))
#define SYS_REG_DEC_CHINFO(n, ch) (((n) >> (28 + (ch))) & 0x1)
#define SYS_REG_ENC_DDRTYPE(n) ((n) << 13)
#define SYS_REG_DEC_DDRTYPE(n) (((n) >> 13) & 0x7)
#define SYS_REG_ENC_NUM_CH(n) (((n) - 1) << 12)
#define SYS_REG_DEC_NUM_CH(n) (1 + (((n) >> 12) & 0x1))
#define SYS_REG_ENC_RANK(n, ch) (((n) - 1) << (11 + (ch) * 16))
#define SYS_REG_DEC_RANK(n, ch) (1 + (((n) >> (11 + (ch) * 16)) & 0x1))
#define SYS_REG_ENC_COL(n, ch) (((n) - 9) << (9 + (ch) * 16))
#define SYS_REG_DEC_COL(n, ch) (9 + (((n) >> (9 + (ch) * 16)) & 0x3))
#define SYS_REG_ENC_BK(n, ch) (((n) == 3 ? 0 : 1) << (8 + (ch) * 16))
#define SYS_REG_DEC_BK(n, ch) (3 - (((n) >> (8 + (ch) * 16)) & 0x1))
#define SYS_REG_ENC_CS0_ROW(n, ch) (((n) - 13) << (6 + (ch) * 16))
#define SYS_REG_DEC_CS0_ROW(n, ch) (13 + (((n) >> (6 + (ch) * 16)) & 0x3))
#define SYS_REG_ENC_CS1_ROW(n, ch) (((n) - 13) << (4 + (ch) * 16))
#define SYS_REG_DEC_CS1_ROW(n, ch) (13 + (((n) >> (4 + (ch) * 16)) & 0x3))
#define SYS_REG_ENC_BW(n, ch) ((2 >> (n)) << (2 + (ch) * 16))
#define SYS_REG_DEC_BW(n, ch) (2 >> (((n) >> (2 + (ch) * 16)) & 0x3))
#define SYS_REG_ENC_DBW(n, ch) ((2 >> (n)) << (0 + (ch) * 16))
#define SYS_REG_DEC_DBW(n, ch) (2 >> (((n) >> (0 + (ch) * 16)) & 0x3))
#define DDR_STRIDE(n) mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \
(0x1f<<(10+16))|((n)<<10))
#define CTL_REG_NUM 332
#define PHY_REG_NUM 959
#define PI_REG_NUM 200
enum {
DDR3 = 3,
LPDDR2 = 5,
LPDDR3 = 6,
LPDDR4 = 7,
UNUSED = 0xff
};
struct rk3399_ddr_pctl_regs {
uint32_t denali_ctl[332];
uint32_t denali_ctl[CTL_REG_NUM];
};
struct rk3399_ddr_publ_regs {
uint32_t denali_phy[959];
uint32_t denali_phy[PHY_REG_NUM];
};
#define PHY_DRV_ODT_Hi_Z (0x0)
#define PHY_DRV_ODT_240 (0x1)
#define PHY_DRV_ODT_120 (0x8)
#define PHY_DRV_ODT_80 (0x9)
#define PHY_DRV_ODT_60 (0xc)
#define PHY_DRV_ODT_48 (0xd)
#define PHY_DRV_ODT_40 (0xe)
#define PHY_DRV_ODT_34_3 (0xf)
struct rk3399_ddr_pi_regs {
uint32_t denali_pi[200];
uint32_t denali_pi[PI_REG_NUM];
};
union noc_ddrtiminga0 {
uint32_t d32;
......@@ -138,21 +220,6 @@ union noc_ddrmode {
} b;
};
struct rk3399_msch_regs {
uint32_t coreid;
uint32_t revisionid;
uint32_t ddrconf;
uint32_t ddrsize;
union noc_ddrtiminga0 ddrtiminga0;
union noc_ddrtimingb0 ddrtimingb0;
union noc_ddrtimingc0 ddrtimingc0;
union noc_devtodev0 devtodev0;
uint32_t reserved0[(0x110-0x20)/4];
union noc_ddrmode ddrmode;
uint32_t reserved1[(0x1000-0x114)/4];
uint32_t agingx0;
};
struct rk3399_msch_timings {
union noc_ddrtiminga0 ddrtiminga0;
union noc_ddrtimingb0 ddrtimingb0;
......@@ -161,7 +228,7 @@ struct rk3399_msch_timings {
union noc_ddrmode ddrmode;
uint32_t agingx0;
};
#if 1
struct rk3399_sdram_channel {
unsigned char rank;
/* col = 0, means this channel is invalid */
......@@ -193,137 +260,9 @@ struct rk3399_sdram_params {
struct rk3399_ddr_pi_regs pi_regs;
struct rk3399_ddr_publ_regs phy_regs;
};
#endif
struct rk3399_sdram_channel_config {
uint32_t bus_width;
uint32_t cs_cnt;
uint32_t cs0_row;
uint32_t cs1_row;
uint32_t bank;
uint32_t col;
uint32_t each_die_bus_width;
uint32_t each_die_6gb_or_12gb;
};
struct rk3399_sdram_config {
struct rk3399_sdram_channel_config ch[2];
uint32_t dramtype;
uint32_t channal_num;
};
struct rk3399_sdram_default_config {
unsigned char bl;
/* 1:auto precharge, 0:never auto precharge */
unsigned char ap;
/* dram driver strength */
unsigned char dramds;
/* dram ODT, if odt=0, this parameter invalid */
unsigned char dramodt;
/* ca ODT, if odt=0, this parameter invalid
* only used by LPDDR4
*/
unsigned char caodt;
unsigned char burst_ref_cnt;
/* zqcs period, unit(s) */
unsigned char zqcsi;
};
struct ddr_dts_config_timing {
unsigned int ddr3_speed_bin;
unsigned int pd_idle;
unsigned int sr_idle;
unsigned int sr_mc_gate_idle;
unsigned int srpd_lite_idle;
unsigned int standby_idle;
unsigned int auto_pd_dis_freq;
unsigned int ddr3_dll_dis_freq;
unsigned int phy_dll_dis_freq;
unsigned int ddr3_odt_dis_freq;
unsigned int ddr3_drv;
unsigned int ddr3_odt;
unsigned int phy_ddr3_ca_drv;
unsigned int phy_ddr3_dq_drv;
unsigned int phy_ddr3_odt;
unsigned int lpddr3_odt_dis_freq;
unsigned int lpddr3_drv;
unsigned int lpddr3_odt;
unsigned int phy_lpddr3_ca_drv;
unsigned int phy_lpddr3_dq_drv;
unsigned int phy_lpddr3_odt;
unsigned int lpddr4_odt_dis_freq;
unsigned int lpddr4_drv;
unsigned int lpddr4_dq_odt;
unsigned int lpddr4_ca_odt;
unsigned int phy_lpddr4_ca_drv;
unsigned int phy_lpddr4_ck_cs_drv;
unsigned int phy_lpddr4_dq_drv;
unsigned int phy_lpddr4_odt;
uint32_t available;
};
struct drv_odt_lp_config {
uint32_t ddr3_speed_bin;
uint32_t pd_idle;
uint32_t sr_idle;
uint32_t sr_mc_gate_idle;
uint32_t srpd_lite_idle;
uint32_t standby_idle;
uint32_t ddr3_dll_dis_freq;/* for ddr3 only */
uint32_t phy_dll_dis_freq;
uint32_t odt_dis_freq;
uint32_t dram_side_drv;
uint32_t dram_side_dq_odt;
uint32_t dram_side_ca_odt;
uint32_t phy_side_ca_drv;
uint32_t phy_side_ck_cs_drv;
uint32_t phy_side_dq_drv;
uint32_t phy_side_odt;
};
#define KHz (1000)
#define MHz (1000*KHz)
#define GHz (1000*MHz)
#define PI_CA_TRAINING (1 << 0)
#define PI_WRITE_LEVELING (1 << 1)
#define PI_READ_GATE_TRAINING (1 << 2)
#define PI_READ_LEVELING (1 << 3)
#define PI_WDQ_LEVELING (1 << 4)
#define PI_FULL_TARINING (0xff)
#define READ_CH_CNT(val) (1+((val>>12)&0x1))
#define READ_CH_INFO(val) ((val>>28)&0x3)
/* row_3_4:0=normal, 1=6Gb or 12Gb */
#define READ_CH_ROW_INFO(val, ch) ((val>>(30+(ch)))&0x1)
#define READ_DRAMTYPE_INFO(val) ((val>>13)&0x7)
#define READ_CS_INFO(val, ch) ((((val)>>(11+(ch)*16))&0x1)+1)
#define READ_BW_INFO(val, ch) (2>>(((val)>>(2+(ch)*16))&0x3))
#define READ_COL_INFO(val, ch) (9+(((val)>>(9+(ch)*16))&0x3))
#define READ_BK_INFO(val, ch) (3-(((val)>>(8+(ch)*16))&0x1))
#define READ_CS0_ROW_INFO(val, ch) (13+(((val)>>(6+(ch)*16))&0x3))
#define READ_CS1_ROW_INFO(val, ch) (13+(((val)>>(4+(ch)*16))&0x3))
#define READ_DIE_BW_INFO(val, ch) (2>>((val>>((ch)*16))&0x3))
#define __sramdata __attribute__((section(".sram.data")))
#define __sramconst __attribute__((section(".sram.rodata")))
#define __sramlocalfunc __attribute__((section(".sram.text")))
#define __sramfunc __attribute__((section(".sram.text"))) \
__attribute__((noinline))
#define DDR_SAVE_SP(save_sp) (save_sp = ddr_save_sp(((uint32_t)\
(SRAM_CODE_BASE + 0x2000) & (~7))))
extern __sramdata struct rk3399_sdram_params sdram_config;
#define DDR_RESTORE_SP(save_sp) ddr_save_sp(save_sp)
void dram_init(void);
void ddr_init(void);
uint32_t ddr_set_rate(uint32_t hz);
uint32_t ddr_round_rate(uint32_t hz);
uint32_t ddr_get_rate(void);
void clr_dcf_irq(void);
uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
#endif
......@@ -30,6 +30,7 @@
#include <string.h>
#include <stdint.h>
#include <dram.h>
#include "dram_spec_timing.h"
static const uint8_t ddr3_cl_cwl[][7] = {
......
......@@ -32,14 +32,6 @@
#define _DRAM_SPEC_TIMING_HEAD_
#include <stdint.h>
enum {
DDR3 = 3,
LPDDR2 = 5,
LPDDR3 = 6,
LPDDR4 = 7,
UNUSED = 0xFF
};
enum ddr3_speed_rate {
/* 5-5-5 */
DDR3_800D = 0,
......
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <debug.h>
#include <arch_helpers.h>
#include <platform_def.h>
#include <plat_private.h>
#include <dram.h>
#include <pmu_regs.h>
#include <rk3399_def.h>
#include <soc.h>
#include <suspend.h>
#define PMUGRF_OS_REG0 0x300
#define PMUGRF_OS_REG1 0x304
#define PMUGRF_OS_REG2 0x308
#define PMUGRF_OS_REG3 0x30c
#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \
((n) << (8 + (ch) * 4)))
#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \
((n) << (9 + (ch) * 4)))
#define FBDIV_ENC(n) ((n) << 16)
#define FBDIV_DEC(n) (((n) >> 16) & 0xfff)
#define POSTDIV2_ENC(n) ((n) << 12)
#define POSTDIV2_DEC(n) (((n) >> 12) & 0x7)
#define POSTDIV1_ENC(n) ((n) << 8)
#define POSTDIV1_DEC(n) (((n) >> 8) & 0x7)
#define REFDIV_ENC(n) (n)
#define REFDIV_DEC(n) ((n) & 0x3f)
/* PMU CRU */
#define PMUCRU_RSTNHOLD_CON0 0x120
#define PMUCRU_RSTNHOLD_CON1 0x124
#define PRESET_GPIO0_HOLD(n) (((n) << 7) | WMSK_BIT(7))
#define PRESET_GPIO1_HOLD(n) (((n) << 8) | WMSK_BIT(8))
#define SYS_COUNTER_FREQ_IN_MHZ (SYS_COUNTER_FREQ_IN_TICKS / 1000000)
/*
* Copy @num registers from @src to @dst
*/
__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
{
while (num--) {
mmio_write_32(dst, mmio_read_32(src));
dst += sizeof(uint32_t);
src += sizeof(uint32_t);
}
}
static __sramfunc uint32_t sram_get_timer_value(void)
{
/*
* Generic delay timer implementation expects the timer to be a down
* counter. We apply bitwise NOT operator to the tick values returned
* by read_cntpct_el0() to simulate the down counter.
*/
return (uint32_t)(~read_cntpct_el0());
}
static __sramfunc void sram_udelay(uint32_t usec)
{
uint32_t start, cnt, delta, delta_us;
/* counter is decreasing */
start = sram_get_timer_value();
do {
cnt = sram_get_timer_value();
if (cnt > start) {
delta = UINT32_MAX - cnt;
delta += start;
} else
delta = start - cnt;
delta_us = (delta * SYS_COUNTER_FREQ_IN_MHZ);
} while (delta_us < usec);
}
static __sramfunc void configure_sgrf(void)
{
/*
* SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK:
* IC ECO bug, need to set this register.
*
* SGRF_DDR_RGN_BYPS:
* After the PD_CENTER suspend/resume, the DDR region
* related registers in the SGRF will be reset, we
* need to re-initialize them.
*/
mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
SGRF_DDR_RGN_DPLL_CLK |
SGRF_DDR_RGN_RTC_CLK |
SGRF_DDR_RGN_BYPS);
}
static __sramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
uint32_t phy)
{
channel &= 0x1;
ctl &= 0x1;
phy &= 0x1;
mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(4),
CRU_SFTRST_DDR_CTRL(channel, ctl) |
CRU_SFTRST_DDR_PHY(channel, phy));
}
static __sramfunc void phy_pctrl_reset(uint32_t ch)
{
rkclk_ddr_reset(ch, 1, 1);
sram_udelay(10);
rkclk_ddr_reset(ch, 1, 0);
sram_udelay(10);
rkclk_ddr_reset(ch, 0, 0);
sram_udelay(10);
}
static __sramfunc void phy_dll_bypass_set(uint32_t ch, uint32_t hz)
{
if (hz <= 125 * MHz) {
/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
mmio_setbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
mmio_setbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
mmio_setbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
mmio_setbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
mmio_setbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
mmio_setbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
mmio_setbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
} else {
/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
mmio_clrbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
mmio_clrbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
mmio_clrbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
mmio_clrbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
mmio_clrbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
mmio_clrbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
mmio_clrbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
}
}
static __sramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
{
/* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */
mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 24, rank << 24);
mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 24, rank << 24);
mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 24, rank << 24);
mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 24, rank << 24);
}
static __sramfunc void select_per_cs_training_index(uint32_t ch, uint32_t rank)
{
/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1)
set_cs_training_index(ch, rank);
}
static void override_write_leveling_value(uint32_t ch)
{
uint32_t byte;
/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
mmio_setbits_32(PHY_REG(ch, 896), 1);
/*
* PHY_8/136/264/392
* phy_per_cs_training_multicast_en_X 1bit offset_16
*/
mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 16, 1 << 16);
mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 16, 1 << 16);
mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 16, 1 << 16);
mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 16, 1 << 16);
for (byte = 0; byte < 4; byte++)
mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)),
0xffff << 16,
0x200 << 16);
/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
mmio_clrbits_32(PHY_REG(ch, 896), 1);
/* CTL_200 ctrlupd_req 1bit offset_8 */
mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8);
}
static __sramfunc int data_training(uint32_t ch,
struct rk3399_sdram_params *sdram_params,
uint32_t training_flag)
{
uint32_t obs_0, obs_1, obs_2, obs_3, obs_err = 0;
uint32_t rank = sdram_params->ch[ch].rank;
uint32_t rank_mask;
uint32_t i, tmp;
if (sdram_params->dramtype == LPDDR4)
rank_mask = (rank == 1) ? 0x5 : 0xf;
else
rank_mask = (rank == 1) ? 0x1 : 0x3;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
mmio_setbits_32(PHY_REG(ch, 927), (1 << 22));
if (training_flag == PI_FULL_TRAINING) {
if (sdram_params->dramtype == LPDDR4) {
training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING |
PI_WDQ_LEVELING;
} else if (sdram_params->dramtype == LPDDR3) {
training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING;
} else if (sdram_params->dramtype == DDR3) {
training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING;
}
}
/* ca training(LPDDR4,LPDDR3 support) */
if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
for (i = 0; i < 4; i++) {
if (!(rank_mask & (1 << i)))
continue;
select_per_cs_training_index(ch, i);
/* PI_100 PI_CALVL_EN:RW:8:2 */
mmio_clrsetbits_32(PI_REG(ch, 100), 0x3 << 8, 0x2 << 8);
/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
mmio_clrsetbits_32(PI_REG(ch, 92),
(0x1 << 16) | (0x3 << 24),
(0x1 << 16) | (i << 24));
while (1) {
/* PI_174 PI_INT_STATUS:RD:8:18 */
tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
/*
* check status obs
* PHY_532/660/788 phy_adr_calvl_obs1_:0:32
*/
obs_0 = mmio_read_32(PHY_REG(ch, 532));
obs_1 = mmio_read_32(PHY_REG(ch, 660));
obs_2 = mmio_read_32(PHY_REG(ch, 788));
if (((obs_0 >> 30) & 0x3) ||
((obs_1 >> 30) & 0x3) ||
((obs_2 >> 30) & 0x3))
obs_err = 1;
if ((((tmp >> 11) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 5) & 0x1) == 0x0) &&
(obs_err == 0))
break;
else if ((((tmp >> 5) & 0x1) == 0x1) ||
(obs_err == 1))
return -1;
}
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
}
mmio_clrbits_32(PI_REG(ch, 100), 0x3 << 8);
}
/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
for (i = 0; i < rank; i++) {
select_per_cs_training_index(ch, i);
/* PI_60 PI_WRLVL_EN:RW:8:2 */
mmio_clrsetbits_32(PI_REG(ch, 60), 0x3 << 8, 0x2 << 8);
/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
mmio_clrsetbits_32(PI_REG(ch, 59),
(0x1 << 8) | (0x3 << 16),
(0x1 << 8) | (i << 16));
while (1) {
/* PI_174 PI_INT_STATUS:RD:8:18 */
tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
/*
* check status obs, if error maybe can not
* get leveling done PHY_40/168/296/424
* phy_wrlvl_status_obs_X:0:13
*/
obs_0 = mmio_read_32(PHY_REG(ch, 40));
obs_1 = mmio_read_32(PHY_REG(ch, 168));
obs_2 = mmio_read_32(PHY_REG(ch, 296));
obs_3 = mmio_read_32(PHY_REG(ch, 424));
if (((obs_0 >> 12) & 0x1) ||
((obs_1 >> 12) & 0x1) ||
((obs_2 >> 12) & 0x1) ||
((obs_3 >> 12) & 0x1))
obs_err = 1;
if ((((tmp >> 10) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 4) & 0x1) == 0x0) &&
(obs_err == 0))
break;
else if ((((tmp >> 4) & 0x1) == 0x1) ||
(obs_err == 1))
return -1;
}
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
}
override_write_leveling_value(ch);
mmio_clrbits_32(PI_REG(ch, 60), 0x3 << 8);
}
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
for (i = 0; i < rank; i++) {
select_per_cs_training_index(ch, i);
/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 24,
0x2 << 24);
/*
* PI_74 PI_RDLVL_GATE_REQ:WR:16:1
* PI_RDLVL_CS:RW:24:2
*/
mmio_clrsetbits_32(PI_REG(ch, 74),
(0x1 << 16) | (0x3 << 24),
(0x1 << 16) | (i << 24));
while (1) {
/* PI_174 PI_INT_STATUS:RD:8:18 */
tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
/*
* check status obs
* PHY_43/171/299/427
* PHY_GTLVL_STATUS_OBS_x:16:8
*/
obs_0 = mmio_read_32(PHY_REG(ch, 43));
obs_1 = mmio_read_32(PHY_REG(ch, 171));
obs_2 = mmio_read_32(PHY_REG(ch, 299));
obs_3 = mmio_read_32(PHY_REG(ch, 427));
if (((obs_0 >> (16 + 6)) & 0x3) ||
((obs_1 >> (16 + 6)) & 0x3) ||
((obs_2 >> (16 + 6)) & 0x3) ||
((obs_3 >> (16 + 6)) & 0x3))
obs_err = 1;
if ((((tmp >> 9) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 3) & 0x1) == 0x0) &&
(obs_err == 0))
break;
else if ((((tmp >> 3) & 0x1) == 0x1) ||
(obs_err == 1))
return -1;
}
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
}
mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 24);
}
/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
for (i = 0; i < rank; i++) {
select_per_cs_training_index(ch, i);
/* PI_80 PI_RDLVL_EN:RW:16:2 */
mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 16,
0x2 << 16);
/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
mmio_clrsetbits_32(PI_REG(ch, 74),
(0x1 << 8) | (0x3 << 24),
(0x1 << 8) | (i << 24));
while (1) {
/* PI_174 PI_INT_STATUS:RD:8:18 */
tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
/*
* make sure status obs not report error bit
* PHY_46/174/302/430
* phy_rdlvl_status_obs_X:16:8
*/
if ((((tmp >> 8) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 2) & 0x1) == 0x0))
break;
else if (((tmp >> 2) & 0x1) == 0x1)
return -1;
}
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
}
mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 16);
}
/* wdq leveling(LPDDR4 support) */
if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
for (i = 0; i < 4; i++) {
if (!(rank_mask & (1 << i)))
continue;
select_per_cs_training_index(ch, i);
/*
* disable PI_WDQLVL_VREF_EN before wdq leveling?
* PI_181 PI_WDQLVL_VREF_EN:RW:8:1
*/
mmio_clrbits_32(PI_REG(ch, 181), 0x1 << 8);
/* PI_124 PI_WDQLVL_EN:RW:16:2 */
mmio_clrsetbits_32(PI_REG(ch, 124), 0x3 << 16,
0x2 << 16);
/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
mmio_clrsetbits_32(PI_REG(ch, 121),
(0x1 << 8) | (0x3 << 16),
(0x1 << 8) | (i << 16));
while (1) {
/* PI_174 PI_INT_STATUS:RD:8:18 */
tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
if ((((tmp >> 12) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 6) & 0x1) == 0x0))
break;
else if (((tmp >> 6) & 0x1) == 0x1)
return -1;
}
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
}
mmio_clrbits_32(PI_REG(ch, 124), 0x3 << 16);
}
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
mmio_clrbits_32(PHY_REG(ch, 927), (1 << 22));
return 0;
}
static __sramfunc void set_ddrconfig(struct rk3399_sdram_params *sdram_params,
unsigned char channel, uint32_t ddrconfig)
{
/* only need to set ddrconfig */
struct rk3399_sdram_channel *ch = &sdram_params->ch[channel];
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
cs0_cap = (1 << (ch->cs0_row + ch->col + ch->bk + ch->bw - 20));
if (ch->rank > 1)
cs1_cap = cs0_cap >> (ch->cs0_row - ch->cs1_row);
if (ch->row_3_4) {
cs0_cap = cs0_cap * 3 / 4;
cs1_cap = cs1_cap * 3 / 4;
}
mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICECONF,
ddrconfig | (ddrconfig << 6));
mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICESIZE,
((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8));
}
static __sramfunc void dram_all_config(struct rk3399_sdram_params *sdram_params)
{
unsigned int i;
for (i = 0; i < 2; i++) {
struct rk3399_sdram_channel *info = &sdram_params->ch[i];
struct rk3399_msch_timings *noc = &info->noc_timings;
if (sdram_params->ch[i].col == 0)
continue;
mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGA0,
noc->ddrtiminga0.d32);
mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGB0,
noc->ddrtimingb0.d32);
mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGC0,
noc->ddrtimingc0.d32);
mmio_write_32(MSCH_BASE(i) + MSCH_DEVTODEV0,
noc->devtodev0.d32);
mmio_write_32(MSCH_BASE(i) + MSCH_DDRMODE, noc->ddrmode.d32);
/* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
if (sdram_params->ch[i].rank == 1)
mmio_setbits_32(CTL_REG(i, 276), 1 << 17);
}
DDR_STRIDE(sdram_params->stride);
/* reboot hold register set */
mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
CRU_PMU_SGRF_RST_RLS |
PRESET_GPIO0_HOLD(1) |
PRESET_GPIO1_HOLD(1));
mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3);
}
static __sramfunc void pctl_cfg(uint32_t ch,
struct rk3399_sdram_params *sdram_params)
{
const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl;
const uint32_t *params_phy = sdram_params->phy_regs.denali_phy;
const uint32_t *params_pi = sdram_params->pi_regs.denali_pi;
uint32_t tmp, tmp1, tmp2;
/*
* Workaround controller bug:
* Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
*/
sram_regcpy(CTL_REG(ch, 1), (uintptr_t)&params_ctl[1],
CTL_REG_NUM - 1);
mmio_write_32(CTL_REG(ch, 0), params_ctl[0]);
sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_pi[0],
PI_REG_NUM);
mmio_write_32(PHY_REG(ch, 910), params_phy[910]);
mmio_write_32(PHY_REG(ch, 911), params_phy[911]);
mmio_write_32(PHY_REG(ch, 912), params_phy[912]);
mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT,
PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */
mmio_clrsetbits_32(PHY_REG(ch, 957), 0x3 << 24, 1 << 24);
dmbst();
mmio_setbits_32(PI_REG(ch, 0), START);
mmio_setbits_32(CTL_REG(ch, 0), START);
/* wait lock */
while (1) {
tmp = mmio_read_32(PHY_REG(ch, 920));
tmp1 = mmio_read_32(PHY_REG(ch, 921));
tmp2 = mmio_read_32(PHY_REG(ch, 922));
if ((((tmp >> 16) & 0x1) == 0x1) &&
(((tmp1 >> 16) & 0x1) == 0x1) &&
(((tmp1 >> 0) & 0x1) == 0x1) &&
(((tmp2 >> 0) & 0x1) == 0x1))
break;
/* if PLL bypass,don't need wait lock */
if (mmio_read_32(PHY_REG(ch, 911)) & 0x1)
break;
}
sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&params_phy[896], 63);
sram_regcpy(PHY_REG(ch, 0), (uintptr_t)&params_phy[0], 91);
sram_regcpy(PHY_REG(ch, 128), (uintptr_t)&params_phy[128], 91);
sram_regcpy(PHY_REG(ch, 256), (uintptr_t)&params_phy[256], 91);
sram_regcpy(PHY_REG(ch, 384), (uintptr_t)&params_phy[384], 91);
sram_regcpy(PHY_REG(ch, 512), (uintptr_t)&params_phy[512], 38);
sram_regcpy(PHY_REG(ch, 640), (uintptr_t)&params_phy[640], 38);
sram_regcpy(PHY_REG(ch, 768), (uintptr_t)&params_phy[768], 38);
}
static __sramfunc int dram_switch_to_phy_index1(
struct rk3399_sdram_params *sdram_params)
{
uint32_t ch, ch_count;
mmio_write_32(CIC_BASE + CIC_CTRL0,
(((0x3 << 4) | (1 << 2) | 1) << 16) |
(1 << 4) | (1 << 2) | 1);
while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)))
;
mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002);
while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)))
;
ch_count = sdram_params->num_channels;
/* LPDDR4 f2 cann't do training, all training will fail */
for (ch = 0; ch < ch_count; ch++) {
mmio_clrsetbits_32(PHY_REG(ch, 896), (0x3 << 8) | 1,
1 << 8);
/* data_training failed */
if (data_training(ch, sdram_params, PI_FULL_TRAINING))
return -1;
}
return 0;
}
/*
* Needs to be done for both channels at once in case of a shared reset signal
* between channels.
*/
static __sramfunc int pctl_start(uint32_t channel_mask,
struct rk3399_sdram_params *sdram_params)
{
uint32_t count;
mmio_setbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
mmio_setbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
/* need de-access IO retention before controller START */
if (channel_mask & (1 << 0))
mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 19));
if (channel_mask & (1 << 1))
mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 23));
/* PHY_DLL_RST_EN */
if (channel_mask & (1 << 0))
mmio_clrsetbits_32(PHY_REG(0, 957), 0x3 << 24,
0x2 << 24);
if (channel_mask & (1 << 1))
mmio_clrsetbits_32(PHY_REG(1, 957), 0x3 << 24,
0x2 << 24);
/* check ERROR bit */
if (channel_mask & (1 << 0)) {
count = 0;
while (!(mmio_read_32(CTL_REG(0, 203)) & (1 << 3))) {
/* CKE is low, loop 10ms */
if (count > 100)
return -1;
sram_udelay(100);
count++;
}
mmio_clrbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
}
if (channel_mask & (1 << 1)) {
count = 0;
while (!(mmio_read_32(CTL_REG(1, 203)) & (1 << 3))) {
/* CKE is low, loop 10ms */
if (count > 100)
return -1;
sram_udelay(100);
count++;
}
mmio_clrbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
}
return 0;
}
void dmc_save(void)
{
struct rk3399_sdram_params *sdram_params = &sdram_config;
uint32_t *params_ctl;
uint32_t *params_pi;
uint32_t *params_phy;
uint32_t refdiv, postdiv2, postdiv1, fbdiv;
uint32_t tmp;
params_ctl = sdram_params->pctl_regs.denali_ctl;
params_pi = sdram_params->pi_regs.denali_pi;
params_phy = sdram_params->phy_regs.denali_phy;
fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
tmp = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1));
postdiv2 = POSTDIV2_DEC(tmp);
postdiv1 = POSTDIV1_DEC(tmp);
refdiv = REFDIV_DEC(tmp);
sdram_params->ddr_freq = ((fbdiv * 24) /
(refdiv * postdiv1 * postdiv2)) * MHz;
INFO("sdram_params->ddr_freq = %d\n", sdram_params->ddr_freq);
sdram_params->odt = (((mmio_read_32(PHY_REG(0, 5)) >> 16) &
0x7) != 0) ? 1 : 0;
/* copy the registers CTL PI and PHY */
sram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
/* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */
params_ctl[0] &= ~(0x1 << 0);
sram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
PI_REG_NUM);
/* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/
params_pi[0] &= ~(0x1 << 0);
sram_regcpy((uintptr_t)&params_phy[0], PHY_REG(0, 0), 91);
sram_regcpy((uintptr_t)&params_phy[128], PHY_REG(0, 128), 91);
sram_regcpy((uintptr_t)&params_phy[256], PHY_REG(0, 256), 91);
sram_regcpy((uintptr_t)&params_phy[384], PHY_REG(0, 384), 91);
sram_regcpy((uintptr_t)&params_phy[512], PHY_REG(0, 512), 38);
sram_regcpy((uintptr_t)&params_phy[640], PHY_REG(0, 640), 38);
sram_regcpy((uintptr_t)&params_phy[768], PHY_REG(0, 768), 38);
sram_regcpy((uintptr_t)&params_phy[896], PHY_REG(0, 896), 63);
/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
params_phy[957] &= ~(0x3 << 24);
params_phy[957] |= 1 << 24;
params_phy[896] |= 1;
params_phy[896] &= ~(0x3 << 8);
}
__sramfunc void dmc_restore(void)
{
struct rk3399_sdram_params *sdram_params = &sdram_config;
uint32_t channel_mask = 0;
uint32_t channel;
configure_sgrf();
retry:
for (channel = 0; channel < sdram_params->num_channels; channel++) {
phy_pctrl_reset(channel);
phy_dll_bypass_set(channel, sdram_params->ddr_freq);
if (channel >= sdram_params->num_channels)
continue;
pctl_cfg(channel, sdram_params);
}
for (channel = 0; channel < 2; channel++) {
if (sdram_params->ch[channel].col)
channel_mask |= 1 << channel;
}
if (pctl_start(channel_mask, sdram_params) < 0)
goto retry;
for (channel = 0; channel < sdram_params->num_channels; channel++) {
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (sdram_params->dramtype == LPDDR3)
sram_udelay(10);
/* If traning fail, retry to do it again. */
if (data_training(channel, sdram_params, PI_FULL_TRAINING))
goto retry;
set_ddrconfig(sdram_params, channel,
sdram_params->ch[channel].ddrconfig);
}
dram_all_config(sdram_params);
/* Switch to index 1 and prepare for DDR frequency switch. */
dram_switch_to_phy_index1(sdram_params);
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SOC_ROCKCHIP_RK3399_SUSPEND_H__
#define __SOC_ROCKCHIP_RK3399_SUSPEND_H__
#include <dram.h>
#define KHz (1000)
#define MHz (1000 * KHz)
#define GHz (1000 * MHz)
#define PI_CA_TRAINING (1 << 0)
#define PI_WRITE_LEVELING (1 << 1)
#define PI_READ_GATE_TRAINING (1 << 2)
#define PI_READ_LEVELING (1 << 3)
#define PI_WDQ_LEVELING (1 << 4)
#define PI_FULL_TRAINING (0xff)
void dmc_save(void);
__sramfunc void dmc_restore(void);
__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num);
#endif /* __DRAM_H__ */
......@@ -27,9 +27,25 @@
#include <arch.h>
#include <asm_macros.S>
#include <platform_def.h>
#include <pmu_regs.h>
.globl clst_warmboot_data
.macro sram_func _name
.section .sram.text, "ax"
.type \_name, %function
.func \_name
\_name:
.endm
#define CRU_CLKSEL_CON6 0x118
#define DDRCTL0_C_SYSREQ_CFG 0x0100
#define DDRCTL1_C_SYSREQ_CFG 0x1000
#define DDRC0_SREF_DONE_EXT 0x01
#define DDRC1_SREF_DONE_EXT 0x04
#define PLL_MODE_SHIFT (0x8)
#define PLL_NORMAL_MODE ((0x3 << (PLL_MODE_SHIFT + 16)) | \
(0x1 << PLL_MODE_SHIFT))
......@@ -65,3 +81,75 @@ clst_warmboot_data:
.word 0
.endr
.endm
/* -----------------------------------------------
* void sram_func_set_ddrctl_pll(uint32_t pll_src)
* Function to switch the PLL source for ddrctrl
* In: x0 - The PLL of the clk_ddrc clock source
* out: None
* Clobber list : x0 - x3, x5, x8 - x10
* -----------------------------------------------
*/
.globl sram_func_set_ddrctl_pll
sram_func sram_func_set_ddrctl_pll
/* backup parameter */
mov x8, x0
/* disable the MMU at EL3 */
mrs x9, sctlr_el3
bic x10, x9, #(SCTLR_M_BIT)
msr sctlr_el3, x10
isb
dsb sy
/* enable ddrctl0_1 idle request */
mov x5, PMU_BASE
ldr w0, [x5, #PMU_SFT_CON]
orr w0, w0, #DDRCTL0_C_SYSREQ_CFG
orr w0, w0, #DDRCTL1_C_SYSREQ_CFG
str w0, [x5, #PMU_SFT_CON]
check_ddrc0_1_sref_enter:
ldr w1, [x5, #PMU_DDR_SREF_ST]
and w2, w1, #DDRC0_SREF_DONE_EXT
and w3, w1, #DDRC1_SREF_DONE_EXT
orr w2, w2, w3
cmp w2, #(DDRC0_SREF_DONE_EXT | DDRC1_SREF_DONE_EXT)
b.eq check_ddrc0_1_sref_enter
/*
* select a PLL for ddrctrl:
* x0 = 0: ALPLL
* x0 = 1: ABPLL
* x0 = 2: DPLL
* x0 = 3: GPLLL
*/
mov x5, CRU_BASE
lsl w0, w8, #4
orr w0, w0, #0x00300000
str w0, [x5, #CRU_CLKSEL_CON6]
/* disable ddrctl0_1 idle request */
mov x5, PMU_BASE
ldr w0, [x5, #PMU_SFT_CON]
bic w0, w0, #DDRCTL0_C_SYSREQ_CFG
bic w0, w0, #DDRCTL1_C_SYSREQ_CFG
str w0, [x5, #PMU_SFT_CON]
check_ddrc0_1_sref_exit:
ldr w1, [x5, #PMU_DDR_SREF_ST]
and w2, w1, #DDRC0_SREF_DONE_EXT
and w3, w1, #DDRC1_SREF_DONE_EXT
orr w2, w2, w3
cmp w2, #0x0
b.eq check_ddrc0_1_sref_exit
/* reenable the MMU at EL3 */
msr sctlr_el3, x9
isb
dsb sy
ret
endfunc sram_func_set_ddrctl_pll
......@@ -46,9 +46,9 @@
#include <pmu.h>
#include <pmu_com.h>
#include <pwm.h>
#include <soc.h>
#include <bl31.h>
#include <rk3399m0.h>
#include <suspend.h>
DEFINE_BAKERY_LOCK(rockchip_pd_lock);
......@@ -102,7 +102,6 @@ static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
bus_ack);
}
}
struct pmu_slpdata_s pmu_slpdata;
......@@ -818,10 +817,19 @@ static void init_pmu_counts(void)
mmio_write_32(PMU_BASE + PMU_GPU_PWRUP_CNT, CYCL_24M_CNT_US(1));
}
static uint32_t clk_ddrc_save;
static void sys_slp_config(void)
{
uint32_t slp_mode_cfg = 0;
/* keep enabling clk_ddrc_bpll_src_en gate for DDRC */
clk_ddrc_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(3));
mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), WMSK_BIT(1));
prepare_abpll_for_ddrctrl();
sram_func_set_ddrctl_pll(ABPLL_ID);
mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP);
mmio_write_32(PMU_BASE + PMU_CCI500_CON,
BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
......@@ -849,6 +857,7 @@ static void sys_slp_config(void)
BIT(PMU_DDRIO0_RET_EN) |
BIT(PMU_DDRIO1_RET_EN) |
BIT(PMU_DDRIO_RET_HW_DE_REQ) |
BIT(PMU_CENTER_PD_EN) |
BIT(PMU_PLL_PD_EN) |
BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
BIT(PMU_OSC_DIS) |
......@@ -857,7 +866,6 @@ static void sys_slp_config(void)
mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN));
mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW);
mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K);
mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */
......@@ -1094,6 +1102,9 @@ static int sys_pwr_domain_suspend(void)
uint32_t wait_cnt = 0;
uint32_t status = 0;
dmc_save();
pmu_scu_b_pwrdn();
pmu_power_domains_suspend();
set_hw_idle(BIT(PMU_CLR_CENTER1) |
BIT(PMU_CLR_ALIVE) |
......@@ -1114,8 +1125,6 @@ static int sys_pwr_domain_suspend(void)
(PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
CPU_BOOT_ADDR_WMASK);
pmu_scu_b_pwrdn();
mmio_write_32(PMU_BASE + PMU_ADB400_CON,
BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
......@@ -1134,6 +1143,7 @@ static int sys_pwr_domain_suspend(void)
}
}
mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
/*
* Disabling PLLs/PWM/DVFS is approaching WFI which is
* the last steps in suspend.
......@@ -1163,6 +1173,10 @@ static int sys_pwr_domain_resume(void)
enable_dvfs_plls();
plls_resume_finish();
/* restore clk_ddrc_bpll_src_en gate */
mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0));
/*
* The wakeup status is not cleared by itself, we need to clear it
* manually. Otherwise we will alway query some interrupt next time.
......@@ -1209,8 +1223,12 @@ static int sys_pwr_domain_resume(void)
pmu_sgrf_rst_hld_release();
pmu_scu_b_pwrup();
pmu_power_domains_resume();
restore_dpll();
sram_func_set_ddrctl_pll(DPLL_ID);
restore_abpll();
clr_hw_idle(BIT(PMU_CLR_CENTER1) |
BIT(PMU_CLR_ALIVE) |
BIT(PMU_CLR_MSCH0) |
......@@ -1301,9 +1319,10 @@ void plat_rockchip_pmu_init(void)
for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
clst_warmboot_data[cpu] = 0;
psram_sleep_cfg->ddr_func = 0x00;
psram_sleep_cfg->ddr_data = 0x00;
psram_sleep_cfg->ddr_flag = 0x00;
psram_sleep_cfg->ddr_func = (uint64_t)dmc_restore;
psram_sleep_cfg->ddr_data = (uint64_t)&sdram_config;
psram_sleep_cfg->ddr_flag = 0x01;
psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
/* config cpu's warm boot address */
......
......@@ -31,6 +31,9 @@
#ifndef __PMU_H__
#define __PMU_H__
#include <pmu_regs.h>
#include <soc.h>
/* Allocate sp reginon in pmusram */
#define PSRAM_SP_SIZE 0x80
#define PSRAM_SP_BOTTOM (PSRAM_SP_TOP - PSRAM_SP_SIZE)
......@@ -751,72 +754,7 @@ enum pmu_core_pwr_st {
STANDBY_BY_WFIL2_CLUSTER_B,
};
#define PMU_WKUP_CFG0 0x00
#define PMU_WKUP_CFG1 0x04
#define PMU_WKUP_CFG2 0x08
#define PMU_WKUP_CFG3 0x0c
#define PMU_WKUP_CFG4 0x10
#define PMU_PWRDN_CON 0x14
#define PMU_PWRDN_ST 0x18
#define PMU_PLL_CON 0x1c
#define PMU_PWRMODE_CON 0x20
#define PMU_SFT_CON 0x24
#define PMU_INT_CON 0x28
#define PMU_INT_ST 0x2c
#define PMU_GPIO0_POS_INT_CON 0x30
#define PMU_GPIO0_NEG_INT_CON 0x34
#define PMU_GPIO1_POS_INT_CON 0x38
#define PMU_GPIO1_NEG_INT_CON 0x3c
#define PMU_GPIO0_POS_INT_ST 0x40
#define PMU_GPIO0_NEG_INT_ST 0x44
#define PMU_GPIO1_POS_INT_ST 0x48
#define PMU_GPIO1_NEG_INT_ST 0x4c
#define PMU_PWRDN_INTEN 0x50
#define PMU_PWRDN_STATUS 0x54
#define PMU_WAKEUP_STATUS 0x58
#define PMU_BUS_CLR 0x5c
#define PMU_BUS_IDLE_REQ 0x60
#define PMU_BUS_IDLE_ST 0x64
#define PMU_BUS_IDLE_ACK 0x68
#define PMU_CCI500_CON 0x6c
#define PMU_ADB400_CON 0x70
#define PMU_ADB400_ST 0x74
#define PMU_POWER_ST 0x78
#define PMU_CORE_PWR_ST 0x7c
#define PMU_OSC_CNT 0x80
#define PMU_PLLLOCK_CNT 0x84
#define PMU_PLLRST_CNT 0x88
#define PMU_STABLE_CNT 0x8c
#define PMU_DDRIO_PWRON_CNT 0x90
#define PMU_WAKEUP_RST_CLR_CNT 0x94
#define PMU_DDR_SREF_ST 0x98
#define PMU_SCU_L_PWRDN_CNT 0x9c
#define PMU_SCU_L_PWRUP_CNT 0xa0
#define PMU_SCU_B_PWRDN_CNT 0xa4
#define PMU_SCU_B_PWRUP_CNT 0xa8
#define PMU_GPU_PWRDN_CNT 0xac
#define PMU_GPU_PWRUP_CNT 0xb0
#define PMU_CENTER_PWRDN_CNT 0xb4
#define PMU_CENTER_PWRUP_CNT 0xb8
#define PMU_TIMEOUT_CNT 0xbc
#define PMU_CPU0APM_CON 0xc0
#define PMU_CPU1APM_CON 0xc4
#define PMU_CPU2APM_CON 0xc8
#define PMU_CPU3APM_CON 0xcc
#define PMU_CPU0BPM_CON 0xd0
#define PMU_CPU1BPM_CON 0xd4
#define PMU_NOC_AUTO_ENA 0xd8
#define PMU_PWRDN_CON1 0xdc
#define PMUGRF_GPIO0A_IOMUX 0x00
#define PMUGRF_GPIO1A_IOMUX 0x10
#define PMUGRF_GPIO1C_IOMUX 0x18
#define PMUGRF_GPIO0A6_IOMUX_SHIFT 12
#define PMUGRF_GPIO0A6_IOMUX_PWM 0x1
#define PMUGRF_GPIO1C3_IOMUX_SHIFT 6
#define PMUGRF_GPIO1C3_IOMUX_PWM 0x1
/* Specific features required */
#define AP_PWROFF 0x0a
#define GPIO0A0_SMT_ENABLE BITS_WITH_WMASK(1, 3, 0)
......@@ -824,51 +762,6 @@ enum pmu_core_pwr_st {
#define TSADC_INT_PIN 38
#define CORES_PM_DISABLE 0x0
#define CPU_AXI_QOS_ID_COREID 0x00
#define CPU_AXI_QOS_REVISIONID 0x04
#define CPU_AXI_QOS_PRIORITY 0x08
#define CPU_AXI_QOS_MODE 0x0c
#define CPU_AXI_QOS_BANDWIDTH 0x10
#define CPU_AXI_QOS_SATURATION 0x14
#define CPU_AXI_QOS_EXTCONTROL 0x18
#define CPU_AXI_QOS_NUM_REGS 0x07
#define CPU_AXI_CCI_M0_QOS_BASE 0xffa50000
#define CPU_AXI_CCI_M1_QOS_BASE 0xffad8000
#define CPU_AXI_DMAC0_QOS_BASE 0xffa64200
#define CPU_AXI_DMAC1_QOS_BASE 0xffa64280
#define CPU_AXI_DCF_QOS_BASE 0xffa64180
#define CPU_AXI_CRYPTO0_QOS_BASE 0xffa64100
#define CPU_AXI_CRYPTO1_QOS_BASE 0xffa64080
#define CPU_AXI_PMU_CM0_QOS_BASE 0xffa68000
#define CPU_AXI_PERI_CM1_QOS_BASE 0xffa64300
#define CPU_AXI_GIC_QOS_BASE 0xffa78000
#define CPU_AXI_SDIO_QOS_BASE 0xffa76000
#define CPU_AXI_SDMMC_QOS_BASE 0xffa74000
#define CPU_AXI_EMMC_QOS_BASE 0xffa58000
#define CPU_AXI_GMAC_QOS_BASE 0xffa5c000
#define CPU_AXI_USB_OTG0_QOS_BASE 0xffa70000
#define CPU_AXI_USB_OTG1_QOS_BASE 0xffa70080
#define CPU_AXI_USB_HOST0_QOS_BASE 0xffa60100
#define CPU_AXI_USB_HOST1_QOS_BASE 0xffa60180
#define CPU_AXI_GPU_QOS_BASE 0xffae0000
#define CPU_AXI_VIDEO_M0_QOS_BASE 0xffab8000
#define CPU_AXI_VIDEO_M1_R_QOS_BASE 0xffac0000
#define CPU_AXI_VIDEO_M1_W_QOS_BASE 0xffac0080
#define CPU_AXI_RGA_R_QOS_BASE 0xffab0000
#define CPU_AXI_RGA_W_QOS_BASE 0xffab0080
#define CPU_AXI_IEP_QOS_BASE 0xffa98000
#define CPU_AXI_VOP_BIG_R_QOS_BASE 0xffac8000
#define CPU_AXI_VOP_BIG_W_QOS_BASE 0xffac8080
#define CPU_AXI_VOP_LITTLE_QOS_BASE 0xffad0000
#define CPU_AXI_ISP0_M0_QOS_BASE 0xffaa0000
#define CPU_AXI_ISP0_M1_QOS_BASE 0xffaa0080
#define CPU_AXI_ISP1_M0_QOS_BASE 0xffaa8000
#define CPU_AXI_ISP1_M1_QOS_BASE 0xffaa8080
#define CPU_AXI_HDCP_QOS_BASE 0xffa90000
#define CPU_AXI_PERIHP_NSP_QOS_BASE 0xffad8080
#define CPU_AXI_PERILP_NSP_QOS_BASE 0xffad8180
#define CPU_AXI_PERILPSLV_NSP_QOS_BASE 0xffad8100
#define PD_CTR_LOOP 500
#define CHK_CPU_LOOP 500
......@@ -876,32 +769,6 @@ enum pmu_core_pwr_st {
#define GRF_SOC_CON4 0x0e210
#define GRF_GPIO2A_IOMUX 0xe000
#define GRF_GPIO2B_IOMUX 0xe004
#define GRF_GPIO2C_IOMUX 0xe008
#define GRF_GPIO2D_IOMUX 0xe00c
#define GRF_GPIO3A_IOMUX 0xe010
#define GRF_GPIO3B_IOMUX 0xe014
#define GRF_GPIO3C_IOMUX 0xe018
#define GRF_GPIO3D_IOMUX 0xe01c
#define GRF_GPIO4A_IOMUX 0xe020
#define GRF_GPIO4B_IOMUX 0xe024
#define GRF_GPIO4C_IOMUX 0xe028
#define GRF_GPIO4D_IOMUX 0xe02c
#define GRF_GPIO2A_P 0xe040
#define GRF_GPIO2B_P 0xe044
#define GRF_GPIO2C_P 0xe048
#define GRF_GPIO2D_P 0xe04C
#define GRF_GPIO3A_P 0xe050
#define GRF_GPIO3B_P 0xe054
#define GRF_GPIO3C_P 0xe058
#define GRF_GPIO3D_P 0xe05C
#define GRF_GPIO4A_P 0xe060
#define GRF_GPIO4B_P 0xe064
#define GRF_GPIO4C_P 0xe068
#define GRF_GPIO4D_P 0xe06C
#define PMUGRF_GPIO0A_SMT 0x0120
#define PMUGRF_SOC_CON0 0x0180
......@@ -977,4 +844,7 @@ struct pmu_slpdata_s {
};
extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT];
extern void sram_func_set_ddrctl_pll(uint32_t pll_src);
#endif /* __PMU_H__ */
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PMU_REGS_H__
#define __PMU_REGS_H__
#define PMU_WKUP_CFG0 0x00
#define PMU_WKUP_CFG1 0x04
#define PMU_WKUP_CFG2 0x08
#define PMU_WKUP_CFG3 0x0c
#define PMU_WKUP_CFG4 0x10
#define PMU_PWRDN_CON 0x14
#define PMU_PWRDN_ST 0x18
#define PMU_PLL_CON 0x1c
#define PMU_PWRMODE_CON 0x20
#define PMU_SFT_CON 0x24
#define PMU_INT_CON 0x28
#define PMU_INT_ST 0x2c
#define PMU_GPIO0_POS_INT_CON 0x30
#define PMU_GPIO0_NEG_INT_CON 0x34
#define PMU_GPIO1_POS_INT_CON 0x38
#define PMU_GPIO1_NEG_INT_CON 0x3c
#define PMU_GPIO0_POS_INT_ST 0x40
#define PMU_GPIO0_NEG_INT_ST 0x44
#define PMU_GPIO1_POS_INT_ST 0x48
#define PMU_GPIO1_NEG_INT_ST 0x4c
#define PMU_PWRDN_INTEN 0x50
#define PMU_PWRDN_STATUS 0x54
#define PMU_WAKEUP_STATUS 0x58
#define PMU_BUS_CLR 0x5c
#define PMU_BUS_IDLE_REQ 0x60
#define PMU_BUS_IDLE_ST 0x64
#define PMU_BUS_IDLE_ACK 0x68
#define PMU_CCI500_CON 0x6c
#define PMU_ADB400_CON 0x70
#define PMU_ADB400_ST 0x74
#define PMU_POWER_ST 0x78
#define PMU_CORE_PWR_ST 0x7c
#define PMU_OSC_CNT 0x80
#define PMU_PLLLOCK_CNT 0x84
#define PMU_PLLRST_CNT 0x88
#define PMU_STABLE_CNT 0x8c
#define PMU_DDRIO_PWRON_CNT 0x90
#define PMU_WAKEUP_RST_CLR_CNT 0x94
#define PMU_DDR_SREF_ST 0x98
#define PMU_SCU_L_PWRDN_CNT 0x9c
#define PMU_SCU_L_PWRUP_CNT 0xa0
#define PMU_SCU_B_PWRDN_CNT 0xa4
#define PMU_SCU_B_PWRUP_CNT 0xa8
#define PMU_GPU_PWRDN_CNT 0xac
#define PMU_GPU_PWRUP_CNT 0xb0
#define PMU_CENTER_PWRDN_CNT 0xb4
#define PMU_CENTER_PWRUP_CNT 0xb8
#define PMU_TIMEOUT_CNT 0xbc
#define PMU_CPU0APM_CON 0xc0
#define PMU_CPU1APM_CON 0xc4
#define PMU_CPU2APM_CON 0xc8
#define PMU_CPU3APM_CON 0xcc
#define PMU_CPU0BPM_CON 0xd0
#define PMU_CPU1BPM_CON 0xd4
#define PMU_NOC_AUTO_ENA 0xd8
#define PMU_PWRDN_CON1 0xdc
#define PMUGRF_GPIO0A_IOMUX 0x00
#define PMUGRF_GPIO1A_IOMUX 0x10
#define PMUGRF_GPIO1C_IOMUX 0x18
#define PMUGRF_GPIO0A6_IOMUX_SHIFT 12
#define PMUGRF_GPIO0A6_IOMUX_PWM 0x1
#define PMUGRF_GPIO1C3_IOMUX_SHIFT 6
#define PMUGRF_GPIO1C3_IOMUX_PWM 0x1
#define CPU_AXI_QOS_ID_COREID 0x00
#define CPU_AXI_QOS_REVISIONID 0x04
#define CPU_AXI_QOS_PRIORITY 0x08
#define CPU_AXI_QOS_MODE 0x0c
#define CPU_AXI_QOS_BANDWIDTH 0x10
#define CPU_AXI_QOS_SATURATION 0x14
#define CPU_AXI_QOS_EXTCONTROL 0x18
#define CPU_AXI_QOS_NUM_REGS 0x07
#define CPU_AXI_CCI_M0_QOS_BASE 0xffa50000
#define CPU_AXI_CCI_M1_QOS_BASE 0xffad8000
#define CPU_AXI_DMAC0_QOS_BASE 0xffa64200
#define CPU_AXI_DMAC1_QOS_BASE 0xffa64280
#define CPU_AXI_DCF_QOS_BASE 0xffa64180
#define CPU_AXI_CRYPTO0_QOS_BASE 0xffa64100
#define CPU_AXI_CRYPTO1_QOS_BASE 0xffa64080
#define CPU_AXI_PMU_CM0_QOS_BASE 0xffa68000
#define CPU_AXI_PERI_CM1_QOS_BASE 0xffa64300
#define CPU_AXI_GIC_QOS_BASE 0xffa78000
#define CPU_AXI_SDIO_QOS_BASE 0xffa76000
#define CPU_AXI_SDMMC_QOS_BASE 0xffa74000
#define CPU_AXI_EMMC_QOS_BASE 0xffa58000
#define CPU_AXI_GMAC_QOS_BASE 0xffa5c000
#define CPU_AXI_USB_OTG0_QOS_BASE 0xffa70000
#define CPU_AXI_USB_OTG1_QOS_BASE 0xffa70080
#define CPU_AXI_USB_HOST0_QOS_BASE 0xffa60100
#define CPU_AXI_USB_HOST1_QOS_BASE 0xffa60180
#define CPU_AXI_GPU_QOS_BASE 0xffae0000
#define CPU_AXI_VIDEO_M0_QOS_BASE 0xffab8000
#define CPU_AXI_VIDEO_M1_R_QOS_BASE 0xffac0000
#define CPU_AXI_VIDEO_M1_W_QOS_BASE 0xffac0080
#define CPU_AXI_RGA_R_QOS_BASE 0xffab0000
#define CPU_AXI_RGA_W_QOS_BASE 0xffab0080
#define CPU_AXI_IEP_QOS_BASE 0xffa98000
#define CPU_AXI_VOP_BIG_R_QOS_BASE 0xffac8000
#define CPU_AXI_VOP_BIG_W_QOS_BASE 0xffac8080
#define CPU_AXI_VOP_LITTLE_QOS_BASE 0xffad0000
#define CPU_AXI_ISP0_M0_QOS_BASE 0xffaa0000
#define CPU_AXI_ISP0_M1_QOS_BASE 0xffaa0080
#define CPU_AXI_ISP1_M0_QOS_BASE 0xffaa8000
#define CPU_AXI_ISP1_M1_QOS_BASE 0xffaa8080
#define CPU_AXI_HDCP_QOS_BASE 0xffa90000
#define CPU_AXI_PERIHP_NSP_QOS_BASE 0xffad8080
#define CPU_AXI_PERILP_NSP_QOS_BASE 0xffad8180
#define CPU_AXI_PERILPSLV_NSP_QOS_BASE 0xffad8100
#define GRF_GPIO2A_IOMUX 0xe000
#define GRF_GPIO2B_IOMUX 0xe004
#define GRF_GPIO2C_IOMUX 0xe008
#define GRF_GPIO2D_IOMUX 0xe00c
#define GRF_GPIO3A_IOMUX 0xe010
#define GRF_GPIO3B_IOMUX 0xe014
#define GRF_GPIO3C_IOMUX 0xe018
#define GRF_GPIO3D_IOMUX 0xe01c
#define GRF_GPIO4A_IOMUX 0xe020
#define GRF_GPIO4B_IOMUX 0xe024
#define GRF_GPIO4C_IOMUX 0xe028
#define GRF_GPIO4D_IOMUX 0xe02c
#define GRF_GPIO2A_P 0xe040
#define GRF_GPIO2B_P 0xe044
#define GRF_GPIO2C_P 0xe048
#define GRF_GPIO2D_P 0xe04C
#define GRF_GPIO3A_P 0xe050
#define GRF_GPIO3B_P 0xe054
#define GRF_GPIO3C_P 0xe058
#define GRF_GPIO3D_P 0xe05C
#define GRF_GPIO4A_P 0xe060
#define GRF_GPIO4B_P 0xe064
#define GRF_GPIO4C_P 0xe068
#define GRF_GPIO4D_P 0xe06C
#endif /* __PMU_REGS_H__ */
......@@ -34,6 +34,7 @@
#include <mmio.h>
#include <platform_def.h>
#include <plat_private.h>
#include <dram.h>
#include <rk3399_def.h>
#include <rk3399m0.h>
#include <soc.h>
......@@ -42,6 +43,8 @@
const mmap_region_t plat_rk_mmap[] = {
MAP_REGION_FLAT(RK3399_DEV_RNG0_BASE, RK3399_DEV_RNG0_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
MT_MEMORY | MT_RW | MT_SECURE),
{ 0 }
};
......@@ -237,21 +240,105 @@ static void _pll_suspend(uint32_t pll_id)
set_pll_bypass(pll_id);
}
/**
* disable_dvfs_plls - To suspend the specific PLLs
*
* When we close the center logic, the DPLL will be closed,
* so we need to keep the ABPLL and switch to it to supply
* clock for DDR during suspend, then we should not close
* the ABPLL and exclude ABPLL_ID.
*/
void disable_dvfs_plls(void)
{
_pll_suspend(CPLL_ID);
_pll_suspend(NPLL_ID);
_pll_suspend(VPLL_ID);
_pll_suspend(GPLL_ID);
_pll_suspend(ABPLL_ID);
_pll_suspend(ALPLL_ID);
}
/**
* disable_nodvfs_plls - To suspend the PPLL
*/
void disable_nodvfs_plls(void)
{
_pll_suspend(PPLL_ID);
}
/**
* restore_pll - Copy PLL settings from memory to a PLL.
*
* This will copy PLL settings from an array in memory to the memory mapped
* registers for a PLL.
*
* Note that: above the PLL exclude PPLL.
*
* pll_id: One of the values from enum plls_id
* src: Pointer to the array of values to restore from
*/
static void restore_pll(int pll_id, uint32_t *src)
{
/* Nice to have PLL off while configuring */
mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK);
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK);
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]);
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK);
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK);
/* Do PLL_CON3 since that will enable things */
mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK);
/* Wait for PLL lock done */
while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) &
0x80000000) == 0x0)
;
}
/**
* save_pll - Copy PLL settings a PLL to memory
*
* This will copy PLL settings from the memory mapped registers for a PLL to
* an array in memory.
*
* Note that: above the PLL exclude PPLL.
*
* pll_id: One of the values from enum plls_id
* src: Pointer to the array of values to save to.
*/
static void save_pll(uint32_t *dst, int pll_id)
{
int i;
for (i = 0; i < PLL_CON_COUNT; i++)
dst[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i));
}
/**
* prepare_abpll_for_ddrctrl - Copy DPLL settings to ABPLL
*
* This will copy DPLL settings from the memory mapped registers for a PLL to
* an array in memory.
*/
void prepare_abpll_for_ddrctrl(void)
{
save_pll(slp_data.plls_con[ABPLL_ID], ABPLL_ID);
save_pll(slp_data.plls_con[DPLL_ID], DPLL_ID);
restore_pll(ABPLL_ID, slp_data.plls_con[DPLL_ID]);
}
void restore_abpll(void)
{
restore_pll(ABPLL_ID, slp_data.plls_con[ABPLL_ID]);
}
void restore_dpll(void)
{
restore_pll(DPLL_ID, slp_data.plls_con[DPLL_ID]);
}
void plls_suspend_prepare(void)
{
uint32_t i, pll_id;
......@@ -342,16 +429,25 @@ void plls_resume_finish(void)
REG_SOC_WMSK | slp_data.pmucru_clksel_con[i]);
}
/**
* enable_dvfs_plls - To resume the specific PLLs
*
* Please see the comment at the disable_dvfs_plls()
* we don't suspend the ABPLL, so don't need resume
* it too.
*/
void enable_dvfs_plls(void)
{
_pll_resume(ALPLL_ID);
_pll_resume(ABPLL_ID);
_pll_resume(GPLL_ID);
_pll_resume(VPLL_ID);
_pll_resume(NPLL_ID);
_pll_resume(CPLL_ID);
}
/**
* enable_nodvfs_plls - To resume the PPLL
*/
void enable_nodvfs_plls(void)
{
_pll_resume(PPLL_ID);
......@@ -410,4 +506,5 @@ void plat_rockchip_soc_init(void)
soc_global_soft_reset_init();
plat_rockchip_gpio_init();
soc_m0_init();
dram_init();
}
......@@ -245,6 +245,8 @@ struct deepsleep_data_s {
#define SGRF_PMU_SLV_CON1_CFG (SGRF_SLV_S_WMSK | \
SGRF_PMUSRAM_S)
/* ddr region */
#define SGRF_DDR_RGN_DPLL_CLK BIT_WITH_WMSK(15) /* DDR PLL output clock */
#define SGRF_DDR_RGN_RTC_CLK BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */
#define SGRF_DDR_RGN_BYPS BIT_WITH_WMSK(9) /* All of ddr rgn is ns */
/* The MST access the ddr rgn n with secure attribution */
......@@ -334,7 +336,11 @@ void disable_nodvfs_plls(void);
void plls_resume_finish(void);
void enable_dvfs_plls(void);
void enable_nodvfs_plls(void);
void prepare_abpll_for_ddrctrl(void);
void restore_abpll(void);
void restore_dpll(void);
void clk_gate_con_save(void);
void clk_gate_con_disable(void);
void clk_gate_con_restore(void);
void sgrf_init(void);
#endif /* __SOC_H__ */
......@@ -29,7 +29,7 @@
#include <plat_sip_calls.h>
#include <rockchip_sip_svc.h>
#include <runtime_svc.h>
#include <dram.h>
#include <dfs.h>
#define RK_SIP_DDR_CFG 0x82000008
#define DRAM_INIT 0x00
......@@ -45,7 +45,7 @@ uint32_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id)
{
switch (id) {
case DRAM_INIT:
ddr_init();
ddr_dfs_init();
break;
case DRAM_SET_RATE:
return ddr_set_rate((uint32_t)arg0);
......
......@@ -79,6 +79,8 @@ BL31_SOURCES += ${RK_GIC_SOURCES}
${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c \
${RK_PLAT_SOC}/drivers/pwm/pwm.c \
${RK_PLAT_SOC}/drivers/soc/soc.c \
${RK_PLAT_SOC}/drivers/dram/dfs.c \
${RK_PLAT_SOC}/drivers/dram/suspend.c \
${RK_PLAT_SOC}/drivers/dram/dram.c \
${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment