Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d62fe5b authored by Tomi Valkeinen's avatar Tomi Valkeinen
Browse files

OMAPDSS: Merge omapdss topic branches

Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect(
			ret = connector_status_connected;
		else
			ret = connector_status_disconnected;
	} else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI ||
			dssdev->type == OMAP_DISPLAY_TYPE_DBI ||
			dssdev->type == OMAP_DISPLAY_TYPE_SDI ||
			dssdev->type == OMAP_DISPLAY_TYPE_DSI) {
		ret = connector_status_connected;
	} else {
		ret = connector_status_unknown;
	}
@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
	struct omap_video_timings timings = {0};
	struct drm_device *dev = connector->dev;
	struct drm_display_mode *new_mode;
	int ret = MODE_BAD;
	int r, ret = MODE_BAD;

	copy_timings_drm_to_omap(&timings, mode);
	mode->vrefresh = drm_mode_vrefresh(mode);

	if (!dssdrv->check_timings(dssdev, &timings)) {
	/*
	 * if the panel driver doesn't have a check_timings, it's most likely
	 * a fixed resolution panel, check if the timings match with the
	 * panel's timings
	 */
	if (dssdrv->check_timings) {
		r = dssdrv->check_timings(dssdev, &timings);
	} else {
		struct omap_video_timings t = {0};

		dssdrv->get_timings(dssdev, &t);

		if (memcmp(&timings, &t, sizeof(struct omap_video_timings)))
			r = -EINVAL;
		else
			r = 0;
	}

	if (!r) {
		/* check if vrefresh is still valid */
		new_mode = drm_mode_duplicate(dev, mode);
		new_mode->clock = timings.pixel_clock;
+14 −7
Original line number Diff line number Diff line
@@ -74,6 +74,13 @@ struct omap_crtc {
	struct work_struct page_flip_work;
};

uint32_t pipe2vbl(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	return dispc_mgr_get_vsync_irq(omap_crtc->channel);
}

/*
 * Manager-ops, callbacks from output when they need to configure
 * the upstream part of the video pipe.
@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
	omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
	omap_crtc->apply.post_apply = omap_crtc_post_apply;

	omap_crtc->apply_irq.irqmask = pipe2vbl(id);
	omap_crtc->channel = channel;
	omap_crtc->plane = plane;
	omap_crtc->plane->crtc = crtc;
	omap_crtc->name = channel_names[channel];
	omap_crtc->pipe = id;

	omap_crtc->apply_irq.irqmask = pipe2vbl(crtc);
	omap_crtc->apply_irq.irq = omap_crtc_apply_irq;

	omap_crtc->error_irq.irqmask =
@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
	omap_crtc->error_irq.irq = omap_crtc_error_irq;
	omap_irq_register(dev, &omap_crtc->error_irq);

	omap_crtc->channel = channel;
	omap_crtc->plane = plane;
	omap_crtc->plane->crtc = crtc;
	omap_crtc->name = channel_names[channel];
	omap_crtc->pipe = id;

	/* temporary: */
	omap_crtc->mgr.id = channel;

+133 −32
Original line number Diff line number Diff line
@@ -74,54 +74,53 @@ static int get_connector_type(struct omap_dss_device *dssdev)
	}
}

static bool channel_used(struct drm_device *dev, enum omap_channel channel)
{
	struct omap_drm_private *priv = dev->dev_private;
	int i;

	for (i = 0; i < priv->num_crtcs; i++) {
		struct drm_crtc *crtc = priv->crtcs[i];

		if (omap_crtc_channel(crtc) == channel)
			return true;
	}

	return false;
}

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;
	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);

	/*
	 * Create private planes and CRTCs for the last NUM_CRTCs overlay
	 * plus manager:
	 * 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.
	 */
	for (id = 0; id < min(num_crtc, num_ovls); id++) {
		struct drm_plane *plane;
		struct drm_crtc *crtc;
	num_crtcs = min3(num_crtc, num_mgrs, num_ovls);

		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;
	}
	dssdev = NULL;

	for_each_dss_dev(dssdev) {
		struct drm_connector *connector;
		struct drm_encoder *encoder;
		enum omap_channel channel;

		if (!dssdev->driver) {
			dev_warn(dev->dev, "%s has no driver.. skipping it\n",
					dssdev->name);
			return 0;
			continue;
		}

		if (!(dssdev->driver->get_timings ||
@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev)
			dev_warn(dev->dev, "%s driver does not support "
				"get_timings or read_edid.. skipping it!\n",
				dssdev->name);
			return 0;
			continue;
		}

		encoder = omap_encoder_init(dev, dssdev);
@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev)

		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.
		 */
		channel = dssdev->output->dispc_channel;

		/*
		 * 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);

		/* 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));
			struct drm_crtc *crtc = priv->crtcs[id];
			enum omap_channel crtc_channel;
			enum omap_dss_output_id supported_outputs;

			crtc_channel = omap_crtc_channel(crtc);
			supported_outputs =
				dss_feat_get_supported_outputs(crtc_channel);

			if (supported_outputs & dssdev->output->id)
				encoder->possible_crtcs |= (1 << id);
		}
	}

	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;

@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
	return ret;
}

struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
static struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
	DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH),
	DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH),
@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = {
};
#endif

struct platform_driver pdev = {
static struct platform_driver pdev = {
		.driver = {
			.name = DRIVER_NAME,
			.owner = THIS_MODULE,
+4 −34
Original line number Diff line number Diff line
@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
int omap_gem_resume(struct device *dev);
#endif

int omap_irq_enable_vblank(struct drm_device *dev, int crtc);
void omap_irq_disable_vblank(struct drm_device *dev, int crtc);
int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id);
void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id);
irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
void omap_irq_preinstall(struct drm_device *dev);
int omap_irq_postinstall(struct drm_device *dev);
@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp)
	return ALIGN(pitch, 8 * bytespp);
}

static inline enum omap_channel pipe2chan(int pipe)
{
	int num_mgrs = dss_feat_get_num_mgrs();

	/*
	 * 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.  The higher #'d managers tend
	 * to have more features so start in reverse order.
	 */
	return num_mgrs - pipe - 1;
}

/* map crtc to vblank mask */
static inline uint32_t pipe2vbl(int crtc)
{
	enum omap_channel channel = pipe2chan(crtc);
	return dispc_mgr_get_vsync_irq(channel);
}

static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc)
{
	struct omap_drm_private *priv = dev->dev_private;
	int i;

	for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++)
		if (priv->crtcs[i] == crtc)
			return i;

	BUG();  /* bogus CRTC ptr */
	return -1;
}
uint32_t pipe2vbl(struct drm_crtc *crtc);
struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);

/* should these be made into common util helpers?
 */
+22 −2
Original line number Diff line number Diff line
@@ -41,6 +41,13 @@ struct omap_encoder {
	struct omap_dss_device *dssdev;
};

struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
{
	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);

	return omap_encoder->dssdev;
}

static void omap_encoder_destroy(struct drm_encoder *encoder)
{
	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
@@ -128,12 +135,25 @@ int omap_encoder_update(struct drm_encoder *encoder,

	dssdev->output->manager = mgr;

	if (dssdrv->check_timings) {
		ret = dssdrv->check_timings(dssdev, timings);
	} else {
		struct omap_video_timings t = {0};

		dssdrv->get_timings(dssdev, &t);

		if (memcmp(timings, &t, sizeof(struct omap_video_timings)))
			ret = -EINVAL;
		else
			ret = 0;
	}

	if (ret) {
		dev_err(dev->dev, "could not set timings: %d\n", ret);
		return ret;
	}

	if (dssdrv->set_timings)
		dssdrv->set_timings(dssdev, timings);

	return 0;
Loading