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
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -42,37 +42,19 @@
|
|||
* @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);
|
||||
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) {
|
||||
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
|
||||
exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
|
@ -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>");
|
||||
|
|
|
@ -39,7 +39,12 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
|||
void (*fn)(struct drm_encoder *, void *));
|
||||
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_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_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_disable(struct drm_encoder *encoder, void *data);
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
|
|||
|
||||
static struct drm_framebuffer *
|
||||
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 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__);
|
||||
|
||||
mode_cmd->pitch = max(mode_cmd->pitch,
|
||||
mode_cmd->width * (mode_cmd->bpp >> 3));
|
||||
|
||||
DRM_LOG_KMS("drm fb create(%dx%d)\n",
|
||||
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);
|
||||
|
||||
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
|
||||
* would be allocated.
|
||||
*/
|
||||
if (!mode_cmd->handle) {
|
||||
if (!mode_cmd->handles[0]) {
|
||||
if (!file_priv) {
|
||||
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;
|
||||
} else {
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
|
||||
&mode_cmd->handle,
|
||||
&mode_cmd->handles[0],
|
||||
size);
|
||||
if (IS_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 {
|
||||
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) {
|
||||
DRM_ERROR("failed to lookup gem object.\n");
|
||||
goto err_buffer;
|
||||
|
@ -215,7 +213,7 @@ err_init:
|
|||
|
||||
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
||||
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__);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
||||
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);
|
||||
|
||||
|
|
|
@ -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 drm_device *dev = helper->dev;
|
||||
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;
|
||||
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.height = sizes->surface_height;
|
||||
mode_cmd.bpp = sizes->surface_bpp;
|
||||
mode_cmd.depth = sizes->surface_depth;
|
||||
mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
|
||||
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
|
||||
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 exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
|
||||
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__);
|
||||
|
||||
|
@ -220,8 +221,9 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
|
|||
|
||||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
mode_cmd.bpp = sizes->surface_bpp;
|
||||
mode_cmd.depth = sizes->surface_depth;
|
||||
mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
|
||||
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
|
||||
if (fb->funcs->destroy)
|
||||
fb->funcs->destroy(fb);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/exynos_drm.h>
|
||||
#include <plat/regs-fb-v4.h>
|
||||
|
@ -68,6 +69,7 @@ struct fimd_win_data {
|
|||
void __iomem *vaddr;
|
||||
unsigned int buf_offsize;
|
||||
unsigned int line_size; /* bytes */
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct fimd_context {
|
||||
|
@ -84,6 +86,7 @@ struct fimd_context {
|
|||
unsigned long irq_flags;
|
||||
u32 vidcon0;
|
||||
u32 vidcon1;
|
||||
bool suspended;
|
||||
|
||||
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__);
|
||||
|
||||
/* TODO. */
|
||||
/* TODO */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,6 +135,46 @@ static struct exynos_drm_display_ops fimd_display_ops = {
|
|||
.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)
|
||||
{
|
||||
struct fimd_context *ctx = get_fimd_context(dev);
|
||||
|
@ -177,40 +220,6 @@ static void fimd_commit(struct device *dev)
|
|||
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)
|
||||
{
|
||||
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__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return -EPERM;
|
||||
|
||||
if (!test_and_set_bit(0, &ctx->irq_flags)) {
|
||||
val = readl(ctx->regs + VIDINTCON0);
|
||||
|
||||
|
@ -242,6 +254,9 @@ static void fimd_disable_vblank(struct device *dev)
|
|||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags)) {
|
||||
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 = {
|
||||
.dpms = fimd_dpms,
|
||||
.apply = fimd_apply,
|
||||
.commit = fimd_commit,
|
||||
.disable = fimd_disable,
|
||||
.enable_vblank = fimd_enable_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_win_data *win_data;
|
||||
int win;
|
||||
unsigned long offset;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
@ -273,12 +290,19 @@ static void fimd_win_mode_set(struct device *dev,
|
|||
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_y * 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_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));
|
||||
}
|
||||
|
||||
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_win_data *win_data;
|
||||
int win = ctx->default_win;
|
||||
int win = zpos;
|
||||
unsigned long val, alpha, size;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
|
||||
if (win < 0 || win > WINDOWS_NR)
|
||||
return;
|
||||
|
||||
|
@ -472,24 +499,37 @@ static void fimd_win_commit(struct device *dev)
|
|||
if (win != 0)
|
||||
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 */
|
||||
val = readl(ctx->regs + SHADOWCON);
|
||||
val |= SHADOWCON_CHx_ENABLE(win);
|
||||
val &= ~SHADOWCON_WINx_PROTECT(win);
|
||||
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);
|
||||
int win = ctx->default_win;
|
||||
struct fimd_win_data *win_data;
|
||||
int win = zpos;
|
||||
u32 val;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
|
||||
if (win < 0 || win > WINDOWS_NR)
|
||||
return;
|
||||
|
||||
win_data = &ctx->win_data[win];
|
||||
|
||||
/* protect windows */
|
||||
val = readl(ctx->regs + SHADOWCON);
|
||||
val |= SHADOWCON_WINx_PROTECT(win);
|
||||
|
@ -505,6 +545,8 @@ static void fimd_win_disable(struct device *dev)
|
|||
val &= ~SHADOWCON_CHx_ENABLE(win);
|
||||
val &= ~SHADOWCON_WINx_PROTECT(win);
|
||||
writel(val, ctx->regs + SHADOWCON);
|
||||
|
||||
win_data->enabled = false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (is_checked)
|
||||
if (is_checked) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -560,19 +610,14 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
|
|||
/* VSYNC interrupt */
|
||||
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
|
||||
|
||||
/*
|
||||
* in case that vblank_disable_allowed is 1, it could induce
|
||||
* the problem that manager->pipe could be -1 because with
|
||||
* 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;
|
||||
/* check the crtc is detached already from encoder */
|
||||
if (manager->pipe < 0)
|
||||
goto out;
|
||||
|
||||
drm_handle_vblank(drm_dev, manager->pipe);
|
||||
fimd_finish_pageflip(drm_dev, manager->pipe);
|
||||
|
||||
out:
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
@ -739,15 +791,19 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
|||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "irq request failed.\n");
|
||||
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->vidcon0 = pdata->vidcon0;
|
||||
ctx->vidcon1 = pdata->vidcon1;
|
||||
|
@ -797,14 +853,25 @@ err_clk_get:
|
|||
|
||||
static int __devexit fimd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct fimd_context *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
||||
|
||||
if (ctx->suspended)
|
||||
goto out;
|
||||
|
||||
clk_disable(ctx->lcd_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->bus_clk);
|
||||
|
||||
|
@ -818,12 +885,53 @@ static int __devexit fimd_remove(struct platform_device *pdev)
|
|||
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 = {
|
||||
.probe = fimd_probe,
|
||||
.remove = __devexit_p(fimd_remove),
|
||||
.driver = {
|
||||
.name = "exynos4-fb",
|
||||
.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;
|
||||
};
|
||||
|
||||
struct drm_exynos_plane_set_zpos {
|
||||
__u32 plane_id;
|
||||
__s32 zpos;
|
||||
};
|
||||
|
||||
#define DRM_EXYNOS_GEM_CREATE 0x00
|
||||
#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
|
||||
#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 + \
|
||||
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 + \
|
||||
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.
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue