static int modeset_init(struct mdp5_kms *mdp5_kms) { struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; const struct mdp5_cfg_hw *hw_cfg; unsigned int num_crtcs; int i, ret, pi = 0, ci = 0; struct drm_plane *primary[MAX_BASES] = { NULL }; struct drm_plane *cursor[MAX_BASES] = { NULL }; hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); /* * Construct encoders and modeset initialize connector devices * for each external display interface. */ for (i = 0; i < mdp5_kms->num_intfs; i++) { ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]); if (ret) goto fail; } /* * We should ideally have less number of encoders (set up by parsing * the MDP5 interfaces) than the number of layer mixers present in HW, * but let's be safe here anyway */ num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers); /* * Construct planes equaling the number of hw pipes, and CRTCs for the * N encoders set up by the driver. The first N planes become primary * planes for the CRTCs, with the remainder as overlay planes: */ for (i = 0; i < mdp5_kms->num_hwpipes; i++) { struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i]; struct drm_plane *plane; enum drm_plane_type type; if (i < num_crtcs) type = DRM_PLANE_TYPE_PRIMARY; else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR) type = DRM_PLANE_TYPE_CURSOR; else type = DRM_PLANE_TYPE_OVERLAY; plane = mdp5_plane_init(dev, type); if (IS_ERR(plane)) { ret = PTR_ERR(plane); dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret); goto fail; } priv->planes[priv->num_planes++] = plane; if (type == DRM_PLANE_TYPE_PRIMARY) primary[pi++] = plane; if (type == DRM_PLANE_TYPE_CURSOR) cursor[ci++] = plane; } for (i = 0; i < num_crtcs; i++) { struct drm_crtc *crtc; crtc = mdp5_crtc_init(dev, primary[i], cursor[i], i); if (IS_ERR(crtc)) { ret = PTR_ERR(crtc); dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret); goto fail; } priv->crtcs[priv->num_crtcs++] = crtc; } /* * Now that we know the number of crtcs we've created, set the possible * crtcs for the encoders */ for (i = 0; i < priv->num_encoders; i++) { struct drm_encoder *encoder = priv->encoders[i]; encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; } return 0; fail: return ret; }
static int modeset_init(struct mdp5_kms *mdp5_kms) { static const enum mdp5_pipe crtcs[] = { SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3, }; static const enum mdp5_pipe pub_planes[] = { SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3, }; struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; const struct mdp5_cfg_hw *hw_cfg; int i, ret; hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); /* register our interrupt-controller for hdmi/eDP/dsi/etc * to use for irqs routed through mdp: */ ret = mdp5_irq_domain_init(mdp5_kms); if (ret) goto fail; /* construct CRTCs and their private planes: */ for (i = 0; i < hw_cfg->pipe_rgb.count; i++) { struct drm_plane *plane; struct drm_crtc *crtc; plane = mdp5_plane_init(dev, crtcs[i], true, hw_cfg->pipe_rgb.base[i]); if (IS_ERR(plane)) { ret = PTR_ERR(plane); dev_err(dev->dev, "failed to construct plane for %s (%d)\n", pipe2name(crtcs[i]), ret); goto fail; } crtc = mdp5_crtc_init(dev, plane, i); if (IS_ERR(crtc)) { ret = PTR_ERR(crtc); dev_err(dev->dev, "failed to construct crtc for %s (%d)\n", pipe2name(crtcs[i]), ret); goto fail; } priv->crtcs[priv->num_crtcs++] = crtc; } /* Construct public planes: */ for (i = 0; i < hw_cfg->pipe_vig.count; i++) { struct drm_plane *plane; plane = mdp5_plane_init(dev, pub_planes[i], false, hw_cfg->pipe_vig.base[i]); if (IS_ERR(plane)) { ret = PTR_ERR(plane); dev_err(dev->dev, "failed to construct %s plane: %d\n", pipe2name(pub_planes[i]), ret); goto fail; } } /* Construct encoders and modeset initialize connector devices * for each external display interface. */ for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) { ret = modeset_init_intf(mdp5_kms, i); if (ret) goto fail; } return 0; fail: return ret; }