blob: 5416eef387888401108eb2328d8d5d41c085c233 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2018 Rockchip Electronics Co., Ltd.
*/
#include <ram.h>
#include <asm/io.h>
#include <asm/arch-rockchip/sdram.h>
#include <asm/arch-rockchip/sdram_common.h>
#include <asm/arch-rockchip/sdram_phy_px30.h>
#include <linux/delay.h>
static void sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq)
{
u32 tmp;
u32 i, j;
u32 dqs_dll_freq;
setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
for (i = 0; i < 4; i++) {
j = 0x26 + i * 0x10;
setbits_le32(PHY_REG(phy_base, j), 1 << 4);
clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
}
if (freq <= 400)
/* DLL bypass */
setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
else
clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
#ifdef CONFIG_ROCKCHIP_RK3328
dqs_dll_freq = 680;
#else
dqs_dll_freq = 801;
#endif
if (freq <= dqs_dll_freq)
tmp = 2;
else
tmp = 1;
for (i = 0; i < 4; i++) {
j = 0x28 + i * 0x10;
writel(tmp, PHY_REG(phy_base, j));
}
}
static void sdram_phy_set_ds_odt(void __iomem *phy_base,
u32 dram_type)
{
u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
u32 i, j;
if (dram_type == DDR3) {
cmd_drv = PHY_DDR3_RON_RTT_34ohm;
clk_drv = PHY_DDR3_RON_RTT_45ohm;
dqs_drv = PHY_DDR3_RON_RTT_34ohm;
dqs_odt = PHY_DDR3_RON_RTT_225ohm;
} else {
cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
if (dram_type == LPDDR2)
dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
else
dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
}
/* DS */
writel(cmd_drv, PHY_REG(phy_base, 0x11));
clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
writel(clk_drv, PHY_REG(phy_base, 0x16));
writel(clk_drv, PHY_REG(phy_base, 0x18));
for (i = 0; i < 4; i++) {
j = 0x20 + i * 0x10;
writel(dqs_drv, PHY_REG(phy_base, j));
writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
/* ODT */
writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
}
}
void phy_soft_reset(void __iomem *phy_base)
{
clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
udelay(1);
setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
udelay(5);
setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
udelay(1);
}
void phy_dram_set_bw(void __iomem *phy_base, u32 bw)
{
if (bw == 2) {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
} else if (bw == 1) {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
} else if (bw == 0) {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
}
phy_soft_reset(phy_base);
}
int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype)
{
u32 ret;
u32 odt_val;
u32 i, j;
odt_val = readl(PHY_REG(phy_base, 0x2e));
for (i = 0; i < 4; i++) {
j = 0x20 + i * 0x10;
writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
writel(0, PHY_REG(phy_base, j + 0xe));
}
if (dramtype == DDR4) {
clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
}
/* choose training cs */
clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
/* enable gate training */
clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
udelay(50);
ret = readl(PHY_REG(phy_base, 0xff));
/* disable gate training */
clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
#ifndef CONFIG_ROCKCHIP_RK3328
clrbits_le32(PHY_REG(phy_base, 2), 0x30);
#endif
if (dramtype == DDR4) {
clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
}
if (ret & 0x10) {
ret = -1;
} else {
ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
ret = (ret == 0) ? 0 : -1;
}
for (i = 0; i < 4; i++) {
j = 0x20 + i * 0x10;
writel(odt_val, PHY_REG(phy_base, j + 0x1));
writel(odt_val, PHY_REG(phy_base, j + 0xe));
}
return ret;
}
void phy_cfg(void __iomem *phy_base,
struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew,
struct sdram_base_params *base, u32 bw)
{
u32 i;
sdram_phy_dll_bypass_set(phy_base, base->ddr_freq);
for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) {
writel(phy_regs->phy[i][1],
phy_base + phy_regs->phy[i][0]);
}
if (bw == 2) {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
} else if (bw == 1) {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
/* disable DQS2,DQS3 tx dll for saving power */
clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
} else {
clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
/* disable DQS2,DQS3 tx dll for saving power */
clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
}
sdram_phy_set_ds_odt(phy_base, base->dramtype);
/* deskew */
setbits_le32(PHY_REG(phy_base, 2), 8);
sdram_copy_to_reg(PHY_REG(phy_base, 0xb0),
&skew->a0_a1_skew[0], 15 * 4);
sdram_copy_to_reg(PHY_REG(phy_base, 0x70),
&skew->cs0_dm0_skew[0], 44 * 4);
sdram_copy_to_reg(PHY_REG(phy_base, 0xc0),
&skew->cs1_dm0_skew[0], 44 * 4);
}