Commit 864ee9e6 authored by Joonyoung Shim's avatar Joonyoung Shim Committed by Inki Dae

drm/exynos: Add plane support with fimd

The exynos fimd supports 5 window overlays. Only one window overlay of
fimd is used by the crtc, so we need plane feature to use the rest
window overlays.

This creates one ioctl exynos specific - DRM_EXYNOS_PLANE_SET_ZPOS, it
is the ioctl to decide for user to assign which window overlay.
Signed-off-by: default avatarJoonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
parent cb91f6a0
...@@ -5,7 +5,8 @@ ...@@ -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
...@@ -380,6 +380,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) ...@@ -380,6 +380,7 @@ 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->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;
......
...@@ -36,6 +36,7 @@ ...@@ -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) ...@@ -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,8 @@ static struct drm_ioctl_desc exynos_ioctls[] = { ...@@ -163,6 +170,8 @@ 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 = { static const struct file_operations exynos_drm_driver_fops = {
......
...@@ -33,6 +33,8 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
...@@ -294,12 +294,27 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data) ...@@ -294,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__);
...@@ -309,8 +324,7 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data) ...@@ -309,8 +324,7 @@ 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) void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
...@@ -375,11 +389,15 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data) ...@@ -375,11 +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 (data)
zpos = *(int *)data;
if (overlay_ops && overlay_ops->disable) if (overlay_ops && overlay_ops->disable)
overlay_ops->disable(manager->dev); overlay_ops->disable(manager->dev, zpos);
} }
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
......
...@@ -39,6 +39,8 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, ...@@ -39,6 +39,8 @@ 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 exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
void *data); void *data);
......
...@@ -161,12 +161,15 @@ static void fimd_apply(struct device *subdrv_dev) ...@@ -161,12 +161,15 @@ static void fimd_apply(struct device *subdrv_dev)
struct exynos_drm_manager_ops *mgr_ops = mgr->ops; struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops; struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int i;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
win_data = &ctx->win_data[ctx->default_win]; for (i = 0; i < WINDOWS_NR; i++) {
if (win_data->enabled && (ovl_ops && ovl_ops->commit)) win_data = &ctx->win_data[i];
ovl_ops->commit(subdrv_dev); if (win_data->enabled && (ovl_ops && ovl_ops->commit))
ovl_ops->commit(subdrv_dev, i);
}
if (mgr_ops && mgr_ops->commit) if (mgr_ops && mgr_ops->commit)
mgr_ops->commit(subdrv_dev); mgr_ops->commit(subdrv_dev);
...@@ -277,6 +280,7 @@ static void fimd_win_mode_set(struct device *dev, ...@@ -277,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__);
...@@ -286,12 +290,19 @@ static void fimd_win_mode_set(struct device *dev, ...@@ -286,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;
...@@ -394,15 +405,18 @@ static void fimd_win_set_colkey(struct device *dev, unsigned int win) ...@@ -394,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;
...@@ -499,15 +513,18 @@ static void fimd_win_commit(struct device *dev) ...@@ -499,15 +513,18 @@ static void fimd_win_commit(struct device *dev)
win_data->enabled = true; 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);
struct fimd_win_data *win_data; struct fimd_win_data *win_data;
int win = ctx->default_win; 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;
......
/*
* 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;
}
/*
* 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 { ...@@ -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 { ...@@ -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.
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment