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
This commit is contained in:
commit
3e54f5b72b
13 changed files with 567 additions and 127 deletions
|
@ -5,7 +5,8 @@
|
||||||
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
|
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
|
||||||
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
|
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_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) += exynosdrm.o
|
||||||
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||||
|
|
|
@ -52,11 +52,13 @@
|
||||||
* drm framework doesn't support multiple irq yet.
|
* drm framework doesn't support multiple irq yet.
|
||||||
* we can refer to the crtc to current hardware interrupt occured through
|
* we can refer to the crtc to current hardware interrupt occured through
|
||||||
* this pipe value.
|
* this pipe value.
|
||||||
|
* @dpms: store the crtc dpms value
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_crtc {
|
struct exynos_drm_crtc {
|
||||||
struct drm_crtc drm_crtc;
|
struct drm_crtc drm_crtc;
|
||||||
struct exynos_drm_overlay overlay;
|
struct exynos_drm_overlay overlay;
|
||||||
unsigned int pipe;
|
unsigned int pipe;
|
||||||
|
unsigned int dpms;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
|
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)
|
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);
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
|
||||||
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
|
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) {
|
switch (mode) {
|
||||||
case DRM_MODE_DPMS_ON:
|
case DRM_MODE_DPMS_ON:
|
||||||
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
exynos_drm_fn_encoder(crtc, &mode,
|
||||||
exynos_drm_encoder_crtc_commit);
|
exynos_drm_encoder_crtc_dpms);
|
||||||
|
exynos_crtc->dpms = mode;
|
||||||
break;
|
break;
|
||||||
case DRM_MODE_DPMS_STANDBY:
|
case DRM_MODE_DPMS_STANDBY:
|
||||||
case DRM_MODE_DPMS_SUSPEND:
|
case DRM_MODE_DPMS_SUSPEND:
|
||||||
case DRM_MODE_DPMS_OFF:
|
case DRM_MODE_DPMS_OFF:
|
||||||
/* TODO */
|
exynos_drm_fn_encoder(crtc, &mode,
|
||||||
exynos_drm_fn_encoder(crtc, NULL,
|
exynos_drm_encoder_crtc_dpms);
|
||||||
exynos_drm_encoder_crtc_disable);
|
exynos_crtc->dpms = mode;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
|
DRM_ERROR("unspecified mode %d\n", mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
|
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__);
|
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_fn_encoder(crtc, &exynos_crtc->pipe,
|
||||||
exynos_drm_encoder_crtc_commit);
|
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->pipe = nr;
|
||||||
|
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
|
||||||
|
exynos_crtc->overlay.zpos = DEFAULT_ZPOS;
|
||||||
crtc = &exynos_crtc->drm_crtc;
|
crtc = &exynos_crtc->drm_crtc;
|
||||||
|
|
||||||
private->crtc[nr] = 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)
|
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
struct exynos_drm_private *private = dev->dev_private;
|
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__);
|
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_fn_encoder(private->crtc[crtc], &crtc,
|
||||||
exynos_drm_enable_vblank);
|
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)
|
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
struct exynos_drm_private *private = dev->dev_private;
|
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__);
|
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_fn_encoder(private->crtc[crtc], &crtc,
|
||||||
exynos_drm_disable_vblank);
|
exynos_drm_disable_vblank);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "exynos_drm_fbdev.h"
|
#include "exynos_drm_fbdev.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_gem.h"
|
||||||
|
#include "exynos_drm_plane.h"
|
||||||
|
|
||||||
#define DRIVER_NAME "exynos-drm"
|
#define DRIVER_NAME "exynos-drm"
|
||||||
#define DRIVER_DESC "Samsung SoC 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;
|
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);
|
ret = drm_vblank_init(dev, MAX_CRTC);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_crtc;
|
goto err_crtc;
|
||||||
|
@ -163,6 +170,18 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
|
||||||
DRM_AUTH),
|
DRM_AUTH),
|
||||||
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
|
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
|
||||||
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
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 = {
|
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_map_offset = exynos_drm_gem_dumb_map_offset,
|
||||||
.dumb_destroy = exynos_drm_gem_dumb_destroy,
|
.dumb_destroy = exynos_drm_gem_dumb_destroy,
|
||||||
.ioctls = exynos_ioctls,
|
.ioctls = exynos_ioctls,
|
||||||
.fops = {
|
.fops = &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,
|
|
||||||
},
|
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.desc = DRIVER_DESC,
|
.desc = DRIVER_DESC,
|
||||||
.date = DRIVER_DATE,
|
.date = DRIVER_DATE,
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
|
|
||||||
#define MAX_CRTC 2
|
#define MAX_CRTC 2
|
||||||
|
#define MAX_PLANE 5
|
||||||
|
#define DEFAULT_ZPOS -1
|
||||||
|
|
||||||
struct drm_device;
|
struct drm_device;
|
||||||
struct exynos_drm_overlay;
|
struct exynos_drm_overlay;
|
||||||
|
@ -57,8 +59,8 @@ enum exynos_drm_output_type {
|
||||||
struct exynos_drm_overlay_ops {
|
struct exynos_drm_overlay_ops {
|
||||||
void (*mode_set)(struct device *subdrv_dev,
|
void (*mode_set)(struct device *subdrv_dev,
|
||||||
struct exynos_drm_overlay *overlay);
|
struct exynos_drm_overlay *overlay);
|
||||||
void (*commit)(struct device *subdrv_dev);
|
void (*commit)(struct device *subdrv_dev, int zpos);
|
||||||
void (*disable)(struct device *subdrv_dev);
|
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
|
* @dma_addr: bus(accessed by dma) address to the memory region allocated
|
||||||
* for a overlay.
|
* for a overlay.
|
||||||
* @vaddr: virtual memory addresss to this overlay.
|
* @vaddr: virtual memory addresss to this overlay.
|
||||||
|
* @zpos: order of overlay layer(z position).
|
||||||
* @default_win: a window to be enabled.
|
* @default_win: a window to be enabled.
|
||||||
* @color_key: color key on or off.
|
* @color_key: color key on or off.
|
||||||
* @index_color: if using color key feature then this value would be used
|
* @index_color: if using color key feature then this value would be used
|
||||||
|
@ -111,6 +114,7 @@ struct exynos_drm_overlay {
|
||||||
unsigned int pitch;
|
unsigned int pitch;
|
||||||
dma_addr_t dma_addr;
|
dma_addr_t dma_addr;
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
|
int zpos;
|
||||||
|
|
||||||
bool default_win;
|
bool default_win;
|
||||||
bool color_key;
|
bool color_key;
|
||||||
|
@ -144,17 +148,19 @@ struct exynos_drm_display_ops {
|
||||||
/*
|
/*
|
||||||
* Exynos drm manager 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
|
* @mode_set: convert drm_display_mode to hw specific display mode and
|
||||||
* would be called by encoder->mode_set().
|
* would be called by encoder->mode_set().
|
||||||
* @commit: set current hw specific display mode to hw.
|
* @commit: set current hw specific display mode to hw.
|
||||||
* @disable: disable hardware specific display mode.
|
|
||||||
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
||||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_manager_ops {
|
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 (*mode_set)(struct device *subdrv_dev, void *mode);
|
||||||
void (*commit)(struct device *subdrv_dev);
|
void (*commit)(struct device *subdrv_dev);
|
||||||
void (*disable)(struct device *subdrv_dev);
|
|
||||||
int (*enable_vblank)(struct device *subdrv_dev);
|
int (*enable_vblank)(struct device *subdrv_dev);
|
||||||
void (*disable_vblank)(struct device *subdrv_dev);
|
void (*disable_vblank)(struct device *subdrv_dev);
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,37 +42,19 @@
|
||||||
* @drm_encoder: encoder object.
|
* @drm_encoder: encoder object.
|
||||||
* @manager: specific encoder has its own manager to control a hardware
|
* @manager: specific encoder has its own manager to control a hardware
|
||||||
* appropriately and we can access a hardware drawing on this manager.
|
* appropriately and we can access a hardware drawing on this manager.
|
||||||
|
* @dpms: store the encoder dpms value.
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_encoder {
|
struct exynos_drm_encoder {
|
||||||
struct drm_encoder drm_encoder;
|
struct drm_encoder drm_encoder;
|
||||||
struct exynos_drm_manager *manager;
|
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_device *dev = encoder->dev;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
||||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case DRM_MODE_DPMS_ON:
|
|
||||||
if (manager_ops && manager_ops->commit)
|
|
||||||
manager_ops->commit(manager->dev);
|
|
||||||
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);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DRM_ERROR("unspecified mode %d\n", mode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||||
if (connector->encoder == encoder) {
|
if (connector->encoder == encoder) {
|
||||||
|
@ -87,6 +69,43 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int 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->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:
|
||||||
|
exynos_drm_display_power(encoder, mode);
|
||||||
|
exynos_encoder->dpms = mode;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("unspecified mode %d\n", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
|
exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||||
struct drm_display_mode *mode,
|
struct drm_display_mode *mode,
|
||||||
|
@ -169,7 +188,6 @@ static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
|
||||||
exynos_encoder->manager->pipe = -1;
|
exynos_encoder->manager->pipe = -1;
|
||||||
|
|
||||||
drm_encoder_cleanup(encoder);
|
drm_encoder_cleanup(encoder);
|
||||||
encoder->dev->mode_config.num_encoder--;
|
|
||||||
kfree(exynos_encoder);
|
kfree(exynos_encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,6 +217,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
|
||||||
exynos_encoder->manager = manager;
|
exynos_encoder->manager = manager;
|
||||||
encoder = &exynos_encoder->drm_encoder;
|
encoder = &exynos_encoder->drm_encoder;
|
||||||
encoder->possible_crtcs = possible_crtcs;
|
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);
|
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 =
|
struct exynos_drm_manager *manager =
|
||||||
to_exynos_encoder(encoder)->manager;
|
to_exynos_encoder(encoder)->manager;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
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 crtc = *(int *)data;
|
||||||
|
int zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
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;
|
manager->pipe = crtc;
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->commit)
|
exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
|
||||||
overlay_ops->commit(manager->dev);
|
}
|
||||||
|
|
||||||
|
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)
|
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 =
|
struct exynos_drm_manager *manager =
|
||||||
to_exynos_encoder(encoder)->manager;
|
to_exynos_encoder(encoder)->manager;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
|
int zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("\n");
|
DRM_DEBUG_KMS("\n");
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->disable)
|
if (data)
|
||||||
overlay_ops->disable(manager->dev);
|
zpos = *(int *)data;
|
||||||
|
|
||||||
/*
|
if (overlay_ops && overlay_ops->disable)
|
||||||
* crtc is already detached from encoder and last
|
overlay_ops->disable(manager->dev, zpos);
|
||||||
* function for detaching is properly done, so
|
|
||||||
* clear pipe from manager to prevent repeated call
|
|
||||||
*/
|
|
||||||
if (!encoder->crtc)
|
|
||||||
manager->pipe = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||||
|
|
|
@ -39,7 +39,12 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
||||||
void (*fn)(struct drm_encoder *, void *));
|
void (*fn)(struct drm_encoder *, void *));
|
||||||
void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
|
void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
|
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
|
||||||
|
void *data);
|
||||||
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
|
||||||
|
void *data);
|
||||||
|
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
|
||||||
|
|
||||||
static struct drm_framebuffer *
|
static struct drm_framebuffer *
|
||||||
exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
||||||
struct drm_mode_fb_cmd *mode_cmd)
|
struct drm_mode_fb_cmd2 *mode_cmd)
|
||||||
{
|
{
|
||||||
struct exynos_drm_fb *exynos_fb;
|
struct exynos_drm_fb *exynos_fb;
|
||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
|
@ -115,9 +115,6 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
mode_cmd->pitch = max(mode_cmd->pitch,
|
|
||||||
mode_cmd->width * (mode_cmd->bpp >> 3));
|
|
||||||
|
|
||||||
DRM_LOG_KMS("drm fb create(%dx%d)\n",
|
DRM_LOG_KMS("drm fb create(%dx%d)\n",
|
||||||
mode_cmd->width, mode_cmd->height);
|
mode_cmd->width, mode_cmd->height);
|
||||||
|
|
||||||
|
@ -136,14 +133,14 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
||||||
|
|
||||||
DRM_LOG_KMS("create: fb id: %d\n", fb->base.id);
|
DRM_LOG_KMS("create: fb id: %d\n", fb->base.id);
|
||||||
|
|
||||||
size = mode_cmd->pitch * mode_cmd->height;
|
size = mode_cmd->pitches[0] * mode_cmd->height;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mode_cmd->handle could be NULL at booting time or
|
* mode_cmd->handles[0] could be NULL at booting time or
|
||||||
* with user request. if NULL, a new buffer or a gem object
|
* with user request. if NULL, a new buffer or a gem object
|
||||||
* would be allocated.
|
* would be allocated.
|
||||||
*/
|
*/
|
||||||
if (!mode_cmd->handle) {
|
if (!mode_cmd->handles[0]) {
|
||||||
if (!file_priv) {
|
if (!file_priv) {
|
||||||
struct exynos_drm_gem_buf *buffer;
|
struct exynos_drm_gem_buf *buffer;
|
||||||
|
|
||||||
|
@ -166,7 +163,7 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
|
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
|
||||||
&mode_cmd->handle,
|
&mode_cmd->handles[0],
|
||||||
size);
|
size);
|
||||||
if (IS_ERR(exynos_gem_obj)) {
|
if (IS_ERR(exynos_gem_obj)) {
|
||||||
ret = PTR_ERR(exynos_gem_obj);
|
ret = PTR_ERR(exynos_gem_obj);
|
||||||
|
@ -174,7 +171,8 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
|
obj = drm_gem_object_lookup(dev, file_priv,
|
||||||
|
mode_cmd->handles[0]);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
DRM_ERROR("failed to lookup gem object.\n");
|
DRM_ERROR("failed to lookup gem object.\n");
|
||||||
goto err_buffer;
|
goto err_buffer;
|
||||||
|
@ -214,8 +212,8 @@ err_init:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
||||||
struct drm_file *file_priv,
|
struct drm_file *file_priv,
|
||||||
struct drm_mode_fb_cmd *mode_cmd)
|
struct drm_mode_fb_cmd2 *mode_cmd)
|
||||||
{
|
{
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
#define _EXYNOS_DRM_FB_H
|
#define _EXYNOS_DRM_FB_H
|
||||||
|
|
||||||
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
||||||
struct drm_file *filp,
|
struct drm_file *filp,
|
||||||
struct drm_mode_fb_cmd *mode_cmd);
|
struct drm_mode_fb_cmd2 *mode_cmd);
|
||||||
|
|
||||||
void exynos_drm_mode_config_init(struct drm_device *dev);
|
void exynos_drm_mode_config_init(struct drm_device *dev);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
||||||
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
||||||
struct drm_device *dev = helper->dev;
|
struct drm_device *dev = helper->dev;
|
||||||
struct fb_info *fbi;
|
struct fb_info *fbi;
|
||||||
struct drm_mode_fb_cmd mode_cmd = { 0 };
|
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
|
||||||
struct platform_device *pdev = dev->platformdev;
|
struct platform_device *pdev = dev->platformdev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -138,8 +138,9 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
||||||
|
|
||||||
mode_cmd.width = sizes->surface_width;
|
mode_cmd.width = sizes->surface_width;
|
||||||
mode_cmd.height = sizes->surface_height;
|
mode_cmd.height = sizes->surface_height;
|
||||||
mode_cmd.bpp = sizes->surface_bpp;
|
mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
|
||||||
mode_cmd.depth = sizes->surface_depth;
|
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||||
|
sizes->surface_depth);
|
||||||
|
|
||||||
mutex_lock(&dev->struct_mutex);
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
@ -206,7 +207,7 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
|
||||||
struct drm_device *dev = helper->dev;
|
struct drm_device *dev = helper->dev;
|
||||||
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
||||||
struct drm_framebuffer *fb = exynos_fbdev->fb;
|
struct drm_framebuffer *fb = exynos_fbdev->fb;
|
||||||
struct drm_mode_fb_cmd mode_cmd = { 0 };
|
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
@ -220,8 +221,9 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
|
||||||
|
|
||||||
mode_cmd.width = sizes->surface_width;
|
mode_cmd.width = sizes->surface_width;
|
||||||
mode_cmd.height = sizes->surface_height;
|
mode_cmd.height = sizes->surface_height;
|
||||||
mode_cmd.bpp = sizes->surface_bpp;
|
mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
|
||||||
mode_cmd.depth = sizes->surface_depth;
|
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||||
|
sizes->surface_depth);
|
||||||
|
|
||||||
if (fb->funcs->destroy)
|
if (fb->funcs->destroy)
|
||||||
fb->funcs->destroy(fb);
|
fb->funcs->destroy(fb);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
#include <plat/regs-fb-v4.h>
|
#include <plat/regs-fb-v4.h>
|
||||||
|
@ -68,6 +69,7 @@ struct fimd_win_data {
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
unsigned int buf_offsize;
|
unsigned int buf_offsize;
|
||||||
unsigned int line_size; /* bytes */
|
unsigned int line_size; /* bytes */
|
||||||
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fimd_context {
|
struct fimd_context {
|
||||||
|
@ -84,6 +86,7 @@ struct fimd_context {
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
u32 vidcon0;
|
u32 vidcon0;
|
||||||
u32 vidcon1;
|
u32 vidcon1;
|
||||||
|
bool suspended;
|
||||||
|
|
||||||
struct fb_videomode *timing;
|
struct fb_videomode *timing;
|
||||||
};
|
};
|
||||||
|
@ -119,7 +122,7 @@ static int fimd_display_power_on(struct device *dev, int mode)
|
||||||
{
|
{
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
/* TODO. */
|
/* TODO */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +135,46 @@ static struct exynos_drm_display_ops fimd_display_ops = {
|
||||||
.power_on = fimd_display_power_on,
|
.power_on = fimd_display_power_on,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void fimd_dpms(struct device *subdrv_dev, int mode)
|
||||||
|
{
|
||||||
|
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case DRM_MODE_DPMS_ON:
|
||||||
|
pm_runtime_get_sync(subdrv_dev);
|
||||||
|
break;
|
||||||
|
case DRM_MODE_DPMS_STANDBY:
|
||||||
|
case DRM_MODE_DPMS_SUSPEND:
|
||||||
|
case DRM_MODE_DPMS_OFF:
|
||||||
|
pm_runtime_put_sync(subdrv_dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fimd_apply(struct device *subdrv_dev)
|
||||||
|
{
|
||||||
|
struct fimd_context *ctx = get_fimd_context(subdrv_dev);
|
||||||
|
struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
|
||||||
|
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
|
||||||
|
struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
|
||||||
|
struct fimd_win_data *win_data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
for (i = 0; i < WINDOWS_NR; i++) {
|
||||||
|
win_data = &ctx->win_data[i];
|
||||||
|
if (win_data->enabled && (ovl_ops && ovl_ops->commit))
|
||||||
|
ovl_ops->commit(subdrv_dev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mgr_ops && mgr_ops->commit)
|
||||||
|
mgr_ops->commit(subdrv_dev);
|
||||||
|
}
|
||||||
|
|
||||||
static void fimd_commit(struct device *dev)
|
static void fimd_commit(struct device *dev)
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
|
@ -177,40 +220,6 @@ static void fimd_commit(struct device *dev)
|
||||||
writel(val, ctx->regs + VIDCON0);
|
writel(val, ctx->regs + VIDCON0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimd_disable(struct device *dev)
|
|
||||||
{
|
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
|
||||||
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
|
|
||||||
struct drm_device *drm_dev = subdrv->drm_dev;
|
|
||||||
struct exynos_drm_manager *manager = &subdrv->manager;
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
|
||||||
|
|
||||||
/* fimd dma off */
|
|
||||||
val = readl(ctx->regs + VIDCON0);
|
|
||||||
val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F);
|
|
||||||
writel(val, ctx->regs + VIDCON0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if vblank is enabled status with dma off then
|
|
||||||
* it disables vsync interrupt.
|
|
||||||
*/
|
|
||||||
if (drm_dev->vblank_enabled[manager->pipe] &&
|
|
||||||
atomic_read(&drm_dev->vblank_refcount[manager->pipe])) {
|
|
||||||
drm_vblank_put(drm_dev, manager->pipe);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if vblank_disable_allowed is 0 then disable
|
|
||||||
* vsync interrupt right now else the vsync interrupt
|
|
||||||
* would be disabled by drm timer once a current process
|
|
||||||
* gives up ownershop of vblank event.
|
|
||||||
*/
|
|
||||||
if (!drm_dev->vblank_disable_allowed)
|
|
||||||
drm_vblank_off(drm_dev, manager->pipe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fimd_enable_vblank(struct device *dev)
|
static int fimd_enable_vblank(struct device *dev)
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
|
@ -218,6 +227,9 @@ static int fimd_enable_vblank(struct device *dev)
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (ctx->suspended)
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
if (!test_and_set_bit(0, &ctx->irq_flags)) {
|
if (!test_and_set_bit(0, &ctx->irq_flags)) {
|
||||||
val = readl(ctx->regs + VIDINTCON0);
|
val = readl(ctx->regs + VIDINTCON0);
|
||||||
|
|
||||||
|
@ -242,6 +254,9 @@ static void fimd_disable_vblank(struct device *dev)
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (ctx->suspended)
|
||||||
|
return;
|
||||||
|
|
||||||
if (test_and_clear_bit(0, &ctx->irq_flags)) {
|
if (test_and_clear_bit(0, &ctx->irq_flags)) {
|
||||||
val = readl(ctx->regs + VIDINTCON0);
|
val = readl(ctx->regs + VIDINTCON0);
|
||||||
|
|
||||||
|
@ -253,8 +268,9 @@ static void fimd_disable_vblank(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct exynos_drm_manager_ops fimd_manager_ops = {
|
static struct exynos_drm_manager_ops fimd_manager_ops = {
|
||||||
|
.dpms = fimd_dpms,
|
||||||
|
.apply = fimd_apply,
|
||||||
.commit = fimd_commit,
|
.commit = fimd_commit,
|
||||||
.disable = fimd_disable,
|
|
||||||
.enable_vblank = fimd_enable_vblank,
|
.enable_vblank = fimd_enable_vblank,
|
||||||
.disable_vblank = fimd_disable_vblank,
|
.disable_vblank = fimd_disable_vblank,
|
||||||
};
|
};
|
||||||
|
@ -264,6 +280,7 @@ static void fimd_win_mode_set(struct device *dev,
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
struct fimd_win_data *win_data;
|
struct fimd_win_data *win_data;
|
||||||
|
int win;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
@ -273,12 +290,19 @@ static void fimd_win_mode_set(struct device *dev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
win = overlay->zpos;
|
||||||
|
if (win == DEFAULT_ZPOS)
|
||||||
|
win = ctx->default_win;
|
||||||
|
|
||||||
|
if (win < 0 || win > WINDOWS_NR)
|
||||||
|
return;
|
||||||
|
|
||||||
offset = overlay->fb_x * (overlay->bpp >> 3);
|
offset = overlay->fb_x * (overlay->bpp >> 3);
|
||||||
offset += overlay->fb_y * overlay->pitch;
|
offset += overlay->fb_y * overlay->pitch;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
|
DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
|
||||||
|
|
||||||
win_data = &ctx->win_data[ctx->default_win];
|
win_data = &ctx->win_data[win];
|
||||||
|
|
||||||
win_data->offset_x = overlay->crtc_x;
|
win_data->offset_x = overlay->crtc_x;
|
||||||
win_data->offset_y = overlay->crtc_y;
|
win_data->offset_y = overlay->crtc_y;
|
||||||
|
@ -381,15 +405,18 @@ static void fimd_win_set_colkey(struct device *dev, unsigned int win)
|
||||||
writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
|
writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimd_win_commit(struct device *dev)
|
static void fimd_win_commit(struct device *dev, int zpos)
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
struct fimd_win_data *win_data;
|
struct fimd_win_data *win_data;
|
||||||
int win = ctx->default_win;
|
int win = zpos;
|
||||||
unsigned long val, alpha, size;
|
unsigned long val, alpha, size;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (win == DEFAULT_ZPOS)
|
||||||
|
win = ctx->default_win;
|
||||||
|
|
||||||
if (win < 0 || win > WINDOWS_NR)
|
if (win < 0 || win > WINDOWS_NR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -472,24 +499,37 @@ static void fimd_win_commit(struct device *dev)
|
||||||
if (win != 0)
|
if (win != 0)
|
||||||
fimd_win_set_colkey(dev, win);
|
fimd_win_set_colkey(dev, win);
|
||||||
|
|
||||||
|
/* wincon */
|
||||||
|
val = readl(ctx->regs + WINCON(win));
|
||||||
|
val |= WINCONx_ENWIN;
|
||||||
|
writel(val, ctx->regs + WINCON(win));
|
||||||
|
|
||||||
/* Enable DMA channel and unprotect windows */
|
/* Enable DMA channel and unprotect windows */
|
||||||
val = readl(ctx->regs + SHADOWCON);
|
val = readl(ctx->regs + SHADOWCON);
|
||||||
val |= SHADOWCON_CHx_ENABLE(win);
|
val |= SHADOWCON_CHx_ENABLE(win);
|
||||||
val &= ~SHADOWCON_WINx_PROTECT(win);
|
val &= ~SHADOWCON_WINx_PROTECT(win);
|
||||||
writel(val, ctx->regs + SHADOWCON);
|
writel(val, ctx->regs + SHADOWCON);
|
||||||
|
|
||||||
|
win_data->enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimd_win_disable(struct device *dev)
|
static void fimd_win_disable(struct device *dev, int zpos)
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
int win = ctx->default_win;
|
struct fimd_win_data *win_data;
|
||||||
|
int win = zpos;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (win == DEFAULT_ZPOS)
|
||||||
|
win = ctx->default_win;
|
||||||
|
|
||||||
if (win < 0 || win > WINDOWS_NR)
|
if (win < 0 || win > WINDOWS_NR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
win_data = &ctx->win_data[win];
|
||||||
|
|
||||||
/* protect windows */
|
/* protect windows */
|
||||||
val = readl(ctx->regs + SHADOWCON);
|
val = readl(ctx->regs + SHADOWCON);
|
||||||
val |= SHADOWCON_WINx_PROTECT(win);
|
val |= SHADOWCON_WINx_PROTECT(win);
|
||||||
|
@ -505,6 +545,8 @@ static void fimd_win_disable(struct device *dev)
|
||||||
val &= ~SHADOWCON_CHx_ENABLE(win);
|
val &= ~SHADOWCON_CHx_ENABLE(win);
|
||||||
val &= ~SHADOWCON_WINx_PROTECT(win);
|
val &= ~SHADOWCON_WINx_PROTECT(win);
|
||||||
writel(val, ctx->regs + SHADOWCON);
|
writel(val, ctx->regs + SHADOWCON);
|
||||||
|
|
||||||
|
win_data->enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct exynos_drm_overlay_ops fimd_overlay_ops = {
|
static struct exynos_drm_overlay_ops fimd_overlay_ops = {
|
||||||
|
@ -540,9 +582,17 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
|
||||||
wake_up_interruptible(&e->base.file_priv->event_wait);
|
wake_up_interruptible(&e->base.file_priv->event_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_checked)
|
if (is_checked) {
|
||||||
drm_vblank_put(drm_dev, crtc);
|
drm_vblank_put(drm_dev, crtc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't off vblank if vblank_disable_allowed is 1,
|
||||||
|
* because vblank would be off by timer handler.
|
||||||
|
*/
|
||||||
|
if (!drm_dev->vblank_disable_allowed)
|
||||||
|
drm_vblank_off(drm_dev, crtc);
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
|
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,19 +610,14 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
|
||||||
/* VSYNC interrupt */
|
/* VSYNC interrupt */
|
||||||
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
|
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
|
||||||
|
|
||||||
/*
|
/* check the crtc is detached already from encoder */
|
||||||
* in case that vblank_disable_allowed is 1, it could induce
|
if (manager->pipe < 0)
|
||||||
* the problem that manager->pipe could be -1 because with
|
goto out;
|
||||||
* disable callback, vsync interrupt isn't disabled and at this moment,
|
|
||||||
* vsync interrupt could occur. the vsync interrupt would be disabled
|
|
||||||
* by timer handler later.
|
|
||||||
*/
|
|
||||||
if (manager->pipe == -1)
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
|
|
||||||
drm_handle_vblank(drm_dev, manager->pipe);
|
drm_handle_vblank(drm_dev, manager->pipe);
|
||||||
fimd_finish_pageflip(drm_dev, manager->pipe);
|
fimd_finish_pageflip(drm_dev, manager->pipe);
|
||||||
|
|
||||||
|
out:
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,6 +635,13 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
||||||
*/
|
*/
|
||||||
drm_dev->irq_enabled = 1;
|
drm_dev->irq_enabled = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* with vblank_disable_allowed = 1, vblank interrupt will be disabled
|
||||||
|
* by drm timer once a current process gives up ownership of
|
||||||
|
* vblank event.(after drm_vblank_put function is called)
|
||||||
|
*/
|
||||||
|
drm_dev->vblank_disable_allowed = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,15 +791,19 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ctx->irq = res->start;
|
ctx->irq = res->start;
|
||||||
|
|
||||||
for (win = 0; win < WINDOWS_NR; win++)
|
|
||||||
fimd_clear_win(ctx, win);
|
|
||||||
|
|
||||||
ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
|
ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "irq request failed.\n");
|
dev_err(dev, "irq request failed.\n");
|
||||||
goto err_req_irq;
|
goto err_req_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
|
for (win = 0; win < WINDOWS_NR; win++)
|
||||||
|
fimd_clear_win(ctx, win);
|
||||||
|
|
||||||
ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
|
ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
|
||||||
ctx->vidcon0 = pdata->vidcon0;
|
ctx->vidcon0 = pdata->vidcon0;
|
||||||
ctx->vidcon1 = pdata->vidcon1;
|
ctx->vidcon1 = pdata->vidcon1;
|
||||||
|
@ -797,14 +853,25 @@ err_clk_get:
|
||||||
|
|
||||||
static int __devexit fimd_remove(struct platform_device *pdev)
|
static int __devexit fimd_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
struct fimd_context *ctx = platform_get_drvdata(pdev);
|
struct fimd_context *ctx = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
||||||
|
|
||||||
|
if (ctx->suspended)
|
||||||
|
goto out;
|
||||||
|
|
||||||
clk_disable(ctx->lcd_clk);
|
clk_disable(ctx->lcd_clk);
|
||||||
clk_disable(ctx->bus_clk);
|
clk_disable(ctx->bus_clk);
|
||||||
|
|
||||||
|
pm_runtime_set_suspended(dev);
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
|
out:
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
clk_put(ctx->lcd_clk);
|
clk_put(ctx->lcd_clk);
|
||||||
clk_put(ctx->bus_clk);
|
clk_put(ctx->bus_clk);
|
||||||
|
|
||||||
|
@ -818,12 +885,53 @@ static int __devexit fimd_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_RUNTIME
|
||||||
|
static int fimd_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
clk_disable(ctx->lcd_clk);
|
||||||
|
clk_disable(ctx->bus_clk);
|
||||||
|
|
||||||
|
ctx->suspended = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fimd_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
ret = clk_enable(ctx->bus_clk);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_enable(ctx->lcd_clk);
|
||||||
|
if (ret < 0) {
|
||||||
|
clk_disable(ctx->bus_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->suspended = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct dev_pm_ops fimd_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_driver fimd_driver = {
|
static struct platform_driver fimd_driver = {
|
||||||
.probe = fimd_probe,
|
.probe = fimd_probe,
|
||||||
.remove = __devexit_p(fimd_remove),
|
.remove = __devexit_p(fimd_remove),
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "exynos4-fb",
|
.name = "exynos4-fb",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.pm = &fimd_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
163
drivers/gpu/drm/exynos/exynos_drm_plane.c
Normal file
163
drivers/gpu/drm/exynos/exynos_drm_plane.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||||
|
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
|
||||||
|
#include "exynos_drm.h"
|
||||||
|
#include "exynos_drm_crtc.h"
|
||||||
|
#include "exynos_drm_drv.h"
|
||||||
|
#include "exynos_drm_encoder.h"
|
||||||
|
|
||||||
|
struct exynos_plane {
|
||||||
|
struct drm_plane base;
|
||||||
|
struct exynos_drm_overlay overlay;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||||
|
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||||
|
unsigned int crtc_w, unsigned int crtc_h,
|
||||||
|
uint32_t src_x, uint32_t src_y,
|
||||||
|
uint32_t src_w, uint32_t src_h)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane =
|
||||||
|
container_of(plane, struct exynos_plane, base);
|
||||||
|
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
||||||
|
struct exynos_drm_crtc_pos pos;
|
||||||
|
unsigned int x = src_x >> 16;
|
||||||
|
unsigned int y = src_y >> 16;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
|
||||||
|
pos.crtc_x = crtc_x;
|
||||||
|
pos.crtc_y = crtc_y;
|
||||||
|
pos.crtc_w = crtc_w;
|
||||||
|
pos.crtc_h = crtc_h;
|
||||||
|
|
||||||
|
pos.fb_x = x;
|
||||||
|
pos.fb_y = y;
|
||||||
|
|
||||||
|
/* TODO: scale feature */
|
||||||
|
ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(crtc, overlay,
|
||||||
|
exynos_drm_encoder_crtc_mode_set);
|
||||||
|
exynos_drm_fn_encoder(crtc, &overlay->zpos,
|
||||||
|
exynos_drm_encoder_crtc_plane_commit);
|
||||||
|
|
||||||
|
exynos_plane->enabled = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exynos_disable_plane(struct drm_plane *plane)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane =
|
||||||
|
container_of(plane, struct exynos_plane, base);
|
||||||
|
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
if (!exynos_plane->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||||
|
exynos_drm_encoder_crtc_disable);
|
||||||
|
|
||||||
|
exynos_plane->enabled = false;
|
||||||
|
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exynos_plane_destroy(struct drm_plane *plane)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane =
|
||||||
|
container_of(plane, struct exynos_plane, base);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
exynos_disable_plane(plane);
|
||||||
|
drm_plane_cleanup(plane);
|
||||||
|
kfree(exynos_plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct drm_plane_funcs exynos_plane_funcs = {
|
||||||
|
.update_plane = exynos_update_plane,
|
||||||
|
.disable_plane = exynos_disable_plane,
|
||||||
|
.destroy = exynos_plane_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
int exynos_plane_init(struct drm_device *dev, unsigned int nr)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane;
|
||||||
|
uint32_t possible_crtcs;
|
||||||
|
|
||||||
|
exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
|
||||||
|
if (!exynos_plane)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* all CRTCs are available */
|
||||||
|
possible_crtcs = (1 << MAX_CRTC) - 1;
|
||||||
|
|
||||||
|
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
|
/* TODO: format */
|
||||||
|
return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
|
||||||
|
&exynos_plane_funcs, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_exynos_plane_set_zpos *zpos_req = data;
|
||||||
|
struct drm_mode_object *obj;
|
||||||
|
struct drm_plane *plane;
|
||||||
|
struct exynos_plane *exynos_plane;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
|
||||||
|
if (zpos_req->zpos != DEFAULT_ZPOS) {
|
||||||
|
DRM_ERROR("zpos not within limits\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&dev->mode_config.mutex);
|
||||||
|
|
||||||
|
obj = drm_mode_object_find(dev, zpos_req->plane_id,
|
||||||
|
DRM_MODE_OBJECT_PLANE);
|
||||||
|
if (!obj) {
|
||||||
|
DRM_DEBUG_KMS("Unknown plane ID %d\n",
|
||||||
|
zpos_req->plane_id);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane = obj_to_plane(obj);
|
||||||
|
exynos_plane = container_of(plane, struct exynos_plane, base);
|
||||||
|
|
||||||
|
exynos_plane->overlay.zpos = zpos_req->zpos;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&dev->mode_config.mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
14
drivers/gpu/drm/exynos/exynos_drm_plane.h
Normal file
14
drivers/gpu/drm/exynos/exynos_drm_plane.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||||
|
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int exynos_plane_init(struct drm_device *dev, unsigned int nr);
|
||||||
|
int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv);
|
|
@ -74,9 +74,16 @@ struct drm_exynos_gem_mmap {
|
||||||
uint64_t mapped;
|
uint64_t mapped;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct drm_exynos_plane_set_zpos {
|
||||||
|
__u32 plane_id;
|
||||||
|
__s32 zpos;
|
||||||
|
};
|
||||||
|
|
||||||
#define DRM_EXYNOS_GEM_CREATE 0x00
|
#define DRM_EXYNOS_GEM_CREATE 0x00
|
||||||
#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
|
#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
|
||||||
#define DRM_EXYNOS_GEM_MMAP 0x02
|
#define DRM_EXYNOS_GEM_MMAP 0x02
|
||||||
|
/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
|
||||||
|
#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06
|
||||||
|
|
||||||
#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
|
#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
|
||||||
DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
|
DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
|
||||||
|
@ -87,6 +94,9 @@ struct drm_exynos_gem_mmap {
|
||||||
#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
|
#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
|
||||||
DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
|
DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
|
||||||
|
|
||||||
|
#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \
|
||||||
|
DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Platform Specific Structure for DRM based FIMD.
|
* Platform Specific Structure for DRM based FIMD.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue