static int dw_hdmi_imx_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); const struct dw_hdmi_plat_data *plat_data; const struct of_device_id *match; struct drm_device *drm = data; struct drm_encoder *encoder; struct imx_hdmi *hdmi; struct resource *iores; int irq; int ret; if (!pdev->dev.of_node) return -ENODEV; hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node); plat_data = match->data; hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iores) return -ENXIO; platform_set_drvdata(pdev, hdmi); encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has * not been registered yet. Defer probing, and hope that * the required CRTC is added later. */ if (encoder->possible_crtcs == 0) return -EPROBE_DEFER; ret = dw_hdmi_imx_parse_dt(hdmi); if (ret < 0) return ret; drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs); drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); }
int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np) { uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has * not been registered yet. Defer probing, and hope that * the required CRTC is added later. */ if (crtc_mask == 0) return -EPROBE_DEFER; encoder->possible_crtcs = crtc_mask; /* FIXME: this is the mask of outputs which can clone this output. */ encoder->possible_clones = ~0; return 0; }
static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) { struct drm_encoder *encoder = &dp->encoder; struct drm_device *drm_dev = dp->drm_dev; struct device *dev = dp->dev; int ret; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node); DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) { DRM_ERROR("failed to initialize encoder with drm\n"); return ret; } drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs); return 0; }
static int dw_mipi_dsi_register(struct drm_device *drm, struct dw_mipi_dsi *dsi) { struct drm_encoder *encoder = &dsi->encoder; struct drm_connector *connector = &dsi->connector; struct device *dev = dsi->dev; int ret; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has * not been registered yet. Defer probing, and hope that * the required CRTC is added later. */ if (encoder->possible_crtcs == 0) return -EPROBE_DEFER; drm_encoder_helper_add(&dsi->encoder, &dw_mipi_dsi_encoder_helper_funcs); ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI, NULL); if (ret) { dev_err(dev, "Failed to initialize encoder with drm\n"); return ret; } drm_connector_helper_add(connector, &dw_mipi_dsi_connector_helper_funcs); drm_connector_init(drm, &dsi->connector, &dw_mipi_dsi_atomic_connector_funcs, DRM_MODE_CONNECTOR_DSI); drm_mode_connector_attach_encoder(connector, encoder); return 0; }
static int sun4i_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct sun4i_drv *drv = drm->dev_private; struct sun4i_hdmi *hdmi; struct resource *res; u32 reg; int ret; hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; dev_set_drvdata(dev, hdmi); hdmi->dev = dev; hdmi->drv = drv; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hdmi->base = devm_ioremap_resource(dev, res); if (IS_ERR(hdmi->base)) { dev_err(dev, "Couldn't map the HDMI encoder registers\n"); return PTR_ERR(hdmi->base); } hdmi->bus_clk = devm_clk_get(dev, "ahb"); if (IS_ERR(hdmi->bus_clk)) { dev_err(dev, "Couldn't get the HDMI bus clock\n"); return PTR_ERR(hdmi->bus_clk); } clk_prepare_enable(hdmi->bus_clk); hdmi->mod_clk = devm_clk_get(dev, "mod"); if (IS_ERR(hdmi->mod_clk)) { dev_err(dev, "Couldn't get the HDMI mod clock\n"); ret = PTR_ERR(hdmi->mod_clk); goto err_disable_bus_clk; } clk_prepare_enable(hdmi->mod_clk); hdmi->pll0_clk = devm_clk_get(dev, "pll-0"); if (IS_ERR(hdmi->pll0_clk)) { dev_err(dev, "Couldn't get the HDMI PLL 0 clock\n"); ret = PTR_ERR(hdmi->pll0_clk); goto err_disable_mod_clk; } hdmi->pll1_clk = devm_clk_get(dev, "pll-1"); if (IS_ERR(hdmi->pll1_clk)) { dev_err(dev, "Couldn't get the HDMI PLL 1 clock\n"); ret = PTR_ERR(hdmi->pll1_clk); goto err_disable_mod_clk; } ret = sun4i_tmds_create(hdmi); if (ret) { dev_err(dev, "Couldn't create the TMDS clock\n"); goto err_disable_mod_clk; } writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG); writel(SUN4I_HDMI_PAD_CTRL0_TXEN | SUN4I_HDMI_PAD_CTRL0_CKEN | SUN4I_HDMI_PAD_CTRL0_PWENG | SUN4I_HDMI_PAD_CTRL0_PWEND | SUN4I_HDMI_PAD_CTRL0_PWENC | SUN4I_HDMI_PAD_CTRL0_LDODEN | SUN4I_HDMI_PAD_CTRL0_LDOCEN | SUN4I_HDMI_PAD_CTRL0_BIASEN, hdmi->base + SUN4I_HDMI_PAD_CTRL0_REG); /* * We can't just initialize the register there, we need to * protect the clock bits that have already been read out and * cached by the clock framework. */ reg = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); reg &= SUN4I_HDMI_PAD_CTRL1_HALVE_CLK; reg |= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) | SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) | SUN4I_HDMI_PAD_CTRL1_REG_DENCK | SUN4I_HDMI_PAD_CTRL1_REG_DEN | SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT | SUN4I_HDMI_PAD_CTRL1_EMP_OPT | SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT | SUN4I_HDMI_PAD_CTRL1_AMP_OPT; writel(reg, hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); reg = readl(hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); reg &= SUN4I_HDMI_PLL_CTRL_DIV_MASK; reg |= SUN4I_HDMI_PLL_CTRL_VCO_S(8) | SUN4I_HDMI_PLL_CTRL_CS(7) | SUN4I_HDMI_PLL_CTRL_CP_S(15) | SUN4I_HDMI_PLL_CTRL_S(7) | SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) | SUN4I_HDMI_PLL_CTRL_SDIV2 | SUN4I_HDMI_PLL_CTRL_LDO2_EN | SUN4I_HDMI_PLL_CTRL_LDO1_EN | SUN4I_HDMI_PLL_CTRL_HV_IS_33 | SUN4I_HDMI_PLL_CTRL_BWS | SUN4I_HDMI_PLL_CTRL_PLL_EN; writel(reg, hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); ret = sun4i_hdmi_i2c_create(dev, hdmi); if (ret) { dev_err(dev, "Couldn't create the HDMI I2C adapter\n"); goto err_disable_mod_clk; } drm_encoder_helper_add(&hdmi->encoder, &sun4i_hdmi_helper_funcs); ret = drm_encoder_init(drm, &hdmi->encoder, &sun4i_hdmi_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) { dev_err(dev, "Couldn't initialise the HDMI encoder\n"); goto err_del_i2c_adapter; } hdmi->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); if (!hdmi->encoder.possible_crtcs) { ret = -EPROBE_DEFER; goto err_del_i2c_adapter; } #ifdef CONFIG_DRM_SUN4I_HDMI_CEC hdmi->cec_adap = cec_pin_allocate_adapter(&sun4i_hdmi_cec_pin_ops, hdmi, "sun4i", CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC); ret = PTR_ERR_OR_ZERO(hdmi->cec_adap); if (ret < 0) goto err_cleanup_connector; writel(readl(hdmi->base + SUN4I_HDMI_CEC) & ~SUN4I_HDMI_CEC_TX, hdmi->base + SUN4I_HDMI_CEC); #endif drm_connector_helper_add(&hdmi->connector, &sun4i_hdmi_connector_helper_funcs); ret = drm_connector_init(drm, &hdmi->connector, &sun4i_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); if (ret) { dev_err(dev, "Couldn't initialise the HDMI connector\n"); goto err_cleanup_connector; } /* There is no HPD interrupt, so we need to poll the controller */ hdmi->connector.polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; ret = cec_register_adapter(hdmi->cec_adap, dev); if (ret < 0) goto err_cleanup_connector; drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); return 0; err_cleanup_connector: cec_delete_adapter(hdmi->cec_adap); drm_encoder_cleanup(&hdmi->encoder); err_del_i2c_adapter: i2c_del_adapter(hdmi->i2c); err_disable_mod_clk: clk_disable_unprepare(hdmi->mod_clk); err_disable_bus_clk: clk_disable_unprepare(hdmi->bus_clk); return ret; }
static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct dw_hdmi_plat_data *plat_data; const struct of_device_id *match; struct drm_device *drm = data; struct drm_encoder *encoder; struct rockchip_hdmi *hdmi; int ret; if (!pdev->dev.of_node) return -ENODEV; hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); plat_data = devm_kmemdup(&pdev->dev, match->data, sizeof(*plat_data), GFP_KERNEL); if (!plat_data) return -ENOMEM; hdmi->dev = &pdev->dev; hdmi->chip_data = plat_data->phy_data; plat_data->phy_data = hdmi; encoder = &hdmi->encoder; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has * not been registered yet. Defer probing, and hope that * the required CRTC is added later. */ if (encoder->possible_crtcs == 0) return -EPROBE_DEFER; ret = rockchip_hdmi_parse_dt(hdmi); if (ret) { DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); return ret; } ret = clk_prepare_enable(hdmi->vpll_clk); if (ret) { DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); return ret; } hdmi->phy = devm_phy_optional_get(dev, "hdmi"); if (IS_ERR(hdmi->phy)) { ret = PTR_ERR(hdmi->phy); if (ret != -EPROBE_DEFER) DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); return ret; } drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); platform_set_drvdata(pdev, hdmi); hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); /* * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), * which would have called the encoder cleanup. Do it manually. */ if (IS_ERR(hdmi->hdmi)) { ret = PTR_ERR(hdmi->hdmi); drm_encoder_cleanup(encoder); clk_disable_unprepare(hdmi->vpll_clk); } return ret; }