summaryrefslogtreecommitdiff
path: root/drivers/ram/rockchip
diff options
context:
space:
mode:
authorKever Yang <kever.yang@rock-chips.com>2019-11-15 06:04:41 +0300
committerKever Yang <kever.yang@rock-chips.com>2019-11-17 11:23:56 +0300
commit691368c7f76ff231ef48261feaa65b87a3be66b6 (patch)
tree96fd88cf10d2987ed0ed6d1bf14bdc343c0777bc /drivers/ram/rockchip
parent09d7872336ff298d20ef13d36d89098bd8cd50b3 (diff)
downloadu-boot-691368c7f76ff231ef48261feaa65b87a3be66b6.tar.xz
ram: rockchip: add phy driver code for PX30
This sdram_phy_px30.c is based on PX30 SoC, the functions are common for phy, other SoCs with similar hardware could re-use it. Signed-off-by: YouMin Chen <cym@rock-chips.com> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
Diffstat (limited to 'drivers/ram/rockchip')
-rw-r--r--drivers/ram/rockchip/sdram_phy_px30.c205
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);
+}