ram: rockchip: add phy driver code for PX30
authorKever Yang <kever.yang@rock-chips.com>
Fri, 15 Nov 2019 03:04:41 +0000 (11:04 +0800)
committerKever Yang <kever.yang@rock-chips.com>
Sun, 17 Nov 2019 08:23:56 +0000 (16:23 +0800)
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>
arch/arm/include/asm/arch-rockchip/sdram_phy_px30.h [new file with mode: 0644]
arch/arm/include/asm/arch-rockchip/sdram_phy_ron_rtt_px30.h [new file with mode: 0644]
drivers/ram/rockchip/sdram_phy_px30.c [new file with mode: 0644]

diff --git a/arch/arm/include/asm/arch-rockchip/sdram_phy_px30.h b/arch/arm/include/asm/arch-rockchip/sdram_phy_px30.h
new file mode 100644 (file)
index 0000000..c75a633
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef _ASM_ARCH_SDRAM_PHY_PX30_H
+#define _ASM_ARCH_SDRAM_PHY_PX30_H
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_phy_ron_rtt_px30.h>
+
+struct ddr_phy_regs {
+       u32 phy[5][2];
+};
+
+#define PHY_REG(base, n)               ((base) + 4 * (n))
+
+/* PHY_REG0 */
+#define DIGITAL_DERESET                        BIT(3)
+#define ANALOG_DERESET                 BIT(2)
+#define DIGITAL_RESET                  (0 << 3)
+#define ANALOG_RESET                   (0 << 2)
+
+/* PHY_REG1 */
+#define PHY_DDR2                       (0)
+#define PHY_LPDDR2                     (1)
+#define PHY_DDR3                       (2)
+#define PHY_LPDDR3                     (3)
+#define PHY_DDR4                       (4)
+#define PHY_BL_4                       (0 << 2)
+#define PHY_BL_8                       BIT(2)
+
+/* PHY_REG2 */
+#define PHY_DTT_EN                     BIT(0)
+#define PHY_DTT_DISB                   (0 << 0)
+#define PHY_WRITE_LEVELING_EN          BIT(2)
+#define PHY_WRITE_LEVELING_DISB                (0 << 2)
+#define PHY_SELECT_CS0                 (2)
+#define PHY_SELECT_CS1                 (1)
+#define PHY_SELECT_CS0_1               (0)
+#define PHY_WRITE_LEVELING_SELECTCS(n) ((n) << 6)
+#define PHY_DATA_TRAINING_SELECTCS(n)  ((n) << 4)
+
+struct ddr_phy_skew {
+       u32 a0_a1_skew[15];
+       u32 cs0_dm0_skew[11];
+       u32 cs0_dm1_skew[11];
+       u32 cs0_dm2_skew[11];
+       u32 cs0_dm3_skew[11];
+       u32 cs1_dm0_skew[11];
+       u32 cs1_dm1_skew[11];
+       u32 cs1_dm2_skew[11];
+       u32 cs1_dm3_skew[11];
+};
+
+void phy_soft_reset(void __iomem *phy_base);
+void phy_dram_set_bw(void __iomem *phy_base, u32 bw);
+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);
+int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype);
+
+#endif
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_phy_ron_rtt_px30.h b/arch/arm/include/asm/arch-rockchip/sdram_phy_ron_rtt_px30.h
new file mode 100644 (file)
index 0000000..9c15232
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef _ASM_ARCH_SDRAM_PHY_RON_RTT_PX30_H
+#define _ASM_ARCH_SDRAM_PHY_RON_RTT_PX30_H
+
+#define PHY_DDR3_RON_RTT_DISABLE       (0)
+#define PHY_DDR3_RON_RTT_451ohm                (1)
+#define PHY_DDR3_RON_RTT_225ohm                (2)
+#define PHY_DDR3_RON_RTT_150ohm                (3)
+#define PHY_DDR3_RON_RTT_112ohm                (4)
+#define PHY_DDR3_RON_RTT_90ohm         (5)
+#define PHY_DDR3_RON_RTT_75ohm         (6)
+#define PHY_DDR3_RON_RTT_64ohm         (7)
+#define PHY_DDR3_RON_RTT_56ohm         (16)
+#define PHY_DDR3_RON_RTT_50ohm         (17)
+#define PHY_DDR3_RON_RTT_45ohm         (18)
+#define PHY_DDR3_RON_RTT_41ohm         (19)
+#define PHY_DDR3_RON_RTT_37ohm         (20)
+#define PHY_DDR3_RON_RTT_34ohm         (21)
+#define PHY_DDR3_RON_RTT_33ohm         (22)
+#define PHY_DDR3_RON_RTT_30ohm         (23)
+#define PHY_DDR3_RON_RTT_28ohm         (24)
+#define PHY_DDR3_RON_RTT_26ohm         (25)
+#define PHY_DDR3_RON_RTT_25ohm         (26)
+#define PHY_DDR3_RON_RTT_23ohm         (27)
+#define PHY_DDR3_RON_RTT_22ohm         (28)
+#define PHY_DDR3_RON_RTT_21ohm         (29)
+#define PHY_DDR3_RON_RTT_20ohm         (30)
+#define PHY_DDR3_RON_RTT_19ohm         (31)
+
+#define PHY_DDR4_LPDDR3_RON_RTT_DISABLE        (0)
+#define PHY_DDR4_LPDDR3_RON_RTT_480ohm (1)
+#define PHY_DDR4_LPDDR3_RON_RTT_240ohm (2)
+#define PHY_DDR4_LPDDR3_RON_RTT_160ohm (3)
+#define PHY_DDR4_LPDDR3_RON_RTT_120ohm (4)
+#define PHY_DDR4_LPDDR3_RON_RTT_96ohm  (5)
+#define PHY_DDR4_LPDDR3_RON_RTT_80ohm  (6)
+#define PHY_DDR4_LPDDR3_RON_RTT_68ohm  (7)
+#define PHY_DDR4_LPDDR3_RON_RTT_60ohm  (16)
+#define PHY_DDR4_LPDDR3_RON_RTT_53ohm  (17)
+#define PHY_DDR4_LPDDR3_RON_RTT_48ohm  (18)
+#define PHY_DDR4_LPDDR3_RON_RTT_43ohm  (19)
+#define PHY_DDR4_LPDDR3_RON_RTT_40ohm  (20)
+#define PHY_DDR4_LPDDR3_RON_RTT_37ohm  (21)
+#define PHY_DDR4_LPDDR3_RON_RTT_34ohm  (22)
+#define PHY_DDR4_LPDDR3_RON_RTT_32ohm  (23)
+#define PHY_DDR4_LPDDR3_RON_RTT_30ohm  (24)
+#define PHY_DDR4_LPDDR3_RON_RTT_28ohm  (25)
+#define PHY_DDR4_LPDDR3_RON_RTT_26ohm  (26)
+#define PHY_DDR4_LPDDR3_RON_RTT_25ohm  (27)
+#define PHY_DDR4_LPDDR3_RON_RTT_24ohm  (28)
+#define PHY_DDR4_LPDDR3_RON_RTT_22ohm  (29)
+#define PHY_DDR4_LPDDR3_RON_RTT_21ohm  (30)
+#define PHY_DDR4_LPDDR3_RON_RTT_20ohm  (31)
+
+#endif
diff --git a/drivers/ram/rockchip/sdram_phy_px30.c b/drivers/ram/rockchip/sdram_phy_px30.c
new file mode 100644 (file)
index 0000000..5de7377
--- /dev/null
@@ -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);
+}