Commit 863f78b5 authored by Dave Airlie's avatar Dave Airlie

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

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

these patch sets include the following features:
- add Samsung SoC Exynos based HDMI support.
- add pm feature for fimd driver.
- add multi buffer plane pixel formats to drm/drm_fourcc.h.
  multi buffer plane pixel format has seperated memory spaces for each
  plane. for exampme, NV12M has Y plane and CbCr plane and these are in
  non-continuous memory region. compared with NV12, NV12M's memory shape
  is like following.
  NV12  : ______(Y)(CbCr)_______
  NV12M : __(Y)_ ..... _(CbCr)__
- bug fix to vblank.
- code clean to exynos gem framework.

* 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung:
  drm/exynos: added hdmi display support
  drm/exynos: added mutex lock and code clean.
  drm/exynos: extend vblank off delay time.
  drm/exynos: change driver name.
  drm/exynos: Support multi buffers
  drm: Add multi buffer plane pixel formats
  drm/exynos: added pm support.
  drm/exynos: remove buffer creation of fbdev from drm framebuffer creation
  drm/exynos: Split creation of gem object and gem handle
  drm/exynos: Fix a fake mmap offset creation
  drm/exynos: gem code cleanup
parents 5c2a5ce6 d8408326
...@@ -18,3 +18,10 @@ config DRM_EXYNOS_FIMD ...@@ -18,3 +18,10 @@ config DRM_EXYNOS_FIMD
help help
Choose this option if you want to use Exynos FIMD for DRM. Choose this option if you want to use Exynos FIMD for DRM.
If M is selected, the module will be called exynos_drm_fimd If M is selected, the module will be called exynos_drm_fimd
config DRM_EXYNOS_HDMI
tristate "Exynos DRM HDMI"
depends on DRM_EXYNOS
help
Choose this option if you want to use Exynos HDMI for DRM.
If M is selected, the module will be called exynos_drm_hdmi
...@@ -10,3 +10,5 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \ ...@@ -10,3 +10,5 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.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
obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
exynos_hdmiphy.o exynos_drm_hdmi.o
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Authors:
* Seung-Woo Kim <sw0312.kim@samsung.com>
* Inki Dae <inki.dae@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 <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include "exynos_drm_drv.h"
#include "exynos_hdmi.h"
static int s5p_ddc_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
hdmi_attach_ddc_client(client);
dev_info(&client->adapter->dev, "attached s5p_ddc "
"into i2c adapter successfully\n");
return 0;
}
static int s5p_ddc_remove(struct i2c_client *client)
{
dev_info(&client->adapter->dev, "detached s5p_ddc "
"from i2c adapter successfully\n");
return 0;
}
static struct i2c_device_id ddc_idtable[] = {
{"s5p_ddc", 0},
{ },
};
struct i2c_driver ddc_driver = {
.driver = {
.name = "s5p_ddc",
.owner = THIS_MODULE,
},
.id_table = ddc_idtable,
.probe = s5p_ddc_probe,
.remove = __devexit_p(s5p_ddc_remove),
.command = NULL,
};
EXPORT_SYMBOL(ddc_driver);
...@@ -73,7 +73,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, ...@@ -73,7 +73,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) { if (!buffer) {
DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n"); DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
return ERR_PTR(-ENOMEM); return NULL;
} }
buffer->size = size; buffer->size = size;
...@@ -84,8 +84,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, ...@@ -84,8 +84,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
*/ */
if (lowlevel_buffer_allocate(dev, buffer) < 0) { if (lowlevel_buffer_allocate(dev, buffer) < 0) {
kfree(buffer); kfree(buffer);
buffer = NULL; return NULL;
return ERR_PTR(-ENOMEM);
} }
return buffer; return buffer;
......
...@@ -30,9 +30,6 @@ ...@@ -30,9 +30,6 @@
struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
unsigned int size); unsigned int size);
/* get memory information of a drm framebuffer. */
struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb);
/* remove allocated physical memory. */ /* remove allocated physical memory. */
void exynos_drm_buf_destroy(struct drm_device *dev, void exynos_drm_buf_destroy(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer); struct exynos_drm_gem_buf *buffer);
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
#include "exynos_drm_encoder.h" #include "exynos_drm_encoder.h"
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
drm_crtc) drm_crtc)
...@@ -80,19 +79,23 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, ...@@ -80,19 +79,23 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_buf *buffer;
unsigned int actual_w; unsigned int actual_w;
unsigned int actual_h; unsigned int actual_h;
int nr = exynos_drm_format_num_buffers(fb->pixel_format);
int i;
for (i = 0; i < nr; i++) {
buffer = exynos_drm_fb_buffer(fb, i);
if (!buffer) {
DRM_LOG_KMS("buffer is null\n");
return -EFAULT;
}
buffer = exynos_drm_fb_get_buf(fb); overlay->dma_addr[i] = buffer->dma_addr;
if (!buffer) { overlay->vaddr[i] = buffer->kvaddr;
DRM_LOG_KMS("buffer is null.\n");
return -EFAULT;
}
overlay->dma_addr = buffer->dma_addr;
overlay->vaddr = buffer->kvaddr;
DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
(unsigned long)overlay->vaddr, i, (unsigned long)overlay->vaddr[i],
(unsigned long)overlay->dma_addr); (unsigned long)overlay->dma_addr[i]);
}
actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w); actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h); actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
...@@ -104,6 +107,7 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, ...@@ -104,6 +107,7 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
overlay->fb_height = fb->height; overlay->fb_height = fb->height;
overlay->bpp = fb->bits_per_pixel; overlay->bpp = fb->bits_per_pixel;
overlay->pitch = fb->pitches[0]; overlay->pitch = fb->pitches[0];
overlay->pixel_format = fb->pixel_format;
/* set overlay range to be displayed. */ /* set overlay range to be displayed. */
overlay->crtc_x = pos->crtc_x; overlay->crtc_x = pos->crtc_x;
......
...@@ -38,12 +38,14 @@ ...@@ -38,12 +38,14 @@
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#define DRIVER_NAME "exynos-drm" #define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM" #define DRIVER_DESC "Samsung SoC DRM"
#define DRIVER_DATE "20110530" #define DRIVER_DATE "20110530"
#define DRIVER_MAJOR 1 #define DRIVER_MAJOR 1
#define DRIVER_MINOR 0 #define DRIVER_MINOR 0
#define VBLANK_OFF_DELAY 50000
static int exynos_drm_load(struct drm_device *dev, unsigned long flags) static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{ {
struct exynos_drm_private *private; struct exynos_drm_private *private;
...@@ -107,6 +109,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) ...@@ -107,6 +109,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
goto err_drm_device; goto err_drm_device;
} }
drm_vblank_offdelay = VBLANK_OFF_DELAY;
return 0; return 0;
err_drm_device: err_drm_device:
......
...@@ -34,12 +34,15 @@ ...@@ -34,12 +34,15 @@
#define MAX_CRTC 2 #define MAX_CRTC 2
#define MAX_PLANE 5 #define MAX_PLANE 5
#define MAX_FB_BUFFER 3
#define DEFAULT_ZPOS -1 #define DEFAULT_ZPOS -1
struct drm_device; struct drm_device;
struct exynos_drm_overlay; struct exynos_drm_overlay;
struct drm_connector; struct drm_connector;
extern unsigned int drm_vblank_offdelay;
/* this enumerates display type. */ /* this enumerates display type. */
enum exynos_drm_output_type { enum exynos_drm_output_type {
EXYNOS_DISPLAY_TYPE_NONE, EXYNOS_DISPLAY_TYPE_NONE,
...@@ -82,9 +85,10 @@ struct exynos_drm_overlay_ops { ...@@ -82,9 +85,10 @@ struct exynos_drm_overlay_ops {
* @scan_flag: interlace or progressive way. * @scan_flag: interlace or progressive way.
* (it could be DRM_MODE_FLAG_*) * (it could be DRM_MODE_FLAG_*)
* @bpp: pixel size.(in bit) * @bpp: pixel size.(in bit)
* @dma_addr: bus(accessed by dma) address to the memory region allocated * @pixel_format: fourcc pixel format of this overlay
* for a overlay. * @dma_addr: array of bus(accessed by dma) address to the memory region
* @vaddr: virtual memory addresss to this overlay. * allocated for a overlay.
* @vaddr: array of virtual memory addresss to this overlay.
* @zpos: order of overlay layer(z position). * @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.
...@@ -112,8 +116,9 @@ struct exynos_drm_overlay { ...@@ -112,8 +116,9 @@ struct exynos_drm_overlay {
unsigned int scan_flag; unsigned int scan_flag;
unsigned int bpp; unsigned int bpp;
unsigned int pitch; unsigned int pitch;
dma_addr_t dma_addr; uint32_t pixel_format;
void __iomem *vaddr; dma_addr_t dma_addr[MAX_FB_BUFFER];
void __iomem *vaddr[MAX_FB_BUFFER];
int zpos; int zpos;
bool default_win; bool default_win;
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
#include "exynos_drm_buf.h"
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
...@@ -42,15 +41,11 @@ ...@@ -42,15 +41,11 @@
* exynos specific framebuffer structure. * exynos specific framebuffer structure.
* *
* @fb: drm framebuffer obejct. * @fb: drm framebuffer obejct.
* @exynos_gem_obj: exynos specific gem object containing a gem object. * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
* @buffer: pointer to exynos_drm_gem_buffer object.
* - contain the memory information to memory region allocated
* at default framebuffer creation.
*/ */
struct exynos_drm_fb { struct exynos_drm_fb {
struct drm_framebuffer fb; struct drm_framebuffer fb;
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
struct exynos_drm_gem_buf *buffer;
}; };
static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
...@@ -61,13 +56,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) ...@@ -61,13 +56,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
drm_framebuffer_cleanup(fb); drm_framebuffer_cleanup(fb);
/*
* default framebuffer has no gem object so
* a buffer of the default framebuffer should be released at here.
*/
if (!exynos_fb->exynos_gem_obj && exynos_fb->buffer)
exynos_drm_buf_destroy(fb->dev, exynos_fb->buffer);
kfree(exynos_fb); kfree(exynos_fb);
exynos_fb = NULL; exynos_fb = NULL;
} }
...@@ -81,7 +69,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, ...@@ -81,7 +69,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
return drm_gem_handle_create(file_priv, return drm_gem_handle_create(file_priv,
&exynos_fb->exynos_gem_obj->base, handle); &exynos_fb->exynos_gem_obj[0]->base, handle);
} }
static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
...@@ -102,132 +90,88 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { ...@@ -102,132 +90,88 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
.dirty = exynos_drm_fb_dirty, .dirty = exynos_drm_fb_dirty,
}; };
static struct drm_framebuffer * struct drm_framebuffer *
exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd) struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{ {
struct exynos_drm_fb *exynos_fb; struct exynos_drm_fb *exynos_fb;
struct drm_framebuffer *fb;
struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
struct drm_gem_object *obj;
unsigned int size;
int ret; int ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
DRM_LOG_KMS("drm fb create(%dx%d)\n",
mode_cmd->width, mode_cmd->height);
exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
if (!exynos_fb) { if (!exynos_fb) {
DRM_ERROR("failed to allocate exynos drm framebuffer.\n"); DRM_ERROR("failed to allocate exynos drm framebuffer\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
fb = &exynos_fb->fb; ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs);
if (ret) { if (ret) {
DRM_ERROR("failed to initialize framebuffer.\n"); DRM_ERROR("failed to initialize framebuffer\n");
goto err_init; return ERR_PTR(ret);
} }
DRM_LOG_KMS("create: fb id: %d\n", fb->base.id); drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
size = mode_cmd->pitches[0] * mode_cmd->height; return &exynos_fb->fb;
}
/* static struct drm_framebuffer *
* mode_cmd->handles[0] could be NULL at booting time or exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
* with user request. if NULL, a new buffer or a gem object struct drm_mode_fb_cmd2 *mode_cmd)
* would be allocated. {
*/ struct drm_gem_object *obj;
if (!mode_cmd->handles[0]) { struct drm_framebuffer *fb;
if (!file_priv) { struct exynos_drm_fb *exynos_fb;
struct exynos_drm_gem_buf *buffer; int nr;
int i;
/*
* in case that file_priv is NULL, it allocates
* only buffer and this buffer would be used
* for default framebuffer.
*/
buffer = exynos_drm_buf_create(dev, size);
if (IS_ERR(buffer)) {
ret = PTR_ERR(buffer);
goto err_buffer;
}
exynos_fb->buffer = buffer;
DRM_LOG_KMS("default: dma_addr = 0x%lx, size = 0x%x\n",
(unsigned long)buffer->dma_addr, size);
goto out;
} else {
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
&mode_cmd->handles[0],
size);
if (IS_ERR(exynos_gem_obj)) {
ret = PTR_ERR(exynos_gem_obj);
goto err_buffer;
}
}
} else {
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;
}
exynos_gem_obj = to_exynos_gem_obj(obj); DRM_DEBUG_KMS("%s\n", __FILE__);
drm_gem_object_unreference_unlocked(obj); obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
if (!obj) {
DRM_ERROR("failed to lookup gem object\n");
return ERR_PTR(-ENOENT);
} }
/* drm_gem_object_unreference_unlocked(obj);
* if got a exynos_gem_obj from either a handle or
* a new creation then exynos_fb->exynos_gem_obj is NULL
* so that default framebuffer has no its own gem object,
* only its own buffer object.
*/
exynos_fb->buffer = exynos_gem_obj->buffer;
DRM_LOG_KMS("dma_addr = 0x%lx, size = 0x%x, gem object = 0x%x\n",
(unsigned long)exynos_fb->buffer->dma_addr, size,
(unsigned int)&exynos_gem_obj->base);
out: fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj);
exynos_fb->exynos_gem_obj = exynos_gem_obj; if (IS_ERR(fb))
return fb;
drm_helper_mode_fill_fb_struct(fb, mode_cmd); exynos_fb = to_exynos_fb(fb);
nr = exynos_drm_format_num_buffers(fb->pixel_format);
return fb; for (i = 1; i < nr; i++) {
obj = drm_gem_object_lookup(dev, file_priv,
err_buffer: mode_cmd->handles[i]);
drm_framebuffer_cleanup(fb); if (!obj) {
DRM_ERROR("failed to lookup gem object\n");
err_init: exynos_drm_fb_destroy(fb);
kfree(exynos_fb); return ERR_PTR(-ENOENT);
}
return ERR_PTR(ret); drm_gem_object_unreference_unlocked(obj);
}
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
struct drm_file *file_priv, }
struct drm_mode_fb_cmd2 *mode_cmd)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
return exynos_drm_fb_init(file_priv, dev, mode_cmd); return fb;
} }
struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb) struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
int index)
{ {
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_buf *buffer;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
buffer = exynos_fb->buffer; if (index >= MAX_FB_BUFFER)
return NULL;
buffer = exynos_fb->exynos_gem_obj[index]->buffer;
if (!buffer) if (!buffer)
return NULL; return NULL;
...@@ -248,7 +192,7 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) ...@@ -248,7 +192,7 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
} }
static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_drm_fb_create, .fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed, .output_poll_changed = exynos_drm_output_poll_changed,
}; };
......
...@@ -28,9 +28,27 @@ ...@@ -28,9 +28,27 @@
#ifndef _EXYNOS_DRM_FB_H_ #ifndef _EXYNOS_DRM_FB_H_
#define _EXYNOS_DRM_FB_H #define _EXYNOS_DRM_FB_H
struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, static inline int exynos_drm_format_num_buffers(uint32_t format)
struct drm_file *filp, {
struct drm_mode_fb_cmd2 *mode_cmd); switch (format) {
case DRM_FORMAT_NV12M:
case DRM_FORMAT_NV12MT:
return 2;
case DRM_FORMAT_YUV420M:
return 3;
default:
return 1;
}
}
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
/* get memory information of a drm framebuffer */
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
int index);
void exynos_drm_mode_config_init(struct drm_device *dev); void exynos_drm_mode_config_init(struct drm_device *dev);
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#define MAX_CONNECTOR 4 #define MAX_CONNECTOR 4
#define PREFERRED_BPP 32 #define PREFERRED_BPP 32
...@@ -43,8 +42,8 @@ ...@@ -43,8 +42,8 @@
drm_fb_helper) drm_fb_helper)
struct exynos_drm_fbdev { struct exynos_drm_fbdev {
struct drm_fb_helper drm_fb_helper; struct drm_fb_helper drm_fb_helper;
struct drm_framebuffer *fb; struct exynos_drm_gem_obj *exynos_gem_obj;
}; };
static int exynos_drm_fbdev_set_par(struct fb_info *info) static int exynos_drm_fbdev_set_par(struct fb_info *info)
...@@ -90,19 +89,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -90,19 +89,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
{ {
struct fb_info *fbi = helper->fbdev; struct fb_info *fbi = helper->fbdev;
struct drm_device *dev = helper->dev; struct drm_device *dev = helper->dev;
struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper);
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_buf *buffer;
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
unsigned long offset; unsigned long offset;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
exynos_fb->fb = fb;
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
buffer = exynos_drm_fb_get_buf(fb); /* RGB formats use only one buffer */
buffer = exynos_drm_fb_buffer(fb, 0);
if (!buffer) { if (!buffer) {
DRM_LOG_KMS("buffer is null.\n"); DRM_LOG_KMS("buffer is null.\n");
return -EFAULT; return -EFAULT;
...@@ -124,10 +121,12 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -124,10 +121,12 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes) struct drm_fb_helper_surface_size *sizes)
{ {
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_device *dev = helper->dev; struct drm_device *dev = helper->dev;
struct fb_info *fbi; struct fb_info *fbi;
struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = dev->platformdev;
unsigned long size;
int ret; int ret;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -151,14 +150,23 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -151,14 +150,23 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
goto out; goto out;
} }
exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd); size = mode_cmd.pitches[0] * mode_cmd.height;
if (IS_ERR_OR_NULL(exynos_fbdev->fb)) { exynos_gem_obj = exynos_drm_gem_create(dev, size);
if (IS_ERR(exynos_gem_obj)) {
ret = PTR_ERR(exynos_gem_obj);
goto out;
}
exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
&exynos_gem_obj->base);
if (IS_ERR_OR_NULL(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n"); DRM_ERROR("failed to create drm framebuffer.\n");
ret = PTR_ERR(exynos_fbdev->fb); ret = PTR_ERR(helper->fb);
goto out; goto out;
} }
helper->fb = exynos_fbdev->fb;
helper->fbdev = fbi; helper->fbdev = fbi;
fbi->par = helper; fbi->par = helper;
...@@ -172,8 +180,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -172,8 +180,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
} }
ret = exynos_drm_fbdev_update(helper, helper->fb); ret = exynos_drm_fbdev_update(helper, helper->fb);
if (ret < 0) if (ret < 0) {
fb_dealloc_cmap(&fbi->cmap); fb_dealloc_cmap(&fbi->cmap);
goto out;
}
/* /*
* if failed, all resources allocated above would be released by * if failed, all resources allocated above would be released by
...@@ -206,16 +216,13 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper, ...@@ -206,16 +216,13 @@ 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 exynos_drm_gem_obj *exynos_gem_obj;
struct drm_framebuffer *fb = helper->fb;
struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct drm_mode_fb_cmd2 mode_cmd = { 0 };
unsigned long size;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
if (helper->fb != fb) {
DRM_ERROR("drm framebuffer is different\n");
return -EINVAL;
}
if (exynos_drm_fbdev_is_samefb(fb, sizes)) if (exynos_drm_fbdev_is_samefb(fb, sizes))
return 0; return 0;
...@@ -225,16 +232,26 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper, ...@@ -225,16 +232,26 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth); sizes->surface_depth);
if (exynos_fbdev->exynos_gem_obj)
exynos_drm_gem_destroy(exynos_fbdev->exynos_gem_obj);
if (fb->funcs->destroy) if (fb->funcs->destroy)
fb->funcs->destroy(fb); fb->funcs->destroy(fb);
exynos_fbdev->fb = exynos_drm_fb_create(dev, NULL, &mode_cmd); size = mode_cmd.pitches[0] * mode_cmd.height;
if (IS_ERR(exynos_fbdev->fb)) { exynos_gem_obj = exynos_drm_gem_create(dev, size);
DRM_ERROR("failed to allocate fb.\n"); if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_fbdev->fb); return PTR_ERR(exynos_gem_obj);
exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
&exynos_gem_obj->base);
if (IS_ERR_OR_NULL(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n");
return PTR_ERR(helper->fb);
} }
helper->fb = exynos_fbdev->fb;
return exynos_drm_fbdev_update(helper, helper->fb); return exynos_drm_fbdev_update(helper, helper->fb);
} }
...@@ -368,6 +385,9 @@ void exynos_drm_fbdev_fini(struct drm_device *dev) ...@@ -368,6 +385,9 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
fbdev = to_exynos_fbdev(private->fb_helper); fbdev = to_exynos_fbdev(private->fb_helper);
if (fbdev->exynos_gem_obj)
exynos_drm_gem_destroy(fbdev->exynos_gem_obj);
exynos_drm_fbdev_destroy(dev, private->fb_helper); exynos_drm_fbdev_destroy(dev, private->fb_helper);
kfree(fbdev); kfree(fbdev);
private->fb_helper = NULL; private->fb_helper = NULL;
......
...@@ -87,6 +87,7 @@ struct fimd_context { ...@@ -87,6 +87,7 @@ struct fimd_context {
u32 vidcon0; u32 vidcon0;
u32 vidcon1; u32 vidcon1;
bool suspended; bool suspended;
struct mutex lock;
struct fb_videomode *timing; struct fb_videomode *timing;
}; };
...@@ -137,11 +138,22 @@ static struct exynos_drm_display_ops fimd_display_ops = { ...@@ -137,11 +138,22 @@ static struct exynos_drm_display_ops fimd_display_ops = {
static void fimd_dpms(struct device *subdrv_dev, int mode) static void fimd_dpms(struct device *subdrv_dev, int mode)
{ {
struct fimd_context *ctx = get_fimd_context(subdrv_dev);
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
mutex_lock(&ctx->lock);
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
pm_runtime_get_sync(subdrv_dev); /*
* enable fimd hardware only if suspended status.
*
* P.S. fimd_dpms function would be called at booting time so
* clk_enable could be called double time.
*/
if (ctx->suspended)
pm_runtime_get_sync(subdrv_dev);
break; break;
case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
...@@ -152,6 +164,8 @@ static void fimd_dpms(struct device *subdrv_dev, int mode) ...@@ -152,6 +164,8 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
DRM_DEBUG_KMS("unspecified mode %d\n", mode); DRM_DEBUG_KMS("unspecified mode %d\n", mode);
break; break;
} }
mutex_unlock(&ctx->lock);
} }
static void fimd_apply(struct device *subdrv_dev) static void fimd_apply(struct device *subdrv_dev)
...@@ -181,6 +195,9 @@ static void fimd_commit(struct device *dev) ...@@ -181,6 +195,9 @@ static void fimd_commit(struct device *dev)
struct fb_videomode *timing = ctx->timing; struct fb_videomode *timing = ctx->timing;
u32 val; u32 val;
if (ctx->suspended)
return;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
/* setup polarity values from machine code. */ /* setup polarity values from machine code. */
...@@ -310,8 +327,8 @@ static void fimd_win_mode_set(struct device *dev, ...@@ -310,8 +327,8 @@ static void fimd_win_mode_set(struct device *dev,
win_data->ovl_height = overlay->crtc_height; win_data->ovl_height = overlay->crtc_height;
win_data->fb_width = overlay->fb_width; win_data->fb_width = overlay->fb_width;
win_data->fb_height = overlay->fb_height; win_data->fb_height = overlay->fb_height;
win_data->dma_addr = overlay->dma_addr + offset; win_data->dma_addr = overlay->dma_addr[0] + offset;
win_data->vaddr = overlay->vaddr + offset; win_data->vaddr = overlay->vaddr[0] + offset;
win_data->bpp = overlay->bpp; win_data->bpp = overlay->bpp;
win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
(overlay->bpp >> 3); (overlay->bpp >> 3);
...@@ -414,6 +431,9 @@ static void fimd_win_commit(struct device *dev, int zpos) ...@@ -414,6 +431,9 @@ static void fimd_win_commit(struct device *dev, int zpos)
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
if (ctx->suspended)
return;
if (win == DEFAULT_ZPOS) if (win == DEFAULT_ZPOS)
win = ctx->default_win; win = ctx->default_win;
...@@ -797,13 +817,6 @@ static int __devinit fimd_probe(struct platform_device *pdev) ...@@ -797,13 +817,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
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;
...@@ -825,7 +838,17 @@ static int __devinit fimd_probe(struct platform_device *pdev) ...@@ -825,7 +838,17 @@ static int __devinit fimd_probe(struct platform_device *pdev)
subdrv->manager.display_ops = &fimd_display_ops; subdrv->manager.display_ops = &fimd_display_ops;
subdrv->manager.dev = dev; subdrv->manager.dev = dev;
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
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);
exynos_drm_subdrv_register(subdrv); exynos_drm_subdrv_register(subdrv);
return 0; return 0;
...@@ -885,6 +908,47 @@ static int __devexit fimd_remove(struct platform_device *pdev) ...@@ -885,6 +908,47 @@ static int __devexit fimd_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int fimd_suspend(struct device *dev)
{
int ret;
if (pm_runtime_suspended(dev))
return 0;
ret = pm_runtime_suspend(dev);
if (ret < 0)
return ret;
return 0;
}
static int fimd_resume(struct device *dev)
{
int ret;
ret = pm_runtime_resume(dev);
if (ret < 0) {
DRM_ERROR("failed to resume runtime pm.\n");
return ret;
}
pm_runtime_disable(dev);
ret = pm_runtime_set_active(dev);
if (ret < 0) {
DRM_ERROR("failed to active runtime pm.\n");
pm_runtime_enable(dev);
pm_runtime_suspend(dev);
return ret;
}
pm_runtime_enable(dev);
return 0;
}
#endif
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
static int fimd_runtime_suspend(struct device *dev) static int fimd_runtime_suspend(struct device *dev)
{ {
...@@ -917,11 +981,19 @@ static int fimd_runtime_resume(struct device *dev) ...@@ -917,11 +981,19 @@ static int fimd_runtime_resume(struct device *dev)
} }
ctx->suspended = false; ctx->suspended = false;
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
fimd_enable_vblank(dev);
fimd_apply(dev);
return 0; return 0;
} }
#endif #endif
static const struct dev_pm_ops fimd_pm_ops = { static const struct dev_pm_ops fimd_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
}; };
......
...@@ -55,17 +55,54 @@ static unsigned int convert_to_vm_err_msg(int msg) ...@@ -55,17 +55,54 @@ static unsigned int convert_to_vm_err_msg(int msg)
return out_msg; return out_msg;
} }
static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
struct drm_file *file_priv,
unsigned int *handle)
{ {
int ret;
/*
* allocate a id of idr table where the obj is registered
* and handle has the id what user can see.
*/
ret = drm_gem_handle_create(file_priv, obj, handle);
if (ret)
return ret;
DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
/* drop reference from allocate - handle holds it now. */
drm_gem_object_unreference_unlocked(obj);
return 0;
}
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
{
struct drm_gem_object *obj;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; if (!exynos_gem_obj)
return;
obj = &exynos_gem_obj->base;
DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
if (obj->map_list.map)
drm_gem_free_mmap_offset(obj);
/* release file pointer to gem object. */
drm_gem_object_release(obj);
kfree(exynos_gem_obj);
} }
static struct exynos_drm_gem_obj static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
*exynos_drm_gem_init(struct drm_device *drm_dev, unsigned long size)
struct drm_file *file_priv, unsigned int *handle,
unsigned int size)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj; struct drm_gem_object *obj;
...@@ -73,75 +110,41 @@ static struct exynos_drm_gem_obj ...@@ -73,75 +110,41 @@ static struct exynos_drm_gem_obj
exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
if (!exynos_gem_obj) { if (!exynos_gem_obj) {
DRM_ERROR("failed to allocate exynos gem object.\n"); DRM_ERROR("failed to allocate exynos gem object\n");
return ERR_PTR(-ENOMEM); return NULL;
} }
obj = &exynos_gem_obj->base; obj = &exynos_gem_obj->base;
ret = drm_gem_object_init(drm_dev, obj, size); ret = drm_gem_object_init(dev, obj, size);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to initialize gem object.\n"); DRM_ERROR("failed to initialize gem object\n");
ret = -EINVAL; kfree(exynos_gem_obj);
goto err_object_init; return NULL;
} }
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
ret = drm_gem_create_mmap_offset(obj);
if (ret < 0) {
DRM_ERROR("failed to allocate mmap offset.\n");
goto err_create_mmap_offset;
}
/*
* allocate a id of idr table where the obj is registered
* and handle has the id what user can see.
*/
ret = drm_gem_handle_create(file_priv, obj, handle);
if (ret)
goto err_handle_create;
DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
/* drop reference from allocate - handle holds it now. */
drm_gem_object_unreference_unlocked(obj);
return exynos_gem_obj; return exynos_gem_obj;
err_handle_create:
drm_gem_free_mmap_offset(obj);
err_create_mmap_offset:
drm_gem_object_release(obj);
err_object_init:
kfree(exynos_gem_obj);
return ERR_PTR(ret);
} }
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
struct drm_file *file_priv, unsigned long size)
unsigned int *handle, unsigned long size)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_buf *buffer;
struct exynos_drm_gem_obj *exynos_gem_obj;
size = roundup(size, PAGE_SIZE); size = roundup(size, PAGE_SIZE);
DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
buffer = exynos_drm_buf_create(dev, size); buffer = exynos_drm_buf_create(dev, size);
if (IS_ERR(buffer)) { if (!buffer)
return ERR_CAST(buffer); return ERR_PTR(-ENOMEM);
}
exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size); exynos_gem_obj = exynos_drm_gem_init(dev, size);
if (IS_ERR(exynos_gem_obj)) { if (!exynos_gem_obj) {
exynos_drm_buf_destroy(dev, buffer); exynos_drm_buf_destroy(dev, buffer);
return exynos_gem_obj; return ERR_PTR(-ENOMEM);
} }
exynos_gem_obj->buffer = buffer; exynos_gem_obj->buffer = buffer;
...@@ -150,23 +153,30 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, ...@@ -150,23 +153,30 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
} }
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_exynos_gem_create *args = data; struct drm_exynos_gem_create *args = data;
struct exynos_drm_gem_obj *exynos_gem_obj = NULL; struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
&args->handle, args->size);
if (IS_ERR(exynos_gem_obj)) if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_gem_obj); return PTR_ERR(exynos_gem_obj);
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
&args->handle);
if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj);
return ret;
}
return 0; return 0;
} }
int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_exynos_gem_map_off *args = data; struct drm_exynos_gem_map_off *args = data;
...@@ -185,7 +195,7 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, ...@@ -185,7 +195,7 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
} }
static int exynos_drm_gem_mmap_buffer(struct file *filp, static int exynos_drm_gem_mmap_buffer(struct file *filp,
struct vm_area_struct *vma) struct vm_area_struct *vma)
{ {
struct drm_gem_object *obj = filp->private_data; struct drm_gem_object *obj = filp->private_data;
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
...@@ -196,6 +206,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, ...@@ -196,6 +206,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
vma->vm_flags |= (VM_IO | VM_RESERVED); vma->vm_flags |= (VM_IO | VM_RESERVED);
/* in case of direct mapping, always having non-cachable attribute */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_file = filp; vma->vm_file = filp;
...@@ -232,7 +243,7 @@ static const struct file_operations exynos_drm_gem_fops = { ...@@ -232,7 +243,7 @@ static const struct file_operations exynos_drm_gem_fops = {
}; };
int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_exynos_gem_mmap *args = data; struct drm_exynos_gem_mmap *args = data;
struct drm_gem_object *obj; struct drm_gem_object *obj;
...@@ -278,32 +289,19 @@ int exynos_drm_gem_init_object(struct drm_gem_object *obj) ...@@ -278,32 +289,19 @@ int exynos_drm_gem_init_object(struct drm_gem_object *obj)
return 0; return 0;
} }
void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj) void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
DRM_DEBUG_KMS("handle count = %d\n", exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
atomic_read(&gem_obj->handle_count));
if (gem_obj->map_list.map)
drm_gem_free_mmap_offset(gem_obj);
/* release file pointer to gem object. */
drm_gem_object_release(gem_obj);
exynos_gem_obj = to_exynos_gem_obj(gem_obj);
exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->buffer);
kfree(exynos_gem_obj);
} }
int exynos_drm_gem_dumb_create(struct drm_file *file_priv, int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev, struct drm_mode_create_dumb *args) struct drm_device *dev,
struct drm_mode_create_dumb *args)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -316,19 +314,27 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, ...@@ -316,19 +314,27 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
args->pitch = args->width * args->bpp >> 3; args->pitch = args->width * args->bpp >> 3;
args->size = args->pitch * args->height; args->size = args->pitch * args->height;
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle, exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
args->size);
if (IS_ERR(exynos_gem_obj)) if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_gem_obj); return PTR_ERR(exynos_gem_obj);
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
&args->handle);
if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj);
return ret;
}
return 0; return 0;
} }
int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle, uint64_t *offset) struct drm_device *dev, uint32_t handle,
uint64_t *offset)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj; struct drm_gem_object *obj;
int ret = 0;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -343,19 +349,46 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, ...@@ -343,19 +349,46 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
obj = drm_gem_object_lookup(dev, file_priv, handle); obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj) { if (!obj) {
DRM_ERROR("failed to lookup gem object.\n"); DRM_ERROR("failed to lookup gem object.\n");
mutex_unlock(&dev->struct_mutex); ret = -EINVAL;
return -EINVAL; goto unlock;
} }
exynos_gem_obj = to_exynos_gem_obj(obj); exynos_gem_obj = to_exynos_gem_obj(obj);
*offset = get_gem_mmap_offset(&exynos_gem_obj->base); if (!exynos_gem_obj->base.map_list.map) {
ret = drm_gem_create_mmap_offset(&exynos_gem_obj->base);
drm_gem_object_unreference(obj); if (ret)
goto out;
}
*offset = (u64)exynos_gem_obj->base.map_list.hash.key << PAGE_SHIFT;
DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
out:
drm_gem_object_unreference(obj);
unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret;
}
int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
struct drm_device *dev,
unsigned int handle)
{
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
/*
* obj->refcount and obj->handle_count are decreased and
* if both them are 0 then exynos_drm_gem_free_object()
* would be called by callback to release resources.
*/
ret = drm_gem_handle_delete(file_priv, handle);
if (ret < 0) {
DRM_ERROR("failed to delete drm_gem_handle.\n");
return ret;
}
return 0; return 0;
} }
...@@ -403,28 +436,6 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -403,28 +436,6 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret; return ret;
} }
int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
struct drm_device *dev, unsigned int handle)
{
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
/*
* obj->refcount and obj->handle_count are decreased and
* if both them are 0 then exynos_drm_gem_free_object()
* would be called by callback to release resources.
*/
ret = drm_gem_handle_delete(file_priv, handle);
if (ret < 0) {
DRM_ERROR("failed to delete drm_gem_handle.\n");
return ret;
}
return 0;
}
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DRM GEM Module"); MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -60,14 +60,16 @@ struct exynos_drm_gem_buf { ...@@ -60,14 +60,16 @@ struct exynos_drm_gem_buf {
* user can access the buffer through kms_bo.handle. * user can access the buffer through kms_bo.handle.
*/ */
struct exynos_drm_gem_obj { struct exynos_drm_gem_obj {
struct drm_gem_object base; struct drm_gem_object base;
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_buf *buffer;
}; };
/* create a new buffer and get a new gem handle. */ /* destroy a buffer with gem object */
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
/* create a new buffer with gem object */
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
struct drm_file *file_priv, unsigned long size);
unsigned int *handle, unsigned long size);
/* /*
* request gem object creation and buffer allocation as the size * request gem object creation and buffer allocation as the size
...@@ -75,15 +77,18 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, ...@@ -75,15 +77,18 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
* height and bpp. * height and bpp.
*/ */
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
/* get buffer offset to map to user space. */ /* get buffer offset to map to user space. */
int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
/* unmap a buffer from user space. */ /*
int exynos_drm_gem_munmap_ioctl(struct drm_device *dev, void *data, * mmap the physically continuous memory that a gem object contains
struct drm_file *file_priv); * to user space.
*/
int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* initialize gem object. */ /* initialize gem object. */
int exynos_drm_gem_init_object(struct drm_gem_object *obj); int exynos_drm_gem_init_object(struct drm_gem_object *obj);
...@@ -93,24 +98,13 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj); ...@@ -93,24 +98,13 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
/* create memory region for drm framebuffer. */ /* create memory region for drm framebuffer. */
int exynos_drm_gem_dumb_create(struct drm_file *file_priv, int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev, struct drm_mode_create_dumb *args); struct drm_device *dev,
struct drm_mode_create_dumb *args);
/* map memory region for drm framebuffer to user space. */ /* map memory region for drm framebuffer to user space. */
int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle, uint64_t *offset); struct drm_device *dev, uint32_t handle,
uint64_t *offset);
/* page fault handler and mmap fault address(virtual) to physical memory. */
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/*
* mmap the physically continuous memory that a gem object contains
* to user space.
*/
int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
/* /*
* destroy memory region allocated. * destroy memory region allocated.
...@@ -118,6 +112,13 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); ...@@ -118,6 +112,13 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
* would be released by drm_gem_handle_delete(). * would be released by drm_gem_handle_delete().
*/ */
int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv, int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
struct drm_device *dev, unsigned int handle); struct drm_device *dev,
unsigned int handle);
/* page fault handler and mmap fault address(virtual) to physical memory. */
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
#endif #endif
This diff is collapsed.
/* exynos_drm_hdmi.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authoer: Inki Dae <inki.dae@samsung.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _EXYNOS_DRM_HDMI_H_
#define _EXYNOS_DRM_HDMI_H_
/*
* exynos hdmi common context structure.
*
* @drm_dev: pointer to drm_device.
* @ctx: pointer to the context of specific device driver.
* this context should be hdmi_context or mixer_context.
*/
struct exynos_drm_hdmi_context {
struct drm_device *drm_dev;
void *ctx;
};
struct exynos_hdmi_display_ops {
bool (*is_connected)(void *ctx);
int (*get_edid)(void *ctx, struct drm_connector *connector,
u8 *edid, int len);
int (*check_timing)(void *ctx, void *timing);
int (*power_on)(void *ctx, int mode);
};
struct exynos_hdmi_manager_ops {
void (*mode_set)(void *ctx, void *mode);
void (*commit)(void *ctx);
void (*disable)(void *ctx);
};
struct exynos_hdmi_overlay_ops {
int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx);
void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
void (*win_commit)(void *ctx, int zpos);
void (*win_disable)(void *ctx, int zpos);
};
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
*display_ops);
void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
*manager_ops);
void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
*overlay_ops);
#endif
This diff is collapsed.
/*
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Seung-Woo Kim <sw0312.kim@samsung.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _EXYNOS_HDMI_H_
#define _EXYNOS_HDMI_H_
struct hdmi_conf {
int width;
int height;
int vrefresh;
bool interlace;
const u8 *hdmiphy_data;
const struct hdmi_preset_conf *conf;
};
struct hdmi_resources {
struct clk *hdmi;
struct clk *sclk_hdmi;
struct clk *sclk_pixel;
struct clk *sclk_hdmiphy;
struct clk *hdmiphy;
struct regulator_bulk_data *regul_bulk;
int regul_count;
};
struct hdmi_context {
struct device *dev;
struct drm_device *drm_dev;
struct fb_videomode *default_timing;
unsigned int default_win;
unsigned int default_bpp;
bool hpd_handle;
bool enabled;
struct resource *regs_res;
/** base address of HDMI registers */
void __iomem *regs;
/** HDMI hotplug interrupt */
unsigned int irq;
/** workqueue for delayed work */
struct workqueue_struct *wq;
/** hotplug handling work */
struct work_struct hotplug_work;
struct i2c_client *ddc_port;
struct i2c_client *hdmiphy_port;
/** current hdmiphy conf index */
int cur_conf;
/** other resources */
struct hdmi_resources res;
void *parent_ctx;
};
void hdmi_attach_ddc_client(struct i2c_client *ddc);
void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
extern struct i2c_driver hdmiphy_driver;
extern struct i2c_driver ddc_driver;
#endif
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Authors:
* Seung-Woo Kim <sw0312.kim@samsung.com>
* Inki Dae <inki.dae@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 <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include "exynos_drm_drv.h"
#include "exynos_hdmi.h"
static int hdmiphy_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
hdmi_attach_hdmiphy_client(client);
dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
"into i2c adapter successfully\n");
return 0;
}
static int hdmiphy_remove(struct i2c_client *client)
{
dev_info(&client->adapter->dev, "detached s5p_hdmiphy "
"from i2c adapter successfully\n");
return 0;
}
static const struct i2c_device_id hdmiphy_id[] = {
{ "s5p_hdmiphy", 0 },
{ },
};
struct i2c_driver hdmiphy_driver = {
.driver = {
.name = "s5p-hdmiphy",
.owner = THIS_MODULE,
},
.id_table = hdmiphy_id,
.probe = hdmiphy_probe,
.remove = __devexit_p(hdmiphy_remove),
.command = NULL,
};
EXPORT_SYMBOL(hdmiphy_driver);
This diff is collapsed.
/*
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Seung-Woo Kim <sw0312.kim@samsung.com>
* Inki Dae <inki.dae@samsung.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _EXYNOS_MIXER_H_
#define _EXYNOS_MIXER_H_
#define HDMI_OVERLAY_NUMBER 3
struct hdmi_win_data {
dma_addr_t dma_addr;
void __iomem *vaddr;
dma_addr_t chroma_dma_addr;
void __iomem *chroma_vaddr;
uint32_t pixel_format;
unsigned int bpp;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_width;
unsigned int crtc_height;
unsigned int fb_x;
unsigned int fb_y;
unsigned int fb_width;
unsigned int fb_height;
unsigned int mode_width;
unsigned int mode_height;
unsigned int scan_flags;
};
struct mixer_resources {
struct device *dev;
/** interrupt index */
int irq;
/** pointer to Mixer registers */
void __iomem *mixer_regs;
/** pointer to Video Processor registers */
void __iomem *vp_regs;
/** spinlock for protection of registers */
spinlock_t reg_slock;
/** other resources */
struct clk *mixer;
struct clk *vp;
struct clk *sclk_mixer;
struct clk *sclk_hdmi;
struct clk *sclk_dac;
};
struct mixer_context {
unsigned int default_win;
struct fb_videomode *default_timing;
unsigned int default_bpp;
/** mixer interrupt */
unsigned int irq;
/** current crtc pipe for vblank */
int pipe;
/** interlace scan mode */
bool interlace;
/** vp enabled status */
bool vp_enabled;
/** mixer and vp resources */
struct mixer_resources mixer_res;
/** overlay window data */
struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
};
#endif
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-hdmi.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* HDMI register header file for Samsung TVOUT driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef SAMSUNG_REGS_HDMI_H
#define SAMSUNG_REGS_HDMI_H
/*
* Register part
*/
#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
#define HDMI_TG_BASE(x) ((x) + 0x00050000)
/* Control registers */
#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018)
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C)
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
/* Core registers */
#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014)
#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
#define HDMI_HPD HDMI_CORE_BASE(0x0030)
#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
#define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
#define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
#define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
#define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
#define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
#define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
#define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
#define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
#define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
#define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
#define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
#define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
#define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
#define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
#define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
#define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
#define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
#define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
#define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
#define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
#define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
#define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
#define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
#define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0180)
#define HDMI_AVI_CON HDMI_CORE_BASE(0x0300)
#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0)
#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
#define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8)
#define HDMI_AUI_CON HDMI_CORE_BASE(0x0360)
#define HDMI_SPD_CON HDMI_CORE_BASE(0x0400)
/* Timing generator registers */
#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018)
#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C)
#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020)
#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024)
#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028)
#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C)
#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030)
#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034)
#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038)
#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C)
#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040)
#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044)
#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048)
#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C)
#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050)
#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054)
#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058)
#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C)
#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060)
#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064)
#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078)
#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C)
#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080)
#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084)
#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088)
#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C)
#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090)
#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094)
/*
* Bit definition part
*/
/* HDMI_INTC_CON */
#define HDMI_INTC_EN_GLOBAL (1 << 6)
#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
/* HDMI_INTC_FLAG */
#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
/* HDMI_PHY_RSTOUT */
#define HDMI_PHY_SW_RSTOUT (1 << 0)
/* HDMI_CORE_RSTOUT */
#define HDMI_CORE_SW_RSTOUT (1 << 0)
/* HDMI_CON_0 */
#define HDMI_BLUE_SCR_EN (1 << 5)
#define HDMI_EN (1 << 0)
/* HDMI_PHY_STATUS */
#define HDMI_PHY_STATUS_READY (1 << 0)
/* HDMI_MODE_SEL */
#define HDMI_MODE_HDMI_EN (1 << 1)
#define HDMI_MODE_DVI_EN (1 << 0)
#define HDMI_MODE_MASK (3 << 0)
/* HDMI_TG_CMD */
#define HDMI_TG_EN (1 << 0)
#define HDMI_FIELD_EN (1 << 1)
#endif /* SAMSUNG_REGS_HDMI_H */
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-mixer.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Mixer register header file for Samsung Mixer driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef SAMSUNG_REGS_MIXER_H
#define SAMSUNG_REGS_MIXER_H
/*
* Register part
*/
#define MXR_STATUS 0x0000
#define MXR_CFG 0x0004
#define MXR_INT_EN 0x0008
#define MXR_INT_STATUS 0x000C
#define MXR_LAYER_CFG 0x0010
#define MXR_VIDEO_CFG 0x0014
#define MXR_GRAPHIC0_CFG 0x0020
#define MXR_GRAPHIC0_BASE 0x0024
#define MXR_GRAPHIC0_SPAN 0x0028
#define MXR_GRAPHIC0_SXY 0x002C
#define MXR_GRAPHIC0_WH 0x0030
#define MXR_GRAPHIC0_DXY 0x0034
#define MXR_GRAPHIC0_BLANK 0x0038
#define MXR_GRAPHIC1_CFG 0x0040
#define MXR_GRAPHIC1_BASE 0x0044
#define MXR_GRAPHIC1_SPAN 0x0048
#define MXR_GRAPHIC1_SXY 0x004C
#define MXR_GRAPHIC1_WH 0x0050
#define MXR_GRAPHIC1_DXY 0x0054
#define MXR_GRAPHIC1_BLANK 0x0058
#define MXR_BG_CFG 0x0060
#define MXR_BG_COLOR0 0x0064
#define MXR_BG_COLOR1 0x0068
#define MXR_BG_COLOR2 0x006C
#define MXR_CM_COEFF_Y 0x0080
#define MXR_CM_COEFF_CB 0x0084
#define MXR_CM_COEFF_CR 0x0088
#define MXR_GRAPHIC0_BASE_S 0x2024
#define MXR_GRAPHIC1_BASE_S 0x2044
/* for parametrized access to layer registers */
#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
#define MXR_GRAPHIC_BLANK(i) (0x0038 + (i) * 0x20)
#define MXR_GRAPHIC_BASE_S(i) (0x2024 + (i) * 0x20)
/*
* Bit definition part
*/
/* generates mask for range of bits */
#define MXR_MASK(high_bit, low_bit) \
(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
#define MXR_MASK_VAL(val, high_bit, low_bit) \
(((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
/* bits for MXR_STATUS */
#define MXR_STATUS_16_BURST (1 << 7)
#define MXR_STATUS_BURST_MASK (1 << 7)
#define MXR_STATUS_BIG_ENDIAN (1 << 3)
#define MXR_STATUS_ENDIAN_MASK (1 << 3)
#define MXR_STATUS_SYNC_ENABLE (1 << 2)
#define MXR_STATUS_REG_RUN (1 << 0)
/* bits for MXR_CFG */
#define MXR_CFG_RGB601_0_255 (0 << 9)
#define MXR_CFG_RGB601_16_235 (1 << 9)
#define MXR_CFG_RGB709_0_255 (2 << 9)
#define MXR_CFG_RGB709_16_235 (3 << 9)
#define MXR_CFG_RGB_FMT_MASK 0x600
#define MXR_CFG_OUT_YUV444 (0 << 8)
#define MXR_CFG_OUT_RGB888 (1 << 8)
#define MXR_CFG_OUT_MASK (1 << 8)
#define MXR_CFG_DST_SDO (0 << 7)
#define MXR_CFG_DST_HDMI (1 << 7)
#define MXR_CFG_DST_MASK (1 << 7)
#define MXR_CFG_SCAN_HD_720 (0 << 6)
#define MXR_CFG_SCAN_HD_1080 (1 << 6)
#define MXR_CFG_GRP1_ENABLE (1 << 5)
#define MXR_CFG_GRP0_ENABLE (1 << 4)
#define MXR_CFG_VP_ENABLE (1 << 3)
#define MXR_CFG_SCAN_INTERLACE (0 << 2)
#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
#define MXR_CFG_SCAN_NTSC (0 << 1)
#define MXR_CFG_SCAN_PAL (1 << 1)
#define MXR_CFG_SCAN_SD (0 << 0)
#define MXR_CFG_SCAN_HD (1 << 0)
#define MXR_CFG_SCAN_MASK 0x47
/* bits for MXR_GRAPHICn_CFG */
#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17)
#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
/* bits for MXR_GRAPHICn_WH */
#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_GRAPHICn_SXY */
#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_GRAPHICn_DXY */
#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_INT_EN */
#define MXR_INT_EN_VSYNC (1 << 11)
#define MXR_INT_EN_ALL (0x0f << 8)
/* bit for MXR_INT_STATUS */
#define MXR_INT_CLEAR_VSYNC (1 << 11)
#define MXR_INT_STATUS_VSYNC (1 << 0)
/* bit for MXR_LAYER_CFG */
#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
#endif /* SAMSUNG_REGS_MIXER_H */
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-vp.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Video processor register header file for Samsung Mixer driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef SAMSUNG_REGS_VP_H
#define SAMSUNG_REGS_VP_H
/*
* Register part
*/
#define VP_ENABLE 0x0000
#define VP_SRESET 0x0004
#define VP_SHADOW_UPDATE 0x0008
#define VP_FIELD_ID 0x000C
#define VP_MODE 0x0010
#define VP_IMG_SIZE_Y 0x0014
#define VP_IMG_SIZE_C 0x0018
#define VP_PER_RATE_CTRL 0x001C
#define VP_TOP_Y_PTR 0x0028
#define VP_BOT_Y_PTR 0x002C
#define VP_TOP_C_PTR 0x0030
#define VP_BOT_C_PTR 0x0034
#define VP_ENDIAN_MODE 0x03CC
#define VP_SRC_H_POSITION 0x0044
#define VP_SRC_V_POSITION 0x0048
#define VP_SRC_WIDTH 0x004C
#define VP_SRC_HEIGHT 0x0050
#define VP_DST_H_POSITION 0x0054
#define VP_DST_V_POSITION 0x0058
#define VP_DST_WIDTH 0x005C
#define VP_DST_HEIGHT 0x0060
#define VP_H_RATIO 0x0064
#define VP_V_RATIO 0x0068
#define VP_POLY8_Y0_LL 0x006C
#define VP_POLY4_Y0_LL 0x00EC
#define VP_POLY4_C0_LL 0x012C
/*
* Bit definition part
*/
/* generates mask for range of bits */
#define VP_MASK(high_bit, low_bit) \
(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
#define VP_MASK_VAL(val, high_bit, low_bit) \
(((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
/* VP_ENABLE */
#define VP_ENABLE_ON (1 << 0)
/* VP_SRESET */
#define VP_SRESET_PROCESSING (1 << 0)
/* VP_SHADOW_UPDATE */
#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
/* VP_MODE */
#define VP_MODE_NV12 (0 << 6)
#define VP_MODE_NV21 (1 << 6)
#define VP_MODE_LINE_SKIP (1 << 5)
#define VP_MODE_MEM_LINEAR (0 << 4)
#define VP_MODE_MEM_TILED (1 << 4)
#define VP_MODE_FMT_MASK (5 << 4)
#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
#define VP_MODE_2D_IPC (1 << 1)
/* VP_IMG_SIZE_Y */
/* VP_IMG_SIZE_C */
#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
/* VP_SRC_H_POSITION */
#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
/* VP_ENDIAN_MODE */
#define VP_ENDIAN_MODE_LITTLE (1 << 0)
#endif /* SAMSUNG_REGS_VP_H */
...@@ -107,6 +107,10 @@ ...@@ -107,6 +107,10 @@
#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ #define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
/* 2 non contiguous plane YCbCr */
#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */
#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */
/* /*
* 3 plane YCbCr * 3 plane YCbCr
* index 0: Y plane, [7:0] Y * index 0: Y plane, [7:0] Y
...@@ -127,4 +131,7 @@ ...@@ -127,4 +131,7 @@
#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
/* 3 non contiguous plane YCbCr */
#define DRM_FORMAT_YUV420M fourcc_code('Y', 'M', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
#endif /* DRM_FOURCC_H */ #endif /* DRM_FOURCC_H */
...@@ -112,4 +112,31 @@ struct exynos_drm_fimd_pdata { ...@@ -112,4 +112,31 @@ struct exynos_drm_fimd_pdata {
unsigned int bpp; unsigned int bpp;
}; };
/**
* Platform Specific Structure for DRM based HDMI.
*
* @hdmi_dev: device point to specific hdmi driver.
* @mixer_dev: device point to specific mixer driver.
*
* this structure is used for common hdmi driver and each device object
* would be used to access specific device driver(hdmi or mixer driver)
*/
struct exynos_drm_common_hdmi_pd {
struct device *hdmi_dev;
struct device *mixer_dev;
};
/**
* Platform Specific Structure for DRM based HDMI core.
*
* @timing: default video mode for initializing
* @default_win: default window layer number to be used for UI.
* @bpp: default bit per pixel.
*/
struct exynos_drm_hdmi_pdata {
struct fb_videomode timing;
unsigned int default_win;
unsigned int bpp;
};
#endif #endif
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