diff options
Diffstat (limited to 'drivers/ram/rockchip')
-rw-r--r-- | drivers/ram/rockchip/sdram_phy_px30.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/ram/rockchip/sdram_phy_px30.c b/drivers/ram/rockchip/sdram_phy_px30.c new file mode 100644 index 0000000000..5de73770a8 --- /dev/null +++ b/drivers/ram/rockchip/sdram_phy_px30.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2018 Rockchip Electronics Co., Ltd. + */ + +#include <common.h> +#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> + +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); +} |