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); }
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; }
static int meson_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); const struct meson_dw_hdmi_data *match; struct meson_dw_hdmi *meson_dw_hdmi; struct drm_device *drm = data; struct meson_drm *priv = drm->dev_private; struct dw_hdmi_plat_data *dw_plat_data; struct drm_encoder *encoder; struct resource *res; int irq; int ret; DRM_DEBUG_DRIVER("\n"); if (!meson_hdmi_connector_is_available(dev)) { dev_info(drm->dev, "HDMI Output connector not available\n"); return -ENODEV; } match = of_device_get_match_data(&pdev->dev); if (!match) { dev_err(&pdev->dev, "failed to get match data\n"); return -ENODEV; } meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), GFP_KERNEL); if (!meson_dw_hdmi) return -ENOMEM; meson_dw_hdmi->priv = priv; meson_dw_hdmi->dev = dev; meson_dw_hdmi->data = match; dw_plat_data = &meson_dw_hdmi->dw_plat_data; encoder = &meson_dw_hdmi->encoder; meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi"); if (IS_ERR(meson_dw_hdmi->hdmi_supply)) { if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER) return -EPROBE_DEFER; meson_dw_hdmi->hdmi_supply = NULL; } else { ret = regulator_enable(meson_dw_hdmi->hdmi_supply); if (ret) return ret; } meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev, "hdmitx_apb"); if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) { dev_err(dev, "Failed to get hdmitx_apb reset\n"); return PTR_ERR(meson_dw_hdmi->hdmitx_apb); } meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev, "hdmitx"); if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) { dev_err(dev, "Failed to get hdmitx reset\n"); return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl); } meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev, "hdmitx_phy"); if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) { dev_err(dev, "Failed to get hdmitx_phy reset\n"); return PTR_ERR(meson_dw_hdmi->hdmitx_phy); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res); if (IS_ERR(meson_dw_hdmi->hdmitx)) return PTR_ERR(meson_dw_hdmi->hdmitx); meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr"); if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) { dev_err(dev, "Unable to get HDMI pclk\n"); return PTR_ERR(meson_dw_hdmi->hdmi_pclk); } clk_prepare_enable(meson_dw_hdmi->hdmi_pclk); meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci"); if (IS_ERR(meson_dw_hdmi->venci_clk)) { dev_err(dev, "Unable to get venci clk\n"); return PTR_ERR(meson_dw_hdmi->venci_clk); } clk_prepare_enable(meson_dw_hdmi->venci_clk); dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi, &meson_dw_hdmi_regmap_config); if (IS_ERR(dw_plat_data->regm)) return PTR_ERR(dw_plat_data->regm); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "Failed to get hdmi top irq\n"); return irq; } ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq, dw_hdmi_top_thread_irq, IRQF_SHARED, "dw_hdmi_top_irq", meson_dw_hdmi); if (ret) { dev_err(dev, "Failed to request hdmi top irq\n"); return ret; } /* Encoder */ drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs); ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, DRM_MODE_ENCODER_TMDS, "meson_hdmi"); if (ret) { dev_err(priv->dev, "Failed to init HDMI encoder\n"); return ret; } encoder->possible_crtcs = BIT(0); DRM_DEBUG_DRIVER("encoder initialized\n"); /* Enable clocks */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); /* Bring HDMITX MEM output of power down */ regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); /* Reset HDMITX APB & TX & PHY */ reset_control_reset(meson_dw_hdmi->hdmitx_apb); reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); reset_control_reset(meson_dw_hdmi->hdmitx_phy); /* Enable APB3 fail on error */ if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { writel_bits_relaxed(BIT(15), BIT(15), meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); writel_bits_relaxed(BIT(15), BIT(15), meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); } /* Bring out of reset */ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); msleep(20); meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); /* Enable HDMI-TX Interrupt */ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, HDMITX_TOP_INTR_CORE); meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, HDMITX_TOP_INTR_CORE); /* Bridge / Connector */ dw_plat_data->mode_valid = dw_hdmi_mode_valid; dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; dw_plat_data->phy_name = "meson_dw_hdmi_phy"; dw_plat_data->phy_data = meson_dw_hdmi; dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; platform_set_drvdata(pdev, meson_dw_hdmi); meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data); if (IS_ERR(meson_dw_hdmi->hdmi)) return PTR_ERR(meson_dw_hdmi->hdmi); DRM_DEBUG_DRIVER("HDMI controller initialized\n"); return 0; }