/* create connectors for each display device */ static int create_connector(struct drm_device *dev, struct omap_dss_device *dssdev) { struct omap_drm_private *priv = dev->dev_private; static struct notifier_block *notifier; struct drm_connector *connector; int j; 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; } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev); if (!connector) { dev_err(dev->dev, "could not create connector: %s\n", dssdev->name); return -ENOMEM; } BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); priv->connectors[priv->num_connectors++] = connector; #if 0 /* enable when dss2 supports hotplug */ notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); notifier->notifier_call = omap_drm_notifier; omap_dss_add_notify(dssdev, notifier); #else notifier = NULL; #endif for (j = 0; j < priv->num_encoders; j++) { struct omap_overlay_manager *mgr = omap_encoder_get_manager(priv->encoders[j]); if (mgr->device == dssdev) { drm_mode_connector_attach_encoder(connector, priv->encoders[j]); } } return 0; }
static int omap_modeset_init(struct drm_device *dev) { const struct omap_gpu_platform_data *pdata = dev->dev->platform_data; struct omap_gpu_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int i, j; unsigned int connected_connectors = 0; /* create encoders for each manager */ int create_encoder(int i) { struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(i); struct drm_encoder *encoder = omap_encoder_init(dev, mgr); if (!encoder) { dev_err(dev->dev, "could not create encoder\n"); return -ENOMEM; } priv->encoders[priv->num_encoders++] = encoder; return 0; } /* create connectors for each display device */ int create_connector(struct omap_dss_device *dssdev) { static struct notifier_block *notifier; struct drm_connector *connector; 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->get_edid)) { dev_warn(dev->dev, "%s driver does not support " "get_timings or get_edid.. skipping it!\n", dssdev->name); return 0; } connector = omap_connector_init(dev, get_connector_type(dssdev->type), dssdev); if (!connector) { dev_err(dev->dev, "could not create connector\n"); return -ENOMEM; } /* track what is already connected.. rather than looping thru all * connectors twice later, first for connected then for remainder * (which could be a race condition if connected status changes) */ if (omap_connector_detect (connector) == connector_status_connected) { connected_connectors |= (1 << priv->num_connectors); } priv->connectors[priv->num_connectors++] = connector; notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); notifier->notifier_call = omap_gpu_notifier; omap_dss_add_notify(dssdev, notifier); for (j = 0; j < priv->num_encoders; j++) { struct omap_overlay_manager *mgr = omap_encoder_get_manager(priv->encoders[j]); if (mgr->device == dssdev) { drm_mode_connector_attach_encoder(connector, priv->encoders[j]); } } return 0; } /* create up to max_overlays CRTCs mapping to overlays.. by default, * connect the overlays to different managers/encoders, giving priority * to encoders connected to connectors with a detected connection */ int create_crtc(int i) { struct omap_overlay *ovl = omap_dss_get_overlay(i); struct omap_overlay_manager *mgr = NULL; struct drm_crtc *crtc; if (ovl->manager) { DBG("disconnecting %s from %s", ovl->name, ovl->manager->name); ovl->unset_manager(ovl); } /* find next best connector... ones with detected connection first */ while (j < priv->num_connectors && !mgr) { if (connected_connectors & (1 << j)) { struct drm_encoder * encoder = omap_connector_attached_encoder (priv->connectors[j]); if (encoder) { mgr = omap_encoder_get_manager (encoder); } } j++; } /* if we couldn't find another connected connector, lets start looking * at the unconnected connectors: */ while (j < 2 * priv->num_connectors && !mgr) { int idx = j - priv->num_connectors; if (!(connected_connectors & (1 << idx))) { struct drm_encoder * encoder = omap_connector_attached_encoder (priv->connectors[idx]); if (encoder) { mgr = omap_encoder_get_manager (encoder); } } j++; } if (mgr) { DBG("connecting %s to %s", ovl->name, mgr->name); ovl->set_manager(ovl, mgr); } crtc = omap_crtc_init(dev, ovl); if (!crtc) { dev_err(dev->dev, "could not create CRTC\n"); return -ENOMEM; } priv->crtcs[priv->num_crtcs++] = crtc; return 0; } drm_mode_config_init(dev); if (pdata) { /* if platform data is provided by the board file, use it to control * which overlays, managers, and devices we own. */ for (i = 0; i < pdata->mgr_cnt; i++) { if (create_encoder(pdata->mgr_ids[i])) { goto fail; } } for (i = 0; i < pdata->dev_cnt; i++) { int m(struct omap_dss_device *dssdev, void *data) { return ! strcmp(dssdev->name, data); } struct omap_dss_device *dssdev = omap_dss_find_device((void *)pdata->dev_names[i], m); if (!dssdev) { dev_warn(dev->dev, "no such dssdev: %s\n", pdata->dev_names[i]); continue; } if (create_connector(dssdev)) { goto fail; } } j = 0; for (i = 0; i < pdata->ovl_cnt; i++) { if (create_crtc(pdata->ovl_ids[i])) { goto fail; } } } else {