blob: 69a2286ce2f63614892b575e42719a26517af61d [file] [log] [blame]
Benjamin Gaignard54026262014-07-30 19:24:55 +02001/*
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>
Benjamin Gaignardde4b00b2015-03-19 13:35:16 +010016#include <drm/drm_atomic_helper.h>
Benjamin Gaignard54026262014-07-30 19:24:55 +020017#include <drm/drm_crtc_helper.h>
18#include <drm/drm_edid.h>
19
20#include "sti_hdmi.h"
21#include "sti_hdmi_tx3g4c28phy.h"
22#include "sti_hdmi_tx3g0c55phy.h"
23#include "sti_vtg.h"
24
25#define HDMI_CFG 0x0000
26#define HDMI_INT_EN 0x0004
27#define HDMI_INT_STA 0x0008
28#define HDMI_INT_CLR 0x000C
29#define HDMI_STA 0x0010
30#define HDMI_ACTIVE_VID_XMIN 0x0100
31#define HDMI_ACTIVE_VID_XMAX 0x0104
32#define HDMI_ACTIVE_VID_YMIN 0x0108
33#define HDMI_ACTIVE_VID_YMAX 0x010C
34#define HDMI_DFLT_CHL0_DAT 0x0110
35#define HDMI_DFLT_CHL1_DAT 0x0114
36#define HDMI_DFLT_CHL2_DAT 0x0118
37#define HDMI_SW_DI_1_HEAD_WORD 0x0210
38#define HDMI_SW_DI_1_PKT_WORD0 0x0214
39#define HDMI_SW_DI_1_PKT_WORD1 0x0218
40#define HDMI_SW_DI_1_PKT_WORD2 0x021C
41#define HDMI_SW_DI_1_PKT_WORD3 0x0220
42#define HDMI_SW_DI_1_PKT_WORD4 0x0224
43#define HDMI_SW_DI_1_PKT_WORD5 0x0228
44#define HDMI_SW_DI_1_PKT_WORD6 0x022C
45#define HDMI_SW_DI_CFG 0x0230
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +010046#define HDMI_SW_DI_2_HEAD_WORD 0x0600
47#define HDMI_SW_DI_2_PKT_WORD0 0x0604
48#define HDMI_SW_DI_2_PKT_WORD1 0x0608
49#define HDMI_SW_DI_2_PKT_WORD2 0x060C
50#define HDMI_SW_DI_2_PKT_WORD3 0x0610
51#define HDMI_SW_DI_2_PKT_WORD4 0x0614
52#define HDMI_SW_DI_2_PKT_WORD5 0x0618
53#define HDMI_SW_DI_2_PKT_WORD6 0x061C
Vincent Abrioue42e7bd2016-02-01 10:35:26 +010054#define HDMI_SW_DI_3_HEAD_WORD 0x0620
55#define HDMI_SW_DI_3_PKT_WORD0 0x0624
56#define HDMI_SW_DI_3_PKT_WORD1 0x0628
57#define HDMI_SW_DI_3_PKT_WORD2 0x062C
58#define HDMI_SW_DI_3_PKT_WORD3 0x0630
59#define HDMI_SW_DI_3_PKT_WORD4 0x0634
60#define HDMI_SW_DI_3_PKT_WORD5 0x0638
61#define HDMI_SW_DI_3_PKT_WORD6 0x063C
Benjamin Gaignard54026262014-07-30 19:24:55 +020062
63#define HDMI_IFRAME_SLOT_AVI 1
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +010064#define HDMI_IFRAME_SLOT_AUDIO 2
Vincent Abrioue42e7bd2016-02-01 10:35:26 +010065#define HDMI_IFRAME_SLOT_VENDOR 3
Benjamin Gaignard54026262014-07-30 19:24:55 +020066
67#define XCAT(prefix, x, suffix) prefix ## x ## suffix
68#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
69#define HDMI_SW_DI_N_PKT_WORD0(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD0)
70#define HDMI_SW_DI_N_PKT_WORD1(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD1)
71#define HDMI_SW_DI_N_PKT_WORD2(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD2)
72#define HDMI_SW_DI_N_PKT_WORD3(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD3)
73#define HDMI_SW_DI_N_PKT_WORD4(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD4)
74#define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5)
75#define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
76
Vincent Abriou181975a2016-02-01 10:32:42 +010077#define HDMI_SW_DI_MAX_WORD 7
78
Benjamin Gaignard54026262014-07-30 19:24:55 +020079#define HDMI_IFRAME_DISABLED 0x0
80#define HDMI_IFRAME_SINGLE_SHOT 0x1
81#define HDMI_IFRAME_FIELD 0x2
82#define HDMI_IFRAME_FRAME 0x3
83#define HDMI_IFRAME_MASK 0x3
84#define HDMI_IFRAME_CFG_DI_N(x, n) ((x) << ((n-1)*4)) /* n from 1 to 6 */
85
86#define HDMI_CFG_DEVICE_EN BIT(0)
87#define HDMI_CFG_HDMI_NOT_DVI BIT(1)
88#define HDMI_CFG_HDCP_EN BIT(2)
89#define HDMI_CFG_ESS_NOT_OESS BIT(3)
90#define HDMI_CFG_H_SYNC_POL_NEG BIT(4)
91#define HDMI_CFG_SINK_TERM_DET_EN BIT(5)
92#define HDMI_CFG_V_SYNC_POL_NEG BIT(6)
93#define HDMI_CFG_422_EN BIT(8)
94#define HDMI_CFG_FIFO_OVERRUN_CLR BIT(12)
95#define HDMI_CFG_FIFO_UNDERRUN_CLR BIT(13)
96#define HDMI_CFG_SW_RST_EN BIT(31)
97
98#define HDMI_INT_GLOBAL BIT(0)
99#define HDMI_INT_SW_RST BIT(1)
100#define HDMI_INT_PIX_CAP BIT(3)
101#define HDMI_INT_HOT_PLUG BIT(4)
102#define HDMI_INT_DLL_LCK BIT(5)
103#define HDMI_INT_NEW_FRAME BIT(6)
104#define HDMI_INT_GENCTRL_PKT BIT(7)
105#define HDMI_INT_SINK_TERM_PRESENT BIT(11)
106
107#define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \
108 | HDMI_INT_DLL_LCK \
109 | HDMI_INT_HOT_PLUG \
110 | HDMI_INT_GLOBAL)
111
112#define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \
113 | HDMI_INT_GENCTRL_PKT \
114 | HDMI_INT_NEW_FRAME \
115 | HDMI_INT_DLL_LCK \
116 | HDMI_INT_HOT_PLUG \
117 | HDMI_INT_PIX_CAP \
118 | HDMI_INT_SW_RST \
119 | HDMI_INT_GLOBAL)
120
121#define HDMI_STA_SW_RST BIT(1)
122
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100123#define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
124#define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
125#define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16)
126
Benjamin Gaignard54026262014-07-30 19:24:55 +0200127struct sti_hdmi_connector {
128 struct drm_connector drm_connector;
129 struct drm_encoder *encoder;
130 struct sti_hdmi *hdmi;
Vincent Abriou5671cef2016-02-10 11:24:28 +0100131 struct drm_property *colorspace_property;
Vincent Abriouffc4a6a2016-02-10 11:21:37 +0100132 struct drm_property *hdmi_mode_property;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200133};
134
135#define to_sti_hdmi_connector(x) \
136 container_of(x, struct sti_hdmi_connector, drm_connector)
137
138u32 hdmi_read(struct sti_hdmi *hdmi, int offset)
139{
140 return readl(hdmi->regs + offset);
141}
142
143void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset)
144{
145 writel(val, hdmi->regs + offset);
146}
147
148/**
149 * HDMI interrupt handler threaded
150 *
151 * @irq: irq number
152 * @arg: connector structure
153 */
154static irqreturn_t hdmi_irq_thread(int irq, void *arg)
155{
156 struct sti_hdmi *hdmi = arg;
157
158 /* Hot plug/unplug IRQ */
159 if (hdmi->irq_status & HDMI_INT_HOT_PLUG) {
Benjamin Gaignard76569202014-10-09 08:53:35 +0200160 hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200161 if (hdmi->drm_dev)
162 drm_helper_hpd_irq_event(hdmi->drm_dev);
163 }
164
165 /* Sw reset and PLL lock are exclusive so we can use the same
166 * event to signal them
167 */
168 if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) {
169 hdmi->event_received = true;
170 wake_up_interruptible(&hdmi->wait_event);
171 }
172
173 return IRQ_HANDLED;
174}
175
176/**
177 * HDMI interrupt handler
178 *
179 * @irq: irq number
180 * @arg: connector structure
181 */
182static irqreturn_t hdmi_irq(int irq, void *arg)
183{
184 struct sti_hdmi *hdmi = arg;
185
186 /* read interrupt status */
187 hdmi->irq_status = hdmi_read(hdmi, HDMI_INT_STA);
188
189 /* clear interrupt status */
190 hdmi_write(hdmi, hdmi->irq_status, HDMI_INT_CLR);
191
192 /* force sync bus write */
193 hdmi_read(hdmi, HDMI_INT_STA);
194
195 return IRQ_WAKE_THREAD;
196}
197
198/**
199 * Set hdmi active area depending on the drm display mode selected
200 *
201 * @hdmi: pointer on the hdmi internal structure
202 */
203static void hdmi_active_area(struct sti_hdmi *hdmi)
204{
205 u32 xmin, xmax;
206 u32 ymin, ymax;
207
Vincent Abriou86615322015-06-05 10:24:43 +0200208 xmin = sti_vtg_get_pixel_number(hdmi->mode, 1);
209 xmax = sti_vtg_get_pixel_number(hdmi->mode, hdmi->mode.hdisplay);
Benjamin Gaignard54026262014-07-30 19:24:55 +0200210 ymin = sti_vtg_get_line_number(hdmi->mode, 0);
211 ymax = sti_vtg_get_line_number(hdmi->mode, hdmi->mode.vdisplay - 1);
212
213 hdmi_write(hdmi, xmin, HDMI_ACTIVE_VID_XMIN);
214 hdmi_write(hdmi, xmax, HDMI_ACTIVE_VID_XMAX);
215 hdmi_write(hdmi, ymin, HDMI_ACTIVE_VID_YMIN);
216 hdmi_write(hdmi, ymax, HDMI_ACTIVE_VID_YMAX);
217}
218
219/**
220 * Overall hdmi configuration
221 *
222 * @hdmi: pointer on the hdmi internal structure
223 */
224static void hdmi_config(struct sti_hdmi *hdmi)
225{
226 u32 conf;
227
228 DRM_DEBUG_DRIVER("\n");
229
230 /* Clear overrun and underrun fifo */
231 conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
232
Vincent Abriouffc4a6a2016-02-10 11:21:37 +0100233 /* Select encryption type and the framing mode */
234 conf |= HDMI_CFG_ESS_NOT_OESS;
235 if (hdmi->hdmi_mode == HDMI_MODE_HDMI)
236 conf |= HDMI_CFG_HDMI_NOT_DVI;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200237
238 /* Enable sink term detection */
239 conf |= HDMI_CFG_SINK_TERM_DET_EN;
240
241 /* Set Hsync polarity */
242 if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) {
243 DRM_DEBUG_DRIVER("H Sync Negative\n");
244 conf |= HDMI_CFG_H_SYNC_POL_NEG;
245 }
246
247 /* Set Vsync polarity */
248 if (hdmi->mode.flags & DRM_MODE_FLAG_NVSYNC) {
249 DRM_DEBUG_DRIVER("V Sync Negative\n");
250 conf |= HDMI_CFG_V_SYNC_POL_NEG;
251 }
252
253 /* Enable HDMI */
254 conf |= HDMI_CFG_DEVICE_EN;
255
256 hdmi_write(hdmi, conf, HDMI_CFG);
257}
258
Vincent Abriou181975a2016-02-01 10:32:42 +0100259/*
260 * Helper to reset info frame
261 *
262 * @hdmi: pointer on the hdmi internal structure
263 * @slot: infoframe to reset
264 */
265static void hdmi_infoframe_reset(struct sti_hdmi *hdmi,
266 u32 slot)
267{
268 u32 val, i;
269 u32 head_offset, pack_offset;
270
271 switch (slot) {
272 case HDMI_IFRAME_SLOT_AVI:
273 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
274 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
275 break;
276 case HDMI_IFRAME_SLOT_AUDIO:
277 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
278 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
279 break;
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100280 case HDMI_IFRAME_SLOT_VENDOR:
281 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
282 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
283 break;
Vincent Abriou181975a2016-02-01 10:32:42 +0100284 default:
285 DRM_ERROR("unsupported infoframe slot: %#x\n", slot);
286 return;
287 }
288
289 /* Disable transmission for the selected slot */
290 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
291 val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
292 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
293
294 /* Reset info frame registers */
295 hdmi_write(hdmi, 0x0, head_offset);
296 for (i = 0; i < HDMI_SW_DI_MAX_WORD; i += sizeof(u32))
297 hdmi_write(hdmi, 0x0, pack_offset + i);
298}
299
Benjamin Gaignard54026262014-07-30 19:24:55 +0200300/**
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100301 * Helper to concatenate infoframe in 32 bits word
302 *
303 * @ptr: pointer on the hdmi internal structure
304 * @data: infoframe to write
305 * @size: size to write
306 */
307static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size)
308{
309 unsigned long value = 0;
310 size_t i;
311
312 for (i = size; i > 0; i--)
313 value = (value << 8) | ptr[i - 1];
314
315 return value;
316}
317
318/**
319 * Helper to write info frame
320 *
321 * @hdmi: pointer on the hdmi internal structure
322 * @data: infoframe to write
323 * @size: size to write
324 */
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100325static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi,
326 const u8 *data,
327 size_t size)
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100328{
329 const u8 *ptr = data;
330 u32 val, slot, mode, i;
331 u32 head_offset, pack_offset;
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100332
333 switch (*ptr) {
334 case HDMI_INFOFRAME_TYPE_AVI:
335 slot = HDMI_IFRAME_SLOT_AVI;
336 mode = HDMI_IFRAME_FIELD;
337 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
338 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100339 break;
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100340 case HDMI_INFOFRAME_TYPE_AUDIO:
341 slot = HDMI_IFRAME_SLOT_AUDIO;
342 mode = HDMI_IFRAME_FRAME;
343 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
344 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100345 break;
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100346 case HDMI_INFOFRAME_TYPE_VENDOR:
347 slot = HDMI_IFRAME_SLOT_VENDOR;
348 mode = HDMI_IFRAME_FRAME;
349 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
350 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
351 break;
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100352 default:
353 DRM_ERROR("unsupported infoframe type: %#x\n", *ptr);
354 return;
355 }
356
357 /* Disable transmission slot for updated infoframe */
358 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
359 val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
360 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
361
362 val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++);
363 val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++);
364 val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++);
365 writel(val, hdmi->regs + head_offset);
366
367 /*
368 * Each subpack contains 4 bytes
369 * The First Bytes of the first subpacket must contain the checksum
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100370 * Packet size is increase by one.
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100371 */
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100372 size = size - HDMI_INFOFRAME_HEADER_SIZE + 1;
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100373 for (i = 0; i < size; i += sizeof(u32)) {
374 size_t num;
375
376 num = min_t(size_t, size - i, sizeof(u32));
377 val = hdmi_infoframe_subpack(ptr, num);
378 ptr += sizeof(u32);
379 writel(val, hdmi->regs + pack_offset + i);
380 }
381
382 /* Enable transmission slot for updated infoframe */
383 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
Vincent Abriou50f21382016-02-02 17:03:57 +0100384 val |= HDMI_IFRAME_CFG_DI_N(mode, slot);
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100385 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
386}
387
388/**
Benjamin Gaignard54026262014-07-30 19:24:55 +0200389 * Prepare and configure the AVI infoframe
390 *
391 * AVI infoframe are transmitted at least once per two video field and
392 * contains information about HDMI transmission mode such as color space,
393 * colorimetry, ...
394 *
395 * @hdmi: pointer on the hdmi internal structure
396 *
397 * Return negative value if error occurs
398 */
399static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
400{
401 struct drm_display_mode *mode = &hdmi->mode;
402 struct hdmi_avi_infoframe infoframe;
403 u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
Benjamin Gaignard54026262014-07-30 19:24:55 +0200404 int ret;
405
406 DRM_DEBUG_DRIVER("\n");
407
408 ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode);
409 if (ret < 0) {
410 DRM_ERROR("failed to setup AVI infoframe: %d\n", ret);
411 return ret;
412 }
413
414 /* fixed infoframe configuration not linked to the mode */
Vincent Abriou5671cef2016-02-10 11:24:28 +0100415 infoframe.colorspace = hdmi->colorspace;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200416 infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
417 infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
418
419 ret = hdmi_avi_infoframe_pack(&infoframe, buffer, sizeof(buffer));
420 if (ret < 0) {
421 DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
422 return ret;
423 }
424
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100425 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
Benjamin Gaignard54026262014-07-30 19:24:55 +0200426
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100427 return 0;
428}
Benjamin Gaignard54026262014-07-30 19:24:55 +0200429
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100430/**
431 * Prepare and configure the AUDIO infoframe
432 *
433 * AUDIO infoframe are transmitted once per frame and
434 * contains information about HDMI transmission mode such as audio codec,
435 * sample size, ...
436 *
437 * @hdmi: pointer on the hdmi internal structure
438 *
439 * Return negative value if error occurs
440 */
441static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
442{
443 struct hdmi_audio_infoframe infofame;
444 u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
445 int ret;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200446
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100447 ret = hdmi_audio_infoframe_init(&infofame);
448 if (ret < 0) {
449 DRM_ERROR("failed to setup audio infoframe: %d\n", ret);
450 return ret;
451 }
Benjamin Gaignard54026262014-07-30 19:24:55 +0200452
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100453 infofame.channels = 2;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200454
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100455 ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer));
456 if (ret < 0) {
457 DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
458 return ret;
459 }
Benjamin Gaignard54026262014-07-30 19:24:55 +0200460
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100461 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
462
463 return 0;
464}
465
466/*
467 * Prepare and configure the VS infoframe
468 *
469 * Vendor Specific infoframe are transmitted once per frame and
470 * contains vendor specific information.
471 *
472 * @hdmi: pointer on the hdmi internal structure
473 *
474 * Return negative value if error occurs
475 */
476#define HDMI_VENDOR_INFOFRAME_MAX_SIZE 6
477static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi)
478{
479 struct drm_display_mode *mode = &hdmi->mode;
480 struct hdmi_vendor_infoframe infoframe;
481 u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_MAX_SIZE];
482 int ret;
483
484 DRM_DEBUG_DRIVER("\n");
485
486 ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode);
487 if (ret < 0) {
488 /*
489 * Going into that statement does not means vendor infoframe
490 * fails. It just informed us that vendor infoframe is not
491 * needed for the selected mode. Only 4k or stereoscopic 3D
492 * mode requires vendor infoframe. So just simply return 0.
493 */
494 return 0;
495 }
496
497 ret = hdmi_vendor_infoframe_pack(&infoframe, buffer, sizeof(buffer));
498 if (ret < 0) {
499 DRM_ERROR("failed to pack VS infoframe: %d\n", ret);
500 return ret;
501 }
502
503 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
Benjamin Gaignard54026262014-07-30 19:24:55 +0200504
505 return 0;
506}
507
508/**
509 * Software reset of the hdmi subsystem
510 *
511 * @hdmi: pointer on the hdmi internal structure
512 *
513 */
514#define HDMI_TIMEOUT_SWRESET 100 /*milliseconds */
515static void hdmi_swreset(struct sti_hdmi *hdmi)
516{
517 u32 val;
518
519 DRM_DEBUG_DRIVER("\n");
520
521 /* Enable hdmi_audio clock only during hdmi reset */
522 if (clk_prepare_enable(hdmi->clk_audio))
523 DRM_INFO("Failed to prepare/enable hdmi_audio clk\n");
524
525 /* Sw reset */
526 hdmi->event_received = false;
527
528 val = hdmi_read(hdmi, HDMI_CFG);
529 val |= HDMI_CFG_SW_RST_EN;
530 hdmi_write(hdmi, val, HDMI_CFG);
531
532 /* Wait reset completed */
533 wait_event_interruptible_timeout(hdmi->wait_event,
534 hdmi->event_received == true,
535 msecs_to_jiffies
536 (HDMI_TIMEOUT_SWRESET));
537
538 /*
539 * HDMI_STA_SW_RST bit is set to '1' when SW_RST bit in HDMI_CFG is
540 * set to '1' and clk_audio is running.
541 */
542 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_SW_RST) == 0)
543 DRM_DEBUG_DRIVER("Warning: HDMI sw reset timeout occurs\n");
544
545 val = hdmi_read(hdmi, HDMI_CFG);
546 val &= ~HDMI_CFG_SW_RST_EN;
547 hdmi_write(hdmi, val, HDMI_CFG);
548
549 /* Disable hdmi_audio clock. Not used anymore for drm purpose */
550 clk_disable_unprepare(hdmi->clk_audio);
551}
552
553static void sti_hdmi_disable(struct drm_bridge *bridge)
554{
555 struct sti_hdmi *hdmi = bridge->driver_private;
556
557 u32 val = hdmi_read(hdmi, HDMI_CFG);
558
559 if (!hdmi->enabled)
560 return;
561
562 DRM_DEBUG_DRIVER("\n");
563
564 /* Disable HDMI */
565 val &= ~HDMI_CFG_DEVICE_EN;
566 hdmi_write(hdmi, val, HDMI_CFG);
567
568 hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR);
569
570 /* Stop the phy */
571 hdmi->phy_ops->stop(hdmi);
572
Vincent Abriou181975a2016-02-01 10:32:42 +0100573 /* Reset info frame transmission */
574 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI);
575 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO);
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100576 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_VENDOR);
Vincent Abriou181975a2016-02-01 10:32:42 +0100577
Benjamin Gaignard54026262014-07-30 19:24:55 +0200578 /* Set the default channel data to be a dark red */
579 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT);
580 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
581 hdmi_write(hdmi, 0x0060, HDMI_DFLT_CHL2_DAT);
582
583 /* Disable/unprepare hdmi clock */
584 clk_disable_unprepare(hdmi->clk_phy);
585 clk_disable_unprepare(hdmi->clk_tmds);
586 clk_disable_unprepare(hdmi->clk_pix);
587
588 hdmi->enabled = false;
589}
590
591static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
592{
593 struct sti_hdmi *hdmi = bridge->driver_private;
594
595 DRM_DEBUG_DRIVER("\n");
596
597 if (hdmi->enabled)
598 return;
599
600 /* Prepare/enable clocks */
601 if (clk_prepare_enable(hdmi->clk_pix))
602 DRM_ERROR("Failed to prepare/enable hdmi_pix clk\n");
603 if (clk_prepare_enable(hdmi->clk_tmds))
604 DRM_ERROR("Failed to prepare/enable hdmi_tmds clk\n");
605 if (clk_prepare_enable(hdmi->clk_phy))
606 DRM_ERROR("Failed to prepare/enable hdmi_rejec_pll clk\n");
607
608 hdmi->enabled = true;
609
610 /* Program hdmi serializer and start phy */
611 if (!hdmi->phy_ops->start(hdmi)) {
612 DRM_ERROR("Unable to start hdmi phy\n");
613 return;
614 }
615
616 /* Program hdmi active area */
617 hdmi_active_area(hdmi);
618
619 /* Enable working interrupts */
620 hdmi_write(hdmi, HDMI_WORKING_INT, HDMI_INT_EN);
621
622 /* Program hdmi config */
623 hdmi_config(hdmi);
624
625 /* Program AVI infoframe */
626 if (hdmi_avi_infoframe_config(hdmi))
627 DRM_ERROR("Unable to configure AVI infoframe\n");
628
Arnaud Pouliquencffe1e82015-02-05 11:55:02 +0100629 /* Program AUDIO infoframe */
630 if (hdmi_audio_infoframe_config(hdmi))
631 DRM_ERROR("Unable to configure AUDIO infoframe\n");
632
Vincent Abrioue42e7bd2016-02-01 10:35:26 +0100633 /* Program VS infoframe */
634 if (hdmi_vendor_infoframe_config(hdmi))
635 DRM_ERROR("Unable to configure VS infoframe\n");
636
Benjamin Gaignard54026262014-07-30 19:24:55 +0200637 /* Sw reset */
638 hdmi_swreset(hdmi);
639}
640
641static void sti_hdmi_set_mode(struct drm_bridge *bridge,
642 struct drm_display_mode *mode,
643 struct drm_display_mode *adjusted_mode)
644{
645 struct sti_hdmi *hdmi = bridge->driver_private;
646 int ret;
647
648 DRM_DEBUG_DRIVER("\n");
649
650 /* Copy the drm display mode in the connector local structure */
651 memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
652
653 /* Update clock framerate according to the selected mode */
654 ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
655 if (ret < 0) {
656 DRM_ERROR("Cannot set rate (%dHz) for hdmi_pix clk\n",
657 mode->clock * 1000);
658 return;
659 }
660 ret = clk_set_rate(hdmi->clk_phy, mode->clock * 1000);
661 if (ret < 0) {
662 DRM_ERROR("Cannot set rate (%dHz) for hdmi_rejection_pll clk\n",
663 mode->clock * 1000);
664 return;
665 }
666}
667
668static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
669{
670 /* do nothing */
671}
672
Benjamin Gaignard54026262014-07-30 19:24:55 +0200673static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
674 .pre_enable = sti_hdmi_pre_enable,
675 .enable = sti_hdmi_bridge_nope,
676 .disable = sti_hdmi_disable,
677 .post_disable = sti_hdmi_bridge_nope,
678 .mode_set = sti_hdmi_set_mode,
Benjamin Gaignard54026262014-07-30 19:24:55 +0200679};
680
681static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
682{
Benjamin Gaignard41a14622014-09-08 15:52:08 +0200683 struct sti_hdmi_connector *hdmi_connector
684 = to_sti_hdmi_connector(connector);
685 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200686 struct edid *edid;
687 int count;
688
689 DRM_DEBUG_DRIVER("\n");
690
Benjamin Gaignard41a14622014-09-08 15:52:08 +0200691 edid = drm_get_edid(connector, hdmi->ddc_adapt);
Benjamin Gaignard54026262014-07-30 19:24:55 +0200692 if (!edid)
693 goto fail;
694
695 count = drm_add_edid_modes(connector, edid);
696 drm_mode_connector_update_edid_property(connector, edid);
697
698 kfree(edid);
699 return count;
700
701fail:
Vincent Abriou871bcdf2015-07-31 11:32:13 +0200702 DRM_ERROR("Can't read HDMI EDID\n");
Benjamin Gaignard54026262014-07-30 19:24:55 +0200703 return 0;
704}
705
706#define CLK_TOLERANCE_HZ 50
707
708static int sti_hdmi_connector_mode_valid(struct drm_connector *connector,
709 struct drm_display_mode *mode)
710{
711 int target = mode->clock * 1000;
712 int target_min = target - CLK_TOLERANCE_HZ;
713 int target_max = target + CLK_TOLERANCE_HZ;
714 int result;
715 struct sti_hdmi_connector *hdmi_connector
716 = to_sti_hdmi_connector(connector);
717 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
718
719
720 result = clk_round_rate(hdmi->clk_pix, target);
721
722 DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
723 target, result);
724
725 if ((result < target_min) || (result > target_max)) {
726 DRM_DEBUG_DRIVER("hdmi pixclk=%d not supported\n", target);
727 return MODE_BAD;
728 }
729
730 return MODE_OK;
731}
732
733struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
734{
735 struct sti_hdmi_connector *hdmi_connector
736 = to_sti_hdmi_connector(connector);
737
738 /* Best encoder is the one associated during connector creation */
739 return hdmi_connector->encoder;
740}
741
Ville Syrjäläc5de4852015-09-02 13:44:15 +0300742static const
743struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
Benjamin Gaignard54026262014-07-30 19:24:55 +0200744 .get_modes = sti_hdmi_connector_get_modes,
745 .mode_valid = sti_hdmi_connector_mode_valid,
746 .best_encoder = sti_hdmi_best_encoder,
747};
748
749/* get detection status of display device */
750static enum drm_connector_status
751sti_hdmi_connector_detect(struct drm_connector *connector, bool force)
752{
753 struct sti_hdmi_connector *hdmi_connector
754 = to_sti_hdmi_connector(connector);
755 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
756
757 DRM_DEBUG_DRIVER("\n");
758
759 if (hdmi->hpd) {
760 DRM_DEBUG_DRIVER("hdmi cable connected\n");
761 return connector_status_connected;
762 }
763
764 DRM_DEBUG_DRIVER("hdmi cable disconnected\n");
765 return connector_status_disconnected;
766}
767
768static void sti_hdmi_connector_destroy(struct drm_connector *connector)
769{
770 struct sti_hdmi_connector *hdmi_connector
771 = to_sti_hdmi_connector(connector);
772
773 drm_connector_unregister(connector);
774 drm_connector_cleanup(connector);
775 kfree(hdmi_connector);
776}
777
Vincent Abriou5671cef2016-02-10 11:24:28 +0100778static void sti_hdmi_connector_init_property(struct drm_device *drm_dev,
779 struct drm_connector *connector)
780{
781 struct sti_hdmi_connector *hdmi_connector
782 = to_sti_hdmi_connector(connector);
783 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
784 struct drm_property *prop;
785
786 /* colorspace property */
787 hdmi->colorspace = DEFAULT_COLORSPACE_MODE;
788 prop = drm_property_create_enum(drm_dev, 0, "colorspace",
789 colorspace_mode_names,
790 ARRAY_SIZE(colorspace_mode_names));
791 if (!prop) {
792 DRM_ERROR("fails to create colorspace property\n");
793 return;
794 }
795 hdmi_connector->colorspace_property = prop;
796 drm_object_attach_property(&connector->base, prop, hdmi->colorspace);
Vincent Abriouffc4a6a2016-02-10 11:21:37 +0100797
798 /* hdmi_mode property */
799 hdmi->hdmi_mode = DEFAULT_HDMI_MODE;
800 prop = drm_property_create_enum(drm_dev, 0, "hdmi_mode",
801 hdmi_mode_names,
802 ARRAY_SIZE(hdmi_mode_names));
803 if (!prop) {
804 DRM_ERROR("fails to create colorspace property\n");
805 return;
806 }
807 hdmi_connector->hdmi_mode_property = prop;
808 drm_object_attach_property(&connector->base, prop, hdmi->hdmi_mode);
809
Vincent Abriou5671cef2016-02-10 11:24:28 +0100810}
811
812static int
813sti_hdmi_connector_set_property(struct drm_connector *connector,
814 struct drm_connector_state *state,
815 struct drm_property *property,
816 uint64_t val)
817{
818 struct sti_hdmi_connector *hdmi_connector
819 = to_sti_hdmi_connector(connector);
820 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
821
822 if (property == hdmi_connector->colorspace_property) {
823 hdmi->colorspace = val;
824 return 0;
825 }
826
Vincent Abriouffc4a6a2016-02-10 11:21:37 +0100827 if (property == hdmi_connector->hdmi_mode_property) {
828 hdmi->hdmi_mode = val;
829 return 0;
830 }
831
Vincent Abriou5671cef2016-02-10 11:24:28 +0100832 DRM_ERROR("failed to set hdmi connector property\n");
833 return -EINVAL;
834}
835
836static int
837sti_hdmi_connector_get_property(struct drm_connector *connector,
838 const struct drm_connector_state *state,
839 struct drm_property *property,
840 uint64_t *val)
841{
842 struct sti_hdmi_connector *hdmi_connector
843 = to_sti_hdmi_connector(connector);
844 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
845
846 if (property == hdmi_connector->colorspace_property) {
847 *val = hdmi->colorspace;
848 return 0;
849 }
850
Vincent Abriouffc4a6a2016-02-10 11:21:37 +0100851 if (property == hdmi_connector->hdmi_mode_property) {
852 *val = hdmi->hdmi_mode;
853 return 0;
854 }
855
Vincent Abriou5671cef2016-02-10 11:24:28 +0100856 DRM_ERROR("failed to get hdmi connector property\n");
857 return -EINVAL;
858}
859
Ville Syrjäläc5de4852015-09-02 13:44:15 +0300860static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
Benjamin Gaignardde4b00b2015-03-19 13:35:16 +0100861 .dpms = drm_atomic_helper_connector_dpms,
Benjamin Gaignard54026262014-07-30 19:24:55 +0200862 .fill_modes = drm_helper_probe_single_connector_modes,
863 .detect = sti_hdmi_connector_detect,
864 .destroy = sti_hdmi_connector_destroy,
Benjamin Gaignardde4b00b2015-03-19 13:35:16 +0100865 .reset = drm_atomic_helper_connector_reset,
Vincent Abriou5671cef2016-02-10 11:24:28 +0100866 .set_property = drm_atomic_helper_connector_set_property,
867 .atomic_set_property = sti_hdmi_connector_set_property,
868 .atomic_get_property = sti_hdmi_connector_get_property,
Benjamin Gaignardde4b00b2015-03-19 13:35:16 +0100869 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
870 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Benjamin Gaignard54026262014-07-30 19:24:55 +0200871};
872
873static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
874{
875 struct drm_encoder *encoder;
876
877 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
878 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
879 return encoder;
880 }
881
882 return NULL;
883}
884
885static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
886{
887 struct sti_hdmi *hdmi = dev_get_drvdata(dev);
888 struct drm_device *drm_dev = data;
889 struct drm_encoder *encoder;
890 struct sti_hdmi_connector *connector;
891 struct drm_connector *drm_connector;
892 struct drm_bridge *bridge;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200893 int err;
894
Benjamin Gaignard54026262014-07-30 19:24:55 +0200895 /* Set the drm device handle */
896 hdmi->drm_dev = drm_dev;
897
898 encoder = sti_hdmi_find_encoder(drm_dev);
899 if (!encoder)
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +0300900 return -EINVAL;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200901
902 connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
903 if (!connector)
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +0300904 return -EINVAL;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200905
906 connector->hdmi = hdmi;
907
908 bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
909 if (!bridge)
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +0300910 return -EINVAL;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200911
912 bridge->driver_private = hdmi;
Ajay Kumarb07b90f2015-01-20 22:08:43 +0530913 bridge->funcs = &sti_hdmi_bridge_funcs;
Ajay Kumar3d3f8b12015-01-20 22:08:44 +0530914 drm_bridge_attach(drm_dev, bridge);
Benjamin Gaignard54026262014-07-30 19:24:55 +0200915
916 encoder->bridge = bridge;
917 connector->encoder = encoder;
918
919 drm_connector = (struct drm_connector *)connector;
920
921 drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
922
923 drm_connector_init(drm_dev, drm_connector,
924 &sti_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
925 drm_connector_helper_add(drm_connector,
926 &sti_hdmi_connector_helper_funcs);
927
Vincent Abriou5671cef2016-02-10 11:24:28 +0100928 /* initialise property */
929 sti_hdmi_connector_init_property(drm_dev, drm_connector);
930
Benjamin Gaignard54026262014-07-30 19:24:55 +0200931 err = drm_connector_register(drm_connector);
932 if (err)
933 goto err_connector;
934
935 err = drm_mode_connector_attach_encoder(drm_connector, encoder);
936 if (err) {
937 DRM_ERROR("Failed to attach a connector to a encoder\n");
938 goto err_sysfs;
939 }
940
941 /* Enable default interrupts */
942 hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
943
944 return 0;
945
946err_sysfs:
947 drm_connector_unregister(drm_connector);
948err_connector:
Benjamin Gaignard54026262014-07-30 19:24:55 +0200949 drm_connector_cleanup(drm_connector);
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +0300950
Benjamin Gaignard54026262014-07-30 19:24:55 +0200951 return -EINVAL;
952}
953
954static void sti_hdmi_unbind(struct device *dev,
955 struct device *master, void *data)
956{
957 /* do nothing */
958}
959
960static const struct component_ops sti_hdmi_ops = {
961 .bind = sti_hdmi_bind,
962 .unbind = sti_hdmi_unbind,
963};
964
Kiran Padwal8e932cf2014-08-26 12:25:24 +0200965static const struct of_device_id hdmi_of_match[] = {
Benjamin Gaignard54026262014-07-30 19:24:55 +0200966 {
967 .compatible = "st,stih416-hdmi",
968 .data = &tx3g0c55phy_ops,
969 }, {
970 .compatible = "st,stih407-hdmi",
971 .data = &tx3g4c28phy_ops,
972 }, {
973 /* end node */
974 }
975};
976MODULE_DEVICE_TABLE(of, hdmi_of_match);
977
978static int sti_hdmi_probe(struct platform_device *pdev)
979{
980 struct device *dev = &pdev->dev;
981 struct sti_hdmi *hdmi;
982 struct device_node *np = dev->of_node;
983 struct resource *res;
Benjamin Gaignard53bdcf52015-07-17 12:06:11 +0200984 struct device_node *ddc;
Benjamin Gaignard54026262014-07-30 19:24:55 +0200985 int ret;
986
987 DRM_INFO("%s\n", __func__);
988
989 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
990 if (!hdmi)
991 return -ENOMEM;
992
Benjamin Gaignard53bdcf52015-07-17 12:06:11 +0200993 ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
994 if (ddc) {
Vladimir Zapolskiy4d5821a2015-09-21 18:51:27 +0300995 hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc);
Benjamin Gaignard53bdcf52015-07-17 12:06:11 +0200996 of_node_put(ddc);
Vladimir Zapolskiy4d5821a2015-09-21 18:51:27 +0300997 if (!hdmi->ddc_adapt)
998 return -EPROBE_DEFER;
Benjamin Gaignard53bdcf52015-07-17 12:06:11 +0200999 }
1000
Benjamin Gaignard54026262014-07-30 19:24:55 +02001001 hdmi->dev = pdev->dev;
1002
1003 /* Get resources */
1004 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
1005 if (!res) {
1006 DRM_ERROR("Invalid hdmi resource\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001007 ret = -ENOMEM;
1008 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001009 }
1010 hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001011 if (!hdmi->regs) {
1012 ret = -ENOMEM;
1013 goto release_adapter;
1014 }
Benjamin Gaignard54026262014-07-30 19:24:55 +02001015
1016 if (of_device_is_compatible(np, "st,stih416-hdmi")) {
1017 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1018 "syscfg");
1019 if (!res) {
1020 DRM_ERROR("Invalid syscfg resource\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001021 ret = -ENOMEM;
1022 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001023 }
1024 hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
1025 resource_size(res));
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001026 if (!hdmi->syscfg) {
1027 ret = -ENOMEM;
1028 goto release_adapter;
1029 }
Benjamin Gaignard54026262014-07-30 19:24:55 +02001030 }
1031
1032 hdmi->phy_ops = (struct hdmi_phy_ops *)
1033 of_match_node(hdmi_of_match, np)->data;
1034
1035 /* Get clock resources */
1036 hdmi->clk_pix = devm_clk_get(dev, "pix");
1037 if (IS_ERR(hdmi->clk_pix)) {
1038 DRM_ERROR("Cannot get hdmi_pix clock\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001039 ret = PTR_ERR(hdmi->clk_pix);
1040 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001041 }
1042
1043 hdmi->clk_tmds = devm_clk_get(dev, "tmds");
1044 if (IS_ERR(hdmi->clk_tmds)) {
1045 DRM_ERROR("Cannot get hdmi_tmds clock\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001046 ret = PTR_ERR(hdmi->clk_tmds);
1047 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001048 }
1049
1050 hdmi->clk_phy = devm_clk_get(dev, "phy");
1051 if (IS_ERR(hdmi->clk_phy)) {
1052 DRM_ERROR("Cannot get hdmi_phy clock\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001053 ret = PTR_ERR(hdmi->clk_phy);
1054 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001055 }
1056
1057 hdmi->clk_audio = devm_clk_get(dev, "audio");
1058 if (IS_ERR(hdmi->clk_audio)) {
1059 DRM_ERROR("Cannot get hdmi_audio clock\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001060 ret = PTR_ERR(hdmi->clk_audio);
1061 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001062 }
1063
Benjamin Gaignard76569202014-10-09 08:53:35 +02001064 hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001065
1066 init_waitqueue_head(&hdmi->wait_event);
1067
1068 hdmi->irq = platform_get_irq_byname(pdev, "irq");
1069
1070 ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq,
1071 hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
1072 if (ret) {
1073 DRM_ERROR("Failed to register HDMI interrupt\n");
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001074 goto release_adapter;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001075 }
1076
1077 hdmi->reset = devm_reset_control_get(dev, "hdmi");
1078 /* Take hdmi out of reset */
1079 if (!IS_ERR(hdmi->reset))
1080 reset_control_deassert(hdmi->reset);
1081
1082 platform_set_drvdata(pdev, hdmi);
1083
1084 return component_add(&pdev->dev, &sti_hdmi_ops);
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001085
1086 release_adapter:
Vladimir Zapolskiy4d5821a2015-09-21 18:51:27 +03001087 i2c_put_adapter(hdmi->ddc_adapt);
Vladimir Zapolskiy807642d2015-09-21 18:51:26 +03001088
1089 return ret;
Benjamin Gaignard54026262014-07-30 19:24:55 +02001090}
1091
1092static int sti_hdmi_remove(struct platform_device *pdev)
1093{
Benjamin Gaignard41a14622014-09-08 15:52:08 +02001094 struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
1095
Vladimir Zapolskiy4d5821a2015-09-21 18:51:27 +03001096 i2c_put_adapter(hdmi->ddc_adapt);
Benjamin Gaignard54026262014-07-30 19:24:55 +02001097 component_del(&pdev->dev, &sti_hdmi_ops);
Vladimir Zapolskiy4d5821a2015-09-21 18:51:27 +03001098
Benjamin Gaignard54026262014-07-30 19:24:55 +02001099 return 0;
1100}
1101
1102struct platform_driver sti_hdmi_driver = {
1103 .driver = {
1104 .name = "sti-hdmi",
1105 .owner = THIS_MODULE,
1106 .of_match_table = hdmi_of_match,
1107 },
1108 .probe = sti_hdmi_probe,
1109 .remove = sti_hdmi_remove,
1110};
1111
Benjamin Gaignard54026262014-07-30 19:24:55 +02001112MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
1113MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
1114MODULE_LICENSE("GPL");