Lines Matching +full:e +full:- +full:ddc

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
37 #define drm_encoder_to_sun4i_hdmi(e) \ argument
38 container_of_const(e, struct sun4i_hdmi, encoder)
51 drm_err(connector->dev, in sun4i_hdmi_write_infoframe()
57 writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i)); in sun4i_hdmi_write_infoframe()
71 val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_disable()
73 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_disable()
75 clk_disable_unprepare(hdmi->tmds_clk); in sun4i_hdmi_disable()
81 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; in sun4i_hdmi_enable()
83 struct drm_connector *connector = &hdmi->connector; in sun4i_hdmi_enable()
84 struct drm_display_info *display = &connector->display_info; in sun4i_hdmi_enable()
87 unsigned long long tmds_rate = conn_state->hdmi.tmds_char_rate; in sun4i_hdmi_enable()
93 clk_set_rate(hdmi->mod_clk, tmds_rate); in sun4i_hdmi_enable()
94 clk_set_rate(hdmi->tmds_clk, tmds_rate); in sun4i_hdmi_enable()
98 hdmi->base + SUN4I_HDMI_UNKNOWN_REG); in sun4i_hdmi_enable()
110 val = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_enable()
112 val |= hdmi->variant->pad_ctrl1_init_val; in sun4i_hdmi_enable()
113 writel(val, hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_enable()
114 val = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); in sun4i_hdmi_enable()
117 writel(SUN4I_HDMI_VID_TIMING_X(mode->hdisplay) | in sun4i_hdmi_enable()
118 SUN4I_HDMI_VID_TIMING_Y(mode->vdisplay), in sun4i_hdmi_enable()
119 hdmi->base + SUN4I_HDMI_VID_TIMING_ACT_REG); in sun4i_hdmi_enable()
121 x = mode->htotal - mode->hsync_start; in sun4i_hdmi_enable()
122 y = mode->vtotal - mode->vsync_start; in sun4i_hdmi_enable()
124 hdmi->base + SUN4I_HDMI_VID_TIMING_BP_REG); in sun4i_hdmi_enable()
126 x = mode->hsync_start - mode->hdisplay; in sun4i_hdmi_enable()
127 y = mode->vsync_start - mode->vdisplay; in sun4i_hdmi_enable()
129 hdmi->base + SUN4I_HDMI_VID_TIMING_FP_REG); in sun4i_hdmi_enable()
131 x = mode->hsync_end - mode->hsync_start; in sun4i_hdmi_enable()
132 y = mode->vsync_end - mode->vsync_start; in sun4i_hdmi_enable()
134 hdmi->base + SUN4I_HDMI_VID_TIMING_SPW_REG); in sun4i_hdmi_enable()
137 if (mode->flags & DRM_MODE_FLAG_PHSYNC) in sun4i_hdmi_enable()
140 if (mode->flags & DRM_MODE_FLAG_PVSYNC) in sun4i_hdmi_enable()
143 writel(val, hdmi->base + SUN4I_HDMI_VID_TIMING_POL_REG); in sun4i_hdmi_enable()
145 clk_prepare_enable(hdmi->tmds_clk); in sun4i_hdmi_enable()
151 writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0)); in sun4i_hdmi_enable()
154 if (display->is_hdmi) in sun4i_hdmi_enable()
157 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); in sun4i_hdmi_enable()
171 unsigned long diff = div_u64(clock, 200); /* +-0.5% allowed by HDMI spec */ in sun4i_hdmi_connector_clock_valid()
174 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in sun4i_hdmi_connector_clock_valid()
181 rounded_rate = clk_round_rate(hdmi->tmds_clk, clock); in sun4i_hdmi_connector_clock_valid()
183 max_t(unsigned long, rounded_rate, clock) - in sun4i_hdmi_connector_clock_valid()
195 struct drm_crtc *crtc = conn_state->crtc; in sun4i_hdmi_connector_atomic_check()
196 struct drm_crtc_state *crtc_state = crtc->state; in sun4i_hdmi_connector_atomic_check()
197 struct drm_display_mode *mode = &crtc_state->adjusted_mode; in sun4i_hdmi_connector_atomic_check()
201 conn_state->hdmi.tmds_char_rate); in sun4i_hdmi_connector_atomic_check()
203 return -EINVAL; in sun4i_hdmi_connector_atomic_check()
224 drm_edid = drm_edid_read_ddc(connector, hdmi->ddc_i2c ?: hdmi->i2c); in sun4i_hdmi_get_modes()
227 cec_s_phys_addr(hdmi->cec_adap, in sun4i_hdmi_get_modes()
228 connector->display_info.source_physical_address, false); in sun4i_hdmi_get_modes()
234 connector->display_info.is_hdmi ? "an HDMI" : "a DVI"); in sun4i_hdmi_get_modes()
246 struct i2c_adapter *ddc; in sun4i_hdmi_get_ddc() local
248 remote = of_graph_get_remote_node(dev->of_node, 1, -1); in sun4i_hdmi_get_ddc()
250 return ERR_PTR(-EINVAL); in sun4i_hdmi_get_ddc()
252 phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); in sun4i_hdmi_get_ddc()
255 return ERR_PTR(-ENODEV); in sun4i_hdmi_get_ddc()
257 ddc = of_get_i2c_adapter_by_node(phandle); in sun4i_hdmi_get_ddc()
259 if (!ddc) in sun4i_hdmi_get_ddc()
260 return ERR_PTR(-EPROBE_DEFER); in sun4i_hdmi_get_ddc()
262 return ddc; in sun4i_hdmi_get_ddc()
282 reg = readl(hdmi->base + SUN4I_HDMI_HPD_REG); in sun4i_hdmi_connector_detect()
284 cec_phys_addr_invalidate(hdmi->cec_adap); in sun4i_hdmi_connector_detect()
294 __drm_atomic_helper_connector_hdmi_reset(connector, connector->state); in sun4i_hdmi_connector_reset()
310 return readl(hdmi->base + SUN4I_HDMI_CEC) & SUN4I_HDMI_CEC_RX; in sun4i_hdmi_cec_pin_read()
318 writel(SUN4I_HDMI_CEC_ENABLE, hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_cec_pin_low()
329 writel(0, hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_cec_pin_high()
515 struct sun4i_drv *drv = drm->dev_private; in sun4i_hdmi_bind()
522 return -ENOMEM; in sun4i_hdmi_bind()
524 hdmi->dev = dev; in sun4i_hdmi_bind()
525 hdmi->drv = drv; in sun4i_hdmi_bind()
527 hdmi->variant = of_device_get_match_data(dev); in sun4i_hdmi_bind()
528 if (!hdmi->variant) in sun4i_hdmi_bind()
529 return -EINVAL; in sun4i_hdmi_bind()
531 hdmi->base = devm_platform_ioremap_resource(pdev, 0); in sun4i_hdmi_bind()
532 if (IS_ERR(hdmi->base)) { in sun4i_hdmi_bind()
534 return PTR_ERR(hdmi->base); in sun4i_hdmi_bind()
537 if (hdmi->variant->has_reset_control) { in sun4i_hdmi_bind()
538 hdmi->reset = devm_reset_control_get(dev, NULL); in sun4i_hdmi_bind()
539 if (IS_ERR(hdmi->reset)) { in sun4i_hdmi_bind()
541 return PTR_ERR(hdmi->reset); in sun4i_hdmi_bind()
544 ret = reset_control_deassert(hdmi->reset); in sun4i_hdmi_bind()
551 hdmi->bus_clk = devm_clk_get(dev, "ahb"); in sun4i_hdmi_bind()
552 if (IS_ERR(hdmi->bus_clk)) { in sun4i_hdmi_bind()
554 ret = PTR_ERR(hdmi->bus_clk); in sun4i_hdmi_bind()
557 clk_prepare_enable(hdmi->bus_clk); in sun4i_hdmi_bind()
559 hdmi->mod_clk = devm_clk_get(dev, "mod"); in sun4i_hdmi_bind()
560 if (IS_ERR(hdmi->mod_clk)) { in sun4i_hdmi_bind()
562 ret = PTR_ERR(hdmi->mod_clk); in sun4i_hdmi_bind()
565 clk_prepare_enable(hdmi->mod_clk); in sun4i_hdmi_bind()
567 hdmi->pll0_clk = devm_clk_get(dev, "pll-0"); in sun4i_hdmi_bind()
568 if (IS_ERR(hdmi->pll0_clk)) { in sun4i_hdmi_bind()
570 ret = PTR_ERR(hdmi->pll0_clk); in sun4i_hdmi_bind()
574 hdmi->pll1_clk = devm_clk_get(dev, "pll-1"); in sun4i_hdmi_bind()
575 if (IS_ERR(hdmi->pll1_clk)) { in sun4i_hdmi_bind()
577 ret = PTR_ERR(hdmi->pll1_clk); in sun4i_hdmi_bind()
581 hdmi->regmap = devm_regmap_init_mmio(dev, hdmi->base, in sun4i_hdmi_bind()
583 if (IS_ERR(hdmi->regmap)) { in sun4i_hdmi_bind()
585 ret = PTR_ERR(hdmi->regmap); in sun4i_hdmi_bind()
595 if (hdmi->variant->has_ddc_parent_clk) { in sun4i_hdmi_bind()
596 hdmi->ddc_parent_clk = devm_clk_get(dev, "ddc"); in sun4i_hdmi_bind()
597 if (IS_ERR(hdmi->ddc_parent_clk)) { in sun4i_hdmi_bind()
598 dev_err(dev, "Couldn't get the HDMI DDC clock\n"); in sun4i_hdmi_bind()
599 ret = PTR_ERR(hdmi->ddc_parent_clk); in sun4i_hdmi_bind()
603 hdmi->ddc_parent_clk = hdmi->tmds_clk; in sun4i_hdmi_bind()
606 writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG); in sun4i_hdmi_bind()
608 writel(hdmi->variant->pad_ctrl0_init_val, in sun4i_hdmi_bind()
609 hdmi->base + SUN4I_HDMI_PAD_CTRL0_REG); in sun4i_hdmi_bind()
611 reg = readl(hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); in sun4i_hdmi_bind()
613 reg |= hdmi->variant->pll_ctrl_init_val; in sun4i_hdmi_bind()
614 writel(reg, hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); in sun4i_hdmi_bind()
622 hdmi->ddc_i2c = sun4i_hdmi_get_ddc(dev); in sun4i_hdmi_bind()
623 if (IS_ERR(hdmi->ddc_i2c)) { in sun4i_hdmi_bind()
624 ret = PTR_ERR(hdmi->ddc_i2c); in sun4i_hdmi_bind()
625 if (ret == -ENODEV) in sun4i_hdmi_bind()
626 hdmi->ddc_i2c = NULL; in sun4i_hdmi_bind()
631 drm_encoder_helper_add(&hdmi->encoder, in sun4i_hdmi_bind()
633 ret = drm_simple_encoder_init(drm, &hdmi->encoder, in sun4i_hdmi_bind()
640 hdmi->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm, in sun4i_hdmi_bind()
641 dev->of_node); in sun4i_hdmi_bind()
642 if (!hdmi->encoder.possible_crtcs) { in sun4i_hdmi_bind()
643 ret = -EPROBE_DEFER; in sun4i_hdmi_bind()
648 hdmi->cec_adap = cec_pin_allocate_adapter(&sun4i_hdmi_cec_pin_ops, in sun4i_hdmi_bind()
650 ret = PTR_ERR_OR_ZERO(hdmi->cec_adap); in sun4i_hdmi_bind()
653 writel(readl(hdmi->base + SUN4I_HDMI_CEC) & ~SUN4I_HDMI_CEC_TX, in sun4i_hdmi_bind()
654 hdmi->base + SUN4I_HDMI_CEC); in sun4i_hdmi_bind()
657 drm_connector_helper_add(&hdmi->connector, in sun4i_hdmi_bind()
659 ret = drmm_connector_hdmi_init(drm, &hdmi->connector, in sun4i_hdmi_bind()
669 hdmi->ddc_i2c, in sun4i_hdmi_bind()
677 cec_fill_conn_info_from_drm(&conn_info, &hdmi->connector); in sun4i_hdmi_bind()
678 cec_s_conn_info(hdmi->cec_adap, &conn_info); in sun4i_hdmi_bind()
681 hdmi->connector.polled = DRM_CONNECTOR_POLL_CONNECT | in sun4i_hdmi_bind()
684 ret = cec_register_adapter(hdmi->cec_adap, dev); in sun4i_hdmi_bind()
687 drm_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); in sun4i_hdmi_bind()
692 cec_delete_adapter(hdmi->cec_adap); in sun4i_hdmi_bind()
693 drm_encoder_cleanup(&hdmi->encoder); in sun4i_hdmi_bind()
695 i2c_put_adapter(hdmi->ddc_i2c); in sun4i_hdmi_bind()
697 i2c_del_adapter(hdmi->i2c); in sun4i_hdmi_bind()
699 clk_disable_unprepare(hdmi->mod_clk); in sun4i_hdmi_bind()
701 clk_disable_unprepare(hdmi->bus_clk); in sun4i_hdmi_bind()
703 reset_control_assert(hdmi->reset); in sun4i_hdmi_bind()
712 cec_unregister_adapter(hdmi->cec_adap); in sun4i_hdmi_unbind()
713 i2c_del_adapter(hdmi->i2c); in sun4i_hdmi_unbind()
714 i2c_put_adapter(hdmi->ddc_i2c); in sun4i_hdmi_unbind()
715 clk_disable_unprepare(hdmi->mod_clk); in sun4i_hdmi_unbind()
716 clk_disable_unprepare(hdmi->bus_clk); in sun4i_hdmi_unbind()
726 return component_add(&pdev->dev, &sun4i_hdmi_ops); in sun4i_hdmi_probe()
731 component_del(&pdev->dev, &sun4i_hdmi_ops); in sun4i_hdmi_remove()
735 { .compatible = "allwinner,sun4i-a10-hdmi", .data = &sun4i_variant, },
736 { .compatible = "allwinner,sun5i-a10s-hdmi", .data = &sun5i_variant, },
737 { .compatible = "allwinner,sun6i-a31-hdmi", .data = &sun6i_variant, },
746 .name = "sun4i-hdmi",
752 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");