struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct omap_overlay *ovl, int id) { struct drm_crtc *crtc = NULL; struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); DBG("%s", ovl->name); if (!omap_crtc) { dev_err(dev->dev, "could not allocate CRTC\n"); goto fail; } crtc = &omap_crtc->base; omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); omap_crtc->plane->crtc = crtc; omap_crtc->name = ovl->name; omap_crtc->id = id; drm_crtc_init(dev, crtc, &omap_crtc_funcs); drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); return crtc; fail: if (crtc) { omap_crtc_destroy(crtc); } return NULL; }
static int create_plane(struct drm_device *dev, struct omap_overlay *ovl, unsigned int possible_crtcs) { struct omap_drm_private *priv = dev->dev_private; struct drm_plane *plane = omap_plane_init(dev, ovl, possible_crtcs, false); if (!plane) { dev_err(dev->dev, "could not create plane: %s\n", ovl->name); return -ENOMEM; } BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; return 0; }
static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); int num_mgrs = dss_feat_get_num_mgrs(); int num_crtcs; int i, id = 0; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* * We usually don't want to create a CRTC for each manager, at least * not until we have a way to expose private planes to userspace. * Otherwise there would not be enough video pipes left for drm planes. * We use the num_crtc argument to limit the number of crtcs we create. */ num_crtcs = min3(num_crtc, num_mgrs, num_ovls); dssdev = NULL; for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; enum omap_channel channel; struct omap_overlay_manager *mgr; if (!omapdss_device_is_connected(dssdev)) continue; encoder = omap_encoder_init(dev, dssdev); if (!encoder) { dev_err(dev->dev, "could not create encoder: %s\n", dssdev->name); return -ENOMEM; } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); if (!connector) { dev_err(dev->dev, "could not create connector: %s\n", dssdev->name); return -ENOMEM; } BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); priv->encoders[priv->num_encoders++] = encoder; priv->connectors[priv->num_connectors++] = connector; drm_mode_connector_attach_encoder(connector, encoder); /* * if we have reached the limit of the crtcs we are allowed to * create, let's not try to look for a crtc for this * panel/encoder and onwards, we will, of course, populate the * the possible_crtcs field for all the encoders with the final * set of crtcs we create */ if (id == num_crtcs) continue; /* * get the recommended DISPC channel for this encoder. For now, * we only try to get create a crtc out of the recommended, the * other possible channels to which the encoder can connect are * not considered. */ mgr = omapdss_find_mgr_from_display(dssdev); channel = mgr->id; /* * if this channel hasn't already been taken by a previously * allocated crtc, we create a new crtc for it */ if (!channel_used(dev, channel)) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, channel, id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; id++; } } /* * we have allocated crtcs according to the need of the panels/encoders, * adding more crtcs here if needed */ for (; id < num_crtcs; id++) { /* find a free manager for this crtc */ for (i = 0; i < num_mgrs; i++) { if (!channel_used(dev, i)) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, i, id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; break; } else { continue; } } if (i == num_mgrs) { /* this shouldn't really happen */ dev_err(dev->dev, "no managers left for crtc\n"); return -ENOMEM; } } /* * Create normal planes for the remaining overlays: */ for (; id < num_ovls; id++) { struct drm_plane *plane = omap_plane_init(dev, id, false); BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; } for (i = 0; i < priv->num_encoders; i++) { struct drm_encoder *encoder = priv->encoders[i]; struct omap_dss_device *dssdev = omap_encoder_get_dssdev(encoder); struct omap_dss_device *output; output = omapdss_find_output_from_display(dssdev); /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; for (id = 0; id < priv->num_crtcs; id++) { struct drm_crtc *crtc = priv->crtcs[id]; enum omap_channel crtc_channel; crtc_channel = omap_crtc_channel(crtc); if (output->dispc_channel == crtc_channel) { encoder->possible_crtcs |= (1 << id); break; } } omap_dss_put_device(output); } DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", priv->num_planes, priv->num_crtcs, priv->num_encoders, priv->num_connectors); dev->mode_config.min_width = 32; dev->mode_config.min_height = 32; /* note: eventually will need some cpu_is_omapXYZ() type stuff here * to fill in these limits properly on different OMAP generations.. */ dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; dev->mode_config.funcs = &omap_mode_config_funcs; return 0; }
static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = priv->dispc_ops->get_num_ovls(); int num_mgrs = priv->dispc_ops->get_num_mgrs(); int num_crtcs, crtc_idx, plane_idx; int ret; u32 plane_crtc_mask; drm_mode_config_init(dev); ret = omap_modeset_init_properties(dev); if (ret < 0) return ret; /* * This function creates exactly one connector, encoder, crtc, * and primary plane per each connected dss-device. Each * connector->encoder->crtc chain is expected to be separate * and each crtc is connect to a single dss-channel. If the * configuration does not match the expectations or exceeds * the available resources, the configuration is rejected. */ num_crtcs = 0; for_each_dss_dev(dssdev) if (omapdss_device_is_connected(dssdev)) num_crtcs++; if (num_crtcs > num_mgrs || num_crtcs > num_ovls || num_crtcs > ARRAY_SIZE(priv->crtcs) || num_crtcs > ARRAY_SIZE(priv->planes) || num_crtcs > ARRAY_SIZE(priv->encoders) || num_crtcs > ARRAY_SIZE(priv->connectors)) { dev_err(dev->dev, "%s(): Too many connected displays\n", __func__); return -EINVAL; } /* All planes can be put to any CRTC */ plane_crtc_mask = (1 << num_crtcs) - 1; dssdev = NULL; crtc_idx = 0; plane_idx = 0; for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; struct drm_plane *plane; struct drm_crtc *crtc; if (!omapdss_device_is_connected(dssdev)) continue; encoder = omap_encoder_init(dev, dssdev); if (!encoder) return -ENOMEM; connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); if (!connector) return -ENOMEM; plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY, plane_crtc_mask); if (IS_ERR(plane)) return PTR_ERR(plane); crtc = omap_crtc_init(dev, plane, dssdev); if (IS_ERR(crtc)) return PTR_ERR(crtc); drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << crtc_idx); priv->crtcs[priv->num_crtcs++] = crtc; priv->planes[priv->num_planes++] = plane; priv->encoders[priv->num_encoders++] = encoder; priv->connectors[priv->num_connectors++] = connector; plane_idx++; crtc_idx++; } /* * Create normal planes for the remaining overlays: */ for (; plane_idx < num_ovls; plane_idx++) { struct drm_plane *plane; if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes))) return -EINVAL; plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY, plane_crtc_mask); if (IS_ERR(plane)) return PTR_ERR(plane); priv->planes[priv->num_planes++] = plane; } DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", priv->num_planes, priv->num_crtcs, priv->num_encoders, priv->num_connectors); dev->mode_config.min_width = 8; dev->mode_config.min_height = 2; /* note: eventually will need some cpu_is_omapXYZ() type stuff here * to fill in these limits properly on different OMAP generations.. */ dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; dev->mode_config.funcs = &omap_mode_config_funcs; dev->mode_config.helper_private = &omap_mode_config_helper_funcs; drm_mode_config_reset(dev); omap_drm_irq_install(dev); return 0; }
static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); int id; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* * Create private planes and CRTCs for the last NUM_CRTCs overlay * plus manager: */ for (id = 0; id < min(num_crtc, num_ovls); id++) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; } /* * Create normal planes for the remaining overlays: */ for (; id < num_ovls; id++) { struct drm_plane *plane = omap_plane_init(dev, id, false); BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; } for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; if (!dssdev->driver) { dev_warn(dev->dev, "%s has no driver.. skipping it\n", dssdev->name); return 0; } if (!(dssdev->driver->get_timings || dssdev->driver->read_edid)) { dev_warn(dev->dev, "%s driver does not support " "get_timings or read_edid.. skipping it!\n", dssdev->name); return 0; } encoder = omap_encoder_init(dev, dssdev); if (!encoder) { dev_err(dev->dev, "could not create encoder: %s\n", dssdev->name); return -ENOMEM; } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); if (!connector) { dev_err(dev->dev, "could not create connector: %s\n", dssdev->name); return -ENOMEM; } BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); priv->encoders[priv->num_encoders++] = encoder; priv->connectors[priv->num_connectors++] = connector; drm_mode_connector_attach_encoder(connector, encoder); /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; for (id = 0; id < priv->num_crtcs; id++) { enum omap_dss_output_id supported_outputs = dss_feat_get_supported_outputs(pipe2chan(id)); if (supported_outputs & dssdev->output->id) encoder->possible_crtcs |= (1 << id); } } dev->mode_config.min_width = 32; dev->mode_config.min_height = 32; /* note: eventually will need some cpu_is_omapXYZ() type stuff here * to fill in these limits properly on different OMAP generations.. */ dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; dev->mode_config.funcs = &omap_mode_config_funcs; return 0; }