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

Commit 3e54f5b7 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'exynos-drm-next' of...

Merge branch 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung into drm-core-next

* 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung:
  drm/exynos: Add plane support with fimd
  drm/exynos: add runtime pm feature for fimd
  drm/exynos: updated crtc and encoder dpms framework.
  drm/exynos: Use struct drm_mode_fb_cmd2
  drm/exynos: Fix compile errors
parents d0d110e0 864ee9e6
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
		exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o
		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
		exynos_drm_plane.o

obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
+53 −6
Original line number Diff line number Diff line
@@ -52,11 +52,13 @@
 *	drm framework doesn't support multiple irq yet.
 *	we can refer to the crtc to current hardware interrupt occured through
 *	this pipe value.
 * @dpms: store the crtc dpms value
 */
struct exynos_drm_crtc {
	struct drm_crtc			drm_crtc;
	struct exynos_drm_overlay	overlay;
	unsigned int			pipe;
	unsigned int			dpms;
};

static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
@@ -153,26 +155,37 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)

static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
	struct drm_device *dev = crtc->dev;
	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);

	if (exynos_crtc->dpms == mode) {
		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
		return;
	}

	mutex_lock(&dev->struct_mutex);

	switch (mode) {
	case DRM_MODE_DPMS_ON:
		exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
				exynos_drm_encoder_crtc_commit);
		exynos_drm_fn_encoder(crtc, &mode,
				exynos_drm_encoder_crtc_dpms);
		exynos_crtc->dpms = mode;
		break;
	case DRM_MODE_DPMS_STANDBY:
	case DRM_MODE_DPMS_SUSPEND:
	case DRM_MODE_DPMS_OFF:
		/* TODO */
		exynos_drm_fn_encoder(crtc, NULL,
				exynos_drm_encoder_crtc_disable);
		exynos_drm_fn_encoder(crtc, &mode,
				exynos_drm_encoder_crtc_dpms);
		exynos_crtc->dpms = mode;
		break;
	default:
		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
		DRM_ERROR("unspecified mode %d\n", mode);
		break;
	}

	mutex_unlock(&dev->struct_mutex);
}

static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
@@ -188,6 +201,28 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)

	DRM_DEBUG_KMS("%s\n", __FILE__);

	/*
	 * when set_crtc is requested from user or at booting time,
	 * crtc->commit would be called without dpms call so if dpms is
	 * no power on then crtc->dpms should be called
	 * with DRM_MODE_DPMS_ON for the hardware power to be on.
	 */
	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
		int mode = DRM_MODE_DPMS_ON;

		/*
		 * enable hardware(power on) to all encoders hdmi connected
		 * to current crtc.
		 */
		exynos_drm_crtc_dpms(crtc, mode);
		/*
		 * enable dma to all encoders connected to current crtc and
		 * lcd panel.
		 */
		exynos_drm_fn_encoder(crtc, &mode,
					exynos_drm_encoder_dpms_from_crtc);
	}

	exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
			exynos_drm_encoder_crtc_commit);
}
@@ -344,6 +379,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
	}

	exynos_crtc->pipe = nr;
	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
	exynos_crtc->overlay.zpos = DEFAULT_ZPOS;
	crtc = &exynos_crtc->drm_crtc;

	private->crtc[nr] = crtc;
@@ -357,9 +394,14 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
{
	struct exynos_drm_private *private = dev->dev_private;
	struct exynos_drm_crtc *exynos_crtc =
		to_exynos_crtc(private->crtc[crtc]);

	DRM_DEBUG_KMS("%s\n", __FILE__);

	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
		return -EPERM;

	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
			exynos_drm_enable_vblank);

@@ -369,9 +411,14 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
{
	struct exynos_drm_private *private = dev->dev_private;
	struct exynos_drm_crtc *exynos_crtc =
		to_exynos_crtc(private->crtc[crtc]);

	DRM_DEBUG_KMS("%s\n", __FILE__);

	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
		return;

	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
			exynos_drm_disable_vblank);
}
+20 −9
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"

#define DRIVER_NAME	"exynos-drm"
#define DRIVER_DESC	"Samsung SoC DRM"
@@ -77,6 +78,12 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
			goto err_crtc;
	}

	for (nr = 0; nr < MAX_PLANE; nr++) {
		ret = exynos_plane_init(dev, nr);
		if (ret)
			goto err_crtc;
	}

	ret = drm_vblank_init(dev, MAX_CRTC);
	if (ret)
		goto err_crtc;
@@ -163,6 +170,18 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
			DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
			DRM_UNLOCKED | DRM_AUTH),
};

static const struct file_operations exynos_drm_driver_fops = {
	.owner		= THIS_MODULE,
	.open		= drm_open,
	.mmap		= exynos_drm_gem_mmap,
	.poll		= drm_poll,
	.read		= drm_read,
	.unlocked_ioctl	= drm_ioctl,
	.release	= drm_release,
};

static struct drm_driver exynos_drm_driver = {
@@ -182,15 +201,7 @@ static struct drm_driver exynos_drm_driver = {
	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
	.dumb_destroy		= exynos_drm_gem_dumb_destroy,
	.ioctls			= exynos_ioctls,
	.fops = {
		.owner		= THIS_MODULE,
		.open		= drm_open,
		.mmap		= exynos_drm_gem_mmap,
		.poll		= drm_poll,
		.read		= drm_read,
		.unlocked_ioctl	= drm_ioctl,
		.release	= drm_release,
	},
	.fops			= &exynos_drm_driver_fops,
	.name	= DRIVER_NAME,
	.desc	= DRIVER_DESC,
	.date	= DRIVER_DATE,
+10 −4
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@
#include "drm.h"

#define MAX_CRTC	2
#define MAX_PLANE	5
#define DEFAULT_ZPOS	-1

struct drm_device;
struct exynos_drm_overlay;
@@ -57,8 +59,8 @@ enum exynos_drm_output_type {
struct exynos_drm_overlay_ops {
	void (*mode_set)(struct device *subdrv_dev,
			 struct exynos_drm_overlay *overlay);
	void (*commit)(struct device *subdrv_dev);
	void (*disable)(struct device *subdrv_dev);
	void (*commit)(struct device *subdrv_dev, int zpos);
	void (*disable)(struct device *subdrv_dev, int zpos);
};

/*
@@ -83,6 +85,7 @@ struct exynos_drm_overlay_ops {
 * @dma_addr: bus(accessed by dma) address to the memory region allocated
 *	for a overlay.
 * @vaddr: virtual memory addresss to this overlay.
 * @zpos: order of overlay layer(z position).
 * @default_win: a window to be enabled.
 * @color_key: color key on or off.
 * @index_color: if using color key feature then this value would be used
@@ -111,6 +114,7 @@ struct exynos_drm_overlay {
	unsigned int pitch;
	dma_addr_t dma_addr;
	void __iomem *vaddr;
	int zpos;

	bool default_win;
	bool color_key;
@@ -144,17 +148,19 @@ struct exynos_drm_display_ops {
/*
 * Exynos drm manager ops
 *
 * @dpms: control device power.
 * @apply: set timing, vblank and overlay data to registers.
 * @mode_set: convert drm_display_mode to hw specific display mode and
 *	      would be called by encoder->mode_set().
 * @commit: set current hw specific display mode to hw.
 * @disable: disable hardware specific display mode.
 * @enable_vblank: specific driver callback for enabling vblank interrupt.
 * @disable_vblank: specific driver callback for disabling vblank interrupt.
 */
struct exynos_drm_manager_ops {
	void (*dpms)(struct device *subdrv_dev, int mode);
	void (*apply)(struct device *subdrv_dev);
	void (*mode_set)(struct device *subdrv_dev, void *mode);
	void (*commit)(struct device *subdrv_dev);
	void (*disable)(struct device *subdrv_dev);
	int (*enable_vblank)(struct device *subdrv_dev);
	void (*disable_vblank)(struct device *subdrv_dev);
};
+105 −30
Original line number Diff line number Diff line
@@ -42,49 +42,68 @@
 * @drm_encoder: encoder object.
 * @manager: specific encoder has its own manager to control a hardware
 *	appropriately and we can access a hardware drawing on this manager.
 * @dpms: store the encoder dpms value.
 */
struct exynos_drm_encoder {
	struct drm_encoder		drm_encoder;
	struct exynos_drm_manager	*manager;
	int dpms;
};

static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
{
	struct drm_device *dev = encoder->dev;
	struct drm_connector *connector;
	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->encoder == encoder) {
			struct exynos_drm_display_ops *display_ops =
							manager->display_ops;

			DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
					connector->base.id, mode);
			if (display_ops && display_ops->power_on)
				display_ops->power_on(manager->dev, mode);
		}
	}
}

static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
	struct drm_device *dev = encoder->dev;
	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
	struct exynos_drm_manager_ops *manager_ops = manager->ops;
	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);

	DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);

	if (exynos_encoder->dpms == mode) {
		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
		return;
	}

	mutex_lock(&dev->struct_mutex);

	switch (mode) {
	case DRM_MODE_DPMS_ON:
		if (manager_ops && manager_ops->commit)
			manager_ops->commit(manager->dev);
		if (manager_ops && manager_ops->apply)
			manager_ops->apply(manager->dev);
		exynos_drm_display_power(encoder, mode);
		exynos_encoder->dpms = mode;
		break;
	case DRM_MODE_DPMS_STANDBY:
	case DRM_MODE_DPMS_SUSPEND:
	case DRM_MODE_DPMS_OFF:
		/* TODO */
		if (manager_ops && manager_ops->disable)
			manager_ops->disable(manager->dev);
		exynos_drm_display_power(encoder, mode);
		exynos_encoder->dpms = mode;
		break;
	default:
		DRM_ERROR("unspecified mode %d\n", mode);
		break;
	}

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->encoder == encoder) {
			struct exynos_drm_display_ops *display_ops =
							manager->display_ops;

			DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
					connector->base.id, mode);
			if (display_ops && display_ops->power_on)
				display_ops->power_on(manager->dev, mode);
		}
	}
	mutex_unlock(&dev->struct_mutex);
}

static bool
@@ -169,7 +188,6 @@ static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
	exynos_encoder->manager->pipe = -1;

	drm_encoder_cleanup(encoder);
	encoder->dev->mode_config.num_encoder--;
	kfree(exynos_encoder);
}

@@ -199,6 +217,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
		return NULL;
	}

	exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
	exynos_encoder->manager = manager;
	encoder = &exynos_encoder->drm_encoder;
	encoder->possible_crtcs = possible_crtcs;
@@ -275,12 +294,27 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
		manager_ops->disable_vblank(manager->dev);
}

void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
					  void *data)
{
	struct exynos_drm_manager *manager =
		to_exynos_encoder(encoder)->manager;
	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
	int zpos = DEFAULT_ZPOS;

	if (data)
		zpos = *(int *)data;

	if (overlay_ops && overlay_ops->commit)
		overlay_ops->commit(manager->dev, zpos);
}

void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
{
	struct exynos_drm_manager *manager =
		to_exynos_encoder(encoder)->manager;
	int crtc = *(int *)data;
	int zpos = DEFAULT_ZPOS;

	DRM_DEBUG_KMS("%s\n", __FILE__);

@@ -290,8 +324,53 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
	 */
	manager->pipe = crtc;

	if (overlay_ops && overlay_ops->commit)
		overlay_ops->commit(manager->dev);
	exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
}

void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
{
	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
	int mode = *(int *)data;

	DRM_DEBUG_KMS("%s\n", __FILE__);

	exynos_drm_encoder_dpms(encoder, mode);

	exynos_encoder->dpms = mode;
}

void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
{
	struct drm_device *dev = encoder->dev;
	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
	struct exynos_drm_manager *manager = exynos_encoder->manager;
	struct exynos_drm_manager_ops *manager_ops = manager->ops;
	struct drm_connector *connector;
	int mode = *(int *)data;

	DRM_DEBUG_KMS("%s\n", __FILE__);

	if (manager_ops && manager_ops->dpms)
		manager_ops->dpms(manager->dev, mode);

	/*
	 * set current dpms mode to the connector connected to
	 * current encoder. connector->dpms would be checked
	 * at drm_helper_connector_dpms()
	 */
	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
		if (connector->encoder == encoder)
			connector->dpms = mode;

	/*
	 * if this condition is ok then it means that the crtc is already
	 * detached from encoder and last function for detaching is properly
	 * done, so clear pipe from manager to prevent repeated call.
	 */
	if (mode > DRM_MODE_DPMS_ON) {
		if (!encoder->crtc)
			manager->pipe = -1;
	}
}

void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
@@ -310,19 +389,15 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
	struct exynos_drm_manager *manager =
		to_exynos_encoder(encoder)->manager;
	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
	int zpos = DEFAULT_ZPOS;

	DRM_DEBUG_KMS("\n");

	if (overlay_ops && overlay_ops->disable)
		overlay_ops->disable(manager->dev);
	if (data)
		zpos = *(int *)data;

	/*
	 * crtc is already detached from encoder and last
	 * function for detaching is properly done, so
	 * clear pipe from manager to prevent repeated call
	 */
	if (!encoder->crtc)
		manager->pipe = -1;
	if (overlay_ops && overlay_ops->disable)
		overlay_ops->disable(manager->dev, zpos);
}

MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
Loading