Ejemplo n.º 1
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
 */
static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
		int *j, unsigned int connected_connectors)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_overlay_manager *mgr = NULL;
	struct drm_crtc *crtc;

	/* 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:
	 *
	 * note: it might not be immediately apparent, but thanks to
	 * the !mgr check in both this loop and the one above, the only
	 * way to enter this loop is with *j == priv->num_connectors,
	 * so idx can never go negative.
	 */
	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)++;
	}

	crtc = omap_crtc_init(dev, ovl, priv->num_crtcs);

	if (!crtc) {
		dev_err(dev->dev, "could not create CRTC: %s\n",
				ovl->name);
		return -ENOMEM;
	}

	BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));

	priv->crtcs[priv->num_crtcs++] = crtc;

	return 0;
}
struct drm_encoder *omap_connector_attached_encoder(
		struct drm_connector *connector)
{
	int i;
	struct omap_connector *omap_connector = to_omap_connector(connector);

	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
		struct drm_mode_object *obj;

		if (connector->encoder_ids[i] == 0)
			break;

		obj = drm_mode_object_find(connector->dev,
				connector->encoder_ids[i],
				DRM_MODE_OBJECT_ENCODER);

		if (obj) {
			struct drm_encoder *encoder = obj_to_encoder(obj);
			struct omap_overlay_manager *mgr =
					omap_encoder_get_manager(encoder);
			DBG("%s: found %s", omap_connector->dssdev->name,
					mgr->name);
			return encoder;
		}
	}

	DBG("%s: no encoder", omap_connector->dssdev->name);

	return NULL;
}
Ejemplo n.º 3
0
/* 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;
}
Ejemplo n.º 4
0
/* when CRTC that we are attached to has potentially changed, this checks
 * if we are attached to proper manager, and if necessary updates.
 */
static void update_manager(struct drm_plane *plane)
{
	struct omap_drm_private *priv = plane->dev->dev_private;
	struct omap_plane *omap_plane = to_omap_plane(plane);
	struct omap_overlay *ovl = omap_plane->ovl;
	struct omap_overlay_manager *mgr = NULL;
	int i;

	if (plane->crtc) {
		for (i = 0; i < priv->num_encoders; i++) {
			struct drm_encoder *encoder = priv->encoders[i];
			if (encoder->crtc == plane->crtc) {
				mgr = omap_encoder_get_manager(encoder);
				break;
			}
		}
	}

	if (ovl->manager != mgr) {
		bool enabled = ovl->is_enabled(ovl);

		/* don't switch things around with enabled overlays: */
		if (enabled)
			omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);

		if (ovl->manager) {
			DBG("disconnecting %s from %s", ovl->name,
					ovl->manager->name);
			ovl->unset_manager(ovl);
		}

		if (mgr) {
			DBG("connecting %s to %s", ovl->name, mgr->name);
			ovl->set_manager(ovl, mgr);
		}

		if (enabled && mgr)
			omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
	}
}
Ejemplo n.º 5
0
static int omap_modeset_init(struct drm_device *dev)
{
	const struct omap_drm_platform_data *pdata = dev->dev->platform_data;
	struct omap_kms_platform_data *kms_pdata = NULL;
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_dss_device *dssdev = NULL;
	int i, j;
	unsigned int connected_connectors = 0;

	drm_mode_config_init(dev);

	if (pdata && pdata->kms_pdata) {
		kms_pdata = pdata->kms_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 < kms_pdata->mgr_cnt; i++) {
			struct omap_overlay_manager *mgr =
				omap_dss_get_overlay_manager(
						kms_pdata->mgr_ids[i]);
			create_encoder(dev, mgr);
		}

		for (i = 0; i < kms_pdata->dev_cnt; i++) {
			struct omap_dss_device *dssdev =
				omap_dss_find_device(
					(void *)kms_pdata->dev_names[i],
					match_dev_name);
			if (!dssdev) {
				dev_warn(dev->dev, "no such dssdev: %s\n",
						kms_pdata->dev_names[i]);
				continue;
			}
			create_connector(dev, dssdev);
		}

		connected_connectors = detect_connectors(dev);

		j = 0;
		for (i = 0; i < kms_pdata->ovl_cnt; i++) {
			struct omap_overlay *ovl =
				omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
			create_crtc(dev, ovl, &j, connected_connectors);
		}

		for (i = 0; i < kms_pdata->pln_cnt; i++) {
			struct omap_overlay *ovl =
				omap_dss_get_overlay(kms_pdata->pln_ids[i]);
			create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
		}
	} else {
		/* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try
		 * to make educated guesses about everything else
		 */
		int max_overlays = min(omap_dss_get_num_overlays(), num_crtc);

		for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
			create_encoder(dev, omap_dss_get_overlay_manager(i));
		}

		for_each_dss_dev(dssdev) {
			create_connector(dev, dssdev);
		}

		connected_connectors = detect_connectors(dev);

		j = 0;
		for (i = 0; i < max_overlays; i++) {
			create_crtc(dev, omap_dss_get_overlay(i),
					&j, connected_connectors);
		}

		/* use any remaining overlays as drm planes */
		for (; i < omap_dss_get_num_overlays(); i++) {
			struct omap_overlay *ovl = omap_dss_get_overlay(i);
			create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
		}
	}

	/* for now keep the mapping of CRTCs and encoders static.. */
	for (i = 0; i < priv->num_encoders; i++) {
		struct drm_encoder *encoder = priv->encoders[i];
		struct omap_overlay_manager *mgr =
				omap_encoder_get_manager(encoder);

		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;

		DBG("%s: possible_crtcs=%08x", mgr->name,
					encoder->possible_crtcs);
	}

	dump_video_chains();

	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;
}
Ejemplo n.º 6
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 {