1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
4 */
5
6#include <common.h>
7#include <ram.h>
8#include <asm/io.h>
9#include <asm/arch-rockchip/sdram.h>
10#include <asm/arch-rockchip/sdram_common.h>
11#include <asm/arch-rockchip/sdram_phy_px30.h>
12#include <linux/delay.h>
13
14static void sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq)
15{
16	u32 tmp;
17	u32 i, j;
18	u32 dqs_dll_freq;
19
20	setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
21	clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
22	for (i = 0; i < 4; i++) {
23		j = 0x26 + i * 0x10;
24		setbits_le32(PHY_REG(phy_base, j), 1 << 4);
25		clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
26	}
27
28	if (freq <= 400)
29		/* DLL bypass */
30		setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
31	else
32		clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
33
34	#ifdef CONFIG_ROCKCHIP_RK3328
35	dqs_dll_freq = 680;
36	#else
37	dqs_dll_freq = 801;
38	#endif
39
40	if (freq <= dqs_dll_freq)
41		tmp = 2;
42	else
43		tmp = 1;
44
45	for (i = 0; i < 4; i++) {
46		j = 0x28 + i * 0x10;
47		writel(tmp, PHY_REG(phy_base, j));
48	}
49}
50
51static void sdram_phy_set_ds_odt(void __iomem *phy_base,
52				 u32 dram_type)
53{
54	u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
55	u32 i, j;
56
57	if (dram_type == DDR3) {
58		cmd_drv = PHY_DDR3_RON_RTT_34ohm;
59		clk_drv = PHY_DDR3_RON_RTT_45ohm;
60		dqs_drv = PHY_DDR3_RON_RTT_34ohm;
61		dqs_odt = PHY_DDR3_RON_RTT_225ohm;
62	} else {
63		cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
64		clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
65		dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
66		if (dram_type == LPDDR2)
67			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
68		else
69			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
70	}
71	/* DS */
72	writel(cmd_drv, PHY_REG(phy_base, 0x11));
73	clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
74	writel(clk_drv, PHY_REG(phy_base, 0x16));
75	writel(clk_drv, PHY_REG(phy_base, 0x18));
76
77	for (i = 0; i < 4; i++) {
78		j = 0x20 + i * 0x10;
79		writel(dqs_drv, PHY_REG(phy_base, j));
80		writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
81		/* ODT */
82		writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
83		writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
84	}
85}
86
87void phy_soft_reset(void __iomem *phy_base)
88{
89	clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
90	udelay(1);
91	setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
92	udelay(5);
93	setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
94	udelay(1);
95}
96
97void phy_dram_set_bw(void __iomem *phy_base, u32 bw)
98{
99	if (bw == 2) {
100		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
101		setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
102		setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
103	} else if (bw == 1) {
104		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
105		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
106		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
107	} else if (bw == 0) {
108		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
109		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
110		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
111		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
112	}
113
114	phy_soft_reset(phy_base);
115}
116
117int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype)
118{
119	u32 ret;
120	u32 odt_val;
121	u32 i, j;
122
123	odt_val = readl(PHY_REG(phy_base, 0x2e));
124
125	for (i = 0; i < 4; i++) {
126		j = 0x20 + i * 0x10;
127		writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
128		writel(0, PHY_REG(phy_base, j + 0xe));
129	}
130
131	if (dramtype == DDR4) {
132		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
133		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
134		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
135		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
136	}
137	/* choose training cs */
138	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
139	/* enable gate training */
140	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
141	udelay(50);
142	ret = readl(PHY_REG(phy_base, 0xff));
143	/* disable gate training */
144	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
145	#ifndef CONFIG_ROCKCHIP_RK3328
146	clrbits_le32(PHY_REG(phy_base, 2), 0x30);
147	#endif
148
149	if (dramtype == DDR4) {
150		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
151		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
152		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
153		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
154	}
155
156	if (ret & 0x10) {
157		ret = -1;
158	} else {
159		ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
160		ret = (ret == 0) ? 0 : -1;
161	}
162
163	for (i = 0; i < 4; i++) {
164		j = 0x20 + i * 0x10;
165		writel(odt_val, PHY_REG(phy_base, j + 0x1));
166		writel(odt_val, PHY_REG(phy_base, j + 0xe));
167	}
168	return ret;
169}
170
171void phy_cfg(void __iomem *phy_base,
172	     struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew,
173	     struct sdram_base_params *base, u32 bw)
174{
175	u32 i;
176
177	sdram_phy_dll_bypass_set(phy_base, base->ddr_freq);
178	for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) {
179		writel(phy_regs->phy[i][1],
180		       phy_base + phy_regs->phy[i][0]);
181	}
182	if (bw == 2) {
183		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
184	} else if (bw == 1) {
185		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
186		/* disable DQS2,DQS3 tx dll  for saving power */
187		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
188		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
189	} else {
190		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
191		/* disable DQS2,DQS3 tx dll  for saving power */
192		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
193		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
194		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
195	}
196	sdram_phy_set_ds_odt(phy_base, base->dramtype);
197
198	/* deskew */
199	setbits_le32(PHY_REG(phy_base, 2), 8);
200	sdram_copy_to_reg(PHY_REG(phy_base, 0xb0),
201			  &skew->a0_a1_skew[0], 15 * 4);
202	sdram_copy_to_reg(PHY_REG(phy_base, 0x70),
203			  &skew->cs0_dm0_skew[0], 44 * 4);
204	sdram_copy_to_reg(PHY_REG(phy_base, 0xc0),
205			  &skew->cs1_dm0_skew[0], 44 * 4);
206}
207