aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/sti
diff options
context:
space:
mode:
authorBenjamin Gaignard <benjamin.gaignard@linaro.org>2014-07-30 13:24:55 -0400
committerBenjamin Gaignard <benjamin.gaignard@linaro.org>2014-07-30 13:24:55 -0400
commit5402626c83a2f19da14859e2bab231a53e16ee74 (patch)
treeffd999a514e86e8d9cd03d6bf9ee313abc9fe7a1 /drivers/gpu/drm/sti
parent9ed68fa74e34c1bc36b76f1c4abf4dd4744ecce9 (diff)
drm: sti: add HDMI driver
Add driver for HDMI output. HDMI PHY registers are mixed into HDMI device registers and their is only one IRQ for all this hardware block. That is why PHYs aren't using phy framework but only a thin hdmi_phy_ops structure with start and stop functions. HDMI driver is mapped on drm_bridge and drm_connector structures. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Reviewed-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/sti')
-rw-r--r--drivers/gpu/drm/sti/Makefile7
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c810
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.h88
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c336
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h14
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c211
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h14
7 files changed, 1479 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
index 1534d4c43e6d..12e1a07492f0 100644
--- a/drivers/gpu/drm/sti/Makefile
+++ b/drivers/gpu/drm/sti/Makefile
@@ -1,3 +1,8 @@
1stihdmi-y := sti_hdmi.o \
2 sti_hdmi_tx3g0c55phy.o \
3 sti_hdmi_tx3g4c28phy.o \
4
1obj-$(CONFIG_DRM_STI) = \ 5obj-$(CONFIG_DRM_STI) = \
2 sti_vtg.o \ 6 sti_vtg.o \
3 sti_vtac.o \ No newline at end of file 7 sti_vtac.o \
8 stihdmi.o \ No newline at end of file
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
new file mode 100644
index 000000000000..284e541d970d
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -0,0 +1,810 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/clk.h>
8#include <linux/component.h>
9#include <linux/hdmi.h>
10#include <linux/module.h>
11#include <linux/of_gpio.h>
12#include <linux/platform_device.h>
13#include <linux/reset.h>
14
15#include <drm/drmP.h>
16#include <drm/drm_crtc_helper.h>
17#include <drm/drm_edid.h>
18
19#include "sti_hdmi.h"
20#include "sti_hdmi_tx3g4c28phy.h"
21#include "sti_hdmi_tx3g0c55phy.h"
22#include "sti_vtg.h"
23
24#define HDMI_CFG 0x0000
25#define HDMI_INT_EN 0x0004
26#define HDMI_INT_STA 0x0008
27#define HDMI_INT_CLR 0x000C
28#define HDMI_STA 0x0010
29#define HDMI_ACTIVE_VID_XMIN 0x0100
30#define HDMI_ACTIVE_VID_XMAX 0x0104
31#define HDMI_ACTIVE_VID_YMIN 0x0108
32#define HDMI_ACTIVE_VID_YMAX 0x010C
33#define HDMI_DFLT_CHL0_DAT 0x0110
34#define HDMI_DFLT_CHL1_DAT 0x0114
35#define HDMI_DFLT_CHL2_DAT 0x0118
36#define HDMI_SW_DI_1_HEAD_WORD 0x0210
37#define HDMI_SW_DI_1_PKT_WORD0 0x0214
38#define HDMI_SW_DI_1_PKT_WORD1 0x0218
39#define HDMI_SW_DI_1_PKT_WORD2 0x021C
40#define HDMI_SW_DI_1_PKT_WORD3 0x0220
41#define HDMI_SW_DI_1_PKT_WORD4 0x0224
42#define HDMI_SW_DI_1_PKT_WORD5 0x0228
43#define HDMI_SW_DI_1_PKT_WORD6 0x022C
44#define HDMI_SW_DI_CFG 0x0230
45
46#define HDMI_IFRAME_SLOT_AVI 1
47
48#define XCAT(prefix, x, suffix) prefix ## x ## suffix
49#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
50#define HDMI_SW_DI_N_PKT_WORD0(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD0)
51#define HDMI_SW_DI_N_PKT_WORD1(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD1)
52#define HDMI_SW_DI_N_PKT_WORD2(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD2)
53#define HDMI_SW_DI_N_PKT_WORD3(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD3)
54#define HDMI_SW_DI_N_PKT_WORD4(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD4)
55#define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5)
56#define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
57
58#define HDMI_IFRAME_DISABLED 0x0
59#define HDMI_IFRAME_SINGLE_SHOT 0x1
60#define HDMI_IFRAME_FIELD 0x2
61#define HDMI_IFRAME_FRAME 0x3
62#define HDMI_IFRAME_MASK 0x3
63#define HDMI_IFRAME_CFG_DI_N(x, n) ((x) << ((n-1)*4)) /* n from 1 to 6 */
64
65#define HDMI_CFG_DEVICE_EN BIT(0)
66#define HDMI_CFG_HDMI_NOT_DVI BIT(1)
67#define HDMI_CFG_HDCP_EN BIT(2)
68#define HDMI_CFG_ESS_NOT_OESS BIT(3)
69#define HDMI_CFG_H_SYNC_POL_NEG BIT(4)
70#define HDMI_CFG_SINK_TERM_DET_EN BIT(5)
71#define HDMI_CFG_V_SYNC_POL_NEG BIT(6)
72#define HDMI_CFG_422_EN BIT(8)
73#define HDMI_CFG_FIFO_OVERRUN_CLR BIT(12)
74#define HDMI_CFG_FIFO_UNDERRUN_CLR BIT(13)
75#define HDMI_CFG_SW_RST_EN BIT(31)
76
77#define HDMI_INT_GLOBAL BIT(0)
78#define HDMI_INT_SW_RST BIT(1)
79#define HDMI_INT_PIX_CAP BIT(3)
80#define HDMI_INT_HOT_PLUG BIT(4)
81#define HDMI_INT_DLL_LCK BIT(5)
82#define HDMI_INT_NEW_FRAME BIT(6)
83#define HDMI_INT_GENCTRL_PKT BIT(7)
84#define HDMI_INT_SINK_TERM_PRESENT BIT(11)
85
86#define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \
87 | HDMI_INT_DLL_LCK \
88 | HDMI_INT_HOT_PLUG \
89 | HDMI_INT_GLOBAL)
90
91#define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \
92 | HDMI_INT_GENCTRL_PKT \
93 | HDMI_INT_NEW_FRAME \
94 | HDMI_INT_DLL_LCK \
95 | HDMI_INT_HOT_PLUG \
96 | HDMI_INT_PIX_CAP \
97 | HDMI_INT_SW_RST \
98 | HDMI_INT_GLOBAL)
99
100#define HDMI_STA_SW_RST BIT(1)
101
102struct sti_hdmi_connector {
103 struct drm_connector drm_connector;
104 struct drm_encoder *encoder;
105 struct sti_hdmi *hdmi;
106};
107
108#define to_sti_hdmi_connector(x) \
109 container_of(x, struct sti_hdmi_connector, drm_connector)
110
111u32 hdmi_read(struct sti_hdmi *hdmi, int offset)
112{
113 return readl(hdmi->regs + offset);
114}
115
116void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset)
117{
118 writel(val, hdmi->regs + offset);
119}
120
121/**
122 * HDMI interrupt handler threaded
123 *
124 * @irq: irq number
125 * @arg: connector structure
126 */
127static irqreturn_t hdmi_irq_thread(int irq, void *arg)
128{
129 struct sti_hdmi *hdmi = arg;
130
131 /* Hot plug/unplug IRQ */
132 if (hdmi->irq_status & HDMI_INT_HOT_PLUG) {
133 /* read gpio to get the status */
134 hdmi->hpd = gpio_get_value(hdmi->hpd_gpio);
135 if (hdmi->drm_dev)
136 drm_helper_hpd_irq_event(hdmi->drm_dev);
137 }
138
139 /* Sw reset and PLL lock are exclusive so we can use the same
140 * event to signal them
141 */
142 if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) {
143 hdmi->event_received = true;
144 wake_up_interruptible(&hdmi->wait_event);
145 }
146
147 return IRQ_HANDLED;
148}
149
150/**
151 * HDMI interrupt handler
152 *
153 * @irq: irq number
154 * @arg: connector structure
155 */
156static irqreturn_t hdmi_irq(int irq, void *arg)
157{
158 struct sti_hdmi *hdmi = arg;
159
160 /* read interrupt status */
161 hdmi->irq_status = hdmi_read(hdmi, HDMI_INT_STA);
162
163 /* clear interrupt status */
164 hdmi_write(hdmi, hdmi->irq_status, HDMI_INT_CLR);
165
166 /* force sync bus write */
167 hdmi_read(hdmi, HDMI_INT_STA);
168
169 return IRQ_WAKE_THREAD;
170}
171
172/**
173 * Set hdmi active area depending on the drm display mode selected
174 *
175 * @hdmi: pointer on the hdmi internal structure
176 */
177static void hdmi_active_area(struct sti_hdmi *hdmi)
178{
179 u32 xmin, xmax;
180 u32 ymin, ymax;
181
182 xmin = sti_vtg_get_pixel_number(hdmi->mode, 0);
183 xmax = sti_vtg_get_pixel_number(hdmi->mode, hdmi->mode.hdisplay - 1);
184 ymin = sti_vtg_get_line_number(hdmi->mode, 0);
185 ymax = sti_vtg_get_line_number(hdmi->mode, hdmi->mode.vdisplay - 1);
186
187 hdmi_write(hdmi, xmin, HDMI_ACTIVE_VID_XMIN);
188 hdmi_write(hdmi, xmax, HDMI_ACTIVE_VID_XMAX);
189 hdmi_write(hdmi, ymin, HDMI_ACTIVE_VID_YMIN);
190 hdmi_write(hdmi, ymax, HDMI_ACTIVE_VID_YMAX);
191}
192
193/**
194 * Overall hdmi configuration
195 *
196 * @hdmi: pointer on the hdmi internal structure
197 */
198static void hdmi_config(struct sti_hdmi *hdmi)
199{
200 u32 conf;
201
202 DRM_DEBUG_DRIVER("\n");
203
204 /* Clear overrun and underrun fifo */
205 conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
206
207 /* Enable HDMI mode not DVI */
208 conf |= HDMI_CFG_HDMI_NOT_DVI | HDMI_CFG_ESS_NOT_OESS;
209
210 /* Enable sink term detection */
211 conf |= HDMI_CFG_SINK_TERM_DET_EN;
212
213 /* Set Hsync polarity */
214 if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) {
215 DRM_DEBUG_DRIVER("H Sync Negative\n");
216 conf |= HDMI_CFG_H_SYNC_POL_NEG;
217 }
218
219 /* Set Vsync polarity */
220 if (hdmi->mode.flags & DRM_MODE_FLAG_NVSYNC) {
221 DRM_DEBUG_DRIVER("V Sync Negative\n");
222 conf |= HDMI_CFG_V_SYNC_POL_NEG;
223 }
224
225 /* Enable HDMI */
226 conf |= HDMI_CFG_DEVICE_EN;
227
228 hdmi_write(hdmi, conf, HDMI_CFG);
229}
230
231/**
232 * Prepare and configure the AVI infoframe
233 *
234 * AVI infoframe are transmitted at least once per two video field and
235 * contains information about HDMI transmission mode such as color space,
236 * colorimetry, ...
237 *
238 * @hdmi: pointer on the hdmi internal structure
239 *
240 * Return negative value if error occurs
241 */
242static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
243{
244 struct drm_display_mode *mode = &hdmi->mode;
245 struct hdmi_avi_infoframe infoframe;
246 u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
247 u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE;
248 u32 val;
249 int ret;
250
251 DRM_DEBUG_DRIVER("\n");
252
253 ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode);
254 if (ret < 0) {
255 DRM_ERROR("failed to setup AVI infoframe: %d\n", ret);
256 return ret;
257 }
258
259 /* fixed infoframe configuration not linked to the mode */
260 infoframe.colorspace = HDMI_COLORSPACE_RGB;
261 infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
262 infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
263
264 ret = hdmi_avi_infoframe_pack(&infoframe, buffer, sizeof(buffer));
265 if (ret < 0) {
266 DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
267 return ret;
268 }
269
270 /* Disable transmission slot for AVI infoframe */
271 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
272 val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI);
273 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
274
275 /* Infoframe header */
276 val = buffer[0x0];
277 val |= buffer[0x1] << 8;
278 val |= buffer[0x2] << 16;
279 hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI));
280
281 /* Infoframe packet bytes */
282 val = frame[0x0];
283 val |= frame[0x1] << 8;
284 val |= frame[0x2] << 16;
285 val |= frame[0x3] << 24;
286 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI));
287
288 val = frame[0x4];
289 val |= frame[0x5] << 8;
290 val |= frame[0x6] << 16;
291 val |= frame[0x7] << 24;
292 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI));
293
294 val = frame[0x8];
295 val |= frame[0x9] << 8;
296 val |= frame[0xA] << 16;
297 val |= frame[0xB] << 24;
298 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI));
299
300 val = frame[0xC];
301 val |= frame[0xD] << 8;
302 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI));
303
304 /* Enable transmission slot for AVI infoframe
305 * According to the hdmi specification, AVI infoframe should be
306 * transmitted at least once per two video fields
307 */
308 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
309 val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI);
310 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
311
312 return 0;
313}
314
315/**
316 * Software reset of the hdmi subsystem
317 *
318 * @hdmi: pointer on the hdmi internal structure
319 *
320 */
321#define HDMI_TIMEOUT_SWRESET 100 /*milliseconds */
322static void hdmi_swreset(struct sti_hdmi *hdmi)
323{
324 u32 val;
325
326 DRM_DEBUG_DRIVER("\n");
327
328 /* Enable hdmi_audio clock only during hdmi reset */
329 if (clk_prepare_enable(hdmi->clk_audio))
330 DRM_INFO("Failed to prepare/enable hdmi_audio clk\n");
331
332 /* Sw reset */
333 hdmi->event_received = false;
334
335 val = hdmi_read(hdmi, HDMI_CFG);
336 val |= HDMI_CFG_SW_RST_EN;
337 hdmi_write(hdmi, val, HDMI_CFG);
338
339 /* Wait reset completed */
340 wait_event_interruptible_timeout(hdmi->wait_event,
341 hdmi->event_received == true,
342 msecs_to_jiffies
343 (HDMI_TIMEOUT_SWRESET));
344
345 /*
346 * HDMI_STA_SW_RST bit is set to '1' when SW_RST bit in HDMI_CFG is
347 * set to '1' and clk_audio is running.
348 */
349 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_SW_RST) == 0)
350 DRM_DEBUG_DRIVER("Warning: HDMI sw reset timeout occurs\n");
351
352 val = hdmi_read(hdmi, HDMI_CFG);
353 val &= ~HDMI_CFG_SW_RST_EN;
354 hdmi_write(hdmi, val, HDMI_CFG);
355
356 /* Disable hdmi_audio clock. Not used anymore for drm purpose */
357 clk_disable_unprepare(hdmi->clk_audio);
358}
359
360static void sti_hdmi_disable(struct drm_bridge *bridge)
361{
362 struct sti_hdmi *hdmi = bridge->driver_private;
363
364 u32 val = hdmi_read(hdmi, HDMI_CFG);
365
366 if (!hdmi->enabled)
367 return;
368
369 DRM_DEBUG_DRIVER("\n");
370
371 /* Disable HDMI */
372 val &= ~HDMI_CFG_DEVICE_EN;
373 hdmi_write(hdmi, val, HDMI_CFG);
374
375 hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR);
376
377 /* Stop the phy */
378 hdmi->phy_ops->stop(hdmi);
379
380 /* Set the default channel data to be a dark red */
381 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT);
382 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
383 hdmi_write(hdmi, 0x0060, HDMI_DFLT_CHL2_DAT);
384
385 /* Disable/unprepare hdmi clock */
386 clk_disable_unprepare(hdmi->clk_phy);
387 clk_disable_unprepare(hdmi->clk_tmds);
388 clk_disable_unprepare(hdmi->clk_pix);
389
390 hdmi->enabled = false;
391}
392
393static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
394{
395 struct sti_hdmi *hdmi = bridge->driver_private;
396
397 DRM_DEBUG_DRIVER("\n");
398
399 if (hdmi->enabled)
400 return;
401
402 /* Prepare/enable clocks */
403 if (clk_prepare_enable(hdmi->clk_pix))
404 DRM_ERROR("Failed to prepare/enable hdmi_pix clk\n");
405 if (clk_prepare_enable(hdmi->clk_tmds))
406 DRM_ERROR("Failed to prepare/enable hdmi_tmds clk\n");
407 if (clk_prepare_enable(hdmi->clk_phy))
408 DRM_ERROR("Failed to prepare/enable hdmi_rejec_pll clk\n");
409
410 hdmi->enabled = true;
411
412 /* Program hdmi serializer and start phy */
413 if (!hdmi->phy_ops->start(hdmi)) {
414 DRM_ERROR("Unable to start hdmi phy\n");
415 return;
416 }
417
418 /* Program hdmi active area */
419 hdmi_active_area(hdmi);
420
421 /* Enable working interrupts */
422 hdmi_write(hdmi, HDMI_WORKING_INT, HDMI_INT_EN);
423
424 /* Program hdmi config */
425 hdmi_config(hdmi);
426
427 /* Program AVI infoframe */
428 if (hdmi_avi_infoframe_config(hdmi))
429 DRM_ERROR("Unable to configure AVI infoframe\n");
430
431 /* Sw reset */
432 hdmi_swreset(hdmi);
433}
434
435static void sti_hdmi_set_mode(struct drm_bridge *bridge,
436 struct drm_display_mode *mode,
437 struct drm_display_mode *adjusted_mode)
438{
439 struct sti_hdmi *hdmi = bridge->driver_private;
440 int ret;
441
442 DRM_DEBUG_DRIVER("\n");
443
444 /* Copy the drm display mode in the connector local structure */
445 memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
446
447 /* Update clock framerate according to the selected mode */
448 ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
449 if (ret < 0) {
450 DRM_ERROR("Cannot set rate (%dHz) for hdmi_pix clk\n",
451 mode->clock * 1000);
452 return;
453 }
454 ret = clk_set_rate(hdmi->clk_phy, mode->clock * 1000);
455 if (ret < 0) {
456 DRM_ERROR("Cannot set rate (%dHz) for hdmi_rejection_pll clk\n",
457 mode->clock * 1000);
458 return;
459 }
460}
461
462static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
463{
464 /* do nothing */
465}
466
467static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
468{
469 drm_bridge_cleanup(bridge);
470 kfree(bridge);
471}
472
473static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
474 .pre_enable = sti_hdmi_pre_enable,
475 .enable = sti_hdmi_bridge_nope,
476 .disable = sti_hdmi_disable,
477 .post_disable = sti_hdmi_bridge_nope,
478 .mode_set = sti_hdmi_set_mode,
479 .destroy = sti_hdmi_brigde_destroy,
480};
481
482static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
483{
484 struct i2c_adapter *i2c_adap;
485 struct edid *edid;
486 int count;
487
488 DRM_DEBUG_DRIVER("\n");
489
490 i2c_adap = i2c_get_adapter(1);
491 if (!i2c_adap)
492 goto fail;
493
494 edid = drm_get_edid(connector, i2c_adap);
495 if (!edid)
496 goto fail;
497
498 count = drm_add_edid_modes(connector, edid);
499 drm_mode_connector_update_edid_property(connector, edid);
500
501 kfree(edid);
502 return count;
503
504fail:
505 DRM_ERROR("Can not read HDMI EDID\n");
506 return 0;
507}
508
509#define CLK_TOLERANCE_HZ 50
510
511static int sti_hdmi_connector_mode_valid(struct drm_connector *connector,
512 struct drm_display_mode *mode)
513{
514 int target = mode->clock * 1000;
515 int target_min = target - CLK_TOLERANCE_HZ;
516 int target_max = target + CLK_TOLERANCE_HZ;
517 int result;
518 struct sti_hdmi_connector *hdmi_connector
519 = to_sti_hdmi_connector(connector);
520 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
521
522
523 result = clk_round_rate(hdmi->clk_pix, target);
524
525 DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
526 target, result);
527
528 if ((result < target_min) || (result > target_max)) {
529 DRM_DEBUG_DRIVER("hdmi pixclk=%d not supported\n", target);
530 return MODE_BAD;
531 }
532
533 return MODE_OK;
534}
535
536struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
537{
538 struct sti_hdmi_connector *hdmi_connector
539 = to_sti_hdmi_connector(connector);
540
541 /* Best encoder is the one associated during connector creation */
542 return hdmi_connector->encoder;
543}
544
545static struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
546 .get_modes = sti_hdmi_connector_get_modes,
547 .mode_valid = sti_hdmi_connector_mode_valid,
548 .best_encoder = sti_hdmi_best_encoder,
549};
550
551/* get detection status of display device */
552static enum drm_connector_status
553sti_hdmi_connector_detect(struct drm_connector *connector, bool force)
554{
555 struct sti_hdmi_connector *hdmi_connector
556 = to_sti_hdmi_connector(connector);
557 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
558
559 DRM_DEBUG_DRIVER("\n");
560
561 if (hdmi->hpd) {
562 DRM_DEBUG_DRIVER("hdmi cable connected\n");
563 return connector_status_connected;
564 }
565
566 DRM_DEBUG_DRIVER("hdmi cable disconnected\n");
567 return connector_status_disconnected;
568}
569
570static void sti_hdmi_connector_destroy(struct drm_connector *connector)
571{
572 struct sti_hdmi_connector *hdmi_connector
573 = to_sti_hdmi_connector(connector);
574
575 drm_connector_unregister(connector);
576 drm_connector_cleanup(connector);
577 kfree(hdmi_connector);
578}
579
580static struct drm_connector_funcs sti_hdmi_connector_funcs = {
581 .dpms = drm_helper_connector_dpms,
582 .fill_modes = drm_helper_probe_single_connector_modes,
583 .detect = sti_hdmi_connector_detect,
584 .destroy = sti_hdmi_connector_destroy,
585};
586
587static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
588{
589 struct drm_encoder *encoder;
590
591 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
592 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
593 return encoder;
594 }
595
596 return NULL;
597}
598
599static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
600{
601 struct sti_hdmi *hdmi = dev_get_drvdata(dev);
602 struct drm_device *drm_dev = data;
603 struct drm_encoder *encoder;
604 struct sti_hdmi_connector *connector;
605 struct drm_connector *drm_connector;
606 struct drm_bridge *bridge;
607 struct i2c_adapter *i2c_adap;
608 int err;
609
610 i2c_adap = i2c_get_adapter(1);
611 if (!i2c_adap)
612 return -EPROBE_DEFER;
613
614 /* Set the drm device handle */
615 hdmi->drm_dev = drm_dev;
616
617 encoder = sti_hdmi_find_encoder(drm_dev);
618 if (!encoder)
619 return -ENOMEM;
620
621 connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
622 if (!connector)
623 return -ENOMEM;
624
625 connector->hdmi = hdmi;
626
627 bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
628 if (!bridge)
629 return -ENOMEM;
630
631 bridge->driver_private = hdmi;
632 drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
633
634 encoder->bridge = bridge;
635 connector->encoder = encoder;
636
637 drm_connector = (struct drm_connector *)connector;
638
639 drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
640
641 drm_connector_init(drm_dev, drm_connector,
642 &sti_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
643 drm_connector_helper_add(drm_connector,
644 &sti_hdmi_connector_helper_funcs);
645
646 err = drm_connector_register(drm_connector);
647 if (err)
648 goto err_connector;
649
650 err = drm_mode_connector_attach_encoder(drm_connector, encoder);
651 if (err) {
652 DRM_ERROR("Failed to attach a connector to a encoder\n");
653 goto err_sysfs;
654 }
655
656 /* Enable default interrupts */
657 hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
658
659 return 0;
660
661err_sysfs:
662 drm_connector_unregister(drm_connector);
663err_connector:
664 drm_bridge_cleanup(bridge);
665 drm_connector_cleanup(drm_connector);
666 return -EINVAL;
667}
668
669static void sti_hdmi_unbind(struct device *dev,
670 struct device *master, void *data)
671{
672 /* do nothing */
673}
674
675static const struct component_ops sti_hdmi_ops = {
676 .bind = sti_hdmi_bind,
677 .unbind = sti_hdmi_unbind,
678};
679
680static struct of_device_id hdmi_of_match[] = {
681 {
682 .compatible = "st,stih416-hdmi",
683 .data = &tx3g0c55phy_ops,
684 }, {
685 .compatible = "st,stih407-hdmi",
686 .data = &tx3g4c28phy_ops,
687 }, {
688 /* end node */
689 }
690};
691MODULE_DEVICE_TABLE(of, hdmi_of_match);
692
693static int sti_hdmi_probe(struct platform_device *pdev)
694{
695 struct device *dev = &pdev->dev;
696 struct sti_hdmi *hdmi;
697 struct device_node *np = dev->of_node;
698 struct resource *res;
699 int ret;
700
701 DRM_INFO("%s\n", __func__);
702
703 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
704 if (!hdmi)
705 return -ENOMEM;
706
707 hdmi->dev = pdev->dev;
708
709 /* Get resources */
710 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
711 if (!res) {
712 DRM_ERROR("Invalid hdmi resource\n");
713 return -ENOMEM;
714 }
715 hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
716 if (IS_ERR(hdmi->regs))
717 return PTR_ERR(hdmi->regs);
718
719 if (of_device_is_compatible(np, "st,stih416-hdmi")) {
720 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
721 "syscfg");
722 if (!res) {
723 DRM_ERROR("Invalid syscfg resource\n");
724 return -ENOMEM;
725 }
726 hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
727 resource_size(res));
728 if (IS_ERR(hdmi->syscfg))
729 return PTR_ERR(hdmi->syscfg);
730
731 }
732
733 hdmi->phy_ops = (struct hdmi_phy_ops *)
734 of_match_node(hdmi_of_match, np)->data;
735
736 /* Get clock resources */
737 hdmi->clk_pix = devm_clk_get(dev, "pix");
738 if (IS_ERR(hdmi->clk_pix)) {
739 DRM_ERROR("Cannot get hdmi_pix clock\n");
740 return PTR_ERR(hdmi->clk_pix);
741 }
742
743 hdmi->clk_tmds = devm_clk_get(dev, "tmds");
744 if (IS_ERR(hdmi->clk_tmds)) {
745 DRM_ERROR("Cannot get hdmi_tmds clock\n");
746 return PTR_ERR(hdmi->clk_tmds);
747 }
748
749 hdmi->clk_phy = devm_clk_get(dev, "phy");
750 if (IS_ERR(hdmi->clk_phy)) {
751 DRM_ERROR("Cannot get hdmi_phy clock\n");
752 return PTR_ERR(hdmi->clk_phy);
753 }
754
755 hdmi->clk_audio = devm_clk_get(dev, "audio");
756 if (IS_ERR(hdmi->clk_audio)) {
757 DRM_ERROR("Cannot get hdmi_audio clock\n");
758 return PTR_ERR(hdmi->clk_audio);
759 }
760
761 hdmi->hpd_gpio = of_get_named_gpio(np, "hdmi,hpd-gpio", 0);
762 if (hdmi->hpd_gpio < 0) {
763 DRM_ERROR("Failed to get hdmi hpd-gpio\n");
764 return -EIO;
765 }
766
767 hdmi->hpd = gpio_get_value(hdmi->hpd_gpio);
768
769 init_waitqueue_head(&hdmi->wait_event);
770
771 hdmi->irq = platform_get_irq_byname(pdev, "irq");
772
773 ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq,
774 hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
775 if (ret) {
776 DRM_ERROR("Failed to register HDMI interrupt\n");
777 return ret;
778 }
779
780 hdmi->reset = devm_reset_control_get(dev, "hdmi");
781 /* Take hdmi out of reset */
782 if (!IS_ERR(hdmi->reset))
783 reset_control_deassert(hdmi->reset);
784
785 platform_set_drvdata(pdev, hdmi);
786
787 return component_add(&pdev->dev, &sti_hdmi_ops);
788}
789
790static int sti_hdmi_remove(struct platform_device *pdev)
791{
792 component_del(&pdev->dev, &sti_hdmi_ops);
793 return 0;
794}
795
796struct platform_driver sti_hdmi_driver = {
797 .driver = {
798 .name = "sti-hdmi",
799 .owner = THIS_MODULE,
800 .of_match_table = hdmi_of_match,
801 },
802 .probe = sti_hdmi_probe,
803 .remove = sti_hdmi_remove,
804};
805
806module_platform_driver(sti_hdmi_driver);
807
808MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
809MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
810MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h
new file mode 100644
index 000000000000..61bec6557ceb
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi.h
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_H_
8#define _STI_HDMI_H_
9
10#include <linux/platform_device.h>
11
12#include <drm/drmP.h>
13
14#define HDMI_STA 0x0010
15#define HDMI_STA_DLL_LCK BIT(5)
16
17struct sti_hdmi;
18
19struct hdmi_phy_ops {
20 bool (*start)(struct sti_hdmi *hdmi);
21 void (*stop)(struct sti_hdmi *hdmi);
22};
23
24/**
25 * STI hdmi structure
26 *
27 * @dev: driver device
28 * @drm_dev: pointer to drm device
29 * @mode: current display mode selected
30 * @regs: hdmi register
31 * @syscfg: syscfg register for pll rejection configuration
32 * @clk_pix: hdmi pixel clock
33 * @clk_tmds: hdmi tmds clock
34 * @clk_phy: hdmi phy clock
35 * @clk_audio: hdmi audio clock
36 * @irq: hdmi interrupt number
37 * @irq_status: interrupt status register
38 * @phy_ops: phy start/stop operations
39 * @enabled: true if hdmi is enabled else false
40 * @hpd_gpio: hdmi hot plug detect gpio number
41 * @hpd: hot plug detect status
42 * @wait_event: wait event
43 * @event_received: wait event status
44 * @reset: reset control of the hdmi phy
45 */
46struct sti_hdmi {
47 struct device dev;
48 struct drm_device *drm_dev;
49 struct drm_display_mode mode;
50 void __iomem *regs;
51 void __iomem *syscfg;
52 struct clk *clk_pix;
53 struct clk *clk_tmds;
54 struct clk *clk_phy;
55 struct clk *clk_audio;
56 int irq;
57 u32 irq_status;
58 struct hdmi_phy_ops *phy_ops;
59 bool enabled;
60 int hpd_gpio;
61 bool hpd;
62 wait_queue_head_t wait_event;
63 bool event_received;
64 struct reset_control *reset;
65};
66
67u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
68void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset);
69
70/**
71 * hdmi phy config structure
72 *
73 * A pointer to an array of these structures is passed to a TMDS (HDMI) output
74 * via the control interface to provide board and SoC specific
75 * configurations of the HDMI PHY. Each entry in the array specifies a hardware
76 * specific configuration for a given TMDS clock frequency range.
77 *
78 * @min_tmds_freq: Lower bound of TMDS clock frequency this entry applies to
79 * @max_tmds_freq: Upper bound of TMDS clock frequency this entry applies to
80 * @config: SoC specific register configuration
81 */
82struct hdmi_phy_config {
83 u32 min_tmds_freq;
84 u32 max_tmds_freq;
85 u32 config[4];
86};
87
88#endif
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c
new file mode 100644
index 000000000000..49ae8e44b285
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c
@@ -0,0 +1,336 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include "sti_hdmi_tx3g0c55phy.h"
8
9#define HDMI_SRZ_PLL_CFG 0x0504
10#define HDMI_SRZ_TAP_1 0x0508
11#define HDMI_SRZ_TAP_2 0x050C
12#define HDMI_SRZ_TAP_3 0x0510
13#define HDMI_SRZ_CTRL 0x0514
14
15#define HDMI_SRZ_PLL_CFG_POWER_DOWN BIT(0)
16#define HDMI_SRZ_PLL_CFG_VCOR_SHIFT 1
17#define HDMI_SRZ_PLL_CFG_VCOR_425MHZ 0
18#define HDMI_SRZ_PLL_CFG_VCOR_850MHZ 1
19#define HDMI_SRZ_PLL_CFG_VCOR_1700MHZ 2
20#define HDMI_SRZ_PLL_CFG_VCOR_3000MHZ 3
21#define HDMI_SRZ_PLL_CFG_VCOR_MASK 3
22#define HDMI_SRZ_PLL_CFG_VCOR(x) (x << HDMI_SRZ_PLL_CFG_VCOR_SHIFT)
23#define HDMI_SRZ_PLL_CFG_NDIV_SHIFT 8
24#define HDMI_SRZ_PLL_CFG_NDIV_MASK (0x1F << HDMI_SRZ_PLL_CFG_NDIV_SHIFT)
25#define HDMI_SRZ_PLL_CFG_MODE_SHIFT 16
26#define HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ 0x1
27#define HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ 0x4
28#define HDMI_SRZ_PLL_CFG_MODE_27_MHZ 0x5
29#define HDMI_SRZ_PLL_CFG_MODE_33_75_MHZ 0x6
30#define HDMI_SRZ_PLL_CFG_MODE_40_5_MHZ 0x7
31#define HDMI_SRZ_PLL_CFG_MODE_54_MHZ 0x8
32#define HDMI_SRZ_PLL_CFG_MODE_67_5_MHZ 0x9
33#define HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ 0xA
34#define HDMI_SRZ_PLL_CFG_MODE_81_MHZ 0xB
35#define HDMI_SRZ_PLL_CFG_MODE_82_5_MHZ 0xC
36#define HDMI_SRZ_PLL_CFG_MODE_108_MHZ 0xD
37#define HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ 0xE
38#define HDMI_SRZ_PLL_CFG_MODE_165_MHZ 0xF
39#define HDMI_SRZ_PLL_CFG_MODE_MASK 0xF
40#define HDMI_SRZ_PLL_CFG_MODE(x) (x << HDMI_SRZ_PLL_CFG_MODE_SHIFT)
41
42#define HDMI_SRZ_CTRL_POWER_DOWN (1 << 0)
43#define HDMI_SRZ_CTRL_EXTERNAL_DATA_EN (1 << 1)
44
45/* sysconf registers */
46#define HDMI_REJECTION_PLL_CONFIGURATION 0x0858 /* SYSTEM_CONFIG2534 */
47#define HDMI_REJECTION_PLL_STATUS 0x0948 /* SYSTEM_CONFIG2594 */
48
49#define REJECTION_PLL_HDMI_ENABLE_SHIFT 0
50#define REJECTION_PLL_HDMI_ENABLE_MASK (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT)
51#define REJECTION_PLL_HDMI_PDIV_SHIFT 24
52#define REJECTION_PLL_HDMI_PDIV_MASK (0x7 << REJECTION_PLL_HDMI_PDIV_SHIFT)
53#define REJECTION_PLL_HDMI_NDIV_SHIFT 16
54#define REJECTION_PLL_HDMI_NDIV_MASK (0xFF << REJECTION_PLL_HDMI_NDIV_SHIFT)
55#define REJECTION_PLL_HDMI_MDIV_SHIFT 8
56#define REJECTION_PLL_HDMI_MDIV_MASK (0xFF << REJECTION_PLL_HDMI_MDIV_SHIFT)
57
58#define REJECTION_PLL_HDMI_REJ_PLL_LOCK BIT(0)
59
60#define HDMI_TIMEOUT_PLL_LOCK 50 /*milliseconds */
61
62/**
63 * pll mode structure
64 *
65 * A pointer to an array of these structures is passed to a TMDS (HDMI) output
66 * via the control interface to provide board and SoC specific
67 * configurations of the HDMI PHY. Each entry in the array specifies a hardware
68 * specific configuration for a given TMDS clock frequency range. The array
69 * should be terminated with an entry that has all fields set to zero.
70 *
71 * @min: Lower bound of TMDS clock frequency this entry applies to
72 * @max: Upper bound of TMDS clock frequency this entry applies to
73 * @mode: SoC specific register configuration
74 */
75struct pllmode {
76 u32 min;
77 u32 max;
78 u32 mode;
79};
80
81#define NB_PLL_MODE 7
82static struct pllmode pllmodes[NB_PLL_MODE] = {
83 {13500000, 13513500, HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ},
84 {25174800, 25200000, HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ},
85 {27000000, 27027000, HDMI_SRZ_PLL_CFG_MODE_27_MHZ},
86 {54000000, 54054000, HDMI_SRZ_PLL_CFG_MODE_54_MHZ},
87 {72000000, 74250000, HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ},
88 {108000000, 108108000, HDMI_SRZ_PLL_CFG_MODE_108_MHZ},
89 {148351648, 297000000, HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ}
90};
91
92#define NB_HDMI_PHY_CONFIG 5
93static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
94 {0, 40000000, {0x00101010, 0x00101010, 0x00101010, 0x02} },
95 {40000000, 140000000, {0x00111111, 0x00111111, 0x00111111, 0x02} },
96 {140000000, 160000000, {0x00131313, 0x00101010, 0x00101010, 0x02} },
97 {160000000, 250000000, {0x00131313, 0x00111111, 0x00111111, 0x03FE} },
98 {250000000, 300000000, {0x00151515, 0x00101010, 0x00101010, 0x03FE} },
99};
100
101#define PLL_CHANGE_DELAY 1 /* ms */
102
103/**
104 * Disable the pll rejection
105 *
106 * @hdmi: pointer on the hdmi internal structure
107 *
108 * return true if the pll has been disabled
109 */
110static bool disable_pll_rejection(struct sti_hdmi *hdmi)
111{
112 u32 val;
113
114 DRM_DEBUG_DRIVER("\n");
115
116 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
117 val &= ~REJECTION_PLL_HDMI_ENABLE_MASK;
118 writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
119
120 msleep(PLL_CHANGE_DELAY);
121 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
122
123 return !(val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
124}
125
126/**
127 * Enable the old BCH/rejection PLL is now reused to provide the CLKPXPLL
128 * clock input to the new PHY PLL that generates the serializer clock
129 * (TMDS*10) and the TMDS clock which is now fed back into the HDMI
130 * formatter instead of the TMDS clock line from ClockGenB.
131 *
132 * @hdmi: pointer on the hdmi internal structure
133 *
134 * return true if pll has been correctly set
135 */
136static bool enable_pll_rejection(struct sti_hdmi *hdmi)
137{
138 unsigned int inputclock;
139 u32 mdiv, ndiv, pdiv, val;
140
141 DRM_DEBUG_DRIVER("\n");
142
143 if (!disable_pll_rejection(hdmi))
144 return false;
145
146 inputclock = hdmi->mode.clock * 1000;
147
148 DRM_DEBUG_DRIVER("hdmi rejection pll input clock = %dHz\n", inputclock);
149
150
151 /* Power up the HDMI rejection PLL
152 * Note: On this SoC (stiH416) we are forced to have the input clock
153 * be equal to the HDMI pixel clock.
154 *
155 * The values here have been suggested by validation however they are
156 * still provisional and subject to change.
157 *
158 * PLLout = (Fin*Mdiv) / ((2 * Ndiv) / 2^Pdiv)
159 */
160 if (inputclock < 50000000) {
161 /*
162 * For slower clocks we need to multiply more to keep the
163 * internal VCO frequency within the physical specification
164 * of the PLL.
165 */
166 pdiv = 4;
167 ndiv = 240;
168 mdiv = 30;
169 } else {
170 pdiv = 2;
171 ndiv = 60;
172 mdiv = 30;
173 }
174
175 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
176
177 val &= ~(REJECTION_PLL_HDMI_PDIV_MASK |
178 REJECTION_PLL_HDMI_NDIV_MASK |
179 REJECTION_PLL_HDMI_MDIV_MASK |
180 REJECTION_PLL_HDMI_ENABLE_MASK);
181
182 val |= (pdiv << REJECTION_PLL_HDMI_PDIV_SHIFT) |
183 (ndiv << REJECTION_PLL_HDMI_NDIV_SHIFT) |
184 (mdiv << REJECTION_PLL_HDMI_MDIV_SHIFT) |
185 (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT);
186
187 writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
188
189 msleep(PLL_CHANGE_DELAY);
190 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
191
192 return (val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
193}
194
195/**
196 * Start hdmi phy macro cell tx3g0c55
197 *
198 * @hdmi: pointer on the hdmi internal structure
199 *
200 * Return false if an error occur
201 */
202static bool sti_hdmi_tx3g0c55phy_start(struct sti_hdmi *hdmi)
203{
204 u32 ckpxpll = hdmi->mode.clock * 1000;
205 u32 val, tmdsck, freqvco, pllctrl = 0;
206 unsigned int i;
207
208 if (!enable_pll_rejection(hdmi))
209 return false;
210
211 DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
212
213 /* Assuming no pixel repetition and 24bits color */
214 tmdsck = ckpxpll;
215 pllctrl = 2 << HDMI_SRZ_PLL_CFG_NDIV_SHIFT;
216
217 /*
218 * Setup the PLL mode parameter based on the ckpxpll. If we haven't got
219 * a clock frequency supported by one of the specific PLL modes then we
220 * will end up using the generic mode (0) which only supports a 10x
221 * multiplier, hence only 24bit color.
222 */
223 for (i = 0; i < NB_PLL_MODE; i++) {
224 if (ckpxpll >= pllmodes[i].min && ckpxpll <= pllmodes[i].max)
225 pllctrl |= HDMI_SRZ_PLL_CFG_MODE(pllmodes[i].mode);
226 }
227
228 freqvco = tmdsck * 10;
229 if (freqvco <= 425000000UL)
230 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_425MHZ);
231 else if (freqvco <= 850000000UL)
232 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_850MHZ);
233 else if (freqvco <= 1700000000UL)
234 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_1700MHZ);
235 else if (freqvco <= 2970000000UL)
236 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_3000MHZ);
237 else {
238 DRM_ERROR("PHY serializer clock out of range\n");
239 goto err;
240 }
241
242 /*
243 * Configure and power up the PHY PLL
244 */
245 hdmi->event_received = false;
246 DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
247 hdmi_write(hdmi, pllctrl, HDMI_SRZ_PLL_CFG);
248
249 /* wait PLL interrupt */
250 wait_event_interruptible_timeout(hdmi->wait_event,
251 hdmi->event_received == true,
252 msecs_to_jiffies
253 (HDMI_TIMEOUT_PLL_LOCK));
254
255 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
256 DRM_ERROR("hdmi phy pll not locked\n");
257 goto err;
258 }
259
260 DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
261
262 /*
263 * To configure the source termination and pre-emphasis appropriately
264 * for different high speed TMDS clock frequencies a phy configuration
265 * table must be provided, tailored to the SoC and board combination.
266 */
267 for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
268 if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
269 (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
270 val = hdmiphy_config[i].config[0];
271 hdmi_write(hdmi, val, HDMI_SRZ_TAP_1);
272 val = hdmiphy_config[i].config[1];
273 hdmi_write(hdmi, val, HDMI_SRZ_TAP_2);
274 val = hdmiphy_config[i].config[2];
275 hdmi_write(hdmi, val, HDMI_SRZ_TAP_3);
276 val = hdmiphy_config[i].config[3];
277 val |= HDMI_SRZ_CTRL_EXTERNAL_DATA_EN;
278 val &= ~HDMI_SRZ_CTRL_POWER_DOWN;
279 hdmi_write(hdmi, val, HDMI_SRZ_CTRL);
280
281 DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x 0x%x\n",
282 hdmiphy_config[i].config[0],
283 hdmiphy_config[i].config[1],
284 hdmiphy_config[i].config[2],
285 hdmiphy_config[i].config[3]);
286 return true;
287 }
288 }
289
290 /*
291 * Default, power up the serializer with no pre-emphasis or source
292 * termination.
293 */
294 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_1);
295 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_2);
296 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_3);
297 hdmi_write(hdmi, HDMI_SRZ_CTRL_EXTERNAL_DATA_EN, HDMI_SRZ_CTRL);
298
299 return true;
300
301err:
302 disable_pll_rejection(hdmi);
303
304 return false;
305}
306
307/**
308 * Stop hdmi phy macro cell tx3g0c55
309 *
310 * @hdmi: pointer on the hdmi internal structure
311 */
312static void sti_hdmi_tx3g0c55phy_stop(struct sti_hdmi *hdmi)
313{
314 DRM_DEBUG_DRIVER("\n");
315
316 hdmi->event_received = false;
317
318 hdmi_write(hdmi, HDMI_SRZ_CTRL_POWER_DOWN, HDMI_SRZ_CTRL);
319 hdmi_write(hdmi, HDMI_SRZ_PLL_CFG_POWER_DOWN, HDMI_SRZ_PLL_CFG);
320
321 /* wait PLL interrupt */
322 wait_event_interruptible_timeout(hdmi->wait_event,
323 hdmi->event_received == true,
324 msecs_to_jiffies
325 (HDMI_TIMEOUT_PLL_LOCK));
326
327 if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
328 DRM_ERROR("hdmi phy pll not well disabled\n");
329
330 disable_pll_rejection(hdmi);
331}
332
333struct hdmi_phy_ops tx3g0c55phy_ops = {
334 .start = sti_hdmi_tx3g0c55phy_start,
335 .stop = sti_hdmi_tx3g0c55phy_stop,
336};
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h
new file mode 100644
index 000000000000..068237b3a303
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_TX3G0C55PHY_H_
8#define _STI_HDMI_TX3G0C55PHY_H_
9
10#include "sti_hdmi.h"
11
12extern struct hdmi_phy_ops tx3g0c55phy_ops;
13
14#endif
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
new file mode 100644
index 000000000000..8e0ceb0ced33
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
@@ -0,0 +1,211 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
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 /*milliseconds */
41
42struct plldividers_s {
43 uint32_t min;
44 uint32_t max;
45 uint32_t idf;
46 uint32_t odf;
47};
48
49/*
50 * Functional specification recommended values
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 * Start hdmi phy macro cell tx3g4c28
69 *
70 * @hdmi: pointer on the hdmi internal structure
71 *
72 * Return false if an error occur
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 /* Assuming no pixel repetition and 24bits color */
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 * Configure and power up the PHY PLL
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 /* wait PLL interrupt */
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 * To configure the source termination and pre-emphasis appropriately
141 * for different high speed TMDS clock frequencies a phy configuration
142 * table must be provided, tailored to the SoC and board combination.
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 * Default, power up the serializer with no pre-emphasis or
167 * output swing correction
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 * Stop hdmi phy macro cell tx3g4c28
181 *
182 * @hdmi: pointer on the hdmi internal structure
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 /* wait PLL interrupt */
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};
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
new file mode 100644
index 000000000000..f99a7ff281ef
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_TX3G4C28PHY_H_
8#define _STI_HDMI_TX3G4C28PHY_H_
9
10#include "sti_hdmi.h"
11
12extern struct hdmi_phy_ops tx3g4c28phy_ops;
13
14#endif