xref: /linux/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c (revision c8afe684c95cd17cf4f273d81af369a0fdfa5a74)
1*c8afe684SRob Clark /*
2*c8afe684SRob Clark  * Copyright (C) 2013 Red Hat
3*c8afe684SRob Clark  * Author: Rob Clark <robdclark@gmail.com>
4*c8afe684SRob Clark  *
5*c8afe684SRob Clark  * This program is free software; you can redistribute it and/or modify it
6*c8afe684SRob Clark  * under the terms of the GNU General Public License version 2 as published by
7*c8afe684SRob Clark  * the Free Software Foundation.
8*c8afe684SRob Clark  *
9*c8afe684SRob Clark  * This program is distributed in the hope that it will be useful, but WITHOUT
10*c8afe684SRob Clark  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*c8afe684SRob Clark  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12*c8afe684SRob Clark  * more details.
13*c8afe684SRob Clark  *
14*c8afe684SRob Clark  * You should have received a copy of the GNU General Public License along with
15*c8afe684SRob Clark  * this program.  If not, see <http://www.gnu.org/licenses/>.
16*c8afe684SRob Clark  */
17*c8afe684SRob Clark 
18*c8afe684SRob Clark #include "hdmi.h"
19*c8afe684SRob Clark 
20*c8afe684SRob Clark struct hdmi_phy_8x60 {
21*c8afe684SRob Clark 	struct hdmi_phy base;
22*c8afe684SRob Clark 	struct hdmi *hdmi;
23*c8afe684SRob Clark };
24*c8afe684SRob Clark #define to_hdmi_phy_8x60(x) container_of(x, struct hdmi_phy_8x60, base)
25*c8afe684SRob Clark 
26*c8afe684SRob Clark static void hdmi_phy_8x60_destroy(struct hdmi_phy *phy)
27*c8afe684SRob Clark {
28*c8afe684SRob Clark 	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy);
29*c8afe684SRob Clark 	kfree(phy_8x60);
30*c8afe684SRob Clark }
31*c8afe684SRob Clark 
32*c8afe684SRob Clark static void hdmi_phy_8x60_reset(struct hdmi_phy *phy)
33*c8afe684SRob Clark {
34*c8afe684SRob Clark 	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy);
35*c8afe684SRob Clark 	struct hdmi *hdmi = phy_8x60->hdmi;
36*c8afe684SRob Clark 	unsigned int val;
37*c8afe684SRob Clark 
38*c8afe684SRob Clark 	val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
39*c8afe684SRob Clark 
40*c8afe684SRob Clark 	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
41*c8afe684SRob Clark 		/* pull low */
42*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
43*c8afe684SRob Clark 				val & ~HDMI_PHY_CTRL_SW_RESET);
44*c8afe684SRob Clark 	} else {
45*c8afe684SRob Clark 		/* pull high */
46*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
47*c8afe684SRob Clark 				val | HDMI_PHY_CTRL_SW_RESET);
48*c8afe684SRob Clark 	}
49*c8afe684SRob Clark 
50*c8afe684SRob Clark 	msleep(100);
51*c8afe684SRob Clark 
52*c8afe684SRob Clark 	if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
53*c8afe684SRob Clark 		/* pull high */
54*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
55*c8afe684SRob Clark 				val | HDMI_PHY_CTRL_SW_RESET);
56*c8afe684SRob Clark 	} else {
57*c8afe684SRob Clark 		/* pull low */
58*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
59*c8afe684SRob Clark 				val & ~HDMI_PHY_CTRL_SW_RESET);
60*c8afe684SRob Clark 	}
61*c8afe684SRob Clark }
62*c8afe684SRob Clark 
63*c8afe684SRob Clark static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy,
64*c8afe684SRob Clark 		unsigned long int pixclock)
65*c8afe684SRob Clark {
66*c8afe684SRob Clark 	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy);
67*c8afe684SRob Clark 	struct hdmi *hdmi = phy_8x60->hdmi;
68*c8afe684SRob Clark 
69*c8afe684SRob Clark 	/* De-serializer delay D/C for non-lbk mode: */
70*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG0,
71*c8afe684SRob Clark 			HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(3));
72*c8afe684SRob Clark 
73*c8afe684SRob Clark 	if (pixclock == 27000000) {
74*c8afe684SRob Clark 		/* video_format == HDMI_VFRMT_720x480p60_16_9 */
75*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1,
76*c8afe684SRob Clark 				HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) |
77*c8afe684SRob Clark 				HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(3));
78*c8afe684SRob Clark 	} else {
79*c8afe684SRob Clark 		hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1,
80*c8afe684SRob Clark 				HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) |
81*c8afe684SRob Clark 				HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(4));
82*c8afe684SRob Clark 	}
83*c8afe684SRob Clark 
84*c8afe684SRob Clark 	/* No matter what, start from the power down mode: */
85*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
86*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_PWRGEN |
87*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_PLL |
88*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
89*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
90*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
91*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
92*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
93*c8afe684SRob Clark 
94*c8afe684SRob Clark 	/* Turn PowerGen on: */
95*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
96*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_PLL |
97*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
98*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
99*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
100*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
101*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
102*c8afe684SRob Clark 
103*c8afe684SRob Clark 	/* Turn PLL power on: */
104*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
105*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
106*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
107*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
108*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
109*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
110*c8afe684SRob Clark 
111*c8afe684SRob Clark 	/* Write to HIGH after PLL power down de-assert: */
112*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3,
113*c8afe684SRob Clark 			HDMI_8x60_PHY_REG3_PLL_ENABLE);
114*c8afe684SRob Clark 
115*c8afe684SRob Clark 	/* ASIC power on; PHY REG9 = 0 */
116*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0);
117*c8afe684SRob Clark 
118*c8afe684SRob Clark 	/* Enable PLL lock detect, PLL lock det will go high after lock
119*c8afe684SRob Clark 	 * Enable the re-time logic
120*c8afe684SRob Clark 	 */
121*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12,
122*c8afe684SRob Clark 			HDMI_8x60_PHY_REG12_RETIMING_EN |
123*c8afe684SRob Clark 			HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN);
124*c8afe684SRob Clark 
125*c8afe684SRob Clark 	/* Drivers are on: */
126*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
127*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
128*c8afe684SRob Clark 
129*c8afe684SRob Clark 	/* If the RX detector is needed: */
130*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
131*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
132*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
133*c8afe684SRob Clark 
134*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG4, 0);
135*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG5, 0);
136*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG6, 0);
137*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG7, 0);
138*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG8, 0);
139*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0);
140*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG10, 0);
141*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG11, 0);
142*c8afe684SRob Clark 
143*c8afe684SRob Clark 	/* If we want to use lock enable based on counting: */
144*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12,
145*c8afe684SRob Clark 			HDMI_8x60_PHY_REG12_RETIMING_EN |
146*c8afe684SRob Clark 			HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN |
147*c8afe684SRob Clark 			HDMI_8x60_PHY_REG12_FORCE_LOCK);
148*c8afe684SRob Clark }
149*c8afe684SRob Clark 
150*c8afe684SRob Clark static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy)
151*c8afe684SRob Clark {
152*c8afe684SRob Clark 	struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy);
153*c8afe684SRob Clark 	struct hdmi *hdmi = phy_8x60->hdmi;
154*c8afe684SRob Clark 
155*c8afe684SRob Clark 	/* Assert RESET PHY from controller */
156*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
157*c8afe684SRob Clark 			HDMI_PHY_CTRL_SW_RESET);
158*c8afe684SRob Clark 	udelay(10);
159*c8afe684SRob Clark 	/* De-assert RESET PHY from controller */
160*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 0);
161*c8afe684SRob Clark 	/* Turn off Driver */
162*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
163*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
164*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
165*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
166*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
167*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
168*c8afe684SRob Clark 	udelay(10);
169*c8afe684SRob Clark 	/* Disable PLL */
170*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3, 0);
171*c8afe684SRob Clark 	/* Power down PHY, but keep RX-sense: */
172*c8afe684SRob Clark 	hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2,
173*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_RCV_SENSE_EN |
174*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_PWRGEN |
175*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_PLL |
176*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_4 |
177*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_3 |
178*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_2 |
179*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DRIVE_1 |
180*c8afe684SRob Clark 			HDMI_8x60_PHY_REG2_PD_DESER);
181*c8afe684SRob Clark }
182*c8afe684SRob Clark 
183*c8afe684SRob Clark static const struct hdmi_phy_funcs hdmi_phy_8x60_funcs = {
184*c8afe684SRob Clark 		.destroy = hdmi_phy_8x60_destroy,
185*c8afe684SRob Clark 		.reset = hdmi_phy_8x60_reset,
186*c8afe684SRob Clark 		.powerup = hdmi_phy_8x60_powerup,
187*c8afe684SRob Clark 		.powerdown = hdmi_phy_8x60_powerdown,
188*c8afe684SRob Clark };
189*c8afe684SRob Clark 
190*c8afe684SRob Clark struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi)
191*c8afe684SRob Clark {
192*c8afe684SRob Clark 	struct hdmi_phy_8x60 *phy_8x60;
193*c8afe684SRob Clark 	struct hdmi_phy *phy = NULL;
194*c8afe684SRob Clark 	int ret;
195*c8afe684SRob Clark 
196*c8afe684SRob Clark 	phy_8x60 = kzalloc(sizeof(*phy_8x60), GFP_KERNEL);
197*c8afe684SRob Clark 	if (!phy_8x60) {
198*c8afe684SRob Clark 		ret = -ENOMEM;
199*c8afe684SRob Clark 		goto fail;
200*c8afe684SRob Clark 	}
201*c8afe684SRob Clark 
202*c8afe684SRob Clark 	phy = &phy_8x60->base;
203*c8afe684SRob Clark 
204*c8afe684SRob Clark 	phy->funcs = &hdmi_phy_8x60_funcs;
205*c8afe684SRob Clark 
206*c8afe684SRob Clark 	phy_8x60->hdmi = hdmi;
207*c8afe684SRob Clark 
208*c8afe684SRob Clark 	return phy;
209*c8afe684SRob Clark 
210*c8afe684SRob Clark fail:
211*c8afe684SRob Clark 	if (phy)
212*c8afe684SRob Clark 		hdmi_phy_8x60_destroy(phy);
213*c8afe684SRob Clark 	return ERR_PTR(ret);
214*c8afe684SRob Clark }
215