1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Maxime Ripard
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 #include <linux/component.h>
10 #include <linux/iopoll.h>
11 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <linux/reset.h>
18 #include <drm/drm_atomic_helper.h>
19 #include <drm/drm_edid.h>
20 #include <drm/drm_encoder.h>
21 #include <drm/drm_of.h>
22 #include <drm/drm_panel.h>
23 #include <drm/drm_print.h>
24 #include <drm/drm_probe_helper.h>
25 #include <drm/drm_simple_kms_helper.h>
27 #include "sun4i_backend.h"
28 #include "sun4i_crtc.h"
29 #include "sun4i_drv.h"
30 #include "sun4i_hdmi.h"
32 static inline struct sun4i_hdmi
*
33 drm_encoder_to_sun4i_hdmi(struct drm_encoder
*encoder
)
35 return container_of(encoder
, struct sun4i_hdmi
,
39 static inline struct sun4i_hdmi
*
40 drm_connector_to_sun4i_hdmi(struct drm_connector
*connector
)
42 return container_of(connector
, struct sun4i_hdmi
,
46 static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi
*hdmi
,
47 struct drm_display_mode
*mode
)
49 struct hdmi_avi_infoframe frame
;
53 ret
= drm_hdmi_avi_infoframe_from_display_mode(&frame
,
54 &hdmi
->connector
, mode
);
56 DRM_ERROR("Failed to get infoframes from mode\n");
60 ret
= hdmi_avi_infoframe_pack(&frame
, buffer
, sizeof(buffer
));
62 DRM_ERROR("Failed to pack infoframes\n");
66 for (i
= 0; i
< sizeof(buffer
); i
++)
67 writeb(buffer
[i
], hdmi
->base
+ SUN4I_HDMI_AVI_INFOFRAME_REG(i
));
72 static int sun4i_hdmi_atomic_check(struct drm_encoder
*encoder
,
73 struct drm_crtc_state
*crtc_state
,
74 struct drm_connector_state
*conn_state
)
76 struct drm_display_mode
*mode
= &crtc_state
->mode
;
78 if (mode
->flags
& DRM_MODE_FLAG_DBLCLK
)
84 static void sun4i_hdmi_disable(struct drm_encoder
*encoder
)
86 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
89 DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
91 val
= readl(hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
92 val
&= ~SUN4I_HDMI_VID_CTRL_ENABLE
;
93 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
95 clk_disable_unprepare(hdmi
->tmds_clk
);
98 static void sun4i_hdmi_enable(struct drm_encoder
*encoder
)
100 struct drm_display_mode
*mode
= &encoder
->crtc
->state
->adjusted_mode
;
101 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
104 DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
106 clk_prepare_enable(hdmi
->tmds_clk
);
108 sun4i_hdmi_setup_avi_infoframes(hdmi
, mode
);
109 val
|= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI
);
110 val
|= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END
);
111 writel(val
, hdmi
->base
+ SUN4I_HDMI_PKT_CTRL_REG(0));
113 val
= SUN4I_HDMI_VID_CTRL_ENABLE
;
114 if (hdmi
->hdmi_monitor
)
115 val
|= SUN4I_HDMI_VID_CTRL_HDMI_MODE
;
117 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_CTRL_REG
);
120 static void sun4i_hdmi_mode_set(struct drm_encoder
*encoder
,
121 struct drm_display_mode
*mode
,
122 struct drm_display_mode
*adjusted_mode
)
124 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
128 clk_set_rate(hdmi
->mod_clk
, mode
->crtc_clock
* 1000);
129 clk_set_rate(hdmi
->tmds_clk
, mode
->crtc_clock
* 1000);
131 /* Set input sync enable */
132 writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC
,
133 hdmi
->base
+ SUN4I_HDMI_UNKNOWN_REG
);
136 * Setup output pad (?) controls
138 * This is done here instead of at probe/bind time because
139 * the controller seems to toggle some of the bits on its own.
141 * We can't just initialize the register there, we need to
142 * protect the clock bits that have already been read out and
143 * cached by the clock framework.
145 val
= readl(hdmi
->base
+ SUN4I_HDMI_PAD_CTRL1_REG
);
146 val
&= SUN4I_HDMI_PAD_CTRL1_HALVE_CLK
;
147 val
|= hdmi
->variant
->pad_ctrl1_init_val
;
148 writel(val
, hdmi
->base
+ SUN4I_HDMI_PAD_CTRL1_REG
);
149 val
= readl(hdmi
->base
+ SUN4I_HDMI_PAD_CTRL1_REG
);
151 /* Setup timing registers */
152 writel(SUN4I_HDMI_VID_TIMING_X(mode
->hdisplay
) |
153 SUN4I_HDMI_VID_TIMING_Y(mode
->vdisplay
),
154 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_ACT_REG
);
156 x
= mode
->htotal
- mode
->hsync_start
;
157 y
= mode
->vtotal
- mode
->vsync_start
;
158 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
159 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_BP_REG
);
161 x
= mode
->hsync_start
- mode
->hdisplay
;
162 y
= mode
->vsync_start
- mode
->vdisplay
;
163 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
164 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_FP_REG
);
166 x
= mode
->hsync_end
- mode
->hsync_start
;
167 y
= mode
->vsync_end
- mode
->vsync_start
;
168 writel(SUN4I_HDMI_VID_TIMING_X(x
) | SUN4I_HDMI_VID_TIMING_Y(y
),
169 hdmi
->base
+ SUN4I_HDMI_VID_TIMING_SPW_REG
);
171 val
= SUN4I_HDMI_VID_TIMING_POL_TX_CLK
;
172 if (mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
173 val
|= SUN4I_HDMI_VID_TIMING_POL_HSYNC
;
175 if (mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
176 val
|= SUN4I_HDMI_VID_TIMING_POL_VSYNC
;
178 writel(val
, hdmi
->base
+ SUN4I_HDMI_VID_TIMING_POL_REG
);
181 static enum drm_mode_status
sun4i_hdmi_mode_valid(struct drm_encoder
*encoder
,
182 const struct drm_display_mode
*mode
)
184 struct sun4i_hdmi
*hdmi
= drm_encoder_to_sun4i_hdmi(encoder
);
185 unsigned long rate
= mode
->clock
* 1000;
186 unsigned long diff
= rate
/ 200; /* +-0.5% allowed by HDMI spec */
189 /* 165 MHz is the typical max pixelclock frequency for HDMI <= 1.2 */
190 if (rate
> 165000000)
191 return MODE_CLOCK_HIGH
;
192 rounded_rate
= clk_round_rate(hdmi
->tmds_clk
, rate
);
193 if (rounded_rate
> 0 &&
194 max_t(unsigned long, rounded_rate
, rate
) -
195 min_t(unsigned long, rounded_rate
, rate
) < diff
)
200 static const struct drm_encoder_helper_funcs sun4i_hdmi_helper_funcs
= {
201 .atomic_check
= sun4i_hdmi_atomic_check
,
202 .disable
= sun4i_hdmi_disable
,
203 .enable
= sun4i_hdmi_enable
,
204 .mode_set
= sun4i_hdmi_mode_set
,
205 .mode_valid
= sun4i_hdmi_mode_valid
,
208 static int sun4i_hdmi_get_modes(struct drm_connector
*connector
)
210 struct sun4i_hdmi
*hdmi
= drm_connector_to_sun4i_hdmi(connector
);
214 edid
= drm_get_edid(connector
, hdmi
->ddc_i2c
?: hdmi
->i2c
);
218 hdmi
->hdmi_monitor
= drm_detect_hdmi_monitor(edid
);
219 DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
220 hdmi
->hdmi_monitor
? "an HDMI" : "a DVI");
222 drm_connector_update_edid_property(connector
, edid
);
223 cec_s_phys_addr_from_edid(hdmi
->cec_adap
, edid
);
224 ret
= drm_add_edid_modes(connector
, edid
);
230 static struct i2c_adapter
*sun4i_hdmi_get_ddc(struct device
*dev
)
232 struct device_node
*phandle
, *remote
;
233 struct i2c_adapter
*ddc
;
235 remote
= of_graph_get_remote_node(dev
->of_node
, 1, -1);
237 return ERR_PTR(-EINVAL
);
239 phandle
= of_parse_phandle(remote
, "ddc-i2c-bus", 0);
242 return ERR_PTR(-ENODEV
);
244 ddc
= of_get_i2c_adapter_by_node(phandle
);
245 of_node_put(phandle
);
247 return ERR_PTR(-EPROBE_DEFER
);
252 static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs
= {
253 .get_modes
= sun4i_hdmi_get_modes
,
256 static enum drm_connector_status
257 sun4i_hdmi_connector_detect(struct drm_connector
*connector
, bool force
)
259 struct sun4i_hdmi
*hdmi
= drm_connector_to_sun4i_hdmi(connector
);
262 reg
= readl(hdmi
->base
+ SUN4I_HDMI_HPD_REG
);
263 if (!(reg
& SUN4I_HDMI_HPD_HIGH
)) {
264 cec_phys_addr_invalidate(hdmi
->cec_adap
);
265 return connector_status_disconnected
;
268 return connector_status_connected
;
271 static const struct drm_connector_funcs sun4i_hdmi_connector_funcs
= {
272 .detect
= sun4i_hdmi_connector_detect
,
273 .fill_modes
= drm_helper_probe_single_connector_modes
,
274 .destroy
= drm_connector_cleanup
,
275 .reset
= drm_atomic_helper_connector_reset
,
276 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
277 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
280 #ifdef CONFIG_DRM_SUN4I_HDMI_CEC
281 static int sun4i_hdmi_cec_pin_read(struct cec_adapter
*adap
)
283 struct sun4i_hdmi
*hdmi
= cec_get_drvdata(adap
);
285 return readl(hdmi
->base
+ SUN4I_HDMI_CEC
) & SUN4I_HDMI_CEC_RX
;
288 static void sun4i_hdmi_cec_pin_low(struct cec_adapter
*adap
)
290 struct sun4i_hdmi
*hdmi
= cec_get_drvdata(adap
);
292 /* Start driving the CEC pin low */
293 writel(SUN4I_HDMI_CEC_ENABLE
, hdmi
->base
+ SUN4I_HDMI_CEC
);
296 static void sun4i_hdmi_cec_pin_high(struct cec_adapter
*adap
)
298 struct sun4i_hdmi
*hdmi
= cec_get_drvdata(adap
);
301 * Stop driving the CEC pin, the pull up will take over
302 * unless another CEC device is driving the pin low.
304 writel(0, hdmi
->base
+ SUN4I_HDMI_CEC
);
307 static const struct cec_pin_ops sun4i_hdmi_cec_pin_ops
= {
308 .read
= sun4i_hdmi_cec_pin_read
,
309 .low
= sun4i_hdmi_cec_pin_low
,
310 .high
= sun4i_hdmi_cec_pin_high
,
314 #define SUN4I_HDMI_PAD_CTRL1_MASK (GENMASK(24, 7) | GENMASK(5, 0))
315 #define SUN4I_HDMI_PLL_CTRL_MASK (GENMASK(31, 8) | GENMASK(3, 0))
317 /* Only difference from sun5i is AMP is 4 instead of 6 */
318 static const struct sun4i_hdmi_variant sun4i_variant
= {
319 .pad_ctrl0_init_val
= SUN4I_HDMI_PAD_CTRL0_TXEN
|
320 SUN4I_HDMI_PAD_CTRL0_CKEN
|
321 SUN4I_HDMI_PAD_CTRL0_PWENG
|
322 SUN4I_HDMI_PAD_CTRL0_PWEND
|
323 SUN4I_HDMI_PAD_CTRL0_PWENC
|
324 SUN4I_HDMI_PAD_CTRL0_LDODEN
|
325 SUN4I_HDMI_PAD_CTRL0_LDOCEN
|
326 SUN4I_HDMI_PAD_CTRL0_BIASEN
,
327 .pad_ctrl1_init_val
= SUN4I_HDMI_PAD_CTRL1_REG_AMP(4) |
328 SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
329 SUN4I_HDMI_PAD_CTRL1_REG_DENCK
|
330 SUN4I_HDMI_PAD_CTRL1_REG_DEN
|
331 SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT
|
332 SUN4I_HDMI_PAD_CTRL1_EMP_OPT
|
333 SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT
|
334 SUN4I_HDMI_PAD_CTRL1_AMP_OPT
,
335 .pll_ctrl_init_val
= SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
336 SUN4I_HDMI_PLL_CTRL_CS(7) |
337 SUN4I_HDMI_PLL_CTRL_CP_S(15) |
338 SUN4I_HDMI_PLL_CTRL_S(7) |
339 SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
340 SUN4I_HDMI_PLL_CTRL_SDIV2
|
341 SUN4I_HDMI_PLL_CTRL_LDO2_EN
|
342 SUN4I_HDMI_PLL_CTRL_LDO1_EN
|
343 SUN4I_HDMI_PLL_CTRL_HV_IS_33
|
344 SUN4I_HDMI_PLL_CTRL_BWS
|
345 SUN4I_HDMI_PLL_CTRL_PLL_EN
,
347 .ddc_clk_reg
= REG_FIELD(SUN4I_HDMI_DDC_CLK_REG
, 0, 6),
348 .ddc_clk_pre_divider
= 2,
349 .ddc_clk_m_offset
= 1,
351 .field_ddc_en
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 31, 31),
352 .field_ddc_start
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 30, 30),
353 .field_ddc_reset
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 0, 0),
354 .field_ddc_addr_reg
= REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG
, 0, 31),
355 .field_ddc_slave_addr
= REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG
, 0, 6),
356 .field_ddc_int_status
= REG_FIELD(SUN4I_HDMI_DDC_INT_STATUS_REG
, 0, 8),
357 .field_ddc_fifo_clear
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 31, 31),
358 .field_ddc_fifo_rx_thres
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 4, 7),
359 .field_ddc_fifo_tx_thres
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 0, 3),
360 .field_ddc_byte_count
= REG_FIELD(SUN4I_HDMI_DDC_BYTE_COUNT_REG
, 0, 9),
361 .field_ddc_cmd
= REG_FIELD(SUN4I_HDMI_DDC_CMD_REG
, 0, 2),
362 .field_ddc_sda_en
= REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG
, 9, 9),
363 .field_ddc_sck_en
= REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG
, 8, 8),
365 .ddc_fifo_reg
= SUN4I_HDMI_DDC_FIFO_DATA_REG
,
366 .ddc_fifo_has_dir
= true,
369 static const struct sun4i_hdmi_variant sun5i_variant
= {
370 .pad_ctrl0_init_val
= SUN4I_HDMI_PAD_CTRL0_TXEN
|
371 SUN4I_HDMI_PAD_CTRL0_CKEN
|
372 SUN4I_HDMI_PAD_CTRL0_PWENG
|
373 SUN4I_HDMI_PAD_CTRL0_PWEND
|
374 SUN4I_HDMI_PAD_CTRL0_PWENC
|
375 SUN4I_HDMI_PAD_CTRL0_LDODEN
|
376 SUN4I_HDMI_PAD_CTRL0_LDOCEN
|
377 SUN4I_HDMI_PAD_CTRL0_BIASEN
,
378 .pad_ctrl1_init_val
= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
379 SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
380 SUN4I_HDMI_PAD_CTRL1_REG_DENCK
|
381 SUN4I_HDMI_PAD_CTRL1_REG_DEN
|
382 SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT
|
383 SUN4I_HDMI_PAD_CTRL1_EMP_OPT
|
384 SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT
|
385 SUN4I_HDMI_PAD_CTRL1_AMP_OPT
,
386 .pll_ctrl_init_val
= SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
387 SUN4I_HDMI_PLL_CTRL_CS(7) |
388 SUN4I_HDMI_PLL_CTRL_CP_S(15) |
389 SUN4I_HDMI_PLL_CTRL_S(7) |
390 SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
391 SUN4I_HDMI_PLL_CTRL_SDIV2
|
392 SUN4I_HDMI_PLL_CTRL_LDO2_EN
|
393 SUN4I_HDMI_PLL_CTRL_LDO1_EN
|
394 SUN4I_HDMI_PLL_CTRL_HV_IS_33
|
395 SUN4I_HDMI_PLL_CTRL_BWS
|
396 SUN4I_HDMI_PLL_CTRL_PLL_EN
,
398 .ddc_clk_reg
= REG_FIELD(SUN4I_HDMI_DDC_CLK_REG
, 0, 6),
399 .ddc_clk_pre_divider
= 2,
400 .ddc_clk_m_offset
= 1,
402 .field_ddc_en
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 31, 31),
403 .field_ddc_start
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 30, 30),
404 .field_ddc_reset
= REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG
, 0, 0),
405 .field_ddc_addr_reg
= REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG
, 0, 31),
406 .field_ddc_slave_addr
= REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG
, 0, 6),
407 .field_ddc_int_status
= REG_FIELD(SUN4I_HDMI_DDC_INT_STATUS_REG
, 0, 8),
408 .field_ddc_fifo_clear
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 31, 31),
409 .field_ddc_fifo_rx_thres
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 4, 7),
410 .field_ddc_fifo_tx_thres
= REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG
, 0, 3),
411 .field_ddc_byte_count
= REG_FIELD(SUN4I_HDMI_DDC_BYTE_COUNT_REG
, 0, 9),
412 .field_ddc_cmd
= REG_FIELD(SUN4I_HDMI_DDC_CMD_REG
, 0, 2),
413 .field_ddc_sda_en
= REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG
, 9, 9),
414 .field_ddc_sck_en
= REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG
, 8, 8),
416 .ddc_fifo_reg
= SUN4I_HDMI_DDC_FIFO_DATA_REG
,
417 .ddc_fifo_has_dir
= true,
420 static const struct sun4i_hdmi_variant sun6i_variant
= {
421 .has_ddc_parent_clk
= true,
422 .has_reset_control
= true,
423 .pad_ctrl0_init_val
= 0xff |
424 SUN4I_HDMI_PAD_CTRL0_TXEN
|
425 SUN4I_HDMI_PAD_CTRL0_CKEN
|
426 SUN4I_HDMI_PAD_CTRL0_PWENG
|
427 SUN4I_HDMI_PAD_CTRL0_PWEND
|
428 SUN4I_HDMI_PAD_CTRL0_PWENC
|
429 SUN4I_HDMI_PAD_CTRL0_LDODEN
|
430 SUN4I_HDMI_PAD_CTRL0_LDOCEN
,
431 .pad_ctrl1_init_val
= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
432 SUN4I_HDMI_PAD_CTRL1_REG_EMP(4) |
433 SUN4I_HDMI_PAD_CTRL1_REG_DENCK
|
434 SUN4I_HDMI_PAD_CTRL1_REG_DEN
|
435 SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT
|
436 SUN4I_HDMI_PAD_CTRL1_EMP_OPT
|
437 SUN4I_HDMI_PAD_CTRL1_PWSDT
|
438 SUN4I_HDMI_PAD_CTRL1_PWSCK
|
439 SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT
|
440 SUN4I_HDMI_PAD_CTRL1_AMP_OPT
|
441 SUN4I_HDMI_PAD_CTRL1_UNKNOWN
,
442 .pll_ctrl_init_val
= SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
443 SUN4I_HDMI_PLL_CTRL_CS(3) |
444 SUN4I_HDMI_PLL_CTRL_CP_S(10) |
445 SUN4I_HDMI_PLL_CTRL_S(4) |
446 SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
447 SUN4I_HDMI_PLL_CTRL_SDIV2
|
448 SUN4I_HDMI_PLL_CTRL_LDO2_EN
|
449 SUN4I_HDMI_PLL_CTRL_LDO1_EN
|
450 SUN4I_HDMI_PLL_CTRL_HV_IS_33
|
451 SUN4I_HDMI_PLL_CTRL_PLL_EN
,
453 .ddc_clk_reg
= REG_FIELD(SUN6I_HDMI_DDC_CLK_REG
, 0, 6),
454 .ddc_clk_pre_divider
= 1,
455 .ddc_clk_m_offset
= 2,
457 .tmds_clk_div_offset
= 1,
459 .field_ddc_en
= REG_FIELD(SUN6I_HDMI_DDC_CTRL_REG
, 0, 0),
460 .field_ddc_start
= REG_FIELD(SUN6I_HDMI_DDC_CTRL_REG
, 27, 27),
461 .field_ddc_reset
= REG_FIELD(SUN6I_HDMI_DDC_CTRL_REG
, 31, 31),
462 .field_ddc_addr_reg
= REG_FIELD(SUN6I_HDMI_DDC_ADDR_REG
, 1, 31),
463 .field_ddc_slave_addr
= REG_FIELD(SUN6I_HDMI_DDC_ADDR_REG
, 1, 7),
464 .field_ddc_int_status
= REG_FIELD(SUN6I_HDMI_DDC_INT_STATUS_REG
, 0, 8),
465 .field_ddc_fifo_clear
= REG_FIELD(SUN6I_HDMI_DDC_FIFO_CTRL_REG
, 18, 18),
466 .field_ddc_fifo_rx_thres
= REG_FIELD(SUN6I_HDMI_DDC_FIFO_CTRL_REG
, 4, 7),
467 .field_ddc_fifo_tx_thres
= REG_FIELD(SUN6I_HDMI_DDC_FIFO_CTRL_REG
, 0, 3),
468 .field_ddc_byte_count
= REG_FIELD(SUN6I_HDMI_DDC_CMD_REG
, 16, 25),
469 .field_ddc_cmd
= REG_FIELD(SUN6I_HDMI_DDC_CMD_REG
, 0, 2),
470 .field_ddc_sda_en
= REG_FIELD(SUN6I_HDMI_DDC_CTRL_REG
, 6, 6),
471 .field_ddc_sck_en
= REG_FIELD(SUN6I_HDMI_DDC_CTRL_REG
, 4, 4),
473 .ddc_fifo_reg
= SUN6I_HDMI_DDC_FIFO_DATA_REG
,
474 .ddc_fifo_thres_incl
= true,
477 static const struct regmap_config sun4i_hdmi_regmap_config
= {
481 .max_register
= 0x580,
484 static int sun4i_hdmi_bind(struct device
*dev
, struct device
*master
,
487 struct platform_device
*pdev
= to_platform_device(dev
);
488 struct drm_device
*drm
= data
;
489 struct cec_connector_info conn_info
;
490 struct sun4i_drv
*drv
= drm
->dev_private
;
491 struct sun4i_hdmi
*hdmi
;
492 struct resource
*res
;
496 hdmi
= devm_kzalloc(dev
, sizeof(*hdmi
), GFP_KERNEL
);
499 dev_set_drvdata(dev
, hdmi
);
503 hdmi
->variant
= of_device_get_match_data(dev
);
507 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
508 hdmi
->base
= devm_ioremap_resource(dev
, res
);
509 if (IS_ERR(hdmi
->base
)) {
510 dev_err(dev
, "Couldn't map the HDMI encoder registers\n");
511 return PTR_ERR(hdmi
->base
);
514 if (hdmi
->variant
->has_reset_control
) {
515 hdmi
->reset
= devm_reset_control_get(dev
, NULL
);
516 if (IS_ERR(hdmi
->reset
)) {
517 dev_err(dev
, "Couldn't get the HDMI reset control\n");
518 return PTR_ERR(hdmi
->reset
);
521 ret
= reset_control_deassert(hdmi
->reset
);
523 dev_err(dev
, "Couldn't deassert HDMI reset\n");
528 hdmi
->bus_clk
= devm_clk_get(dev
, "ahb");
529 if (IS_ERR(hdmi
->bus_clk
)) {
530 dev_err(dev
, "Couldn't get the HDMI bus clock\n");
531 ret
= PTR_ERR(hdmi
->bus_clk
);
532 goto err_assert_reset
;
534 clk_prepare_enable(hdmi
->bus_clk
);
536 hdmi
->mod_clk
= devm_clk_get(dev
, "mod");
537 if (IS_ERR(hdmi
->mod_clk
)) {
538 dev_err(dev
, "Couldn't get the HDMI mod clock\n");
539 ret
= PTR_ERR(hdmi
->mod_clk
);
540 goto err_disable_bus_clk
;
542 clk_prepare_enable(hdmi
->mod_clk
);
544 hdmi
->pll0_clk
= devm_clk_get(dev
, "pll-0");
545 if (IS_ERR(hdmi
->pll0_clk
)) {
546 dev_err(dev
, "Couldn't get the HDMI PLL 0 clock\n");
547 ret
= PTR_ERR(hdmi
->pll0_clk
);
548 goto err_disable_mod_clk
;
551 hdmi
->pll1_clk
= devm_clk_get(dev
, "pll-1");
552 if (IS_ERR(hdmi
->pll1_clk
)) {
553 dev_err(dev
, "Couldn't get the HDMI PLL 1 clock\n");
554 ret
= PTR_ERR(hdmi
->pll1_clk
);
555 goto err_disable_mod_clk
;
558 hdmi
->regmap
= devm_regmap_init_mmio(dev
, hdmi
->base
,
559 &sun4i_hdmi_regmap_config
);
560 if (IS_ERR(hdmi
->regmap
)) {
561 dev_err(dev
, "Couldn't create HDMI encoder regmap\n");
562 ret
= PTR_ERR(hdmi
->regmap
);
563 goto err_disable_mod_clk
;
566 ret
= sun4i_tmds_create(hdmi
);
568 dev_err(dev
, "Couldn't create the TMDS clock\n");
569 goto err_disable_mod_clk
;
572 if (hdmi
->variant
->has_ddc_parent_clk
) {
573 hdmi
->ddc_parent_clk
= devm_clk_get(dev
, "ddc");
574 if (IS_ERR(hdmi
->ddc_parent_clk
)) {
575 dev_err(dev
, "Couldn't get the HDMI DDC clock\n");
576 ret
= PTR_ERR(hdmi
->ddc_parent_clk
);
577 goto err_disable_mod_clk
;
580 hdmi
->ddc_parent_clk
= hdmi
->tmds_clk
;
583 writel(SUN4I_HDMI_CTRL_ENABLE
, hdmi
->base
+ SUN4I_HDMI_CTRL_REG
);
585 writel(hdmi
->variant
->pad_ctrl0_init_val
,
586 hdmi
->base
+ SUN4I_HDMI_PAD_CTRL0_REG
);
588 reg
= readl(hdmi
->base
+ SUN4I_HDMI_PLL_CTRL_REG
);
589 reg
&= SUN4I_HDMI_PLL_CTRL_DIV_MASK
;
590 reg
|= hdmi
->variant
->pll_ctrl_init_val
;
591 writel(reg
, hdmi
->base
+ SUN4I_HDMI_PLL_CTRL_REG
);
593 ret
= sun4i_hdmi_i2c_create(dev
, hdmi
);
595 dev_err(dev
, "Couldn't create the HDMI I2C adapter\n");
596 goto err_disable_mod_clk
;
599 hdmi
->ddc_i2c
= sun4i_hdmi_get_ddc(dev
);
600 if (IS_ERR(hdmi
->ddc_i2c
)) {
601 ret
= PTR_ERR(hdmi
->ddc_i2c
);
603 hdmi
->ddc_i2c
= NULL
;
605 goto err_del_i2c_adapter
;
608 drm_encoder_helper_add(&hdmi
->encoder
,
609 &sun4i_hdmi_helper_funcs
);
610 ret
= drm_simple_encoder_init(drm
, &hdmi
->encoder
,
611 DRM_MODE_ENCODER_TMDS
);
613 dev_err(dev
, "Couldn't initialise the HDMI encoder\n");
614 goto err_put_ddc_i2c
;
617 hdmi
->encoder
.possible_crtcs
= drm_of_find_possible_crtcs(drm
,
619 if (!hdmi
->encoder
.possible_crtcs
) {
621 goto err_put_ddc_i2c
;
624 #ifdef CONFIG_DRM_SUN4I_HDMI_CEC
625 hdmi
->cec_adap
= cec_pin_allocate_adapter(&sun4i_hdmi_cec_pin_ops
,
626 hdmi
, "sun4i", CEC_CAP_DEFAULTS
| CEC_CAP_CONNECTOR_INFO
);
627 ret
= PTR_ERR_OR_ZERO(hdmi
->cec_adap
);
629 goto err_cleanup_connector
;
630 writel(readl(hdmi
->base
+ SUN4I_HDMI_CEC
) & ~SUN4I_HDMI_CEC_TX
,
631 hdmi
->base
+ SUN4I_HDMI_CEC
);
634 drm_connector_helper_add(&hdmi
->connector
,
635 &sun4i_hdmi_connector_helper_funcs
);
636 ret
= drm_connector_init_with_ddc(drm
, &hdmi
->connector
,
637 &sun4i_hdmi_connector_funcs
,
638 DRM_MODE_CONNECTOR_HDMIA
,
642 "Couldn't initialise the HDMI connector\n");
643 goto err_cleanup_connector
;
645 cec_fill_conn_info_from_drm(&conn_info
, &hdmi
->connector
);
646 cec_s_conn_info(hdmi
->cec_adap
, &conn_info
);
648 /* There is no HPD interrupt, so we need to poll the controller */
649 hdmi
->connector
.polled
= DRM_CONNECTOR_POLL_CONNECT
|
650 DRM_CONNECTOR_POLL_DISCONNECT
;
652 ret
= cec_register_adapter(hdmi
->cec_adap
, dev
);
654 goto err_cleanup_connector
;
655 drm_connector_attach_encoder(&hdmi
->connector
, &hdmi
->encoder
);
659 err_cleanup_connector
:
660 cec_delete_adapter(hdmi
->cec_adap
);
661 drm_encoder_cleanup(&hdmi
->encoder
);
663 i2c_put_adapter(hdmi
->ddc_i2c
);
665 i2c_del_adapter(hdmi
->i2c
);
667 clk_disable_unprepare(hdmi
->mod_clk
);
669 clk_disable_unprepare(hdmi
->bus_clk
);
671 reset_control_assert(hdmi
->reset
);
675 static void sun4i_hdmi_unbind(struct device
*dev
, struct device
*master
,
678 struct sun4i_hdmi
*hdmi
= dev_get_drvdata(dev
);
680 cec_unregister_adapter(hdmi
->cec_adap
);
681 i2c_del_adapter(hdmi
->i2c
);
682 i2c_put_adapter(hdmi
->ddc_i2c
);
683 clk_disable_unprepare(hdmi
->mod_clk
);
684 clk_disable_unprepare(hdmi
->bus_clk
);
687 static const struct component_ops sun4i_hdmi_ops
= {
688 .bind
= sun4i_hdmi_bind
,
689 .unbind
= sun4i_hdmi_unbind
,
692 static int sun4i_hdmi_probe(struct platform_device
*pdev
)
694 return component_add(&pdev
->dev
, &sun4i_hdmi_ops
);
697 static int sun4i_hdmi_remove(struct platform_device
*pdev
)
699 component_del(&pdev
->dev
, &sun4i_hdmi_ops
);
704 static const struct of_device_id sun4i_hdmi_of_table
[] = {
705 { .compatible
= "allwinner,sun4i-a10-hdmi", .data
= &sun4i_variant
, },
706 { .compatible
= "allwinner,sun5i-a10s-hdmi", .data
= &sun5i_variant
, },
707 { .compatible
= "allwinner,sun6i-a31-hdmi", .data
= &sun6i_variant
, },
710 MODULE_DEVICE_TABLE(of
, sun4i_hdmi_of_table
);
712 static struct platform_driver sun4i_hdmi_driver
= {
713 .probe
= sun4i_hdmi_probe
,
714 .remove
= sun4i_hdmi_remove
,
716 .name
= "sun4i-hdmi",
717 .of_match_table
= sun4i_hdmi_of_table
,
720 module_platform_driver(sun4i_hdmi_driver
);
722 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
723 MODULE_DESCRIPTION("Allwinner A10 HDMI Driver");
724 MODULE_LICENSE("GPL");