drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c
Extension
.c
Size
5505 bytes
Lines
215
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct imx8mp_hdmi {
	struct dw_hdmi_plat_data plat_data;
	struct dw_hdmi *dw_hdmi;
	struct clk *pixclk;
};

static enum drm_mode_status
imx8mp_hdmi_mode_valid(struct dw_hdmi *dw_hdmi, void *data,
		       const struct drm_display_info *info,
		       const struct drm_display_mode *mode)
{
	struct imx8mp_hdmi *hdmi = (struct imx8mp_hdmi *)data;
	long round_rate;

	if (mode->clock < 13500)
		return MODE_CLOCK_LOW;

	if (mode->clock > 297000)
		return MODE_CLOCK_HIGH;

	round_rate = clk_round_rate(hdmi->pixclk, mode->clock * 1000);
	/* imx8mp's pixel clock generator (fsl-samsung-hdmi) cannot generate
	 * all possible frequencies, so allow some tolerance to support more
	 * modes.
	 * Allow 0.5% difference allowed in various standards (VESA, CEA861)
	 * 0.5% = 5/1000 tolerance (mode->clock is 1/1000)
	 */
	if (abs(round_rate - mode->clock * 1000) > mode->clock * 5)
		return MODE_CLOCK_RANGE;

	/* We don't support double-clocked and Interlaced modes */
	if ((mode->flags & DRM_MODE_FLAG_DBLCLK) ||
	    (mode->flags & DRM_MODE_FLAG_INTERLACE))
		return MODE_BAD;

	return MODE_OK;
}

static int imx8mp_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,
				const struct drm_display_info *display,
				const struct drm_display_mode *mode)
{
	return 0;
}

static void imx8mp_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data)
{
}

static void im8mp_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
{
	/*
	 * Just release PHY core from reset, all other power management is done
	 * by the PHY driver.
	 */
	dw_hdmi_phy_gen1_reset(hdmi);

	dw_hdmi_phy_setup_hpd(hdmi, data);
}

static const struct dw_hdmi_phy_ops imx8mp_hdmi_phy_ops = {
	.init		= imx8mp_hdmi_phy_init,
	.disable	= imx8mp_hdmi_phy_disable,
	.setup_hpd	= im8mp_hdmi_phy_setup_hpd,
	.read_hpd	= dw_hdmi_phy_read_hpd,
	.update_hpd	= dw_hdmi_phy_update_hpd,
};

static int imx8mp_dw_hdmi_bind(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct imx8mp_hdmi *hdmi = dev_get_drvdata(dev);
	int ret;

	ret = component_bind_all(dev, &hdmi->plat_data);
	if (ret)
		return dev_err_probe(dev, ret, "component_bind_all failed!\n");

	hdmi->dw_hdmi = dw_hdmi_probe(pdev, &hdmi->plat_data);
	if (IS_ERR(hdmi->dw_hdmi)) {
		component_unbind_all(dev, &hdmi->plat_data);
		return PTR_ERR(hdmi->dw_hdmi);
	}

	return 0;
}

static void imx8mp_dw_hdmi_unbind(struct device *dev)
{
	struct imx8mp_hdmi *hdmi = dev_get_drvdata(dev);

Annotation

Implementation Notes