2 * Copyright (C) 2016 Maxime Ripard
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_crtc_helper.h>
15 #include <drm/drm_edid.h>
16 #include <drm/drm_encoder.h>
17 #include <drm/drm_of.h>
18 #include <drm/drm_panel.h>
20 #include <linux/clk.h>
21 #include <linux/component.h>
22 #include <linux/iopoll.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_runtime.h>
26 #include "sun4i_backend.h"
27 #include "sun4i_crtc.h"
28 #include "sun4i_drv.h"
29 #include "sun4i_hdmi.h"
30 #include "sun4i_tcon.h"
32 #define DDC_SEGMENT_ADDR 0x30
34 static inline struct sun4i_hdmi
*
35 drm_encoder_to_sun4i_hdmi(struct drm_encoder
*encoder
)
37 return container_of(encoder
, struct sun4i_hdmi
,
41 static inline struct sun4i_hdmi
*
42 drm_connector_to_sun4i_hdmi(struct drm_connector
*connector
)
44 return container_of(connector
, struct sun4i_hdmi
,
48 static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi
*hdmi
,
49 struct drm_display_mode
*mode
)
51 struct hdmi_avi_infoframe frame
;
55 ret
= drm_hdmi_avi_infoframe_from_display_mode(&frame
, mode
);
57 DRM_ERROR("Failed to get infoframes from mode\n");
61 ret
= hdmi_avi_infoframe_pack(&frame
, buffer
, sizeof(buffer
));
63 DRM_ERROR("Failed to pack infoframes\n");
67 for (i
= 0; i
< sizeof(buffer
); i
++)
68 writeb(buffer
[i
], hdmi
->base
+ SUN4I_HDMI_AVI_INFOFRAME_REG(i
));
73 static int sun4i_hdmi_atomic_check(struct drm_encoder
*encoder
,
74 struct drm_crtc_state
*crtc_state
,
75 struct drm_connector_state
*conn_state
)
77 struct drm_display_mode
*mode
= &crtc_state
->mode
;
79 if (mode
->flags
& DRM_MODE_FLAG_DBLCLK
)
85 static void sun4i_hdmi_disable(struct drm_encoder
*encoder
)
87 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
88 struct sun4i_crtc
*crtc
= drm_crtc_to_sun4i_crtc(encoder
->crtc
);
89 struct sun4i_tcon
*tcon
= crtc
->tcon
;
92 DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
94 val
= readl(hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
95 val
&= ~SUN4I_HDMI_VID_CTRL_ENABLE
;
96 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
98 sun4i_tcon_channel_disable(tcon
, 1);
101 static void sun4i_hdmi_enable(struct drm_encoder
*encoder
)
103 struct drm_display_mode
*mode
= &encoder
->crtc
->state
->adjusted_mode
;
104 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
105 struct sun4i_crtc
*crtc
= drm_crtc_to_sun4i_crtc(encoder
->crtc
);
106 struct sun4i_tcon
*tcon
= crtc
->tcon
;
109 DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
111 sun4i_tcon_channel_enable(tcon
, 1);
113 sun4i_hdmi_setup_avi_infoframes(hdmi
, mode
);
114 val
|= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI
);
115 val
|= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END
);
116 writel(val
, hdmi
->base
+ SUN4I_HDMI_PKT_CTRL_REG(0));
118 val
= SUN4I_HDMI_VID_CTRL_ENABLE
;
119 if (hdmi
->hdmi_monitor
)
120 val
|= SUN4I_HDMI_VID_CTRL_HDMI_MODE
;
122 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
125 static void sun4i_hdmi_mode_set(struct drm_encoder
*encoder
,
126 struct drm_display_mode
*mode
,
127 struct drm_display_mode
*adjusted_mode
)
129 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
130 struct sun4i_crtc
*crtc
= drm_crtc_to_sun4i_crtc(encoder
->crtc
);
131 struct sun4i_tcon
*tcon
= crtc
->tcon
;
135 sun4i_tcon1_mode_set(tcon
, mode
);
136 sun4i_tcon_set_mux(tcon
, 1, encoder
);
138 clk_set_rate(tcon
->sclk1
, mode
->crtc_clock
* 1000);
139 clk_set_rate(hdmi
->mod_clk
, mode
->crtc_clock
* 1000);
140 clk_set_rate(hdmi
->tmds_clk
, mode
->crtc_clock
* 1000);
142 /* Set input sync enable */
143 writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC
,
144 hdmi
->base
+ SUN4I_HDMI_UNKNOWN_REG
);
146 /* Setup timing registers */
147 writel(SUN4I_HDMI_VID_TIMING_X(mode
->hdisplay
) |
148 SUN4I_HDMI_VID_TIMING_Y(mode
->vdisplay
),
149 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_ACT_REG
);
151 x
= mode
->htotal
- mode
->hsync_start
;
152 y
= mode
->vtotal
- mode
->vsync_start
;
153 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
154 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_BP_REG
);
156 x
= mode
->hsync_start
- mode
->hdisplay
;
157 y
= mode
->vsync_start
- mode
->vdisplay
;
158 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
159 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_FP_REG
);
161 x
= mode
->hsync_end
- mode
->hsync_start
;
162 y
= mode
->vsync_end
- mode
->vsync_start
;
163 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
164 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_SPW_REG
);
166 val
= SUN4I_HDMI_VID_TIMING_POL_TX_CLK
;
167 if (mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
168 val
|= SUN4I_HDMI_VID_TIMING_POL_HSYNC
;
170 if (mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
171 val
|= SUN4I_HDMI_VID_TIMING_POL_VSYNC
;
173 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_TIMING_POL_REG
);
176 static const struct drm_encoder_helper_funcs sun4i_hdmi_helper_funcs
= {
177 .atomic_check
= sun4i_hdmi_atomic_check
,
178 .disable
= sun4i_hdmi_disable
,
179 .enable
= sun4i_hdmi_enable
,
180 .mode_set
= sun4i_hdmi_mode_set
,
183 static const struct drm_encoder_funcs sun4i_hdmi_funcs
= {
184 .destroy
= drm_encoder_cleanup
,
187 static int sun4i_hdmi_read_sub_block(struct sun4i_hdmi
*hdmi
,
188 unsigned int blk
, unsigned int offset
,
189 u8
*buf
, unsigned int count
)
194 reg
= readl(hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
);
195 reg
&= ~SUN4I_HDMI_DDC_CTRL_FIFO_DIR_MASK
;
196 writel(reg
| SUN4I_HDMI_DDC_CTRL_FIFO_DIR_READ
,
197 hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
);
199 writel(SUN4I_HDMI_DDC_ADDR_SEGMENT(offset
>> 8) |
200 SUN4I_HDMI_DDC_ADDR_EDDC(DDC_SEGMENT_ADDR
<< 1) |
201 SUN4I_HDMI_DDC_ADDR_OFFSET(offset
) |
202 SUN4I_HDMI_DDC_ADDR_SLAVE(DDC_ADDR
),
203 hdmi
->base
+ SUN4I_HDMI_DDC_ADDR_REG
);
205 reg
= readl(hdmi
->base
+ SUN4I_HDMI_DDC_FIFO_CTRL_REG
);
206 writel(reg
| SUN4I_HDMI_DDC_FIFO_CTRL_CLEAR
,
207 hdmi
->base
+ SUN4I_HDMI_DDC_FIFO_CTRL_REG
);
209 writel(count
, hdmi
->base
+ SUN4I_HDMI_DDC_BYTE_COUNT_REG
);
210 writel(SUN4I_HDMI_DDC_CMD_EXPLICIT_EDDC_READ
,
211 hdmi
->base
+ SUN4I_HDMI_DDC_CMD_REG
);
213 reg
= readl(hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
);
214 writel(reg
| SUN4I_HDMI_DDC_CTRL_START_CMD
,
215 hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
);
217 if (readl_poll_timeout(hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
, reg
,
218 !(reg
& SUN4I_HDMI_DDC_CTRL_START_CMD
),
222 for (i
= 0; i
< count
; i
++)
223 buf
[i
] = readb(hdmi
->base
+ SUN4I_HDMI_DDC_FIFO_DATA_REG
);
228 static int sun4i_hdmi_read_edid_block(void *data
, u8
*buf
, unsigned int blk
,
231 struct sun4i_hdmi
*hdmi
= data
;
235 for (i
= 0; i
< length
; i
+= SUN4I_HDMI_DDC_FIFO_SIZE
) {
236 unsigned char offset
= blk
* EDID_LENGTH
+ i
;
237 unsigned int count
= min((unsigned int)SUN4I_HDMI_DDC_FIFO_SIZE
,
241 ret
= sun4i_hdmi_read_sub_block(hdmi
, blk
, offset
,
246 } while (!drm_edid_block_valid(buf
, blk
, true, NULL
) && (retry
--));
251 static int sun4i_hdmi_get_modes(struct drm_connector
*connector
)
253 struct sun4i_hdmi
*hdmi
= drm_connector_to_sun4i_hdmi(connector
);
258 /* Reset i2c controller */
259 writel(SUN4I_HDMI_DDC_CTRL_ENABLE
| SUN4I_HDMI_DDC_CTRL_RESET
,
260 hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
);
261 if (readl_poll_timeout(hdmi
->base
+ SUN4I_HDMI_DDC_CTRL_REG
, reg
,
262 !(reg
& SUN4I_HDMI_DDC_CTRL_RESET
),
266 writel(SUN4I_HDMI_DDC_LINE_CTRL_SDA_ENABLE
|
267 SUN4I_HDMI_DDC_LINE_CTRL_SCL_ENABLE
,
268 hdmi
->base
+ SUN4I_HDMI_DDC_LINE_CTRL_REG
);
270 clk_prepare_enable(hdmi
->ddc_clk
);
271 clk_set_rate(hdmi
->ddc_clk
, 100000);
273 edid
= drm_do_get_edid(connector
, sun4i_hdmi_read_edid_block
, hdmi
);
277 hdmi
->hdmi_monitor
= drm_detect_hdmi_monitor(edid
);
278 DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
279 hdmi
->hdmi_monitor
? "an HDMI" : "a DVI");
281 drm_mode_connector_update_edid_property(connector
, edid
);
282 ret
= drm_add_edid_modes(connector
, edid
);
285 clk_disable_unprepare(hdmi
->ddc_clk
);
290 static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs
= {
291 .get_modes
= sun4i_hdmi_get_modes
,
294 static enum drm_connector_status
295 sun4i_hdmi_connector_detect(struct drm_connector
*connector
, bool force
)
297 struct sun4i_hdmi
*hdmi
= drm_connector_to_sun4i_hdmi(connector
);
300 if (readl_poll_timeout(hdmi
->base
+ SUN4I_HDMI_HPD_REG
, reg
,
301 reg
& SUN4I_HDMI_HPD_HIGH
,
303 return connector_status_disconnected
;
305 return connector_status_connected
;
308 static const struct drm_connector_funcs sun4i_hdmi_connector_funcs
= {
309 .dpms
= drm_atomic_helper_connector_dpms
,
310 .detect
= sun4i_hdmi_connector_detect
,
311 .fill_modes
= drm_helper_probe_single_connector_modes
,
312 .destroy
= drm_connector_cleanup
,
313 .reset
= drm_atomic_helper_connector_reset
,
314 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
315 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
318 static int sun4i_hdmi_bind(struct device
*dev
, struct device
*master
,
321 struct platform_device
*pdev
= to_platform_device(dev
);
322 struct drm_device
*drm
= data
;
323 struct sun4i_drv
*drv
= drm
->dev_private
;
324 struct sun4i_hdmi
*hdmi
;
325 struct resource
*res
;
329 hdmi
= devm_kzalloc(dev
, sizeof(*hdmi
), GFP_KERNEL
);
332 dev_set_drvdata(dev
, hdmi
);
336 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
337 hdmi
->base
= devm_ioremap_resource(dev
, res
);
338 if (IS_ERR(hdmi
->base
)) {
339 dev_err(dev
, "Couldn't map the HDMI encoder registers\n");
340 return PTR_ERR(hdmi
->base
);
343 hdmi
->bus_clk
= devm_clk_get(dev
, "ahb");
344 if (IS_ERR(hdmi
->bus_clk
)) {
345 dev_err(dev
, "Couldn't get the HDMI bus clock\n");
346 return PTR_ERR(hdmi
->bus_clk
);
348 clk_prepare_enable(hdmi
->bus_clk
);
350 hdmi
->mod_clk
= devm_clk_get(dev
, "mod");
351 if (IS_ERR(hdmi
->mod_clk
)) {
352 dev_err(dev
, "Couldn't get the HDMI mod clock\n");
353 return PTR_ERR(hdmi
->mod_clk
);
355 clk_prepare_enable(hdmi
->mod_clk
);
357 hdmi
->pll0_clk
= devm_clk_get(dev
, "pll-0");
358 if (IS_ERR(hdmi
->pll0_clk
)) {
359 dev_err(dev
, "Couldn't get the HDMI PLL 0 clock\n");
360 return PTR_ERR(hdmi
->pll0_clk
);
363 hdmi
->pll1_clk
= devm_clk_get(dev
, "pll-1");
364 if (IS_ERR(hdmi
->pll1_clk
)) {
365 dev_err(dev
, "Couldn't get the HDMI PLL 1 clock\n");
366 return PTR_ERR(hdmi
->pll1_clk
);
369 ret
= sun4i_tmds_create(hdmi
);
371 dev_err(dev
, "Couldn't create the TMDS clock\n");
375 writel(SUN4I_HDMI_CTRL_ENABLE
, hdmi
->base
+ SUN4I_HDMI_CTRL_REG
);
377 writel(SUN4I_HDMI_PAD_CTRL0_TXEN
| SUN4I_HDMI_PAD_CTRL0_CKEN
|
378 SUN4I_HDMI_PAD_CTRL0_PWENG
| SUN4I_HDMI_PAD_CTRL0_PWEND
|
379 SUN4I_HDMI_PAD_CTRL0_PWENC
| SUN4I_HDMI_PAD_CTRL0_LDODEN
|
380 SUN4I_HDMI_PAD_CTRL0_LDOCEN
| SUN4I_HDMI_PAD_CTRL0_BIASEN
,
381 hdmi
->base
+ SUN4I_HDMI_PAD_CTRL0_REG
);
384 * We can't just initialize the register there, we need to
385 * protect the clock bits that have already been read out and
386 * cached by the clock framework.
388 reg
= readl(hdmi
->base
+ SUN4I_HDMI_PAD_CTRL1_REG
);
389 reg
&= SUN4I_HDMI_PAD_CTRL1_HALVE_CLK
;
390 reg
|= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
391 SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
392 SUN4I_HDMI_PAD_CTRL1_REG_DENCK
|
393 SUN4I_HDMI_PAD_CTRL1_REG_DEN
|
394 SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT
|
395 SUN4I_HDMI_PAD_CTRL1_EMP_OPT
|
396 SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT
|
397 SUN4I_HDMI_PAD_CTRL1_AMP_OPT
;
398 writel(reg
, hdmi
->base
+ SUN4I_HDMI_PAD_CTRL1_REG
);
400 reg
= readl(hdmi
->base
+ SUN4I_HDMI_PLL_CTRL_REG
);
401 reg
&= SUN4I_HDMI_PLL_CTRL_DIV_MASK
;
402 reg
|= SUN4I_HDMI_PLL_CTRL_VCO_S(8) | SUN4I_HDMI_PLL_CTRL_CS(7) |
403 SUN4I_HDMI_PLL_CTRL_CP_S(15) | SUN4I_HDMI_PLL_CTRL_S(7) |
404 SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) | SUN4I_HDMI_PLL_CTRL_SDIV2
|
405 SUN4I_HDMI_PLL_CTRL_LDO2_EN
| SUN4I_HDMI_PLL_CTRL_LDO1_EN
|
406 SUN4I_HDMI_PLL_CTRL_HV_IS_33
| SUN4I_HDMI_PLL_CTRL_BWS
|
407 SUN4I_HDMI_PLL_CTRL_PLL_EN
;
408 writel(reg
, hdmi
->base
+ SUN4I_HDMI_PLL_CTRL_REG
);
410 ret
= sun4i_ddc_create(hdmi
, hdmi
->tmds_clk
);
412 dev_err(dev
, "Couldn't create the DDC clock\n");
416 drm_encoder_helper_add(&hdmi
->encoder
,
417 &sun4i_hdmi_helper_funcs
);
418 ret
= drm_encoder_init(drm
,
421 DRM_MODE_ENCODER_TMDS
,
424 dev_err(dev
, "Couldn't initialise the HDMI encoder\n");
428 hdmi
->encoder
.possible_crtcs
= drm_of_find_possible_crtcs(drm
,
430 if (!hdmi
->encoder
.possible_crtcs
)
431 return -EPROBE_DEFER
;
433 drm_connector_helper_add(&hdmi
->connector
,
434 &sun4i_hdmi_connector_helper_funcs
);
435 ret
= drm_connector_init(drm
, &hdmi
->connector
,
436 &sun4i_hdmi_connector_funcs
,
437 DRM_MODE_CONNECTOR_HDMIA
);
440 "Couldn't initialise the HDMI connector\n");
441 goto err_cleanup_connector
;
444 /* There is no HPD interrupt, so we need to poll the controller */
445 hdmi
->connector
.polled
= DRM_CONNECTOR_POLL_CONNECT
|
446 DRM_CONNECTOR_POLL_DISCONNECT
;
448 drm_mode_connector_attach_encoder(&hdmi
->connector
, &hdmi
->encoder
);
452 err_cleanup_connector
:
453 drm_encoder_cleanup(&hdmi
->encoder
);
457 static void sun4i_hdmi_unbind(struct device
*dev
, struct device
*master
,
460 struct sun4i_hdmi
*hdmi
= dev_get_drvdata(dev
);
462 drm_connector_cleanup(&hdmi
->connector
);
463 drm_encoder_cleanup(&hdmi
->encoder
);
466 static const struct component_ops sun4i_hdmi_ops
= {
467 .bind
= sun4i_hdmi_bind
,
468 .unbind
= sun4i_hdmi_unbind
,
471 static int sun4i_hdmi_probe(struct platform_device
*pdev
)
473 return component_add(&pdev
->dev
, &sun4i_hdmi_ops
);
476 static int sun4i_hdmi_remove(struct platform_device
*pdev
)
478 component_del(&pdev
->dev
, &sun4i_hdmi_ops
);
483 static const struct of_device_id sun4i_hdmi_of_table
[] = {
484 { .compatible
= "allwinner,sun5i-a10s-hdmi" },
487 MODULE_DEVICE_TABLE(of
, sun4i_hdmi_of_table
);
489 static struct platform_driver sun4i_hdmi_driver
= {
490 .probe
= sun4i_hdmi_probe
,
491 .remove
= sun4i_hdmi_remove
,
493 .name
= "sun4i-hdmi",
494 .of_match_table
= sun4i_hdmi_of_table
,
497 module_platform_driver(sun4i_hdmi_driver
);
499 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
500 MODULE_DESCRIPTION("Allwinner A10 HDMI Driver");
501 MODULE_LICENSE("GPL");