Lines Matching +full:hdmi +full:- +full:connector
1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
40 drm_connector_to_sun4i_hdmi(struct drm_connector *connector) in drm_connector_to_sun4i_hdmi() argument
42 return container_of(connector, struct sun4i_hdmi, in drm_connector_to_sun4i_hdmi()
43 connector); in drm_connector_to_sun4i_hdmi()
46 static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi, in sun4i_hdmi_setup_avi_infoframes() argument
54 &hdmi->connector, mode); in sun4i_hdmi_setup_avi_infoframes()
67 writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i)); in sun4i_hdmi_setup_avi_infoframes()
76 struct drm_display_mode *mode = &crtc_state->mode; in sun4i_hdmi_atomic_check()
78 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in sun4i_hdmi_atomic_check()
79 return -EINVAL; in sun4i_hdmi_atomic_check()
86 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); in sun4i_hdmi_disable() local
89 DRM_DEBUG_DRIVER("Disabling the HDMI Output\n"); in sun4i_hdmi_disable()
91 val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_disable()
93 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_disable()
95 clk_disable_unprepare(hdmi->tmds_clk); in sun4i_hdmi_disable()
100 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; in sun4i_hdmi_enable()
101 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); in sun4i_hdmi_enable() local
104 DRM_DEBUG_DRIVER("Enabling the HDMI Output\n"); in sun4i_hdmi_enable()
106 clk_prepare_enable(hdmi->tmds_clk); in sun4i_hdmi_enable()
108 sun4i_hdmi_setup_avi_infoframes(hdmi, mode); in sun4i_hdmi_enable()
111 writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0)); in sun4i_hdmi_enable()
114 if (hdmi->hdmi_monitor) in sun4i_hdmi_enable()
117 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_enable()
124 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); in sun4i_hdmi_mode_set() local
128 clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000); in sun4i_hdmi_mode_set()
129 clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000); in sun4i_hdmi_mode_set()
133 hdmi->base + SUN4I_HDMI_UNKNOWN_REG); in sun4i_hdmi_mode_set()
145 val = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_mode_set()
147 val |= hdmi->variant->pad_ctrl1_init_val; in sun4i_hdmi_mode_set()
148 writel(val, hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_mode_set()
149 val = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_mode_set()
152 writel(SUN4I_HDMI_VID_TIMING_X(mode->hdisplay) | in sun4i_hdmi_mode_set()
153 SUN4I_HDMI_VID_TIMING_Y(mode->vdisplay), in sun4i_hdmi_mode_set()
154 hdmi->base + SUN4I_HDMI_VID_TIMING_ACT_REG); in sun4i_hdmi_mode_set()
156 x = mode->htotal - mode->hsync_start; in sun4i_hdmi_mode_set()
157 y = mode->vtotal - mode->vsync_start; in sun4i_hdmi_mode_set()
159 hdmi->base + SUN4I_HDMI_VID_TIMING_BP_REG); in sun4i_hdmi_mode_set()
161 x = mode->hsync_start - mode->hdisplay; in sun4i_hdmi_mode_set()
162 y = mode->vsync_start - mode->vdisplay; in sun4i_hdmi_mode_set()
164 hdmi->base + SUN4I_HDMI_VID_TIMING_FP_REG); in sun4i_hdmi_mode_set()
166 x = mode->hsync_end - mode->hsync_start; in sun4i_hdmi_mode_set()
167 y = mode->vsync_end - mode->vsync_start; in sun4i_hdmi_mode_set()
169 hdmi->base + SUN4I_HDMI_VID_TIMING_SPW_REG); in sun4i_hdmi_mode_set()
172 if (mode->flags & DRM_MODE_FLAG_PHSYNC) in sun4i_hdmi_mode_set()
175 if (mode->flags & DRM_MODE_FLAG_PVSYNC) in sun4i_hdmi_mode_set()
178 writel(val, hdmi->base + SUN4I_HDMI_VID_TIMING_POL_REG); in sun4i_hdmi_mode_set()
184 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); in sun4i_hdmi_mode_valid() local
185 unsigned long rate = mode->clock * 1000; in sun4i_hdmi_mode_valid()
186 unsigned long diff = rate / 200; /* +-0.5% allowed by HDMI spec */ in sun4i_hdmi_mode_valid()
189 /* 165 MHz is the typical max pixelclock frequency for HDMI <= 1.2 */ in sun4i_hdmi_mode_valid()
192 rounded_rate = clk_round_rate(hdmi->tmds_clk, rate); in sun4i_hdmi_mode_valid()
194 max_t(unsigned long, rounded_rate, rate) - in sun4i_hdmi_mode_valid()
208 static int sun4i_hdmi_get_modes(struct drm_connector *connector) in sun4i_hdmi_get_modes() argument
210 struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector); in sun4i_hdmi_get_modes() local
214 edid = drm_get_edid(connector, hdmi->ddc_i2c ?: hdmi->i2c); in sun4i_hdmi_get_modes()
218 hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid); in sun4i_hdmi_get_modes()
220 hdmi->hdmi_monitor ? "an HDMI" : "a DVI"); in sun4i_hdmi_get_modes()
222 drm_connector_update_edid_property(connector, edid); in sun4i_hdmi_get_modes()
223 cec_s_phys_addr_from_edid(hdmi->cec_adap, edid); in sun4i_hdmi_get_modes()
224 ret = drm_add_edid_modes(connector, edid); in sun4i_hdmi_get_modes()
235 remote = of_graph_get_remote_node(dev->of_node, 1, -1); in sun4i_hdmi_get_ddc()
237 return ERR_PTR(-EINVAL); in sun4i_hdmi_get_ddc()
239 phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); in sun4i_hdmi_get_ddc()
242 return ERR_PTR(-ENODEV); in sun4i_hdmi_get_ddc()
247 return ERR_PTR(-EPROBE_DEFER); in sun4i_hdmi_get_ddc()
257 sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force) in sun4i_hdmi_connector_detect() argument
259 struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector); in sun4i_hdmi_connector_detect() local
262 reg = readl(hdmi->base + SUN4I_HDMI_HPD_REG); in sun4i_hdmi_connector_detect()
264 cec_phys_addr_invalidate(hdmi->cec_adap); in sun4i_hdmi_connector_detect()
283 struct sun4i_hdmi *hdmi = cec_get_drvdata(adap); in sun4i_hdmi_cec_pin_read() local
285 return readl(hdmi->base + SUN4I_HDMI_CEC) & SUN4I_HDMI_CEC_RX; in sun4i_hdmi_cec_pin_read()
290 struct sun4i_hdmi *hdmi = cec_get_drvdata(adap); in sun4i_hdmi_cec_pin_low() local
293 writel(SUN4I_HDMI_CEC_ENABLE, hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_cec_pin_low()
298 struct sun4i_hdmi *hdmi = cec_get_drvdata(adap); in sun4i_hdmi_cec_pin_high() local
304 writel(0, hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_cec_pin_high()
490 struct sun4i_drv *drv = drm->dev_private; in sun4i_hdmi_bind()
491 struct sun4i_hdmi *hdmi; in sun4i_hdmi_bind() local
496 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); in sun4i_hdmi_bind()
497 if (!hdmi) in sun4i_hdmi_bind()
498 return -ENOMEM; in sun4i_hdmi_bind()
499 dev_set_drvdata(dev, hdmi); in sun4i_hdmi_bind()
500 hdmi->dev = dev; in sun4i_hdmi_bind()
501 hdmi->drv = drv; in sun4i_hdmi_bind()
503 hdmi->variant = of_device_get_match_data(dev); in sun4i_hdmi_bind()
504 if (!hdmi->variant) in sun4i_hdmi_bind()
505 return -EINVAL; in sun4i_hdmi_bind()
508 hdmi->base = devm_ioremap_resource(dev, res); in sun4i_hdmi_bind()
509 if (IS_ERR(hdmi->base)) { in sun4i_hdmi_bind()
510 dev_err(dev, "Couldn't map the HDMI encoder registers\n"); in sun4i_hdmi_bind()
511 return PTR_ERR(hdmi->base); in sun4i_hdmi_bind()
514 if (hdmi->variant->has_reset_control) { in sun4i_hdmi_bind()
515 hdmi->reset = devm_reset_control_get(dev, NULL); in sun4i_hdmi_bind()
516 if (IS_ERR(hdmi->reset)) { in sun4i_hdmi_bind()
517 dev_err(dev, "Couldn't get the HDMI reset control\n"); in sun4i_hdmi_bind()
518 return PTR_ERR(hdmi->reset); in sun4i_hdmi_bind()
521 ret = reset_control_deassert(hdmi->reset); in sun4i_hdmi_bind()
523 dev_err(dev, "Couldn't deassert HDMI reset\n"); in sun4i_hdmi_bind()
528 hdmi->bus_clk = devm_clk_get(dev, "ahb"); in sun4i_hdmi_bind()
529 if (IS_ERR(hdmi->bus_clk)) { in sun4i_hdmi_bind()
530 dev_err(dev, "Couldn't get the HDMI bus clock\n"); in sun4i_hdmi_bind()
531 ret = PTR_ERR(hdmi->bus_clk); in sun4i_hdmi_bind()
534 clk_prepare_enable(hdmi->bus_clk); in sun4i_hdmi_bind()
536 hdmi->mod_clk = devm_clk_get(dev, "mod"); in sun4i_hdmi_bind()
537 if (IS_ERR(hdmi->mod_clk)) { in sun4i_hdmi_bind()
538 dev_err(dev, "Couldn't get the HDMI mod clock\n"); in sun4i_hdmi_bind()
539 ret = PTR_ERR(hdmi->mod_clk); in sun4i_hdmi_bind()
542 clk_prepare_enable(hdmi->mod_clk); in sun4i_hdmi_bind()
544 hdmi->pll0_clk = devm_clk_get(dev, "pll-0"); in sun4i_hdmi_bind()
545 if (IS_ERR(hdmi->pll0_clk)) { in sun4i_hdmi_bind()
546 dev_err(dev, "Couldn't get the HDMI PLL 0 clock\n"); in sun4i_hdmi_bind()
547 ret = PTR_ERR(hdmi->pll0_clk); in sun4i_hdmi_bind()
551 hdmi->pll1_clk = devm_clk_get(dev, "pll-1"); in sun4i_hdmi_bind()
552 if (IS_ERR(hdmi->pll1_clk)) { in sun4i_hdmi_bind()
553 dev_err(dev, "Couldn't get the HDMI PLL 1 clock\n"); in sun4i_hdmi_bind()
554 ret = PTR_ERR(hdmi->pll1_clk); in sun4i_hdmi_bind()
558 hdmi->regmap = devm_regmap_init_mmio(dev, hdmi->base, in sun4i_hdmi_bind()
560 if (IS_ERR(hdmi->regmap)) { in sun4i_hdmi_bind()
561 dev_err(dev, "Couldn't create HDMI encoder regmap\n"); in sun4i_hdmi_bind()
562 ret = PTR_ERR(hdmi->regmap); in sun4i_hdmi_bind()
566 ret = sun4i_tmds_create(hdmi); in sun4i_hdmi_bind()
572 if (hdmi->variant->has_ddc_parent_clk) { in sun4i_hdmi_bind()
573 hdmi->ddc_parent_clk = devm_clk_get(dev, "ddc"); in sun4i_hdmi_bind()
574 if (IS_ERR(hdmi->ddc_parent_clk)) { in sun4i_hdmi_bind()
575 dev_err(dev, "Couldn't get the HDMI DDC clock\n"); in sun4i_hdmi_bind()
576 ret = PTR_ERR(hdmi->ddc_parent_clk); in sun4i_hdmi_bind()
580 hdmi->ddc_parent_clk = hdmi->tmds_clk; in sun4i_hdmi_bind()
583 writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG); in sun4i_hdmi_bind()
585 writel(hdmi->variant->pad_ctrl0_init_val, in sun4i_hdmi_bind()
586 hdmi->base + SUN4I_HDMI_PAD_CTRL0_REG); in sun4i_hdmi_bind()
588 reg = readl(hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); in sun4i_hdmi_bind()
590 reg |= hdmi->variant->pll_ctrl_init_val; in sun4i_hdmi_bind()
591 writel(reg, hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); in sun4i_hdmi_bind()
593 ret = sun4i_hdmi_i2c_create(dev, hdmi); in sun4i_hdmi_bind()
595 dev_err(dev, "Couldn't create the HDMI I2C adapter\n"); in sun4i_hdmi_bind()
599 hdmi->ddc_i2c = sun4i_hdmi_get_ddc(dev); in sun4i_hdmi_bind()
600 if (IS_ERR(hdmi->ddc_i2c)) { in sun4i_hdmi_bind()
601 ret = PTR_ERR(hdmi->ddc_i2c); in sun4i_hdmi_bind()
602 if (ret == -ENODEV) in sun4i_hdmi_bind()
603 hdmi->ddc_i2c = NULL; in sun4i_hdmi_bind()
608 drm_encoder_helper_add(&hdmi->encoder, in sun4i_hdmi_bind()
610 ret = drm_simple_encoder_init(drm, &hdmi->encoder, in sun4i_hdmi_bind()
613 dev_err(dev, "Couldn't initialise the HDMI encoder\n"); in sun4i_hdmi_bind()
617 hdmi->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm, in sun4i_hdmi_bind()
618 dev->of_node); in sun4i_hdmi_bind()
619 if (!hdmi->encoder.possible_crtcs) { in sun4i_hdmi_bind()
620 ret = -EPROBE_DEFER; in sun4i_hdmi_bind()
625 hdmi->cec_adap = cec_pin_allocate_adapter(&sun4i_hdmi_cec_pin_ops, in sun4i_hdmi_bind()
626 hdmi, "sun4i", CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO); in sun4i_hdmi_bind()
627 ret = PTR_ERR_OR_ZERO(hdmi->cec_adap); in sun4i_hdmi_bind()
630 writel(readl(hdmi->base + SUN4I_HDMI_CEC) & ~SUN4I_HDMI_CEC_TX, in sun4i_hdmi_bind()
631 hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_bind()
634 drm_connector_helper_add(&hdmi->connector, in sun4i_hdmi_bind()
636 ret = drm_connector_init_with_ddc(drm, &hdmi->connector, in sun4i_hdmi_bind()
639 hdmi->ddc_i2c); in sun4i_hdmi_bind()
642 "Couldn't initialise the HDMI connector\n"); in sun4i_hdmi_bind()
645 cec_fill_conn_info_from_drm(&conn_info, &hdmi->connector); in sun4i_hdmi_bind()
646 cec_s_conn_info(hdmi->cec_adap, &conn_info); in sun4i_hdmi_bind()
649 hdmi->connector.polled = DRM_CONNECTOR_POLL_CONNECT | in sun4i_hdmi_bind()
652 ret = cec_register_adapter(hdmi->cec_adap, dev); in sun4i_hdmi_bind()
655 drm_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); in sun4i_hdmi_bind()
660 cec_delete_adapter(hdmi->cec_adap); in sun4i_hdmi_bind()
661 drm_encoder_cleanup(&hdmi->encoder); in sun4i_hdmi_bind()
663 i2c_put_adapter(hdmi->ddc_i2c); in sun4i_hdmi_bind()
665 i2c_del_adapter(hdmi->i2c); in sun4i_hdmi_bind()
667 clk_disable_unprepare(hdmi->mod_clk); in sun4i_hdmi_bind()
669 clk_disable_unprepare(hdmi->bus_clk); in sun4i_hdmi_bind()
671 reset_control_assert(hdmi->reset); in sun4i_hdmi_bind()
678 struct sun4i_hdmi *hdmi = dev_get_drvdata(dev); in sun4i_hdmi_unbind() local
680 cec_unregister_adapter(hdmi->cec_adap); in sun4i_hdmi_unbind()
681 i2c_del_adapter(hdmi->i2c); in sun4i_hdmi_unbind()
682 i2c_put_adapter(hdmi->ddc_i2c); in sun4i_hdmi_unbind()
683 clk_disable_unprepare(hdmi->mod_clk); in sun4i_hdmi_unbind()
684 clk_disable_unprepare(hdmi->bus_clk); in sun4i_hdmi_unbind()
694 return component_add(&pdev->dev, &sun4i_hdmi_ops); in sun4i_hdmi_probe()
699 component_del(&pdev->dev, &sun4i_hdmi_ops); in sun4i_hdmi_remove()
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, },
716 .name = "sun4i-hdmi",
722 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
723 MODULE_DESCRIPTION("Allwinner A10 HDMI Driver");