1
2
3
4
5
6
7#include "sti_hdmi_tx3g4c28phy.h"
8
9#define HDMI_SRZ_CFG 0x504
10#define HDMI_SRZ_PLL_CFG 0x510
11#define HDMI_SRZ_ICNTL 0x518
12#define HDMI_SRZ_CALCODE_EXT 0x520
13
14#define HDMI_SRZ_CFG_EN BIT(0)
15#define HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT BIT(1)
16#define HDMI_SRZ_CFG_EXTERNAL_DATA BIT(16)
17#define HDMI_SRZ_CFG_RBIAS_EXT BIT(17)
18#define HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION BIT(18)
19#define HDMI_SRZ_CFG_EN_BIASRES_DETECTION BIT(19)
20#define HDMI_SRZ_CFG_EN_SRC_TERMINATION BIT(24)
21
22#define HDMI_SRZ_CFG_INTERNAL_MASK (HDMI_SRZ_CFG_EN | \
23 HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT | \
24 HDMI_SRZ_CFG_EXTERNAL_DATA | \
25 HDMI_SRZ_CFG_RBIAS_EXT | \
26 HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION | \
27 HDMI_SRZ_CFG_EN_BIASRES_DETECTION | \
28 HDMI_SRZ_CFG_EN_SRC_TERMINATION)
29
30#define PLL_CFG_EN BIT(0)
31#define PLL_CFG_NDIV_SHIFT (8)
32#define PLL_CFG_IDF_SHIFT (16)
33#define PLL_CFG_ODF_SHIFT (24)
34
35#define ODF_DIV_1 (0)
36#define ODF_DIV_2 (1)
37#define ODF_DIV_4 (2)
38#define ODF_DIV_8 (3)
39
40#define HDMI_TIMEOUT_PLL_LOCK 50
41
42struct plldividers_s {
43 uint32_t min;
44 uint32_t max;
45 uint32_t idf;
46 uint32_t odf;
47};
48
49
50
51
52#define NB_PLL_MODE 5
53static struct plldividers_s plldividers[NB_PLL_MODE] = {
54 {0, 20000000, 1, ODF_DIV_8},
55 {20000000, 42500000, 2, ODF_DIV_8},
56 {42500000, 85000000, 4, ODF_DIV_4},
57 {85000000, 170000000, 8, ODF_DIV_2},
58 {170000000, 340000000, 16, ODF_DIV_1}
59};
60
61#define NB_HDMI_PHY_CONFIG 2
62static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
63 {0, 250000000, {0x0, 0x0, 0x0, 0x0} },
64 {250000000, 300000000, {0x1110, 0x0, 0x0, 0x0} },
65};
66
67
68
69
70
71
72
73
74static bool sti_hdmi_tx3g4c28phy_start(struct sti_hdmi *hdmi)
75{
76 u32 ckpxpll = hdmi->mode.clock * 1000;
77 u32 val, tmdsck, idf, odf, pllctrl = 0;
78 bool foundplldivides = false;
79 int i;
80
81 DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
82
83 for (i = 0; i < NB_PLL_MODE; i++) {
84 if (ckpxpll >= plldividers[i].min &&
85 ckpxpll < plldividers[i].max) {
86 idf = plldividers[i].idf;
87 odf = plldividers[i].odf;
88 foundplldivides = true;
89 break;
90 }
91 }
92
93 if (!foundplldivides) {
94 DRM_ERROR("input TMDS clock speed (%d) not supported\n",
95 ckpxpll);
96 goto err;
97 }
98
99
100 tmdsck = ckpxpll;
101 pllctrl |= 40 << PLL_CFG_NDIV_SHIFT;
102
103 if (tmdsck > 340000000) {
104 DRM_ERROR("output TMDS clock (%d) out of range\n", tmdsck);
105 goto err;
106 }
107
108 pllctrl |= idf << PLL_CFG_IDF_SHIFT;
109 pllctrl |= odf << PLL_CFG_ODF_SHIFT;
110
111
112
113
114 hdmi->event_received = false;
115 DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
116 hdmi_write(hdmi, (pllctrl | PLL_CFG_EN), HDMI_SRZ_PLL_CFG);
117
118
119 wait_event_interruptible_timeout(hdmi->wait_event,
120 hdmi->event_received == true,
121 msecs_to_jiffies
122 (HDMI_TIMEOUT_PLL_LOCK));
123
124 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
125 DRM_ERROR("hdmi phy pll not locked\n");
126 goto err;
127 }
128
129 DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
130
131 val = (HDMI_SRZ_CFG_EN |
132 HDMI_SRZ_CFG_EXTERNAL_DATA |
133 HDMI_SRZ_CFG_EN_BIASRES_DETECTION |
134 HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION);
135
136 if (tmdsck > 165000000)
137 val |= HDMI_SRZ_CFG_EN_SRC_TERMINATION;
138
139
140
141
142
143
144 for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
145 if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
146 (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
147 val |= (hdmiphy_config[i].config[0]
148 & ~HDMI_SRZ_CFG_INTERNAL_MASK);
149 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
150
151 val = hdmiphy_config[i].config[1];
152 hdmi_write(hdmi, val, HDMI_SRZ_ICNTL);
153
154 val = hdmiphy_config[i].config[2];
155 hdmi_write(hdmi, val, HDMI_SRZ_CALCODE_EXT);
156
157 DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x\n",
158 hdmiphy_config[i].config[0],
159 hdmiphy_config[i].config[1],
160 hdmiphy_config[i].config[2]);
161 return true;
162 }
163 }
164
165
166
167
168
169 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
170 hdmi_write(hdmi, 0x0, HDMI_SRZ_ICNTL);
171 hdmi_write(hdmi, 0x0, HDMI_SRZ_CALCODE_EXT);
172
173 return true;
174
175err:
176 return false;
177}
178
179
180
181
182
183
184static void sti_hdmi_tx3g4c28phy_stop(struct sti_hdmi *hdmi)
185{
186 int val = 0;
187
188 DRM_DEBUG_DRIVER("\n");
189
190 hdmi->event_received = false;
191
192 val = HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION;
193 val |= HDMI_SRZ_CFG_EN_BIASRES_DETECTION;
194
195 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
196 hdmi_write(hdmi, 0, HDMI_SRZ_PLL_CFG);
197
198
199 wait_event_interruptible_timeout(hdmi->wait_event,
200 hdmi->event_received == true,
201 msecs_to_jiffies
202 (HDMI_TIMEOUT_PLL_LOCK));
203
204 if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
205 DRM_ERROR("hdmi phy pll not well disabled\n");
206}
207
208struct hdmi_phy_ops tx3g4c28phy_ops = {
209 .start = sti_hdmi_tx3g4c28phy_start,
210 .stop = sti_hdmi_tx3g4c28phy_stop,
211};
212