1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) STMicroelectronics SA 2014
4*4882a593Smuzhiyun * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/clk.h>
8*4882a593Smuzhiyun #include <linux/component.h>
9*4882a593Smuzhiyun #include <linux/debugfs.h>
10*4882a593Smuzhiyun #include <linux/hdmi.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/io.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/reset.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
17*4882a593Smuzhiyun #include <drm/drm_bridge.h>
18*4882a593Smuzhiyun #include <drm/drm_debugfs.h>
19*4882a593Smuzhiyun #include <drm/drm_drv.h>
20*4882a593Smuzhiyun #include <drm/drm_edid.h>
21*4882a593Smuzhiyun #include <drm/drm_file.h>
22*4882a593Smuzhiyun #include <drm/drm_print.h>
23*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <sound/hdmi-codec.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "sti_hdmi.h"
28*4882a593Smuzhiyun #include "sti_hdmi_tx3g4c28phy.h"
29*4882a593Smuzhiyun #include "sti_vtg.h"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define HDMI_CFG 0x0000
32*4882a593Smuzhiyun #define HDMI_INT_EN 0x0004
33*4882a593Smuzhiyun #define HDMI_INT_STA 0x0008
34*4882a593Smuzhiyun #define HDMI_INT_CLR 0x000C
35*4882a593Smuzhiyun #define HDMI_STA 0x0010
36*4882a593Smuzhiyun #define HDMI_ACTIVE_VID_XMIN 0x0100
37*4882a593Smuzhiyun #define HDMI_ACTIVE_VID_XMAX 0x0104
38*4882a593Smuzhiyun #define HDMI_ACTIVE_VID_YMIN 0x0108
39*4882a593Smuzhiyun #define HDMI_ACTIVE_VID_YMAX 0x010C
40*4882a593Smuzhiyun #define HDMI_DFLT_CHL0_DAT 0x0110
41*4882a593Smuzhiyun #define HDMI_DFLT_CHL1_DAT 0x0114
42*4882a593Smuzhiyun #define HDMI_DFLT_CHL2_DAT 0x0118
43*4882a593Smuzhiyun #define HDMI_AUDIO_CFG 0x0200
44*4882a593Smuzhiyun #define HDMI_SPDIF_FIFO_STATUS 0x0204
45*4882a593Smuzhiyun #define HDMI_SW_DI_1_HEAD_WORD 0x0210
46*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD0 0x0214
47*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD1 0x0218
48*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD2 0x021C
49*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD3 0x0220
50*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD4 0x0224
51*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD5 0x0228
52*4882a593Smuzhiyun #define HDMI_SW_DI_1_PKT_WORD6 0x022C
53*4882a593Smuzhiyun #define HDMI_SW_DI_CFG 0x0230
54*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_MASK 0x0244
55*4882a593Smuzhiyun #define HDMI_AUDN 0x0400
56*4882a593Smuzhiyun #define HDMI_AUD_CTS 0x0404
57*4882a593Smuzhiyun #define HDMI_SW_DI_2_HEAD_WORD 0x0600
58*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD0 0x0604
59*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD1 0x0608
60*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD2 0x060C
61*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD3 0x0610
62*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD4 0x0614
63*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD5 0x0618
64*4882a593Smuzhiyun #define HDMI_SW_DI_2_PKT_WORD6 0x061C
65*4882a593Smuzhiyun #define HDMI_SW_DI_3_HEAD_WORD 0x0620
66*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD0 0x0624
67*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD1 0x0628
68*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD2 0x062C
69*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD3 0x0630
70*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD4 0x0634
71*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD5 0x0638
72*4882a593Smuzhiyun #define HDMI_SW_DI_3_PKT_WORD6 0x063C
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun #define HDMI_IFRAME_SLOT_AVI 1
75*4882a593Smuzhiyun #define HDMI_IFRAME_SLOT_AUDIO 2
76*4882a593Smuzhiyun #define HDMI_IFRAME_SLOT_VENDOR 3
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun #define XCAT(prefix, x, suffix) prefix ## x ## suffix
79*4882a593Smuzhiyun #define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
80*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD0(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD0)
81*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD1(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD1)
82*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD2(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD2)
83*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD3(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD3)
84*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD4(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD4)
85*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5)
86*4882a593Smuzhiyun #define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun #define HDMI_SW_DI_MAX_WORD 7
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun #define HDMI_IFRAME_DISABLED 0x0
91*4882a593Smuzhiyun #define HDMI_IFRAME_SINGLE_SHOT 0x1
92*4882a593Smuzhiyun #define HDMI_IFRAME_FIELD 0x2
93*4882a593Smuzhiyun #define HDMI_IFRAME_FRAME 0x3
94*4882a593Smuzhiyun #define HDMI_IFRAME_MASK 0x3
95*4882a593Smuzhiyun #define HDMI_IFRAME_CFG_DI_N(x, n) ((x) << ((n-1)*4)) /* n from 1 to 6 */
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun #define HDMI_CFG_DEVICE_EN BIT(0)
98*4882a593Smuzhiyun #define HDMI_CFG_HDMI_NOT_DVI BIT(1)
99*4882a593Smuzhiyun #define HDMI_CFG_HDCP_EN BIT(2)
100*4882a593Smuzhiyun #define HDMI_CFG_ESS_NOT_OESS BIT(3)
101*4882a593Smuzhiyun #define HDMI_CFG_H_SYNC_POL_NEG BIT(4)
102*4882a593Smuzhiyun #define HDMI_CFG_V_SYNC_POL_NEG BIT(6)
103*4882a593Smuzhiyun #define HDMI_CFG_422_EN BIT(8)
104*4882a593Smuzhiyun #define HDMI_CFG_FIFO_OVERRUN_CLR BIT(12)
105*4882a593Smuzhiyun #define HDMI_CFG_FIFO_UNDERRUN_CLR BIT(13)
106*4882a593Smuzhiyun #define HDMI_CFG_SW_RST_EN BIT(31)
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun #define HDMI_INT_GLOBAL BIT(0)
109*4882a593Smuzhiyun #define HDMI_INT_SW_RST BIT(1)
110*4882a593Smuzhiyun #define HDMI_INT_PIX_CAP BIT(3)
111*4882a593Smuzhiyun #define HDMI_INT_HOT_PLUG BIT(4)
112*4882a593Smuzhiyun #define HDMI_INT_DLL_LCK BIT(5)
113*4882a593Smuzhiyun #define HDMI_INT_NEW_FRAME BIT(6)
114*4882a593Smuzhiyun #define HDMI_INT_GENCTRL_PKT BIT(7)
115*4882a593Smuzhiyun #define HDMI_INT_AUDIO_FIFO_XRUN BIT(8)
116*4882a593Smuzhiyun #define HDMI_INT_SINK_TERM_PRESENT BIT(11)
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \
119*4882a593Smuzhiyun | HDMI_INT_DLL_LCK \
120*4882a593Smuzhiyun | HDMI_INT_HOT_PLUG \
121*4882a593Smuzhiyun | HDMI_INT_GLOBAL)
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun #define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \
124*4882a593Smuzhiyun | HDMI_INT_AUDIO_FIFO_XRUN \
125*4882a593Smuzhiyun | HDMI_INT_GENCTRL_PKT \
126*4882a593Smuzhiyun | HDMI_INT_NEW_FRAME \
127*4882a593Smuzhiyun | HDMI_INT_DLL_LCK \
128*4882a593Smuzhiyun | HDMI_INT_HOT_PLUG \
129*4882a593Smuzhiyun | HDMI_INT_PIX_CAP \
130*4882a593Smuzhiyun | HDMI_INT_SW_RST \
131*4882a593Smuzhiyun | HDMI_INT_GLOBAL)
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #define HDMI_STA_SW_RST BIT(1)
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #define HDMI_AUD_CFG_8CH BIT(0)
136*4882a593Smuzhiyun #define HDMI_AUD_CFG_SPDIF_DIV_2 BIT(1)
137*4882a593Smuzhiyun #define HDMI_AUD_CFG_SPDIF_DIV_3 BIT(2)
138*4882a593Smuzhiyun #define HDMI_AUD_CFG_SPDIF_CLK_DIV_4 (BIT(1) | BIT(2))
139*4882a593Smuzhiyun #define HDMI_AUD_CFG_CTS_CLK_256FS BIT(12)
140*4882a593Smuzhiyun #define HDMI_AUD_CFG_DTS_INVALID BIT(16)
141*4882a593Smuzhiyun #define HDMI_AUD_CFG_ONE_BIT_INVALID (BIT(18) | BIT(19) | BIT(20) | BIT(21))
142*4882a593Smuzhiyun #define HDMI_AUD_CFG_CH12_VALID BIT(28)
143*4882a593Smuzhiyun #define HDMI_AUD_CFG_CH34_VALID BIT(29)
144*4882a593Smuzhiyun #define HDMI_AUD_CFG_CH56_VALID BIT(30)
145*4882a593Smuzhiyun #define HDMI_AUD_CFG_CH78_VALID BIT(31)
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* sample flat mask */
148*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_NO 0
149*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_SP0 BIT(0)
150*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_SP1 BIT(1)
151*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_SP2 BIT(2)
152*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_SP3 BIT(3)
153*4882a593Smuzhiyun #define HDMI_SAMPLE_FLAT_ALL (HDMI_SAMPLE_FLAT_SP0 | HDMI_SAMPLE_FLAT_SP1 |\
154*4882a593Smuzhiyun HDMI_SAMPLE_FLAT_SP2 | HDMI_SAMPLE_FLAT_SP3)
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
157*4882a593Smuzhiyun #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
158*4882a593Smuzhiyun #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16)
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun struct sti_hdmi_connector {
161*4882a593Smuzhiyun struct drm_connector drm_connector;
162*4882a593Smuzhiyun struct drm_encoder *encoder;
163*4882a593Smuzhiyun struct sti_hdmi *hdmi;
164*4882a593Smuzhiyun struct drm_property *colorspace_property;
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun #define to_sti_hdmi_connector(x) \
168*4882a593Smuzhiyun container_of(x, struct sti_hdmi_connector, drm_connector)
169*4882a593Smuzhiyun
hdmi_read(struct sti_hdmi * hdmi,int offset)170*4882a593Smuzhiyun u32 hdmi_read(struct sti_hdmi *hdmi, int offset)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun return readl(hdmi->regs + offset);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
hdmi_write(struct sti_hdmi * hdmi,u32 val,int offset)175*4882a593Smuzhiyun void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun writel(val, hdmi->regs + offset);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /**
181*4882a593Smuzhiyun * HDMI interrupt handler threaded
182*4882a593Smuzhiyun *
183*4882a593Smuzhiyun * @irq: irq number
184*4882a593Smuzhiyun * @arg: connector structure
185*4882a593Smuzhiyun */
hdmi_irq_thread(int irq,void * arg)186*4882a593Smuzhiyun static irqreturn_t hdmi_irq_thread(int irq, void *arg)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun struct sti_hdmi *hdmi = arg;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* Hot plug/unplug IRQ */
191*4882a593Smuzhiyun if (hdmi->irq_status & HDMI_INT_HOT_PLUG) {
192*4882a593Smuzhiyun hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
193*4882a593Smuzhiyun if (hdmi->drm_dev)
194*4882a593Smuzhiyun drm_helper_hpd_irq_event(hdmi->drm_dev);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* Sw reset and PLL lock are exclusive so we can use the same
198*4882a593Smuzhiyun * event to signal them
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) {
201*4882a593Smuzhiyun hdmi->event_received = true;
202*4882a593Smuzhiyun wake_up_interruptible(&hdmi->wait_event);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* Audio FIFO underrun IRQ */
206*4882a593Smuzhiyun if (hdmi->irq_status & HDMI_INT_AUDIO_FIFO_XRUN)
207*4882a593Smuzhiyun DRM_INFO("Warning: audio FIFO underrun occurs!\n");
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun return IRQ_HANDLED;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun * HDMI interrupt handler
214*4882a593Smuzhiyun *
215*4882a593Smuzhiyun * @irq: irq number
216*4882a593Smuzhiyun * @arg: connector structure
217*4882a593Smuzhiyun */
hdmi_irq(int irq,void * arg)218*4882a593Smuzhiyun static irqreturn_t hdmi_irq(int irq, void *arg)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct sti_hdmi *hdmi = arg;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* read interrupt status */
223*4882a593Smuzhiyun hdmi->irq_status = hdmi_read(hdmi, HDMI_INT_STA);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* clear interrupt status */
226*4882a593Smuzhiyun hdmi_write(hdmi, hdmi->irq_status, HDMI_INT_CLR);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* force sync bus write */
229*4882a593Smuzhiyun hdmi_read(hdmi, HDMI_INT_STA);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return IRQ_WAKE_THREAD;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /**
235*4882a593Smuzhiyun * Set hdmi active area depending on the drm display mode selected
236*4882a593Smuzhiyun *
237*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
238*4882a593Smuzhiyun */
hdmi_active_area(struct sti_hdmi * hdmi)239*4882a593Smuzhiyun static void hdmi_active_area(struct sti_hdmi *hdmi)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun u32 xmin, xmax;
242*4882a593Smuzhiyun u32 ymin, ymax;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun xmin = sti_vtg_get_pixel_number(hdmi->mode, 1);
245*4882a593Smuzhiyun xmax = sti_vtg_get_pixel_number(hdmi->mode, hdmi->mode.hdisplay);
246*4882a593Smuzhiyun ymin = sti_vtg_get_line_number(hdmi->mode, 0);
247*4882a593Smuzhiyun ymax = sti_vtg_get_line_number(hdmi->mode, hdmi->mode.vdisplay - 1);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun hdmi_write(hdmi, xmin, HDMI_ACTIVE_VID_XMIN);
250*4882a593Smuzhiyun hdmi_write(hdmi, xmax, HDMI_ACTIVE_VID_XMAX);
251*4882a593Smuzhiyun hdmi_write(hdmi, ymin, HDMI_ACTIVE_VID_YMIN);
252*4882a593Smuzhiyun hdmi_write(hdmi, ymax, HDMI_ACTIVE_VID_YMAX);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /**
256*4882a593Smuzhiyun * Overall hdmi configuration
257*4882a593Smuzhiyun *
258*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
259*4882a593Smuzhiyun */
hdmi_config(struct sti_hdmi * hdmi)260*4882a593Smuzhiyun static void hdmi_config(struct sti_hdmi *hdmi)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun u32 conf;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* Clear overrun and underrun fifo */
267*4882a593Smuzhiyun conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Select encryption type and the framing mode */
270*4882a593Smuzhiyun conf |= HDMI_CFG_ESS_NOT_OESS;
271*4882a593Smuzhiyun if (hdmi->hdmi_monitor)
272*4882a593Smuzhiyun conf |= HDMI_CFG_HDMI_NOT_DVI;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* Set Hsync polarity */
275*4882a593Smuzhiyun if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) {
276*4882a593Smuzhiyun DRM_DEBUG_DRIVER("H Sync Negative\n");
277*4882a593Smuzhiyun conf |= HDMI_CFG_H_SYNC_POL_NEG;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Set Vsync polarity */
281*4882a593Smuzhiyun if (hdmi->mode.flags & DRM_MODE_FLAG_NVSYNC) {
282*4882a593Smuzhiyun DRM_DEBUG_DRIVER("V Sync Negative\n");
283*4882a593Smuzhiyun conf |= HDMI_CFG_V_SYNC_POL_NEG;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Enable HDMI */
287*4882a593Smuzhiyun conf |= HDMI_CFG_DEVICE_EN;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun hdmi_write(hdmi, conf, HDMI_CFG);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /*
293*4882a593Smuzhiyun * Helper to reset info frame
294*4882a593Smuzhiyun *
295*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
296*4882a593Smuzhiyun * @slot: infoframe to reset
297*4882a593Smuzhiyun */
hdmi_infoframe_reset(struct sti_hdmi * hdmi,u32 slot)298*4882a593Smuzhiyun static void hdmi_infoframe_reset(struct sti_hdmi *hdmi,
299*4882a593Smuzhiyun u32 slot)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun u32 val, i;
302*4882a593Smuzhiyun u32 head_offset, pack_offset;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun switch (slot) {
305*4882a593Smuzhiyun case HDMI_IFRAME_SLOT_AVI:
306*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
307*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun case HDMI_IFRAME_SLOT_AUDIO:
310*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
311*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
312*4882a593Smuzhiyun break;
313*4882a593Smuzhiyun case HDMI_IFRAME_SLOT_VENDOR:
314*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
315*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
316*4882a593Smuzhiyun break;
317*4882a593Smuzhiyun default:
318*4882a593Smuzhiyun DRM_ERROR("unsupported infoframe slot: %#x\n", slot);
319*4882a593Smuzhiyun return;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /* Disable transmission for the selected slot */
323*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
324*4882a593Smuzhiyun val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
325*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* Reset info frame registers */
328*4882a593Smuzhiyun hdmi_write(hdmi, 0x0, head_offset);
329*4882a593Smuzhiyun for (i = 0; i < HDMI_SW_DI_MAX_WORD; i += sizeof(u32))
330*4882a593Smuzhiyun hdmi_write(hdmi, 0x0, pack_offset + i);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /**
334*4882a593Smuzhiyun * Helper to concatenate infoframe in 32 bits word
335*4882a593Smuzhiyun *
336*4882a593Smuzhiyun * @ptr: pointer on the hdmi internal structure
337*4882a593Smuzhiyun * @size: size to write
338*4882a593Smuzhiyun */
hdmi_infoframe_subpack(const u8 * ptr,size_t size)339*4882a593Smuzhiyun static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun unsigned long value = 0;
342*4882a593Smuzhiyun size_t i;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun for (i = size; i > 0; i--)
345*4882a593Smuzhiyun value = (value << 8) | ptr[i - 1];
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return value;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /**
351*4882a593Smuzhiyun * Helper to write info frame
352*4882a593Smuzhiyun *
353*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
354*4882a593Smuzhiyun * @data: infoframe to write
355*4882a593Smuzhiyun * @size: size to write
356*4882a593Smuzhiyun */
hdmi_infoframe_write_infopack(struct sti_hdmi * hdmi,const u8 * data,size_t size)357*4882a593Smuzhiyun static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi,
358*4882a593Smuzhiyun const u8 *data,
359*4882a593Smuzhiyun size_t size)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun const u8 *ptr = data;
362*4882a593Smuzhiyun u32 val, slot, mode, i;
363*4882a593Smuzhiyun u32 head_offset, pack_offset;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun switch (*ptr) {
366*4882a593Smuzhiyun case HDMI_INFOFRAME_TYPE_AVI:
367*4882a593Smuzhiyun slot = HDMI_IFRAME_SLOT_AVI;
368*4882a593Smuzhiyun mode = HDMI_IFRAME_FIELD;
369*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
370*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun case HDMI_INFOFRAME_TYPE_AUDIO:
373*4882a593Smuzhiyun slot = HDMI_IFRAME_SLOT_AUDIO;
374*4882a593Smuzhiyun mode = HDMI_IFRAME_FRAME;
375*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
376*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
377*4882a593Smuzhiyun break;
378*4882a593Smuzhiyun case HDMI_INFOFRAME_TYPE_VENDOR:
379*4882a593Smuzhiyun slot = HDMI_IFRAME_SLOT_VENDOR;
380*4882a593Smuzhiyun mode = HDMI_IFRAME_FRAME;
381*4882a593Smuzhiyun head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
382*4882a593Smuzhiyun pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
383*4882a593Smuzhiyun break;
384*4882a593Smuzhiyun default:
385*4882a593Smuzhiyun DRM_ERROR("unsupported infoframe type: %#x\n", *ptr);
386*4882a593Smuzhiyun return;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* Disable transmission slot for updated infoframe */
390*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
391*4882a593Smuzhiyun val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
392*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++);
395*4882a593Smuzhiyun val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++);
396*4882a593Smuzhiyun val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++);
397*4882a593Smuzhiyun writel(val, hdmi->regs + head_offset);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun /*
400*4882a593Smuzhiyun * Each subpack contains 4 bytes
401*4882a593Smuzhiyun * The First Bytes of the first subpacket must contain the checksum
402*4882a593Smuzhiyun * Packet size is increase by one.
403*4882a593Smuzhiyun */
404*4882a593Smuzhiyun size = size - HDMI_INFOFRAME_HEADER_SIZE + 1;
405*4882a593Smuzhiyun for (i = 0; i < size; i += sizeof(u32)) {
406*4882a593Smuzhiyun size_t num;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun num = min_t(size_t, size - i, sizeof(u32));
409*4882a593Smuzhiyun val = hdmi_infoframe_subpack(ptr, num);
410*4882a593Smuzhiyun ptr += sizeof(u32);
411*4882a593Smuzhiyun writel(val, hdmi->regs + pack_offset + i);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /* Enable transmission slot for updated infoframe */
415*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
416*4882a593Smuzhiyun val |= HDMI_IFRAME_CFG_DI_N(mode, slot);
417*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /**
421*4882a593Smuzhiyun * Prepare and configure the AVI infoframe
422*4882a593Smuzhiyun *
423*4882a593Smuzhiyun * AVI infoframe are transmitted at least once per two video field and
424*4882a593Smuzhiyun * contains information about HDMI transmission mode such as color space,
425*4882a593Smuzhiyun * colorimetry, ...
426*4882a593Smuzhiyun *
427*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
428*4882a593Smuzhiyun *
429*4882a593Smuzhiyun * Return negative value if error occurs
430*4882a593Smuzhiyun */
hdmi_avi_infoframe_config(struct sti_hdmi * hdmi)431*4882a593Smuzhiyun static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun struct drm_display_mode *mode = &hdmi->mode;
434*4882a593Smuzhiyun struct hdmi_avi_infoframe infoframe;
435*4882a593Smuzhiyun u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
436*4882a593Smuzhiyun int ret;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe,
441*4882a593Smuzhiyun hdmi->drm_connector, mode);
442*4882a593Smuzhiyun if (ret < 0) {
443*4882a593Smuzhiyun DRM_ERROR("failed to setup AVI infoframe: %d\n", ret);
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /* fixed infoframe configuration not linked to the mode */
448*4882a593Smuzhiyun infoframe.colorspace = hdmi->colorspace;
449*4882a593Smuzhiyun infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
450*4882a593Smuzhiyun infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun ret = hdmi_avi_infoframe_pack(&infoframe, buffer, sizeof(buffer));
453*4882a593Smuzhiyun if (ret < 0) {
454*4882a593Smuzhiyun DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
455*4882a593Smuzhiyun return ret;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun hdmi_infoframe_write_infopack(hdmi, buffer, ret);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return 0;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /**
464*4882a593Smuzhiyun * Prepare and configure the AUDIO infoframe
465*4882a593Smuzhiyun *
466*4882a593Smuzhiyun * AUDIO infoframe are transmitted once per frame and
467*4882a593Smuzhiyun * contains information about HDMI transmission mode such as audio codec,
468*4882a593Smuzhiyun * sample size, ...
469*4882a593Smuzhiyun *
470*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
471*4882a593Smuzhiyun *
472*4882a593Smuzhiyun * Return negative value if error occurs
473*4882a593Smuzhiyun */
hdmi_audio_infoframe_config(struct sti_hdmi * hdmi)474*4882a593Smuzhiyun static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun struct hdmi_audio_params *audio = &hdmi->audio;
477*4882a593Smuzhiyun u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
478*4882a593Smuzhiyun int ret, val;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun DRM_DEBUG_DRIVER("enter %s, AIF %s\n", __func__,
481*4882a593Smuzhiyun audio->enabled ? "enable" : "disable");
482*4882a593Smuzhiyun if (audio->enabled) {
483*4882a593Smuzhiyun /* set audio parameters stored*/
484*4882a593Smuzhiyun ret = hdmi_audio_infoframe_pack(&audio->cea, buffer,
485*4882a593Smuzhiyun sizeof(buffer));
486*4882a593Smuzhiyun if (ret < 0) {
487*4882a593Smuzhiyun DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
488*4882a593Smuzhiyun return ret;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun hdmi_infoframe_write_infopack(hdmi, buffer, ret);
491*4882a593Smuzhiyun } else {
492*4882a593Smuzhiyun /*disable audio info frame transmission */
493*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
494*4882a593Smuzhiyun val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK,
495*4882a593Smuzhiyun HDMI_IFRAME_SLOT_AUDIO);
496*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /*
503*4882a593Smuzhiyun * Prepare and configure the VS infoframe
504*4882a593Smuzhiyun *
505*4882a593Smuzhiyun * Vendor Specific infoframe are transmitted once per frame and
506*4882a593Smuzhiyun * contains vendor specific information.
507*4882a593Smuzhiyun *
508*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
509*4882a593Smuzhiyun *
510*4882a593Smuzhiyun * Return negative value if error occurs
511*4882a593Smuzhiyun */
512*4882a593Smuzhiyun #define HDMI_VENDOR_INFOFRAME_MAX_SIZE 6
hdmi_vendor_infoframe_config(struct sti_hdmi * hdmi)513*4882a593Smuzhiyun static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct drm_display_mode *mode = &hdmi->mode;
516*4882a593Smuzhiyun struct hdmi_vendor_infoframe infoframe;
517*4882a593Smuzhiyun u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_MAX_SIZE];
518*4882a593Smuzhiyun int ret;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe,
523*4882a593Smuzhiyun hdmi->drm_connector,
524*4882a593Smuzhiyun mode);
525*4882a593Smuzhiyun if (ret < 0) {
526*4882a593Smuzhiyun /*
527*4882a593Smuzhiyun * Going into that statement does not means vendor infoframe
528*4882a593Smuzhiyun * fails. It just informed us that vendor infoframe is not
529*4882a593Smuzhiyun * needed for the selected mode. Only 4k or stereoscopic 3D
530*4882a593Smuzhiyun * mode requires vendor infoframe. So just simply return 0.
531*4882a593Smuzhiyun */
532*4882a593Smuzhiyun return 0;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun ret = hdmi_vendor_infoframe_pack(&infoframe, buffer, sizeof(buffer));
536*4882a593Smuzhiyun if (ret < 0) {
537*4882a593Smuzhiyun DRM_ERROR("failed to pack VS infoframe: %d\n", ret);
538*4882a593Smuzhiyun return ret;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun hdmi_infoframe_write_infopack(hdmi, buffer, ret);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun return 0;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun #define HDMI_TIMEOUT_SWRESET 100 /*milliseconds */
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /**
549*4882a593Smuzhiyun * Software reset of the hdmi subsystem
550*4882a593Smuzhiyun *
551*4882a593Smuzhiyun * @hdmi: pointer on the hdmi internal structure
552*4882a593Smuzhiyun *
553*4882a593Smuzhiyun */
hdmi_swreset(struct sti_hdmi * hdmi)554*4882a593Smuzhiyun static void hdmi_swreset(struct sti_hdmi *hdmi)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun u32 val;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun /* Enable hdmi_audio clock only during hdmi reset */
561*4882a593Smuzhiyun if (clk_prepare_enable(hdmi->clk_audio))
562*4882a593Smuzhiyun DRM_INFO("Failed to prepare/enable hdmi_audio clk\n");
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /* Sw reset */
565*4882a593Smuzhiyun hdmi->event_received = false;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_CFG);
568*4882a593Smuzhiyun val |= HDMI_CFG_SW_RST_EN;
569*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_CFG);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun /* Wait reset completed */
572*4882a593Smuzhiyun wait_event_interruptible_timeout(hdmi->wait_event,
573*4882a593Smuzhiyun hdmi->event_received,
574*4882a593Smuzhiyun msecs_to_jiffies
575*4882a593Smuzhiyun (HDMI_TIMEOUT_SWRESET));
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun /*
578*4882a593Smuzhiyun * HDMI_STA_SW_RST bit is set to '1' when SW_RST bit in HDMI_CFG is
579*4882a593Smuzhiyun * set to '1' and clk_audio is running.
580*4882a593Smuzhiyun */
581*4882a593Smuzhiyun if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_SW_RST) == 0)
582*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Warning: HDMI sw reset timeout occurs\n");
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun val = hdmi_read(hdmi, HDMI_CFG);
585*4882a593Smuzhiyun val &= ~HDMI_CFG_SW_RST_EN;
586*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_CFG);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /* Disable hdmi_audio clock. Not used anymore for drm purpose */
589*4882a593Smuzhiyun clk_disable_unprepare(hdmi->clk_audio);
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun #define DBGFS_PRINT_STR(str1, str2) seq_printf(s, "%-24s %s\n", str1, str2)
593*4882a593Smuzhiyun #define DBGFS_PRINT_INT(str1, int2) seq_printf(s, "%-24s %d\n", str1, int2)
594*4882a593Smuzhiyun #define DBGFS_DUMP(str, reg) seq_printf(s, "%s %-25s 0x%08X", str, #reg, \
595*4882a593Smuzhiyun hdmi_read(hdmi, reg))
596*4882a593Smuzhiyun #define DBGFS_DUMP_DI(reg, slot) DBGFS_DUMP("\n", reg(slot))
597*4882a593Smuzhiyun
hdmi_dbg_cfg(struct seq_file * s,int val)598*4882a593Smuzhiyun static void hdmi_dbg_cfg(struct seq_file *s, int val)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun int tmp;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun seq_putc(s, '\t');
603*4882a593Smuzhiyun tmp = val & HDMI_CFG_HDMI_NOT_DVI;
604*4882a593Smuzhiyun DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI");
605*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
606*4882a593Smuzhiyun tmp = val & HDMI_CFG_HDCP_EN;
607*4882a593Smuzhiyun DBGFS_PRINT_STR("HDCP:", tmp ? "enable" : "disable");
608*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
609*4882a593Smuzhiyun tmp = val & HDMI_CFG_ESS_NOT_OESS;
610*4882a593Smuzhiyun DBGFS_PRINT_STR("HDCP mode:", tmp ? "ESS enable" : "OESS enable");
611*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
612*4882a593Smuzhiyun tmp = val & HDMI_CFG_H_SYNC_POL_NEG;
613*4882a593Smuzhiyun DBGFS_PRINT_STR("Hsync polarity:", tmp ? "inverted" : "normal");
614*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
615*4882a593Smuzhiyun tmp = val & HDMI_CFG_V_SYNC_POL_NEG;
616*4882a593Smuzhiyun DBGFS_PRINT_STR("Vsync polarity:", tmp ? "inverted" : "normal");
617*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
618*4882a593Smuzhiyun tmp = val & HDMI_CFG_422_EN;
619*4882a593Smuzhiyun DBGFS_PRINT_STR("YUV422 format:", tmp ? "enable" : "disable");
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
hdmi_dbg_sta(struct seq_file * s,int val)622*4882a593Smuzhiyun static void hdmi_dbg_sta(struct seq_file *s, int val)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun int tmp;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun seq_putc(s, '\t');
627*4882a593Smuzhiyun tmp = (val & HDMI_STA_DLL_LCK);
628*4882a593Smuzhiyun DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked");
629*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
630*4882a593Smuzhiyun tmp = (val & HDMI_STA_HOT_PLUG);
631*4882a593Smuzhiyun DBGFS_PRINT_STR("hdmi cable:", tmp ? "connected" : "not connected");
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
hdmi_dbg_sw_di_cfg(struct seq_file * s,int val)634*4882a593Smuzhiyun static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun int tmp;
637*4882a593Smuzhiyun char *const en_di[] = {"no transmission",
638*4882a593Smuzhiyun "single transmission",
639*4882a593Smuzhiyun "once every field",
640*4882a593Smuzhiyun "once every frame"};
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun seq_putc(s, '\t');
643*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1));
644*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 1:", en_di[tmp]);
645*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
646*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 2)) >> 4;
647*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 2:", en_di[tmp]);
648*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
649*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 3)) >> 8;
650*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 3:", en_di[tmp]);
651*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
652*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 4)) >> 12;
653*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 4:", en_di[tmp]);
654*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
655*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 5)) >> 16;
656*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 5:", en_di[tmp]);
657*4882a593Smuzhiyun seq_puts(s, "\t\t\t\t\t");
658*4882a593Smuzhiyun tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 6)) >> 20;
659*4882a593Smuzhiyun DBGFS_PRINT_STR("Data island 6:", en_di[tmp]);
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
hdmi_dbg_show(struct seq_file * s,void * data)662*4882a593Smuzhiyun static int hdmi_dbg_show(struct seq_file *s, void *data)
663*4882a593Smuzhiyun {
664*4882a593Smuzhiyun struct drm_info_node *node = s->private;
665*4882a593Smuzhiyun struct sti_hdmi *hdmi = (struct sti_hdmi *)node->info_ent->data;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun seq_printf(s, "HDMI: (vaddr = 0x%p)", hdmi->regs);
668*4882a593Smuzhiyun DBGFS_DUMP("\n", HDMI_CFG);
669*4882a593Smuzhiyun hdmi_dbg_cfg(s, hdmi_read(hdmi, HDMI_CFG));
670*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_INT_EN);
671*4882a593Smuzhiyun DBGFS_DUMP("\n", HDMI_STA);
672*4882a593Smuzhiyun hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA));
673*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN);
674*4882a593Smuzhiyun seq_putc(s, '\t');
675*4882a593Smuzhiyun DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN));
676*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX);
677*4882a593Smuzhiyun seq_putc(s, '\t');
678*4882a593Smuzhiyun DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX));
679*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN);
680*4882a593Smuzhiyun seq_putc(s, '\t');
681*4882a593Smuzhiyun DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN));
682*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX);
683*4882a593Smuzhiyun seq_putc(s, '\t');
684*4882a593Smuzhiyun DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX));
685*4882a593Smuzhiyun DBGFS_DUMP("", HDMI_SW_DI_CFG);
686*4882a593Smuzhiyun hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG));
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun DBGFS_DUMP("\n", HDMI_AUDIO_CFG);
689*4882a593Smuzhiyun DBGFS_DUMP("\n", HDMI_SPDIF_FIFO_STATUS);
690*4882a593Smuzhiyun DBGFS_DUMP("\n", HDMI_AUDN);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):",
693*4882a593Smuzhiyun HDMI_IFRAME_SLOT_AVI);
694*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI);
695*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AVI);
696*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AVI);
697*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AVI);
698*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AVI);
699*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI);
700*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI);
701*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI);
702*4882a593Smuzhiyun seq_printf(s, "\n\n AUDIO Infoframe (Data Island slot N=%d):",
703*4882a593Smuzhiyun HDMI_IFRAME_SLOT_AUDIO);
704*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO);
705*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO);
706*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AUDIO);
707*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AUDIO);
708*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AUDIO);
709*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO);
710*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO);
711*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO);
712*4882a593Smuzhiyun seq_printf(s, "\n\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):",
713*4882a593Smuzhiyun HDMI_IFRAME_SLOT_VENDOR);
714*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR);
715*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR);
716*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_VENDOR);
717*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_VENDOR);
718*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_VENDOR);
719*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR);
720*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR);
721*4882a593Smuzhiyun DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR);
722*4882a593Smuzhiyun seq_putc(s, '\n');
723*4882a593Smuzhiyun return 0;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun static struct drm_info_list hdmi_debugfs_files[] = {
727*4882a593Smuzhiyun { "hdmi", hdmi_dbg_show, 0, NULL },
728*4882a593Smuzhiyun };
729*4882a593Smuzhiyun
hdmi_debugfs_init(struct sti_hdmi * hdmi,struct drm_minor * minor)730*4882a593Smuzhiyun static void hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun unsigned int i;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hdmi_debugfs_files); i++)
735*4882a593Smuzhiyun hdmi_debugfs_files[i].data = hdmi;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun drm_debugfs_create_files(hdmi_debugfs_files,
738*4882a593Smuzhiyun ARRAY_SIZE(hdmi_debugfs_files),
739*4882a593Smuzhiyun minor->debugfs_root, minor);
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
sti_hdmi_disable(struct drm_bridge * bridge)742*4882a593Smuzhiyun static void sti_hdmi_disable(struct drm_bridge *bridge)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun struct sti_hdmi *hdmi = bridge->driver_private;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun u32 val = hdmi_read(hdmi, HDMI_CFG);
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun if (!hdmi->enabled)
749*4882a593Smuzhiyun return;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun /* Disable HDMI */
754*4882a593Smuzhiyun val &= ~HDMI_CFG_DEVICE_EN;
755*4882a593Smuzhiyun hdmi_write(hdmi, val, HDMI_CFG);
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /* Stop the phy */
760*4882a593Smuzhiyun hdmi->phy_ops->stop(hdmi);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun /* Reset info frame transmission */
763*4882a593Smuzhiyun hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI);
764*4882a593Smuzhiyun hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO);
765*4882a593Smuzhiyun hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_VENDOR);
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun /* Set the default channel data to be a dark red */
768*4882a593Smuzhiyun hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT);
769*4882a593Smuzhiyun hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
770*4882a593Smuzhiyun hdmi_write(hdmi, 0x0060, HDMI_DFLT_CHL2_DAT);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun /* Disable/unprepare hdmi clock */
773*4882a593Smuzhiyun clk_disable_unprepare(hdmi->clk_phy);
774*4882a593Smuzhiyun clk_disable_unprepare(hdmi->clk_tmds);
775*4882a593Smuzhiyun clk_disable_unprepare(hdmi->clk_pix);
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun hdmi->enabled = false;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun cec_notifier_set_phys_addr(hdmi->notifier, CEC_PHYS_ADDR_INVALID);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /**
783*4882a593Smuzhiyun * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent
784*4882a593Smuzhiyun * clocks. None-coherent clocks means that audio and TMDS clocks have not the
785*4882a593Smuzhiyun * same source (drifts between clocks). In this case assumption is that CTS is
786*4882a593Smuzhiyun * automatically calculated by hardware.
787*4882a593Smuzhiyun *
788*4882a593Smuzhiyun * @audio_fs: audio frame clock frequency in Hz
789*4882a593Smuzhiyun *
790*4882a593Smuzhiyun * Values computed are based on table described in HDMI specification 1.4b
791*4882a593Smuzhiyun *
792*4882a593Smuzhiyun * Returns n value.
793*4882a593Smuzhiyun */
sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs)794*4882a593Smuzhiyun static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs)
795*4882a593Smuzhiyun {
796*4882a593Smuzhiyun unsigned int n;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun switch (audio_fs) {
799*4882a593Smuzhiyun case 32000:
800*4882a593Smuzhiyun n = 4096;
801*4882a593Smuzhiyun break;
802*4882a593Smuzhiyun case 44100:
803*4882a593Smuzhiyun n = 6272;
804*4882a593Smuzhiyun break;
805*4882a593Smuzhiyun case 48000:
806*4882a593Smuzhiyun n = 6144;
807*4882a593Smuzhiyun break;
808*4882a593Smuzhiyun case 88200:
809*4882a593Smuzhiyun n = 6272 * 2;
810*4882a593Smuzhiyun break;
811*4882a593Smuzhiyun case 96000:
812*4882a593Smuzhiyun n = 6144 * 2;
813*4882a593Smuzhiyun break;
814*4882a593Smuzhiyun case 176400:
815*4882a593Smuzhiyun n = 6272 * 4;
816*4882a593Smuzhiyun break;
817*4882a593Smuzhiyun case 192000:
818*4882a593Smuzhiyun n = 6144 * 4;
819*4882a593Smuzhiyun break;
820*4882a593Smuzhiyun default:
821*4882a593Smuzhiyun /* Not pre-defined, recommended value: 128 * fs / 1000 */
822*4882a593Smuzhiyun n = (audio_fs * 128) / 1000;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun return n;
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun
hdmi_audio_configure(struct sti_hdmi * hdmi)828*4882a593Smuzhiyun static int hdmi_audio_configure(struct sti_hdmi *hdmi)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun int audio_cfg, n;
831*4882a593Smuzhiyun struct hdmi_audio_params *params = &hdmi->audio;
832*4882a593Smuzhiyun struct hdmi_audio_infoframe *info = ¶ms->cea;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun if (!hdmi->enabled)
837*4882a593Smuzhiyun return 0;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun /* update N parameter */
840*4882a593Smuzhiyun n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n",
843*4882a593Smuzhiyun params->sample_rate, hdmi->mode.clock * 1000, n);
844*4882a593Smuzhiyun hdmi_write(hdmi, n, HDMI_AUDN);
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun /* update HDMI registers according to configuration */
847*4882a593Smuzhiyun audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
848*4882a593Smuzhiyun HDMI_AUD_CFG_ONE_BIT_INVALID;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun switch (info->channels) {
851*4882a593Smuzhiyun case 8:
852*4882a593Smuzhiyun audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
853*4882a593Smuzhiyun fallthrough;
854*4882a593Smuzhiyun case 6:
855*4882a593Smuzhiyun audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
856*4882a593Smuzhiyun fallthrough;
857*4882a593Smuzhiyun case 4:
858*4882a593Smuzhiyun audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
859*4882a593Smuzhiyun fallthrough;
860*4882a593Smuzhiyun case 2:
861*4882a593Smuzhiyun audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
862*4882a593Smuzhiyun break;
863*4882a593Smuzhiyun default:
864*4882a593Smuzhiyun DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
865*4882a593Smuzhiyun info->channels);
866*4882a593Smuzhiyun return -EINVAL;
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun return hdmi_audio_infoframe_config(hdmi);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
sti_hdmi_pre_enable(struct drm_bridge * bridge)874*4882a593Smuzhiyun static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
875*4882a593Smuzhiyun {
876*4882a593Smuzhiyun struct sti_hdmi *hdmi = bridge->driver_private;
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun if (hdmi->enabled)
881*4882a593Smuzhiyun return;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun /* Prepare/enable clocks */
884*4882a593Smuzhiyun if (clk_prepare_enable(hdmi->clk_pix))
885*4882a593Smuzhiyun DRM_ERROR("Failed to prepare/enable hdmi_pix clk\n");
886*4882a593Smuzhiyun if (clk_prepare_enable(hdmi->clk_tmds))
887*4882a593Smuzhiyun DRM_ERROR("Failed to prepare/enable hdmi_tmds clk\n");
888*4882a593Smuzhiyun if (clk_prepare_enable(hdmi->clk_phy))
889*4882a593Smuzhiyun DRM_ERROR("Failed to prepare/enable hdmi_rejec_pll clk\n");
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun hdmi->enabled = true;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun /* Program hdmi serializer and start phy */
894*4882a593Smuzhiyun if (!hdmi->phy_ops->start(hdmi)) {
895*4882a593Smuzhiyun DRM_ERROR("Unable to start hdmi phy\n");
896*4882a593Smuzhiyun return;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /* Program hdmi active area */
900*4882a593Smuzhiyun hdmi_active_area(hdmi);
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun /* Enable working interrupts */
903*4882a593Smuzhiyun hdmi_write(hdmi, HDMI_WORKING_INT, HDMI_INT_EN);
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun /* Program hdmi config */
906*4882a593Smuzhiyun hdmi_config(hdmi);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* Program AVI infoframe */
909*4882a593Smuzhiyun if (hdmi_avi_infoframe_config(hdmi))
910*4882a593Smuzhiyun DRM_ERROR("Unable to configure AVI infoframe\n");
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun if (hdmi->audio.enabled) {
913*4882a593Smuzhiyun if (hdmi_audio_configure(hdmi))
914*4882a593Smuzhiyun DRM_ERROR("Unable to configure audio\n");
915*4882a593Smuzhiyun } else {
916*4882a593Smuzhiyun hdmi_audio_infoframe_config(hdmi);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun /* Program VS infoframe */
920*4882a593Smuzhiyun if (hdmi_vendor_infoframe_config(hdmi))
921*4882a593Smuzhiyun DRM_ERROR("Unable to configure VS infoframe\n");
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun /* Sw reset */
924*4882a593Smuzhiyun hdmi_swreset(hdmi);
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
sti_hdmi_set_mode(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)927*4882a593Smuzhiyun static void sti_hdmi_set_mode(struct drm_bridge *bridge,
928*4882a593Smuzhiyun const struct drm_display_mode *mode,
929*4882a593Smuzhiyun const struct drm_display_mode *adjusted_mode)
930*4882a593Smuzhiyun {
931*4882a593Smuzhiyun struct sti_hdmi *hdmi = bridge->driver_private;
932*4882a593Smuzhiyun int ret;
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun /* Copy the drm display mode in the connector local structure */
937*4882a593Smuzhiyun memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun /* Update clock framerate according to the selected mode */
940*4882a593Smuzhiyun ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
941*4882a593Smuzhiyun if (ret < 0) {
942*4882a593Smuzhiyun DRM_ERROR("Cannot set rate (%dHz) for hdmi_pix clk\n",
943*4882a593Smuzhiyun mode->clock * 1000);
944*4882a593Smuzhiyun return;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun ret = clk_set_rate(hdmi->clk_phy, mode->clock * 1000);
947*4882a593Smuzhiyun if (ret < 0) {
948*4882a593Smuzhiyun DRM_ERROR("Cannot set rate (%dHz) for hdmi_rejection_pll clk\n",
949*4882a593Smuzhiyun mode->clock * 1000);
950*4882a593Smuzhiyun return;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
sti_hdmi_bridge_nope(struct drm_bridge * bridge)954*4882a593Smuzhiyun static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun /* do nothing */
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
960*4882a593Smuzhiyun .pre_enable = sti_hdmi_pre_enable,
961*4882a593Smuzhiyun .enable = sti_hdmi_bridge_nope,
962*4882a593Smuzhiyun .disable = sti_hdmi_disable,
963*4882a593Smuzhiyun .post_disable = sti_hdmi_bridge_nope,
964*4882a593Smuzhiyun .mode_set = sti_hdmi_set_mode,
965*4882a593Smuzhiyun };
966*4882a593Smuzhiyun
sti_hdmi_connector_get_modes(struct drm_connector * connector)967*4882a593Smuzhiyun static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
970*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
971*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
972*4882a593Smuzhiyun struct edid *edid;
973*4882a593Smuzhiyun int count;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun edid = drm_get_edid(connector, hdmi->ddc_adapt);
978*4882a593Smuzhiyun if (!edid)
979*4882a593Smuzhiyun goto fail;
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
982*4882a593Smuzhiyun DRM_DEBUG_KMS("%s : %dx%d cm\n",
983*4882a593Smuzhiyun (hdmi->hdmi_monitor ? "hdmi monitor" : "dvi monitor"),
984*4882a593Smuzhiyun edid->width_cm, edid->height_cm);
985*4882a593Smuzhiyun cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid);
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun count = drm_add_edid_modes(connector, edid);
988*4882a593Smuzhiyun drm_connector_update_edid_property(connector, edid);
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun kfree(edid);
991*4882a593Smuzhiyun return count;
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun fail:
994*4882a593Smuzhiyun DRM_ERROR("Can't read HDMI EDID\n");
995*4882a593Smuzhiyun return 0;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun #define CLK_TOLERANCE_HZ 50
999*4882a593Smuzhiyun
sti_hdmi_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1000*4882a593Smuzhiyun static int sti_hdmi_connector_mode_valid(struct drm_connector *connector,
1001*4882a593Smuzhiyun struct drm_display_mode *mode)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun int target = mode->clock * 1000;
1004*4882a593Smuzhiyun int target_min = target - CLK_TOLERANCE_HZ;
1005*4882a593Smuzhiyun int target_max = target + CLK_TOLERANCE_HZ;
1006*4882a593Smuzhiyun int result;
1007*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1008*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1009*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun result = clk_round_rate(hdmi->clk_pix, target);
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
1015*4882a593Smuzhiyun target, result);
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if ((result < target_min) || (result > target_max)) {
1018*4882a593Smuzhiyun DRM_DEBUG_DRIVER("hdmi pixclk=%d not supported\n", target);
1019*4882a593Smuzhiyun return MODE_BAD;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun return MODE_OK;
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun static const
1026*4882a593Smuzhiyun struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
1027*4882a593Smuzhiyun .get_modes = sti_hdmi_connector_get_modes,
1028*4882a593Smuzhiyun .mode_valid = sti_hdmi_connector_mode_valid,
1029*4882a593Smuzhiyun };
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* get detection status of display device */
1032*4882a593Smuzhiyun static enum drm_connector_status
sti_hdmi_connector_detect(struct drm_connector * connector,bool force)1033*4882a593Smuzhiyun sti_hdmi_connector_detect(struct drm_connector *connector, bool force)
1034*4882a593Smuzhiyun {
1035*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1036*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1037*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun if (hdmi->hpd) {
1042*4882a593Smuzhiyun DRM_DEBUG_DRIVER("hdmi cable connected\n");
1043*4882a593Smuzhiyun return connector_status_connected;
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun DRM_DEBUG_DRIVER("hdmi cable disconnected\n");
1047*4882a593Smuzhiyun cec_notifier_set_phys_addr(hdmi->notifier, CEC_PHYS_ADDR_INVALID);
1048*4882a593Smuzhiyun return connector_status_disconnected;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
sti_hdmi_connector_init_property(struct drm_device * drm_dev,struct drm_connector * connector)1051*4882a593Smuzhiyun static void sti_hdmi_connector_init_property(struct drm_device *drm_dev,
1052*4882a593Smuzhiyun struct drm_connector *connector)
1053*4882a593Smuzhiyun {
1054*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1055*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1056*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1057*4882a593Smuzhiyun struct drm_property *prop;
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun /* colorspace property */
1060*4882a593Smuzhiyun hdmi->colorspace = DEFAULT_COLORSPACE_MODE;
1061*4882a593Smuzhiyun prop = drm_property_create_enum(drm_dev, 0, "colorspace",
1062*4882a593Smuzhiyun colorspace_mode_names,
1063*4882a593Smuzhiyun ARRAY_SIZE(colorspace_mode_names));
1064*4882a593Smuzhiyun if (!prop) {
1065*4882a593Smuzhiyun DRM_ERROR("fails to create colorspace property\n");
1066*4882a593Smuzhiyun return;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun hdmi_connector->colorspace_property = prop;
1069*4882a593Smuzhiyun drm_object_attach_property(&connector->base, prop, hdmi->colorspace);
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun static int
sti_hdmi_connector_set_property(struct drm_connector * connector,struct drm_connector_state * state,struct drm_property * property,uint64_t val)1073*4882a593Smuzhiyun sti_hdmi_connector_set_property(struct drm_connector *connector,
1074*4882a593Smuzhiyun struct drm_connector_state *state,
1075*4882a593Smuzhiyun struct drm_property *property,
1076*4882a593Smuzhiyun uint64_t val)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1079*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1080*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun if (property == hdmi_connector->colorspace_property) {
1083*4882a593Smuzhiyun hdmi->colorspace = val;
1084*4882a593Smuzhiyun return 0;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun DRM_ERROR("failed to set hdmi connector property\n");
1088*4882a593Smuzhiyun return -EINVAL;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun static int
sti_hdmi_connector_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,uint64_t * val)1092*4882a593Smuzhiyun sti_hdmi_connector_get_property(struct drm_connector *connector,
1093*4882a593Smuzhiyun const struct drm_connector_state *state,
1094*4882a593Smuzhiyun struct drm_property *property,
1095*4882a593Smuzhiyun uint64_t *val)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1098*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1099*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun if (property == hdmi_connector->colorspace_property) {
1102*4882a593Smuzhiyun *val = hdmi->colorspace;
1103*4882a593Smuzhiyun return 0;
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun DRM_ERROR("failed to get hdmi connector property\n");
1107*4882a593Smuzhiyun return -EINVAL;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
sti_hdmi_late_register(struct drm_connector * connector)1110*4882a593Smuzhiyun static int sti_hdmi_late_register(struct drm_connector *connector)
1111*4882a593Smuzhiyun {
1112*4882a593Smuzhiyun struct sti_hdmi_connector *hdmi_connector
1113*4882a593Smuzhiyun = to_sti_hdmi_connector(connector);
1114*4882a593Smuzhiyun struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun hdmi_debugfs_init(hdmi, hdmi->drm_dev->primary);
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun return 0;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
1122*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
1123*4882a593Smuzhiyun .detect = sti_hdmi_connector_detect,
1124*4882a593Smuzhiyun .destroy = drm_connector_cleanup,
1125*4882a593Smuzhiyun .reset = drm_atomic_helper_connector_reset,
1126*4882a593Smuzhiyun .atomic_set_property = sti_hdmi_connector_set_property,
1127*4882a593Smuzhiyun .atomic_get_property = sti_hdmi_connector_get_property,
1128*4882a593Smuzhiyun .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1129*4882a593Smuzhiyun .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1130*4882a593Smuzhiyun .late_register = sti_hdmi_late_register,
1131*4882a593Smuzhiyun };
1132*4882a593Smuzhiyun
sti_hdmi_find_encoder(struct drm_device * dev)1133*4882a593Smuzhiyun static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
1134*4882a593Smuzhiyun {
1135*4882a593Smuzhiyun struct drm_encoder *encoder;
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1138*4882a593Smuzhiyun if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1139*4882a593Smuzhiyun return encoder;
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun return NULL;
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun
hdmi_audio_shutdown(struct device * dev,void * data)1145*4882a593Smuzhiyun static void hdmi_audio_shutdown(struct device *dev, void *data)
1146*4882a593Smuzhiyun {
1147*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1148*4882a593Smuzhiyun int audio_cfg;
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun /* disable audio */
1153*4882a593Smuzhiyun audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
1154*4882a593Smuzhiyun HDMI_AUD_CFG_ONE_BIT_INVALID;
1155*4882a593Smuzhiyun hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun hdmi->audio.enabled = false;
1158*4882a593Smuzhiyun hdmi_audio_infoframe_config(hdmi);
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
hdmi_audio_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * daifmt,struct hdmi_codec_params * params)1161*4882a593Smuzhiyun static int hdmi_audio_hw_params(struct device *dev,
1162*4882a593Smuzhiyun void *data,
1163*4882a593Smuzhiyun struct hdmi_codec_daifmt *daifmt,
1164*4882a593Smuzhiyun struct hdmi_codec_params *params)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1167*4882a593Smuzhiyun int ret;
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv ||
1172*4882a593Smuzhiyun daifmt->frame_clk_inv || daifmt->bit_clk_master ||
1173*4882a593Smuzhiyun daifmt->frame_clk_master) {
1174*4882a593Smuzhiyun dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
1175*4882a593Smuzhiyun daifmt->bit_clk_inv, daifmt->frame_clk_inv,
1176*4882a593Smuzhiyun daifmt->bit_clk_master,
1177*4882a593Smuzhiyun daifmt->frame_clk_master);
1178*4882a593Smuzhiyun return -EINVAL;
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun hdmi->audio.sample_width = params->sample_width;
1182*4882a593Smuzhiyun hdmi->audio.sample_rate = params->sample_rate;
1183*4882a593Smuzhiyun hdmi->audio.cea = params->cea;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun hdmi->audio.enabled = true;
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun ret = hdmi_audio_configure(hdmi);
1188*4882a593Smuzhiyun if (ret < 0)
1189*4882a593Smuzhiyun return ret;
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun return 0;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
hdmi_audio_mute(struct device * dev,void * data,bool enable,int direction)1194*4882a593Smuzhiyun static int hdmi_audio_mute(struct device *dev, void *data,
1195*4882a593Smuzhiyun bool enable, int direction)
1196*4882a593Smuzhiyun {
1197*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun DRM_DEBUG_DRIVER("%s\n", enable ? "enable" : "disable");
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun if (enable)
1202*4882a593Smuzhiyun hdmi_write(hdmi, HDMI_SAMPLE_FLAT_ALL, HDMI_SAMPLE_FLAT_MASK);
1203*4882a593Smuzhiyun else
1204*4882a593Smuzhiyun hdmi_write(hdmi, HDMI_SAMPLE_FLAT_NO, HDMI_SAMPLE_FLAT_MASK);
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun return 0;
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
hdmi_audio_get_eld(struct device * dev,void * data,uint8_t * buf,size_t len)1209*4882a593Smuzhiyun static int hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf, size_t len)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1212*4882a593Smuzhiyun struct drm_connector *connector = hdmi->drm_connector;
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
1215*4882a593Smuzhiyun memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun return 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun static const struct hdmi_codec_ops audio_codec_ops = {
1221*4882a593Smuzhiyun .hw_params = hdmi_audio_hw_params,
1222*4882a593Smuzhiyun .audio_shutdown = hdmi_audio_shutdown,
1223*4882a593Smuzhiyun .mute_stream = hdmi_audio_mute,
1224*4882a593Smuzhiyun .get_eld = hdmi_audio_get_eld,
1225*4882a593Smuzhiyun .no_capture_mute = 1,
1226*4882a593Smuzhiyun };
1227*4882a593Smuzhiyun
sti_hdmi_register_audio_driver(struct device * dev,struct sti_hdmi * hdmi)1228*4882a593Smuzhiyun static int sti_hdmi_register_audio_driver(struct device *dev,
1229*4882a593Smuzhiyun struct sti_hdmi *hdmi)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun struct hdmi_codec_pdata codec_data = {
1232*4882a593Smuzhiyun .ops = &audio_codec_ops,
1233*4882a593Smuzhiyun .max_i2s_channels = 8,
1234*4882a593Smuzhiyun .i2s = 1,
1235*4882a593Smuzhiyun };
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun DRM_DEBUG_DRIVER("\n");
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun hdmi->audio.enabled = false;
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun hdmi->audio_pdev = platform_device_register_data(
1242*4882a593Smuzhiyun dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
1243*4882a593Smuzhiyun &codec_data, sizeof(codec_data));
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun if (IS_ERR(hdmi->audio_pdev))
1246*4882a593Smuzhiyun return PTR_ERR(hdmi->audio_pdev);
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun DRM_INFO("%s Driver bound %s\n", HDMI_CODEC_DRV_NAME, dev_name(dev));
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun return 0;
1251*4882a593Smuzhiyun }
1252*4882a593Smuzhiyun
sti_hdmi_bind(struct device * dev,struct device * master,void * data)1253*4882a593Smuzhiyun static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
1254*4882a593Smuzhiyun {
1255*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1256*4882a593Smuzhiyun struct drm_device *drm_dev = data;
1257*4882a593Smuzhiyun struct drm_encoder *encoder;
1258*4882a593Smuzhiyun struct sti_hdmi_connector *connector;
1259*4882a593Smuzhiyun struct cec_connector_info conn_info;
1260*4882a593Smuzhiyun struct drm_connector *drm_connector;
1261*4882a593Smuzhiyun struct drm_bridge *bridge;
1262*4882a593Smuzhiyun int err;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun /* Set the drm device handle */
1265*4882a593Smuzhiyun hdmi->drm_dev = drm_dev;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun encoder = sti_hdmi_find_encoder(drm_dev);
1268*4882a593Smuzhiyun if (!encoder)
1269*4882a593Smuzhiyun return -EINVAL;
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
1272*4882a593Smuzhiyun if (!connector)
1273*4882a593Smuzhiyun return -EINVAL;
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun connector->hdmi = hdmi;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
1278*4882a593Smuzhiyun if (!bridge)
1279*4882a593Smuzhiyun return -EINVAL;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun bridge->driver_private = hdmi;
1282*4882a593Smuzhiyun bridge->funcs = &sti_hdmi_bridge_funcs;
1283*4882a593Smuzhiyun drm_bridge_attach(encoder, bridge, NULL, 0);
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun connector->encoder = encoder;
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun drm_connector = (struct drm_connector *)connector;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun drm_connector_init_with_ddc(drm_dev, drm_connector,
1292*4882a593Smuzhiyun &sti_hdmi_connector_funcs,
1293*4882a593Smuzhiyun DRM_MODE_CONNECTOR_HDMIA,
1294*4882a593Smuzhiyun hdmi->ddc_adapt);
1295*4882a593Smuzhiyun drm_connector_helper_add(drm_connector,
1296*4882a593Smuzhiyun &sti_hdmi_connector_helper_funcs);
1297*4882a593Smuzhiyun
1298*4882a593Smuzhiyun /* initialise property */
1299*4882a593Smuzhiyun sti_hdmi_connector_init_property(drm_dev, drm_connector);
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun hdmi->drm_connector = drm_connector;
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun err = drm_connector_attach_encoder(drm_connector, encoder);
1304*4882a593Smuzhiyun if (err) {
1305*4882a593Smuzhiyun DRM_ERROR("Failed to attach a connector to a encoder\n");
1306*4882a593Smuzhiyun goto err_sysfs;
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun err = sti_hdmi_register_audio_driver(dev, hdmi);
1310*4882a593Smuzhiyun if (err) {
1311*4882a593Smuzhiyun DRM_ERROR("Failed to attach an audio codec\n");
1312*4882a593Smuzhiyun goto err_sysfs;
1313*4882a593Smuzhiyun }
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun /* Initialize audio infoframe */
1316*4882a593Smuzhiyun err = hdmi_audio_infoframe_init(&hdmi->audio.cea);
1317*4882a593Smuzhiyun if (err) {
1318*4882a593Smuzhiyun DRM_ERROR("Failed to init audio infoframe\n");
1319*4882a593Smuzhiyun goto err_sysfs;
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun cec_fill_conn_info_from_drm(&conn_info, drm_connector);
1323*4882a593Smuzhiyun hdmi->notifier = cec_notifier_conn_register(&hdmi->dev, NULL,
1324*4882a593Smuzhiyun &conn_info);
1325*4882a593Smuzhiyun if (!hdmi->notifier) {
1326*4882a593Smuzhiyun hdmi->drm_connector = NULL;
1327*4882a593Smuzhiyun return -ENOMEM;
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun /* Enable default interrupts */
1331*4882a593Smuzhiyun hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun return 0;
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun err_sysfs:
1336*4882a593Smuzhiyun hdmi->drm_connector = NULL;
1337*4882a593Smuzhiyun return -EINVAL;
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun
sti_hdmi_unbind(struct device * dev,struct device * master,void * data)1340*4882a593Smuzhiyun static void sti_hdmi_unbind(struct device *dev,
1341*4882a593Smuzhiyun struct device *master, void *data)
1342*4882a593Smuzhiyun {
1343*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun cec_notifier_conn_unregister(hdmi->notifier);
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun static const struct component_ops sti_hdmi_ops = {
1349*4882a593Smuzhiyun .bind = sti_hdmi_bind,
1350*4882a593Smuzhiyun .unbind = sti_hdmi_unbind,
1351*4882a593Smuzhiyun };
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun static const struct of_device_id hdmi_of_match[] = {
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun .compatible = "st,stih407-hdmi",
1356*4882a593Smuzhiyun .data = &tx3g4c28phy_ops,
1357*4882a593Smuzhiyun }, {
1358*4882a593Smuzhiyun /* end node */
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun };
1361*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, hdmi_of_match);
1362*4882a593Smuzhiyun
sti_hdmi_probe(struct platform_device * pdev)1363*4882a593Smuzhiyun static int sti_hdmi_probe(struct platform_device *pdev)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun struct device *dev = &pdev->dev;
1366*4882a593Smuzhiyun struct sti_hdmi *hdmi;
1367*4882a593Smuzhiyun struct device_node *np = dev->of_node;
1368*4882a593Smuzhiyun struct resource *res;
1369*4882a593Smuzhiyun struct device_node *ddc;
1370*4882a593Smuzhiyun int ret;
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun DRM_INFO("%s\n", __func__);
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
1375*4882a593Smuzhiyun if (!hdmi)
1376*4882a593Smuzhiyun return -ENOMEM;
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
1379*4882a593Smuzhiyun if (ddc) {
1380*4882a593Smuzhiyun hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc);
1381*4882a593Smuzhiyun of_node_put(ddc);
1382*4882a593Smuzhiyun if (!hdmi->ddc_adapt)
1383*4882a593Smuzhiyun return -EPROBE_DEFER;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun hdmi->dev = pdev->dev;
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun /* Get resources */
1389*4882a593Smuzhiyun res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
1390*4882a593Smuzhiyun if (!res) {
1391*4882a593Smuzhiyun DRM_ERROR("Invalid hdmi resource\n");
1392*4882a593Smuzhiyun ret = -ENOMEM;
1393*4882a593Smuzhiyun goto release_adapter;
1394*4882a593Smuzhiyun }
1395*4882a593Smuzhiyun hdmi->regs = devm_ioremap(dev, res->start, resource_size(res));
1396*4882a593Smuzhiyun if (!hdmi->regs) {
1397*4882a593Smuzhiyun ret = -ENOMEM;
1398*4882a593Smuzhiyun goto release_adapter;
1399*4882a593Smuzhiyun }
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun hdmi->phy_ops = (struct hdmi_phy_ops *)
1402*4882a593Smuzhiyun of_match_node(hdmi_of_match, np)->data;
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun /* Get clock resources */
1405*4882a593Smuzhiyun hdmi->clk_pix = devm_clk_get(dev, "pix");
1406*4882a593Smuzhiyun if (IS_ERR(hdmi->clk_pix)) {
1407*4882a593Smuzhiyun DRM_ERROR("Cannot get hdmi_pix clock\n");
1408*4882a593Smuzhiyun ret = PTR_ERR(hdmi->clk_pix);
1409*4882a593Smuzhiyun goto release_adapter;
1410*4882a593Smuzhiyun }
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun hdmi->clk_tmds = devm_clk_get(dev, "tmds");
1413*4882a593Smuzhiyun if (IS_ERR(hdmi->clk_tmds)) {
1414*4882a593Smuzhiyun DRM_ERROR("Cannot get hdmi_tmds clock\n");
1415*4882a593Smuzhiyun ret = PTR_ERR(hdmi->clk_tmds);
1416*4882a593Smuzhiyun goto release_adapter;
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun
1419*4882a593Smuzhiyun hdmi->clk_phy = devm_clk_get(dev, "phy");
1420*4882a593Smuzhiyun if (IS_ERR(hdmi->clk_phy)) {
1421*4882a593Smuzhiyun DRM_ERROR("Cannot get hdmi_phy clock\n");
1422*4882a593Smuzhiyun ret = PTR_ERR(hdmi->clk_phy);
1423*4882a593Smuzhiyun goto release_adapter;
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun hdmi->clk_audio = devm_clk_get(dev, "audio");
1427*4882a593Smuzhiyun if (IS_ERR(hdmi->clk_audio)) {
1428*4882a593Smuzhiyun DRM_ERROR("Cannot get hdmi_audio clock\n");
1429*4882a593Smuzhiyun ret = PTR_ERR(hdmi->clk_audio);
1430*4882a593Smuzhiyun goto release_adapter;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun init_waitqueue_head(&hdmi->wait_event);
1436*4882a593Smuzhiyun
1437*4882a593Smuzhiyun hdmi->irq = platform_get_irq_byname(pdev, "irq");
1438*4882a593Smuzhiyun if (hdmi->irq < 0) {
1439*4882a593Smuzhiyun DRM_ERROR("Cannot get HDMI irq\n");
1440*4882a593Smuzhiyun ret = hdmi->irq;
1441*4882a593Smuzhiyun goto release_adapter;
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq,
1445*4882a593Smuzhiyun hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
1446*4882a593Smuzhiyun if (ret) {
1447*4882a593Smuzhiyun DRM_ERROR("Failed to register HDMI interrupt\n");
1448*4882a593Smuzhiyun goto release_adapter;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun hdmi->reset = devm_reset_control_get(dev, "hdmi");
1452*4882a593Smuzhiyun /* Take hdmi out of reset */
1453*4882a593Smuzhiyun if (!IS_ERR(hdmi->reset))
1454*4882a593Smuzhiyun reset_control_deassert(hdmi->reset);
1455*4882a593Smuzhiyun
1456*4882a593Smuzhiyun platform_set_drvdata(pdev, hdmi);
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun return component_add(&pdev->dev, &sti_hdmi_ops);
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun release_adapter:
1461*4882a593Smuzhiyun i2c_put_adapter(hdmi->ddc_adapt);
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun return ret;
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun
sti_hdmi_remove(struct platform_device * pdev)1466*4882a593Smuzhiyun static int sti_hdmi_remove(struct platform_device *pdev)
1467*4882a593Smuzhiyun {
1468*4882a593Smuzhiyun struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
1469*4882a593Smuzhiyun
1470*4882a593Smuzhiyun i2c_put_adapter(hdmi->ddc_adapt);
1471*4882a593Smuzhiyun if (hdmi->audio_pdev)
1472*4882a593Smuzhiyun platform_device_unregister(hdmi->audio_pdev);
1473*4882a593Smuzhiyun component_del(&pdev->dev, &sti_hdmi_ops);
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun return 0;
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun struct platform_driver sti_hdmi_driver = {
1479*4882a593Smuzhiyun .driver = {
1480*4882a593Smuzhiyun .name = "sti-hdmi",
1481*4882a593Smuzhiyun .owner = THIS_MODULE,
1482*4882a593Smuzhiyun .of_match_table = hdmi_of_match,
1483*4882a593Smuzhiyun },
1484*4882a593Smuzhiyun .probe = sti_hdmi_probe,
1485*4882a593Smuzhiyun .remove = sti_hdmi_remove,
1486*4882a593Smuzhiyun };
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
1489*4882a593Smuzhiyun MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
1490*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1491