staticlong mdp4_round_pixclk(struct msm_kms *kms, unsignedlong rate, struct drm_encoder *encoder)
{ /* if we had >1 encoder, we'd need something more clever: */ switch (encoder->encoder_type) { case DRM_MODE_ENCODER_TMDS: return mdp4_dtv_round_pixclk(encoder, rate); case DRM_MODE_ENCODER_LVDS: case DRM_MODE_ENCODER_DSI: default: return rate;
}
}
staticint mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms, int intf_type)
{ struct drm_device *dev = mdp4_kms->dev; struct msm_drm_private *priv = dev->dev_private; struct drm_encoder *encoder; struct drm_connector *connector; struct drm_bridge *next_bridge; int dsi_id; int ret;
switch (intf_type) { case DRM_MODE_ENCODER_LVDS: /* * bail out early if there is no panel node (no need to * initialize LCDC encoder and LVDS connector)
*/
next_bridge = devm_drm_of_get_bridge(dev->dev, dev->dev->of_node, 0, 0); if (IS_ERR(next_bridge)) {
ret = PTR_ERR(next_bridge); if (ret == -ENODEV) return 0; return ret;
}
encoder = mdp4_lcdc_encoder_init(dev); if (IS_ERR(encoder)) {
DRM_DEV_ERROR(dev->dev, "failed to construct LCDC encoder\n"); return PTR_ERR(encoder);
}
/* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
encoder->possible_crtcs = 1 << DMA_P;
ret = drm_bridge_attach(encoder, next_bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to attach LVDS panel/bridge: %d\n", ret);
return ret;
}
connector = drm_bridge_connector_init(dev, encoder); if (IS_ERR(connector)) {
DRM_DEV_ERROR(dev->dev, "failed to initialize LVDS connector\n"); return PTR_ERR(connector);
}
ret = drm_connector_attach_encoder(connector, encoder); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to attach LVDS connector: %d\n", ret);
return ret;
}
break; case DRM_MODE_ENCODER_TMDS:
encoder = mdp4_dtv_encoder_init(dev); if (IS_ERR(encoder)) {
DRM_DEV_ERROR(dev->dev, "failed to construct DTV encoder\n"); return PTR_ERR(encoder);
}
/* DTV can be hooked to DMA_E: */
encoder->possible_crtcs = 1 << 1;
if (priv->kms->hdmi) { /* Construct bridge/connector for HDMI: */
ret = msm_hdmi_modeset_init(priv->kms->hdmi, dev, encoder); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to initialize HDMI: %d\n", ret); return ret;
}
}
break; case DRM_MODE_ENCODER_DSI: /* only DSI1 supported for now */
dsi_id = 0;
if (!priv->kms->dsi[dsi_id]) break;
encoder = mdp4_dsi_encoder_init(dev); if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
DRM_DEV_ERROR(dev->dev, "failed to construct DSI encoder: %d\n", ret); return ret;
}
/* construct non-private planes: */ for (i = 0; i < ARRAY_SIZE(vg_planes); i++) {
plane = mdp4_plane_init(dev, vg_planes[i], false); if (IS_ERR(plane)) {
DRM_DEV_ERROR(dev->dev, "failed to construct plane for VG%d\n", i + 1);
ret = PTR_ERR(plane); goto fail;
}
}
for (i = 0; i < ARRAY_SIZE(mdp4_crtcs); i++) {
plane = mdp4_plane_init(dev, rgb_planes[i], true); if (IS_ERR(plane)) {
DRM_DEV_ERROR(dev->dev, "failed to construct plane for RGB%d\n", i + 1);
ret = PTR_ERR(plane); goto fail;
}
crtc = mdp4_crtc_init(dev, plane, i,
mdp4_crtcs[i]); if (IS_ERR(crtc)) {
DRM_DEV_ERROR(dev->dev, "failed to construct crtc for %s\n",
mdp4_crtc_names[i]);
ret = PTR_ERR(crtc); goto fail;
}
}
/* * we currently set up two relatively fixed paths: * * LCDC/LVDS path: RGB1 -> DMA_P -> LCDC -> LVDS * or * DSI path: RGB1 -> DMA_P -> DSI1 -> DSI Panel * * DTV/HDMI path: RGB2 -> DMA_E -> DTV -> HDMI
*/
for (i = 0; i < ARRAY_SIZE(mdp4_intfs); i++) {
ret = mdp4_modeset_init_intf(mdp4_kms, mdp4_intfs[i]); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to initialize intf: %d, %d\n",
i, ret); goto fail;
}
}
/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
max_clk = 266667000;
ret = mdp_kms_init(&mdp4_kms->base, &kms_funcs); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to init kms\n"); goto fail;
}
kms = priv->kms;
mdp4_kms->dev = dev;
if (mdp4_kms->vdd) {
ret = regulator_enable(mdp4_kms->vdd); if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", ret); goto fail;
}
}
clk_set_rate(mdp4_kms->clk, max_clk);
read_mdp_hw_revision(mdp4_kms, &major, &minor);
if (major != 4) {
DRM_DEV_ERROR(dev->dev, "unexpected MDP version: v%d.%d\n",
major, minor);
ret = -ENXIO; goto fail;
}
mdp4_kms->rev = minor;
if (mdp4_kms->rev >= 2) { if (!mdp4_kms->lut_clk) {
DRM_DEV_ERROR(dev->dev, "failed to get lut_clk\n");
ret = -ENODEV; goto fail;
}
clk_set_rate(mdp4_kms->lut_clk, max_clk);
}
/* make sure things are off before attaching iommu (bootloader could * have left things on, in which case we'll start getting faults if * we don't disable):
*/
mdp4_enable(mdp4_kms);
mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
mdp4_disable(mdp4_kms);
mdelay(16);
mmu = msm_iommu_new(&pdev->dev, 0); if (IS_ERR(mmu)) {
ret = PTR_ERR(mmu); goto fail;
} elseif (!mmu) {
DRM_DEV_INFO(dev->dev, "no IOMMU, bailing out\n");
ret = -ENODEV; goto fail;
} else {
vm = msm_gem_vm_create(dev, mmu, "mdp4",
0x1000, 0x100000000 - 0x1000, true);
if (IS_ERR(vm)) { if (!IS_ERR(mmu))
mmu->funcs->destroy(mmu);
ret = PTR_ERR(vm); goto fail;
}
kms->vm = vm;
}
ret = modeset_init(mdp4_kms); if (ret) {
DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret); goto fail;
}
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT); if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
DRM_DEV_ERROR(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
mdp4_kms->blank_cursor_bo = NULL; goto fail;
}
ret = msm_gem_get_and_pin_iova(mdp4_kms->blank_cursor_bo, kms->vm,
&mdp4_kms->blank_cursor_iova); if (ret) {
DRM_DEV_ERROR(dev->dev, "could not pin blank-cursor bo: %d\n", ret); goto fail;
}
mdp4_kms = devm_kzalloc(dev, sizeof(*mdp4_kms), GFP_KERNEL); if (!mdp4_kms) return dev_err_probe(dev, -ENOMEM, "failed to allocate kms\n");
mdp4_kms->mmio = msm_ioremap(pdev, NULL); if (IS_ERR(mdp4_kms->mmio)) return PTR_ERR(mdp4_kms->mmio);
irq = platform_get_irq(pdev, 0); if (irq < 0) return dev_err_probe(dev, irq, "failed to get irq\n");
mdp4_kms->base.base.irq = irq;
/* NOTE: driver for this regulator still missing upstream.. use * _get_exclusive() and ignore the error if it does not exist * (and hope that the bootloader left it on for us)
*/
mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd"); if (IS_ERR(mdp4_kms->vdd))
mdp4_kms->vdd = NULL;
mdp4_kms->clk = devm_clk_get(&pdev->dev, "core_clk"); if (IS_ERR(mdp4_kms->clk)) return dev_err_probe(dev, PTR_ERR(mdp4_kms->clk), "failed to get core_clk\n");
mdp4_kms->pclk = devm_clk_get(&pdev->dev, "iface_clk"); if (IS_ERR(mdp4_kms->pclk))
mdp4_kms->pclk = NULL;
mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk"); if (IS_ERR(mdp4_kms->axi_clk)) return dev_err_probe(dev, PTR_ERR(mdp4_kms->axi_clk), "failed to get axi_clk\n");
/* * This is required for revn >= 2. Handle errors here and let the kms * init bail out if the clock is not provided.
*/
mdp4_kms->lut_clk = devm_clk_get_optional(&pdev->dev, "lut_clk"); if (IS_ERR(mdp4_kms->lut_clk)) return dev_err_probe(dev, PTR_ERR(mdp4_kms->lut_clk), "failed to get lut_clk\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.