xref: /OK3568_Linux_fs/u-boot/drivers/video/drm/inno_mipi_phy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <config.h>
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <malloc.h>
11*4882a593Smuzhiyun #include <asm/unaligned.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <linux/list.h>
14*4882a593Smuzhiyun #include <div64.h>
15*4882a593Smuzhiyun #include <dm/device.h>
16*4882a593Smuzhiyun #include <dm/read.h>
17*4882a593Smuzhiyun #include <dm/uclass.h>
18*4882a593Smuzhiyun #include <dm/uclass-id.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "rockchip_phy.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define NSEC_PER_USEC		1000L
23*4882a593Smuzhiyun #define USEC_PER_SEC		1000000L
24*4882a593Smuzhiyun #define NSEC_PER_SEC		1000000000L
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define UPDATE(v, h, l)		(((v) << (l)) & GENMASK((h), (l)))
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Innosilicon MIPI D-PHY registers */
29*4882a593Smuzhiyun #define INNO_PHY_LANE_CTRL		0x0000
30*4882a593Smuzhiyun #define MIPI_BGPD			BIT(7)
31*4882a593Smuzhiyun #define CLK_LANE_EN_MASK		BIT(6)
32*4882a593Smuzhiyun #define DATA_LANE_3_EN_MASK		BIT(5)
33*4882a593Smuzhiyun #define DATA_LANE_2_EN_MASK		BIT(4)
34*4882a593Smuzhiyun #define DATA_LANE_1_EN_MASK		BIT(3)
35*4882a593Smuzhiyun #define DATA_LANE_0_EN_MASK		BIT(2)
36*4882a593Smuzhiyun #define CLK_LANE_EN			BIT(6)
37*4882a593Smuzhiyun #define DATA_LANE_3_EN			BIT(5)
38*4882a593Smuzhiyun #define DATA_LANE_2_EN			BIT(4)
39*4882a593Smuzhiyun #define DATA_LANE_1_EN			BIT(3)
40*4882a593Smuzhiyun #define DATA_LANE_0_EN			BIT(2)
41*4882a593Smuzhiyun #define PWROK_BP			BIT(1)
42*4882a593Smuzhiyun #define PWROK				BIT(0)
43*4882a593Smuzhiyun #define INNO_PHY_POWER_CTRL		0x0004
44*4882a593Smuzhiyun #define ANALOG_RESET_MASK		BIT(2)
45*4882a593Smuzhiyun #define ANALOG_RESET			BIT(2)
46*4882a593Smuzhiyun #define ANALOG_NORMAL			0
47*4882a593Smuzhiyun #define LDO_POWER_MASK			BIT(1)
48*4882a593Smuzhiyun #define LDO_POWER_DOWN			BIT(1)
49*4882a593Smuzhiyun #define LDO_POWER_ON			0
50*4882a593Smuzhiyun #define PLL_POWER_MASK			BIT(0)
51*4882a593Smuzhiyun #define PLL_POWER_DOWN			BIT(0)
52*4882a593Smuzhiyun #define PLL_POWER_ON			0
53*4882a593Smuzhiyun #define INNO_PHY_PLL_CTRL_0		0x000c
54*4882a593Smuzhiyun #define FBDIV_HI_MASK			BIT(5)
55*4882a593Smuzhiyun #define FBDIV_HI(x)			UPDATE(x, 5, 5)
56*4882a593Smuzhiyun #define PREDIV_MASK			GENMASK(4, 0)
57*4882a593Smuzhiyun #define PREDIV(x)			UPDATE(x, 4, 0)
58*4882a593Smuzhiyun #define INNO_PHY_PLL_CTRL_1		0x0010
59*4882a593Smuzhiyun #define FBDIV_LO_MASK			GENMASK(7, 0)
60*4882a593Smuzhiyun #define FBDIV_LO(x)			UPDATE(x, 7, 0)
61*4882a593Smuzhiyun #define ANALOG_REG_08			0x0020
62*4882a593Smuzhiyun #define PRE_EMPHASIS_ENABLE_MASK	BIT(7)
63*4882a593Smuzhiyun #define PRE_EMPHASIS_ENABLE		BIT(7)
64*4882a593Smuzhiyun #define PRE_EMPHASIS_DISABLE		0
65*4882a593Smuzhiyun #define PLL_POST_DIV_ENABLE_MASK	BIT(5)
66*4882a593Smuzhiyun #define PLL_POST_DIV_ENABLE		BIT(5)
67*4882a593Smuzhiyun #define PLL_POST_DIV_DISABLE		0
68*4882a593Smuzhiyun #define DATA_LANE_VOD_RANGE_SET_MASK	GENMASK(3, 0)
69*4882a593Smuzhiyun #define DATA_LANE_VOD_RANGE_SET(x)	UPDATE(x, 3, 0)
70*4882a593Smuzhiyun #define ANALOG_REG_0B			0x002c
71*4882a593Smuzhiyun #define CLOCK_LANE_VOD_RANGE_SET_MASK	GENMASK(3, 0)
72*4882a593Smuzhiyun #define CLOCK_LANE_VOD_RANGE_SET(x)	UPDATE(x, 3, 0)
73*4882a593Smuzhiyun #define VOD_MIN_RANGE			0x1
74*4882a593Smuzhiyun #define VOD_MID_RANGE			0x3
75*4882a593Smuzhiyun #define VOD_BIG_RANGE			0x7
76*4882a593Smuzhiyun #define VOD_MAX_RANGE			0xf
77*4882a593Smuzhiyun #define INNO_PHY_DIG_CTRL		0x0080
78*4882a593Smuzhiyun #define DIGITAL_RESET_MASK		BIT(0)
79*4882a593Smuzhiyun #define DIGITAL_NORMAL			BIT(0)
80*4882a593Smuzhiyun #define DIGITAL_RESET			0
81*4882a593Smuzhiyun #define INNO_PHY_LVDS_CTRL		0x03ac
82*4882a593Smuzhiyun #define LVDS_BGPD			BIT(0)
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define INNO_CLOCK_LANE_REG_BASE	0x0100
85*4882a593Smuzhiyun #define INNO_DATA_LANE_0_REG_BASE	0x0180
86*4882a593Smuzhiyun #define INNO_DATA_LANE_1_REG_BASE	0x0200
87*4882a593Smuzhiyun #define INNO_DATA_LANE_2_REG_BASE	0x0280
88*4882a593Smuzhiyun #define INNO_DATA_LANE_3_REG_BASE	0x0300
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #define T_LPX_OFFSET		0x0014
91*4882a593Smuzhiyun #define T_HS_PREPARE_OFFSET	0x0018
92*4882a593Smuzhiyun #define T_HS_ZERO_OFFSET	0x001c
93*4882a593Smuzhiyun #define T_HS_TRAIL_OFFSET	0x0020
94*4882a593Smuzhiyun #define T_HS_EXIT_OFFSET	0x0024
95*4882a593Smuzhiyun #define T_CLK_POST_OFFSET	0x0028
96*4882a593Smuzhiyun #define T_WAKUP_H_OFFSET	0x0030
97*4882a593Smuzhiyun #define T_WAKUP_L_OFFSET	0x0034
98*4882a593Smuzhiyun #define T_CLK_PRE_OFFSET	0x0038
99*4882a593Smuzhiyun #define T_TA_GO_OFFSET		0x0040
100*4882a593Smuzhiyun #define T_TA_SURE_OFFSET	0x0044
101*4882a593Smuzhiyun #define T_TA_WAIT_OFFSET	0x0048
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define T_LPX_MASK		GENMASK(5, 0)
104*4882a593Smuzhiyun #define T_LPX(x)		UPDATE(x, 5, 0)
105*4882a593Smuzhiyun #define T_HS_PREPARE_MASK	GENMASK(6, 0)
106*4882a593Smuzhiyun #define T_HS_PREPARE(x)		UPDATE(x, 6, 0)
107*4882a593Smuzhiyun #define T_HS_ZERO_MASK		GENMASK(5, 0)
108*4882a593Smuzhiyun #define T_HS_ZERO(x)		UPDATE(x, 5, 0)
109*4882a593Smuzhiyun #define T_HS_TRAIL_MASK		GENMASK(6, 0)
110*4882a593Smuzhiyun #define T_HS_TRAIL(x)		UPDATE(x, 6, 0)
111*4882a593Smuzhiyun #define T_HS_EXIT_MASK		GENMASK(4, 0)
112*4882a593Smuzhiyun #define T_HS_EXIT(x)		UPDATE(x, 4, 0)
113*4882a593Smuzhiyun #define T_CLK_POST_MASK		GENMASK(3, 0)
114*4882a593Smuzhiyun #define T_CLK_POST(x)		UPDATE(x, 3, 0)
115*4882a593Smuzhiyun #define T_WAKUP_H_MASK		GENMASK(1, 0)
116*4882a593Smuzhiyun #define T_WAKUP_H(x)		UPDATE(x, 1, 0)
117*4882a593Smuzhiyun #define T_WAKUP_L_MASK		GENMASK(7, 0)
118*4882a593Smuzhiyun #define T_WAKUP_L(x)		UPDATE(x, 7, 0)
119*4882a593Smuzhiyun #define T_CLK_PRE_MASK		GENMASK(3, 0)
120*4882a593Smuzhiyun #define T_CLK_PRE(x)		UPDATE(x, 3, 0)
121*4882a593Smuzhiyun #define T_TA_GO_MASK		GENMASK(5, 0)
122*4882a593Smuzhiyun #define T_TA_GO(x)		UPDATE(x, 5, 0)
123*4882a593Smuzhiyun #define T_TA_SURE_MASK		GENMASK(5, 0)
124*4882a593Smuzhiyun #define T_TA_SURE(x)		UPDATE(x, 5, 0)
125*4882a593Smuzhiyun #define T_TA_WAIT_MASK		GENMASK(5, 0)
126*4882a593Smuzhiyun #define T_TA_WAIT(x)		UPDATE(x, 5, 0)
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun enum soc_type {
129*4882a593Smuzhiyun 	RV1108_MIPI_DPHY,
130*4882a593Smuzhiyun 	RK1808_MIPI_DPHY,
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun enum lane_type {
134*4882a593Smuzhiyun 	CLOCK_LANE,
135*4882a593Smuzhiyun 	DATA_LANE_0,
136*4882a593Smuzhiyun 	DATA_LANE_1,
137*4882a593Smuzhiyun 	DATA_LANE_2,
138*4882a593Smuzhiyun 	DATA_LANE_3,
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun struct mipi_dphy_timing {
142*4882a593Smuzhiyun 	unsigned int clkmiss;
143*4882a593Smuzhiyun 	unsigned int clkpost;
144*4882a593Smuzhiyun 	unsigned int clkpre;
145*4882a593Smuzhiyun 	unsigned int clkprepare;
146*4882a593Smuzhiyun 	unsigned int clksettle;
147*4882a593Smuzhiyun 	unsigned int clktermen;
148*4882a593Smuzhiyun 	unsigned int clktrail;
149*4882a593Smuzhiyun 	unsigned int clkzero;
150*4882a593Smuzhiyun 	unsigned int dtermen;
151*4882a593Smuzhiyun 	unsigned int eot;
152*4882a593Smuzhiyun 	unsigned int hsexit;
153*4882a593Smuzhiyun 	unsigned int hsprepare;
154*4882a593Smuzhiyun 	unsigned int hszero;
155*4882a593Smuzhiyun 	unsigned int hssettle;
156*4882a593Smuzhiyun 	unsigned int hsskip;
157*4882a593Smuzhiyun 	unsigned int hstrail;
158*4882a593Smuzhiyun 	unsigned int init;
159*4882a593Smuzhiyun 	unsigned int lpx;
160*4882a593Smuzhiyun 	unsigned int taget;
161*4882a593Smuzhiyun 	unsigned int tago;
162*4882a593Smuzhiyun 	unsigned int tasure;
163*4882a593Smuzhiyun 	unsigned int wakeup;
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun struct inno_mipi_dphy_timing {
167*4882a593Smuzhiyun 	u8 lpx;
168*4882a593Smuzhiyun 	u8 hs_prepare;
169*4882a593Smuzhiyun 	u8 hs_zero;
170*4882a593Smuzhiyun 	u8 hs_trail;
171*4882a593Smuzhiyun 	u8 hs_exit;
172*4882a593Smuzhiyun 	u8 clk_post;
173*4882a593Smuzhiyun 	u8 wakup_h;
174*4882a593Smuzhiyun 	u8 wakup_l;
175*4882a593Smuzhiyun 	u8 clk_pre;
176*4882a593Smuzhiyun 	u8 ta_go;
177*4882a593Smuzhiyun 	u8 ta_sure;
178*4882a593Smuzhiyun 	u8 ta_wait;
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun struct inno_mipi_dphy {
182*4882a593Smuzhiyun 	struct udevice *dev;
183*4882a593Smuzhiyun 	void __iomem *regs;
184*4882a593Smuzhiyun 	unsigned int lane_mbps;
185*4882a593Smuzhiyun 	int lanes;
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun static const u32 lane_reg_offset[] = {
189*4882a593Smuzhiyun 	[CLOCK_LANE] = INNO_CLOCK_LANE_REG_BASE,
190*4882a593Smuzhiyun 	[DATA_LANE_0] = INNO_DATA_LANE_0_REG_BASE,
191*4882a593Smuzhiyun 	[DATA_LANE_1] = INNO_DATA_LANE_1_REG_BASE,
192*4882a593Smuzhiyun 	[DATA_LANE_2] = INNO_DATA_LANE_2_REG_BASE,
193*4882a593Smuzhiyun 	[DATA_LANE_3] = INNO_DATA_LANE_3_REG_BASE,
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun #define FIXED_PARAM(_freq, _lpx, _prepare, _clk_zero, _data_zero, _trail)	\
197*4882a593Smuzhiyun {	\
198*4882a593Smuzhiyun 	.max_freq = _freq,	\
199*4882a593Smuzhiyun 	.lpx = _lpx,	\
200*4882a593Smuzhiyun 	.hs_prepare = _prepare,	\
201*4882a593Smuzhiyun 	.clk_lane = {	\
202*4882a593Smuzhiyun 		.hs_zero = _clk_zero,	\
203*4882a593Smuzhiyun 	},	\
204*4882a593Smuzhiyun 	.data_lane = {	\
205*4882a593Smuzhiyun 		.hs_zero = _data_zero,	\
206*4882a593Smuzhiyun 	},	\
207*4882a593Smuzhiyun 	.hs_trail = _trail,	\
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun struct fixed_param {
211*4882a593Smuzhiyun 	unsigned int max_freq;
212*4882a593Smuzhiyun 	u8 lpx;
213*4882a593Smuzhiyun 	u8 hs_prepare;
214*4882a593Smuzhiyun 	struct {
215*4882a593Smuzhiyun 		u8 hs_zero;
216*4882a593Smuzhiyun 	} clk_lane;
217*4882a593Smuzhiyun 	struct {
218*4882a593Smuzhiyun 		u8 hs_zero;
219*4882a593Smuzhiyun 	} data_lane;
220*4882a593Smuzhiyun 	u8 hs_trail;
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun static const struct fixed_param fixed_param_table[] = {
224*4882a593Smuzhiyun 	FIXED_PARAM(110, 0x0, 0x20, 0x16, 0x02, 0x22),
225*4882a593Smuzhiyun 	FIXED_PARAM(150, 0x0, 0x06, 0x16, 0x03, 0x45),
226*4882a593Smuzhiyun 	FIXED_PARAM(200, 0x0, 0x18, 0x17, 0x04, 0x0b),
227*4882a593Smuzhiyun 	FIXED_PARAM(250, 0x0, 0x05, 0x17, 0x05, 0x16),
228*4882a593Smuzhiyun 	FIXED_PARAM(300, 0x0, 0x51, 0x18, 0x06, 0x2c),
229*4882a593Smuzhiyun 	FIXED_PARAM(400, 0x0, 0x64, 0x19, 0x07, 0x33),
230*4882a593Smuzhiyun 	FIXED_PARAM(500, 0x0, 0x20, 0x1b, 0x07, 0x4e),
231*4882a593Smuzhiyun 	FIXED_PARAM(600, 0x0, 0x6a, 0x1d, 0x08, 0x3a),
232*4882a593Smuzhiyun 	FIXED_PARAM(700, 0x0, 0x3e, 0x1e, 0x08, 0x6a),
233*4882a593Smuzhiyun 	FIXED_PARAM(800, 0x0, 0x21, 0x1f, 0x09, 0x29),
234*4882a593Smuzhiyun 	FIXED_PARAM(1000, 0x0, 0x09, 0x20, 0x09, 0x27)
235*4882a593Smuzhiyun };
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun static const struct fixed_param rk1808_fixed_param_table[] = {
238*4882a593Smuzhiyun 	FIXED_PARAM(110, 0x02, 0x7f, 0x16, 0x02, 0x02),
239*4882a593Smuzhiyun 	FIXED_PARAM(150, 0x02, 0x7f, 0x16, 0x03, 0x02),
240*4882a593Smuzhiyun 	FIXED_PARAM(200, 0x02, 0x7f, 0x17, 0x04, 0x02),
241*4882a593Smuzhiyun 	FIXED_PARAM(250, 0x02, 0x7f, 0x17, 0x05, 0x04),
242*4882a593Smuzhiyun 	FIXED_PARAM(300, 0x02, 0x7f, 0x18, 0x06, 0x04),
243*4882a593Smuzhiyun 	FIXED_PARAM(400, 0x03, 0x7e, 0x19, 0x07, 0x04),
244*4882a593Smuzhiyun 	FIXED_PARAM(500, 0x03, 0x7c, 0x1b, 0x07, 0x08),
245*4882a593Smuzhiyun 	FIXED_PARAM(600, 0x03, 0x70, 0x1d, 0x08, 0x10),
246*4882a593Smuzhiyun 	FIXED_PARAM(700, 0x05, 0x40, 0x1e, 0x08, 0x30),
247*4882a593Smuzhiyun 	FIXED_PARAM(800, 0x05, 0x02, 0x1f, 0x09, 0x30),
248*4882a593Smuzhiyun 	FIXED_PARAM(1000, 0x05, 0x08, 0x20, 0x09, 0x30),
249*4882a593Smuzhiyun 	FIXED_PARAM(1400, 0x09, 0x03, 0x32, 0x14, 0x0f),
250*4882a593Smuzhiyun 	FIXED_PARAM(1600, 0x0d, 0x42, 0x36, 0x0e, 0x0f),
251*4882a593Smuzhiyun 	FIXED_PARAM(1800, 0x0e, 0x47, 0x7a, 0x0e, 0x0f),
252*4882a593Smuzhiyun 	FIXED_PARAM(2000, 0x11, 0x64, 0x7a, 0x0e, 0x0b),
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun 
inno_write(struct inno_mipi_dphy * inno,u32 reg,u32 val)255*4882a593Smuzhiyun static inline void inno_write(struct inno_mipi_dphy *inno, u32 reg, u32 val)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	writel(val, inno->regs + reg);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
inno_read(struct inno_mipi_dphy * inno,u32 reg)260*4882a593Smuzhiyun static inline u32 inno_read(struct inno_mipi_dphy *inno, u32 reg)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	return readl(inno->regs + reg);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
inno_update_bits(struct inno_mipi_dphy * inno,u32 reg,u32 mask,u32 val)265*4882a593Smuzhiyun static inline void inno_update_bits(struct inno_mipi_dphy *inno, u32 reg,
266*4882a593Smuzhiyun 				    u32 mask, u32 val)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	u32 tmp, orig;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	orig = inno_read(inno, reg);
271*4882a593Smuzhiyun 	tmp = orig & ~mask;
272*4882a593Smuzhiyun 	tmp |= val & mask;
273*4882a593Smuzhiyun 	inno_write(inno, reg, tmp);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
mipi_dphy_timing_get_default(struct mipi_dphy_timing * timing,unsigned long period)276*4882a593Smuzhiyun static void mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
277*4882a593Smuzhiyun 					 unsigned long period)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	/* Global Operation Timing Parameters */
280*4882a593Smuzhiyun 	timing->clkmiss = 0;
281*4882a593Smuzhiyun 	timing->clkpost = 70 + 52 * period;
282*4882a593Smuzhiyun 	timing->clkpre = 8 * period;
283*4882a593Smuzhiyun 	timing->clkprepare = 65;
284*4882a593Smuzhiyun 	timing->clksettle = 95;
285*4882a593Smuzhiyun 	timing->clktermen = 0;
286*4882a593Smuzhiyun 	timing->clktrail = 80;
287*4882a593Smuzhiyun 	timing->clkzero = 260;
288*4882a593Smuzhiyun 	timing->dtermen = 0;
289*4882a593Smuzhiyun 	timing->eot = 0;
290*4882a593Smuzhiyun 	timing->hsexit = 120;
291*4882a593Smuzhiyun 	timing->hsprepare = 65 + 4 * period;
292*4882a593Smuzhiyun 	timing->hszero = 145 + 6 * period;
293*4882a593Smuzhiyun 	timing->hssettle = 85 + 6 * period;
294*4882a593Smuzhiyun 	timing->hsskip = 40;
295*4882a593Smuzhiyun 	timing->hstrail = max(8 * period, 60 + 4 * period);
296*4882a593Smuzhiyun 	timing->init = 100000;
297*4882a593Smuzhiyun 	timing->lpx = 60;
298*4882a593Smuzhiyun 	timing->taget = 5 * timing->lpx;
299*4882a593Smuzhiyun 	timing->tago = 4 * timing->lpx;
300*4882a593Smuzhiyun 	timing->tasure = 2 * timing->lpx;
301*4882a593Smuzhiyun 	timing->wakeup = 1000000;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
inno_mipi_dphy_timing_update(struct inno_mipi_dphy * inno,enum lane_type lane_type,struct inno_mipi_dphy_timing * t)304*4882a593Smuzhiyun static void inno_mipi_dphy_timing_update(struct inno_mipi_dphy *inno,
305*4882a593Smuzhiyun 					 enum lane_type lane_type,
306*4882a593Smuzhiyun 					 struct inno_mipi_dphy_timing *t)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	u32 base = lane_reg_offset[lane_type];
309*4882a593Smuzhiyun 	u32 m, v;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	m = T_HS_PREPARE_MASK;
312*4882a593Smuzhiyun 	v = T_HS_PREPARE(t->hs_prepare);
313*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_HS_PREPARE_OFFSET, m, v);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	m = T_HS_ZERO_MASK;
316*4882a593Smuzhiyun 	v = T_HS_ZERO(t->hs_zero);
317*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_HS_ZERO_OFFSET, m, v);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	m = T_HS_TRAIL_MASK;
320*4882a593Smuzhiyun 	v = T_HS_TRAIL(t->hs_trail);
321*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_HS_TRAIL_OFFSET, m, v);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	m = T_HS_EXIT_MASK;
324*4882a593Smuzhiyun 	v = T_HS_EXIT(t->hs_exit);
325*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_HS_EXIT_OFFSET, m, v);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (lane_type == CLOCK_LANE) {
328*4882a593Smuzhiyun 		m = T_CLK_POST_MASK;
329*4882a593Smuzhiyun 		v = T_CLK_POST(t->clk_post);
330*4882a593Smuzhiyun 		inno_update_bits(inno, base + T_CLK_POST_OFFSET, m, v);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 		m = T_CLK_PRE_MASK;
333*4882a593Smuzhiyun 		v = T_CLK_PRE(t->clk_pre);
334*4882a593Smuzhiyun 		inno_update_bits(inno, base + T_CLK_PRE_OFFSET, m, v);
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	m = T_WAKUP_H_MASK;
338*4882a593Smuzhiyun 	v = T_WAKUP_H(t->wakup_h);
339*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_WAKUP_H_OFFSET, m, v);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	m = T_WAKUP_L_MASK;
342*4882a593Smuzhiyun 	v = T_WAKUP_L(t->wakup_l);
343*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_WAKUP_L_OFFSET, m, v);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	m = T_LPX_MASK;
346*4882a593Smuzhiyun 	v = T_LPX(t->lpx);
347*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_LPX_OFFSET, m, v);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	m = T_TA_GO_MASK;
350*4882a593Smuzhiyun 	v = T_TA_GO(t->ta_go);
351*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_TA_GO_OFFSET, m, v);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	m = T_TA_SURE_MASK;
354*4882a593Smuzhiyun 	v = T_TA_SURE(t->ta_sure);
355*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_TA_SURE_OFFSET, m, v);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	m = T_TA_WAIT_MASK;
358*4882a593Smuzhiyun 	v = T_TA_WAIT(t->ta_wait);
359*4882a593Smuzhiyun 	inno_update_bits(inno, base + T_TA_WAIT_OFFSET, m, v);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
inno_mipi_dphy_get_fixed_param(struct inno_mipi_dphy_timing * t,unsigned int freq,enum soc_type soc_type,enum lane_type lane_type)362*4882a593Smuzhiyun static void inno_mipi_dphy_get_fixed_param(struct inno_mipi_dphy_timing *t,
363*4882a593Smuzhiyun 					   unsigned int freq,
364*4882a593Smuzhiyun 					   enum soc_type soc_type,
365*4882a593Smuzhiyun 					   enum lane_type lane_type)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	const struct fixed_param *param, *param_table;
368*4882a593Smuzhiyun 	int i, param_num;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (soc_type == RK1808_MIPI_DPHY) {
371*4882a593Smuzhiyun 		param_table = rk1808_fixed_param_table;
372*4882a593Smuzhiyun 		param_num = ARRAY_SIZE(rk1808_fixed_param_table);
373*4882a593Smuzhiyun 	} else {
374*4882a593Smuzhiyun 		param_table = fixed_param_table;
375*4882a593Smuzhiyun 		param_num = ARRAY_SIZE(fixed_param_table);
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	for (i = 0; i < param_num; i++)
379*4882a593Smuzhiyun 		if (freq <= param_table[i].max_freq)
380*4882a593Smuzhiyun 			break;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (i == param_num)
383*4882a593Smuzhiyun 		--i;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	param = &param_table[i];
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (lane_type == CLOCK_LANE)
388*4882a593Smuzhiyun 		t->hs_zero = param->clk_lane.hs_zero;
389*4882a593Smuzhiyun 	else
390*4882a593Smuzhiyun 		t->hs_zero = param->data_lane.hs_zero;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	t->hs_prepare = param->hs_prepare;
393*4882a593Smuzhiyun 	t->hs_trail = param->hs_trail;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (soc_type == RK1808_MIPI_DPHY)
396*4882a593Smuzhiyun 		t->lpx = param->lpx;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
inno_mipi_dphy_lane_timing_init(struct inno_mipi_dphy * inno,enum lane_type lane_type)399*4882a593Smuzhiyun static void inno_mipi_dphy_lane_timing_init(struct inno_mipi_dphy *inno,
400*4882a593Smuzhiyun 					    enum lane_type lane_type)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct rockchip_phy *phy =
403*4882a593Smuzhiyun 		(struct rockchip_phy *)dev_get_driver_data(inno->dev);
404*4882a593Smuzhiyun 	struct mipi_dphy_timing timing;
405*4882a593Smuzhiyun 	struct inno_mipi_dphy_timing data;
406*4882a593Smuzhiyun 	unsigned long txbyteclk, txclkesc, UI;
407*4882a593Smuzhiyun 	unsigned int esc_clk_div;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	memset(&timing, 0, sizeof(timing));
410*4882a593Smuzhiyun 	memset(&data, 0, sizeof(data));
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	txbyteclk = inno->lane_mbps * USEC_PER_SEC / 8;
413*4882a593Smuzhiyun 	esc_clk_div = DIV_ROUND_UP(txbyteclk, 20000000);
414*4882a593Smuzhiyun 	txclkesc = txbyteclk / esc_clk_div;
415*4882a593Smuzhiyun 	UI = DIV_ROUND_CLOSEST(NSEC_PER_USEC, inno->lane_mbps);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	debug("txbyteclk=%lu, txclkesc=%lu, esc_clk_div=%u, UI=%lu\n",
418*4882a593Smuzhiyun 	      txbyteclk, txclkesc, esc_clk_div, UI);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	mipi_dphy_timing_get_default(&timing, UI);
421*4882a593Smuzhiyun 	inno_mipi_dphy_get_fixed_param(&data, inno->lane_mbps,
422*4882a593Smuzhiyun 				       phy->soc_type, lane_type);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/*
425*4882a593Smuzhiyun 	 * Ttxbyteclk * val >= Ths-exit
426*4882a593Smuzhiyun 	 * Ttxbyteclk * val >= Tclk-post
427*4882a593Smuzhiyun 	 * Ttxbyteclk * val >= Tclk-pre
428*4882a593Smuzhiyun 	 * Ttxbyteclk * (2 + val) >= Tlpx
429*4882a593Smuzhiyun 	 */
430*4882a593Smuzhiyun 	data.hs_exit = DIV_ROUND_UP(timing.hsexit * txbyteclk, NSEC_PER_SEC);
431*4882a593Smuzhiyun 	data.clk_post = DIV_ROUND_UP(timing.clkpost * txbyteclk, NSEC_PER_SEC);
432*4882a593Smuzhiyun 	data.clk_pre = DIV_ROUND_UP(timing.clkpre * txbyteclk, NSEC_PER_SEC);
433*4882a593Smuzhiyun 	data.wakup_h = 0x3;
434*4882a593Smuzhiyun 	data.wakup_l = 0xff;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	if (phy->soc_type == RV1108_MIPI_DPHY) {
437*4882a593Smuzhiyun 		data.lpx = DIV_ROUND_UP(txbyteclk * timing.lpx, NSEC_PER_SEC);
438*4882a593Smuzhiyun 		if (data.lpx > 2)
439*4882a593Smuzhiyun 			data.lpx -= 2;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	/*
443*4882a593Smuzhiyun 	 * Ttxclkesc * val >= Tta-go
444*4882a593Smuzhiyun 	 * Ttxclkesc * val >= Tta-sure
445*4882a593Smuzhiyun 	 * Ttxclkesc * val >= Tta-wait
446*4882a593Smuzhiyun 	 */
447*4882a593Smuzhiyun 	data.ta_go = DIV_ROUND_UP(timing.tago * txclkesc, NSEC_PER_SEC);
448*4882a593Smuzhiyun 	data.ta_sure = DIV_ROUND_UP(timing.tasure * txclkesc, NSEC_PER_SEC);
449*4882a593Smuzhiyun 	data.ta_wait = DIV_ROUND_UP(timing.taget * txclkesc, NSEC_PER_SEC);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	inno_mipi_dphy_timing_update(inno, lane_type, &data);
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun #define TIMING_NS(x, freq) (((x) * (DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq))))
454*4882a593Smuzhiyun 	debug("hs-exit=%lu, clk-post=%lu, clk-pre=%lu, lpx=%lu\n",
455*4882a593Smuzhiyun 	      TIMING_NS(data.hs_exit, txbyteclk),
456*4882a593Smuzhiyun 	      TIMING_NS(data.clk_post, txbyteclk),
457*4882a593Smuzhiyun 	      TIMING_NS(data.clk_pre, txbyteclk),
458*4882a593Smuzhiyun 	      TIMING_NS(data.lpx + 2, txbyteclk));
459*4882a593Smuzhiyun 	debug("ta-go=%lu, ta-sure=%lu, ta-wait=%lu\n",
460*4882a593Smuzhiyun 	      TIMING_NS(data.ta_go, txclkesc),
461*4882a593Smuzhiyun 	      TIMING_NS(data.ta_sure, txclkesc),
462*4882a593Smuzhiyun 	      TIMING_NS(data.ta_wait, txclkesc));
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
inno_mipi_dphy_pll_round_rate(unsigned long fin,unsigned long fout,u8 * prediv,u16 * fbdiv)465*4882a593Smuzhiyun static unsigned long inno_mipi_dphy_pll_round_rate(unsigned long fin,
466*4882a593Smuzhiyun 						   unsigned long fout,
467*4882a593Smuzhiyun 						   u8 *prediv, u16 *fbdiv)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	unsigned long best_freq = 0;
470*4882a593Smuzhiyun 	u8 min_prediv, max_prediv;
471*4882a593Smuzhiyun 	u8 _prediv, best_prediv = 0;
472*4882a593Smuzhiyun 	u16 _fbdiv, best_fbdiv = 0;
473*4882a593Smuzhiyun 	u32 min_delta = 0xffffffff;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	fout *= 2;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	min_prediv = DIV_ROUND_UP(fin, 40000000);
478*4882a593Smuzhiyun 	max_prediv = fin / 5000000;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
481*4882a593Smuzhiyun 		u64 tmp;
482*4882a593Smuzhiyun 		u32 delta;
483*4882a593Smuzhiyun 		tmp = (u64)fout * _prediv;
484*4882a593Smuzhiyun 		do_div(tmp, fin);
485*4882a593Smuzhiyun 		_fbdiv = tmp;
486*4882a593Smuzhiyun 		if ((_fbdiv == 15) || (_fbdiv < 12) || (_fbdiv > 511))
487*4882a593Smuzhiyun 			continue;
488*4882a593Smuzhiyun 		tmp = (u64)_fbdiv * fin;
489*4882a593Smuzhiyun 		do_div(tmp, _prediv);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 		delta = abs(fout - tmp);
492*4882a593Smuzhiyun 		if (delta < min_delta) {
493*4882a593Smuzhiyun 			best_prediv = _prediv;
494*4882a593Smuzhiyun 			best_fbdiv = _fbdiv;
495*4882a593Smuzhiyun 			min_delta = delta;
496*4882a593Smuzhiyun 			best_freq = tmp;
497*4882a593Smuzhiyun 		}
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	if (best_freq) {
501*4882a593Smuzhiyun 		*prediv = best_prediv;
502*4882a593Smuzhiyun 		*fbdiv = best_fbdiv;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	return best_freq / 2;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
inno_mipi_dphy_reset(struct inno_mipi_dphy * inno)508*4882a593Smuzhiyun static inline void inno_mipi_dphy_reset(struct inno_mipi_dphy *inno)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	/* Reset analog */
511*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_POWER_CTRL,
512*4882a593Smuzhiyun 			 ANALOG_RESET_MASK, ANALOG_RESET);
513*4882a593Smuzhiyun 	udelay(1);
514*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_POWER_CTRL,
515*4882a593Smuzhiyun 			 ANALOG_RESET_MASK, ANALOG_NORMAL);
516*4882a593Smuzhiyun 	/* Reset digital */
517*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_DIG_CTRL,
518*4882a593Smuzhiyun 			 DIGITAL_RESET_MASK, DIGITAL_RESET);
519*4882a593Smuzhiyun 	udelay(1);
520*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_DIG_CTRL,
521*4882a593Smuzhiyun 			 DIGITAL_RESET_MASK, DIGITAL_NORMAL);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
inno_mipi_dphy_timing_init(struct inno_mipi_dphy * inno)524*4882a593Smuzhiyun static void inno_mipi_dphy_timing_init(struct inno_mipi_dphy *inno)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	switch (inno->lanes) {
527*4882a593Smuzhiyun 	case 4:
528*4882a593Smuzhiyun 		inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_3);
529*4882a593Smuzhiyun 		/* Fall through */
530*4882a593Smuzhiyun 	case 3:
531*4882a593Smuzhiyun 		inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_2);
532*4882a593Smuzhiyun 		/* Fall through */
533*4882a593Smuzhiyun 	case 2:
534*4882a593Smuzhiyun 		inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_1);
535*4882a593Smuzhiyun 		/* Fall through */
536*4882a593Smuzhiyun 	case 1:
537*4882a593Smuzhiyun 	default:
538*4882a593Smuzhiyun 		inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_0);
539*4882a593Smuzhiyun 		inno_mipi_dphy_lane_timing_init(inno, CLOCK_LANE);
540*4882a593Smuzhiyun 		break;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
inno_mipi_dphy_lane_enable(struct inno_mipi_dphy * inno)544*4882a593Smuzhiyun static inline void inno_mipi_dphy_lane_enable(struct inno_mipi_dphy *inno)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	u32 m = 0, v = 0;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	switch (inno->lanes) {
549*4882a593Smuzhiyun 	case 4:
550*4882a593Smuzhiyun 		m |= DATA_LANE_3_EN_MASK;
551*4882a593Smuzhiyun 		v |= DATA_LANE_3_EN;
552*4882a593Smuzhiyun 		/* Fall through */
553*4882a593Smuzhiyun 	case 3:
554*4882a593Smuzhiyun 		m |= DATA_LANE_2_EN_MASK;
555*4882a593Smuzhiyun 		v |= DATA_LANE_2_EN;
556*4882a593Smuzhiyun 		/* Fall through */
557*4882a593Smuzhiyun 	case 2:
558*4882a593Smuzhiyun 		m |= DATA_LANE_1_EN_MASK;
559*4882a593Smuzhiyun 		v |= DATA_LANE_1_EN;
560*4882a593Smuzhiyun 		/* Fall through */
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 	case 1:
563*4882a593Smuzhiyun 		m |= DATA_LANE_0_EN_MASK | CLK_LANE_EN_MASK;
564*4882a593Smuzhiyun 		v |= DATA_LANE_0_EN | CLK_LANE_EN;
565*4882a593Smuzhiyun 		break;
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, m, v);
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
inno_mipi_dphy_pll_ldo_disable(struct inno_mipi_dphy * inno)571*4882a593Smuzhiyun static inline void inno_mipi_dphy_pll_ldo_disable(struct inno_mipi_dphy *inno)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_POWER_CTRL,
574*4882a593Smuzhiyun 			 PLL_POWER_MASK | LDO_POWER_MASK,
575*4882a593Smuzhiyun 			 PLL_POWER_DOWN | LDO_POWER_DOWN);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
inno_mipi_dphy_pll_ldo_enable(struct inno_mipi_dphy * inno)578*4882a593Smuzhiyun static inline void inno_mipi_dphy_pll_ldo_enable(struct inno_mipi_dphy *inno)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_POWER_CTRL,
581*4882a593Smuzhiyun 			 PLL_POWER_MASK | LDO_POWER_MASK,
582*4882a593Smuzhiyun 			 PLL_POWER_ON | LDO_POWER_ON);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
inno_mipi_dphy_da_pwrok_enable(struct inno_mipi_dphy * inno)585*4882a593Smuzhiyun static inline void inno_mipi_dphy_da_pwrok_enable(struct inno_mipi_dphy *inno)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, PWROK_BP | PWROK, PWROK);
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
inno_mipi_dphy_da_pwrok_disable(struct inno_mipi_dphy * inno)590*4882a593Smuzhiyun static inline void inno_mipi_dphy_da_pwrok_disable(struct inno_mipi_dphy *inno)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, PWROK_BP | PWROK, PWROK_BP);
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
inno_mipi_dphy_bgpd_enable(struct inno_mipi_dphy * inno)595*4882a593Smuzhiyun static inline void inno_mipi_dphy_bgpd_enable(struct inno_mipi_dphy *inno)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, MIPI_BGPD, 0);
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun 
inno_mipi_dphy_bgpd_disable(struct inno_mipi_dphy * inno)600*4882a593Smuzhiyun static inline void inno_mipi_dphy_bgpd_disable(struct inno_mipi_dphy *inno)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, MIPI_BGPD, MIPI_BGPD);
603*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LVDS_CTRL, LVDS_BGPD, LVDS_BGPD);
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun 
inno_mipi_dphy_power_on(struct rockchip_phy * phy)606*4882a593Smuzhiyun static int inno_mipi_dphy_power_on(struct rockchip_phy *phy)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun 	struct inno_mipi_dphy *inno = dev_get_priv(phy->dev);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	inno_mipi_dphy_bgpd_enable(inno);
611*4882a593Smuzhiyun 	inno_mipi_dphy_da_pwrok_enable(inno);
612*4882a593Smuzhiyun 	inno_mipi_dphy_pll_ldo_enable(inno);
613*4882a593Smuzhiyun 	inno_mipi_dphy_lane_enable(inno);
614*4882a593Smuzhiyun 	inno_mipi_dphy_reset(inno);
615*4882a593Smuzhiyun 	inno_mipi_dphy_timing_init(inno);
616*4882a593Smuzhiyun 	udelay(1);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
inno_mipi_dphy_lane_disable(struct inno_mipi_dphy * inno)621*4882a593Smuzhiyun static inline void inno_mipi_dphy_lane_disable(struct inno_mipi_dphy *inno)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_LANE_CTRL, 0x7c, 0x00);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
inno_mipi_dphy_power_off(struct rockchip_phy * phy)626*4882a593Smuzhiyun static int inno_mipi_dphy_power_off(struct rockchip_phy *phy)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct inno_mipi_dphy *inno = dev_get_priv(phy->dev);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	inno_mipi_dphy_lane_disable(inno);
631*4882a593Smuzhiyun 	inno_mipi_dphy_pll_ldo_disable(inno);
632*4882a593Smuzhiyun 	inno_mipi_dphy_da_pwrok_disable(inno);
633*4882a593Smuzhiyun 	inno_mipi_dphy_bgpd_disable(inno);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	return 0;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun 
inno_mipi_dphy_set_pll(struct rockchip_phy * phy,unsigned long rate)638*4882a593Smuzhiyun static unsigned long inno_mipi_dphy_set_pll(struct rockchip_phy *phy,
639*4882a593Smuzhiyun 					    unsigned long rate)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	struct inno_mipi_dphy *inno = dev_get_priv(phy->dev);
642*4882a593Smuzhiyun 	unsigned long fin, fout;
643*4882a593Smuzhiyun 	u16 fbdiv = 0;
644*4882a593Smuzhiyun 	u8 prediv = 0;
645*4882a593Smuzhiyun 	u32 m, v;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	fin = 24000000;
648*4882a593Smuzhiyun 	fout = inno_mipi_dphy_pll_round_rate(fin, rate, &prediv, &fbdiv);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	debug("%s: fin=%lu, fout=%lu, prediv=%u, fbdiv=%u\n",
651*4882a593Smuzhiyun 	       __func__, fin, fout, prediv, fbdiv);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	m = FBDIV_HI_MASK | PREDIV_MASK;
654*4882a593Smuzhiyun 	v = FBDIV_HI(fbdiv >> 8) | PREDIV(prediv);
655*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_PLL_CTRL_0, m, v);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	m = FBDIV_LO_MASK;
658*4882a593Smuzhiyun 	v = FBDIV_LO(fbdiv);
659*4882a593Smuzhiyun 	inno_update_bits(inno, INNO_PHY_PLL_CTRL_1, m, v);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	if (phy->soc_type == RK1808_MIPI_DPHY) {
662*4882a593Smuzhiyun 		inno_update_bits(inno, ANALOG_REG_08,
663*4882a593Smuzhiyun 				 PLL_POST_DIV_ENABLE_MASK, PLL_POST_DIV_ENABLE);
664*4882a593Smuzhiyun 		inno_update_bits(inno, ANALOG_REG_0B,
665*4882a593Smuzhiyun 				 CLOCK_LANE_VOD_RANGE_SET_MASK,
666*4882a593Smuzhiyun 				 CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE));
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	inno->lane_mbps = fout / USEC_PER_SEC;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	return fout;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
inno_mipi_dphy_parse_dt(struct inno_mipi_dphy * inno)674*4882a593Smuzhiyun static int inno_mipi_dphy_parse_dt(struct inno_mipi_dphy *inno)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	struct udevice *dev = inno->dev;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	inno->lanes = ofnode_read_u32_default(dev->node, "inno,lanes", 4);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	return 0;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
inno_mipi_dphy_init(struct rockchip_phy * phy)683*4882a593Smuzhiyun static int inno_mipi_dphy_init(struct rockchip_phy *phy)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	struct inno_mipi_dphy *inno = dev_get_priv(phy->dev);
686*4882a593Smuzhiyun 	int ret;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	ret = inno_mipi_dphy_parse_dt(inno);
689*4882a593Smuzhiyun 	if (ret) {
690*4882a593Smuzhiyun 		printf("%s: failed to parse DT\n", __func__);
691*4882a593Smuzhiyun 		return ret;
692*4882a593Smuzhiyun 	}
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	inno->regs = dev_read_addr_ptr(inno->dev);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	return 0;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun static const struct rockchip_phy_funcs inno_mipi_dphy_funcs = {
700*4882a593Smuzhiyun 	.init = inno_mipi_dphy_init,
701*4882a593Smuzhiyun 	.power_on = inno_mipi_dphy_power_on,
702*4882a593Smuzhiyun 	.power_off = inno_mipi_dphy_power_off,
703*4882a593Smuzhiyun 	.set_pll = inno_mipi_dphy_set_pll,
704*4882a593Smuzhiyun };
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun static const struct udevice_id inno_mipi_dphy_ids[] = {
707*4882a593Smuzhiyun 	{
708*4882a593Smuzhiyun 		.compatible = "rockchip,rv1108-mipi-dphy",
709*4882a593Smuzhiyun 	},
710*4882a593Smuzhiyun 	{
711*4882a593Smuzhiyun 		.compatible = "rockchip,rk1808-mipi-dphy",
712*4882a593Smuzhiyun 	},
713*4882a593Smuzhiyun 	{
714*4882a593Smuzhiyun 		.compatible = "rockchip,rv1126-mipi-dphy",
715*4882a593Smuzhiyun 	},
716*4882a593Smuzhiyun 	{}
717*4882a593Smuzhiyun };
718*4882a593Smuzhiyun 
inno_mipi_dphy_probe(struct udevice * dev)719*4882a593Smuzhiyun static int inno_mipi_dphy_probe(struct udevice *dev)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun 	struct inno_mipi_dphy *inno = dev_get_priv(dev);
722*4882a593Smuzhiyun 	struct rockchip_phy *phy;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	phy = calloc(1, sizeof(*phy));
725*4882a593Smuzhiyun 	if (!phy)
726*4882a593Smuzhiyun 		return -ENOMEM;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	dev->driver_data = (ulong)phy;
729*4882a593Smuzhiyun 	inno->dev = dev;
730*4882a593Smuzhiyun 	phy->dev = dev;
731*4882a593Smuzhiyun 	phy->funcs = &inno_mipi_dphy_funcs;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun #if defined(CONFIG_ROCKCHIP_RV1108)
734*4882a593Smuzhiyun 	phy->soc_type = RV1108_MIPI_DPHY;
735*4882a593Smuzhiyun #else
736*4882a593Smuzhiyun 	phy->soc_type = RK1808_MIPI_DPHY;
737*4882a593Smuzhiyun #endif
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	return 0;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun U_BOOT_DRIVER(inno_mipi_dphy) = {
743*4882a593Smuzhiyun 	.name = "inno_mipi_dphy",
744*4882a593Smuzhiyun 	.id = UCLASS_PHY,
745*4882a593Smuzhiyun 	.of_match = inno_mipi_dphy_ids,
746*4882a593Smuzhiyun 	.probe = inno_mipi_dphy_probe,
747*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct inno_mipi_dphy),
748*4882a593Smuzhiyun };
749