Commit 2c871127 authored by Inki Dae's avatar Inki Dae

drm/exynos: changed buffer structure.

the purpose of this patch is to consider IOMMU support in the future.
EXYNOS4 SoC supports IOMMU also so the address for DMA could be
physical address with IOMMU or device address with IOMMU.
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
parent c7493668
......@@ -27,80 +27,84 @@
#include "drm.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
static int lowlevel_buffer_allocate(struct drm_device *dev,
struct exynos_drm_buf_entry *entry)
struct exynos_drm_gem_buf *buffer)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
entry->vaddr = dma_alloc_writecombine(dev->dev, entry->size,
(dma_addr_t *)&entry->paddr, GFP_KERNEL);
if (!entry->paddr) {
buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size,
&buffer->dma_addr, GFP_KERNEL);
if (!buffer->kvaddr) {
DRM_ERROR("failed to allocate buffer.\n");
return -ENOMEM;
}
DRM_DEBUG_KMS("allocated : vaddr(0x%x), paddr(0x%x), size(0x%x)\n",
(unsigned int)entry->vaddr, entry->paddr, entry->size);
DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)buffer->kvaddr,
(unsigned long)buffer->dma_addr,
buffer->size);
return 0;
}
static void lowlevel_buffer_deallocate(struct drm_device *dev,
struct exynos_drm_buf_entry *entry)
struct exynos_drm_gem_buf *buffer)
{
DRM_DEBUG_KMS("%s.\n", __FILE__);
if (entry->paddr && entry->vaddr && entry->size)
dma_free_writecombine(dev->dev, entry->size, entry->vaddr,
entry->paddr);
if (buffer->dma_addr && buffer->size)
dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
(dma_addr_t)buffer->dma_addr);
else
DRM_DEBUG_KMS("entry data is null.\n");
DRM_DEBUG_KMS("buffer data are invalid.\n");
}
struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
unsigned int size)
{
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
DRM_DEBUG_KMS("%s.\n", __FILE__);
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
DRM_ERROR("failed to allocate exynos_drm_buf_entry.\n");
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) {
DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
return ERR_PTR(-ENOMEM);
}
entry->size = size;
buffer->size = size;
/*
* allocate memory region with size and set the memory information
* to vaddr and paddr of a entry object.
* to vaddr and dma_addr of a buffer object.
*/
if (lowlevel_buffer_allocate(dev, entry) < 0) {
kfree(entry);
entry = NULL;
if (lowlevel_buffer_allocate(dev, buffer) < 0) {
kfree(buffer);
buffer = NULL;
return ERR_PTR(-ENOMEM);
}
return entry;
return buffer;
}
void exynos_drm_buf_destroy(struct drm_device *dev,
struct exynos_drm_buf_entry *entry)
struct exynos_drm_gem_buf *buffer)
{
DRM_DEBUG_KMS("%s.\n", __FILE__);
if (!entry) {
DRM_DEBUG_KMS("entry is null.\n");
if (!buffer) {
DRM_DEBUG_KMS("buffer is null.\n");
return;
}
lowlevel_buffer_deallocate(dev, entry);
lowlevel_buffer_deallocate(dev, buffer);
kfree(entry);
entry = NULL;
kfree(buffer);
buffer = NULL;
}
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
......
......@@ -26,28 +26,15 @@
#ifndef _EXYNOS_DRM_BUF_H_
#define _EXYNOS_DRM_BUF_H_
/*
* exynos drm buffer entry structure.
*
* @paddr: physical address of allocated memory.
* @vaddr: kernel virtual address of allocated memory.
* @size: size of allocated memory.
*/
struct exynos_drm_buf_entry {
dma_addr_t paddr;
void __iomem *vaddr;
unsigned int size;
};
/* allocate physical memory. */
struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
unsigned int size);
/* get physical memory information of a drm framebuffer. */
struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb);
/* 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. */
void exynos_drm_buf_destroy(struct drm_device *dev,
struct exynos_drm_buf_entry *entry);
struct exynos_drm_gem_buf *buffer);
#endif
......@@ -29,35 +29,16 @@
#include "drmP.h"
#include "drm_crtc_helper.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
drm_crtc)
/*
* Exynos specific crtc postion structure.
*
* @fb_x: offset x on a framebuffer to be displyed
* - the unit is screen coordinates.
* @fb_y: offset y on a framebuffer to be displayed
* - the unit is screen coordinates.
* @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen.
* @crtc_w: width of hardware screen.
* @crtc_h: height of hardware screen.
*/
struct exynos_drm_crtc_pos {
unsigned int fb_x;
unsigned int fb_y;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_w;
unsigned int crtc_h;
};
/*
* Exynos specific crtc structure.
*
......@@ -89,27 +70,27 @@ static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
exynos_drm_encoder_crtc_commit);
}
static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
struct drm_framebuffer *fb,
struct drm_display_mode *mode,
struct exynos_drm_crtc_pos *pos)
int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
struct drm_framebuffer *fb,
struct drm_display_mode *mode,
struct exynos_drm_crtc_pos *pos)
{
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
unsigned int actual_w;
unsigned int actual_h;
entry = exynos_drm_fb_get_buf(fb);
if (!entry) {
DRM_LOG_KMS("entry is null.\n");
buffer = exynos_drm_fb_get_buf(fb);
if (!buffer) {
DRM_LOG_KMS("buffer is null.\n");
return -EFAULT;
}
overlay->paddr = entry->paddr;
overlay->vaddr = entry->vaddr;
overlay->dma_addr = buffer->dma_addr;
overlay->vaddr = buffer->kvaddr;
DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n",
(unsigned long)overlay->vaddr,
(unsigned long)overlay->paddr);
(unsigned long)overlay->dma_addr);
actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
......
......@@ -35,4 +35,29 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
/*
* Exynos specific crtc postion structure.
*
* @fb_x: offset x on a framebuffer to be displyed
* - the unit is screen coordinates.
* @fb_y: offset y on a framebuffer to be displayed
* - the unit is screen coordinates.
* @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen.
* @crtc_w: width of hardware screen.
* @crtc_h: height of hardware screen.
*/
struct exynos_drm_crtc_pos {
unsigned int fb_x;
unsigned int fb_y;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_w;
unsigned int crtc_h;
};
int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
struct drm_framebuffer *fb,
struct drm_display_mode *mode,
struct exynos_drm_crtc_pos *pos);
#endif
......@@ -79,8 +79,8 @@ struct exynos_drm_overlay_ops {
* @scan_flag: interlace or progressive way.
* (it could be DRM_MODE_FLAG_*)
* @bpp: pixel size.(in bit)
* @paddr: bus(accessed by dma) physical memory address to this overlay
* and this is physically continuous.
* @dma_addr: bus(accessed by dma) address to the memory region allocated
* for a overlay.
* @vaddr: virtual memory addresss to this overlay.
* @default_win: a window to be enabled.
* @color_key: color key on or off.
......@@ -108,7 +108,7 @@ struct exynos_drm_overlay {
unsigned int scan_flag;
unsigned int bpp;
unsigned int pitch;
dma_addr_t paddr;
dma_addr_t dma_addr;
void __iomem *vaddr;
bool default_win;
......
......@@ -43,14 +43,14 @@
*
* @fb: drm framebuffer obejct.
* @exynos_gem_obj: exynos specific gem object containing a gem object.
* @entry: pointer to exynos drm buffer entry object.
* - containing only the information to physically continuous memory
* region allocated at default framebuffer creation.
* @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 drm_framebuffer fb;
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
};
static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
......@@ -65,8 +65,8 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *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->entry)
exynos_drm_buf_destroy(fb->dev, exynos_fb->entry);
if (!exynos_fb->exynos_gem_obj && exynos_fb->buffer)
exynos_drm_buf_destroy(fb->dev, exynos_fb->buffer);
kfree(exynos_fb);
exynos_fb = NULL;
......@@ -145,23 +145,23 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
*/
if (!mode_cmd->handle) {
if (!file_priv) {
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
/*
* in case that file_priv is NULL, it allocates
* only buffer and this buffer would be used
* for default framebuffer.
*/
entry = exynos_drm_buf_create(dev, size);
if (IS_ERR(entry)) {
ret = PTR_ERR(entry);
buffer = exynos_drm_buf_create(dev, size);
if (IS_ERR(buffer)) {
ret = PTR_ERR(buffer);
goto err_buffer;
}
exynos_fb->entry = entry;
exynos_fb->buffer = buffer;
DRM_LOG_KMS("default fb: paddr = 0x%lx, size = 0x%x\n",
(unsigned long)entry->paddr, size);
DRM_LOG_KMS("default: dma_addr = 0x%lx, size = 0x%x\n",
(unsigned long)buffer->dma_addr, size);
goto out;
} else {
......@@ -191,10 +191,10 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
* so that default framebuffer has no its own gem object,
* only its own buffer object.
*/
exynos_fb->entry = exynos_gem_obj->entry;
exynos_fb->buffer = exynos_gem_obj->buffer;
DRM_LOG_KMS("paddr = 0x%lx, size = 0x%x, gem object = 0x%x\n",
(unsigned long)exynos_fb->entry->paddr, size,
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:
......@@ -222,22 +222,22 @@ struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
return exynos_drm_fb_init(file_priv, dev, mode_cmd);
}
struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb)
struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
DRM_DEBUG_KMS("%s\n", __FILE__);
entry = exynos_fb->entry;
if (!entry)
buffer = exynos_fb->buffer;
if (!buffer)
return NULL;
DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
(unsigned long)entry->vaddr,
(unsigned long)entry->paddr);
DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n",
(unsigned long)buffer->kvaddr,
(unsigned long)buffer->dma_addr);
return entry;
return buffer;
}
static void exynos_drm_output_poll_changed(struct drm_device *dev)
......
......@@ -33,6 +33,7 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#define MAX_CONNECTOR 4
......@@ -90,7 +91,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct fb_info *fbi = helper->fbdev;
struct drm_device *dev = helper->dev;
struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper);
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
unsigned long offset;
......@@ -101,18 +102,18 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
entry = exynos_drm_fb_get_buf(fb);
if (!entry) {
DRM_LOG_KMS("entry is null.\n");
buffer = exynos_drm_fb_get_buf(fb);
if (!buffer) {
DRM_LOG_KMS("buffer is null.\n");
return -EFAULT;
}
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
offset += fbi->var.yoffset * fb->pitch;
dev->mode_config.fb_base = entry->paddr;
fbi->screen_base = entry->vaddr + offset;
fbi->fix.smem_start = entry->paddr + offset;
dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
fbi->screen_base = buffer->kvaddr + offset;
fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset);
fbi->screen_size = size;
fbi->fix.smem_len = size;
......
......@@ -64,7 +64,7 @@ struct fimd_win_data {
unsigned int fb_width;
unsigned int fb_height;
unsigned int bpp;
dma_addr_t paddr;
dma_addr_t dma_addr;
void __iomem *vaddr;
unsigned int buf_offsize;
unsigned int line_size; /* bytes */
......@@ -251,7 +251,7 @@ static void fimd_win_mode_set(struct device *dev,
win_data->ovl_height = overlay->crtc_height;
win_data->fb_width = overlay->fb_width;
win_data->fb_height = overlay->fb_height;
win_data->paddr = overlay->paddr + offset;
win_data->dma_addr = overlay->dma_addr + offset;
win_data->vaddr = overlay->vaddr + offset;
win_data->bpp = overlay->bpp;
win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
......@@ -263,7 +263,7 @@ static void fimd_win_mode_set(struct device *dev,
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
win_data->ovl_width, win_data->ovl_height);
DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
(unsigned long)win_data->paddr,
(unsigned long)win_data->dma_addr,
(unsigned long)win_data->vaddr);
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
overlay->fb_width, overlay->crtc_width);
......@@ -376,16 +376,16 @@ static void fimd_win_commit(struct device *dev)
writel(val, ctx->regs + SHADOWCON);
/* buffer start address */
val = win_data->paddr;
val = (unsigned long)win_data->dma_addr;
writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
/* buffer end address */
size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
val = win_data->paddr + size;
val = (unsigned long)(win_data->dma_addr + size);
writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
(unsigned long)win_data->paddr, val, size);
(unsigned long)win_data->dma_addr, val, size);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
win_data->ovl_width, win_data->ovl_height);
......
......@@ -127,15 +127,15 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
{
struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
int ret;
size = roundup(size, PAGE_SIZE);
DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
entry = exynos_drm_buf_create(dev, size);
if (!entry)
buffer = exynos_drm_buf_create(dev, size);
if (!buffer)
return ERR_PTR(-ENOMEM);
exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size);
......@@ -144,12 +144,12 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
goto err_gem_init;
}
exynos_gem_obj->entry = entry;
exynos_gem_obj->buffer = buffer;
return exynos_gem_obj;
err_gem_init:
exynos_drm_buf_destroy(dev, exynos_gem_obj->entry);
exynos_drm_buf_destroy(dev, exynos_gem_obj->buffer);
return ERR_PTR(ret);
}
......@@ -194,7 +194,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
{
struct drm_gem_object *obj = filp->private_data;
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
unsigned long pfn, vm_size;
DRM_DEBUG_KMS("%s\n", __FILE__);
......@@ -206,20 +206,20 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
vm_size = vma->vm_end - vma->vm_start;
/*
* a entry contains information to physically continuous memory
* a buffer contains information to physically continuous memory
* allocated by user request or at framebuffer creation.
*/
entry = exynos_gem_obj->entry;
buffer = exynos_gem_obj->buffer;
/* check if user-requested size is valid. */
if (vm_size > entry->size)
if (vm_size > buffer->size)
return -EINVAL;
/*
* get page frame number to physical memory to be mapped
* to user space.
*/
pfn = exynos_gem_obj->entry->paddr >> PAGE_SHIFT;
pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT;
DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
......@@ -300,7 +300,7 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj)
exynos_gem_obj = to_exynos_gem_obj(gem_obj);
exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->entry);
exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->buffer);
kfree(exynos_gem_obj);
}
......@@ -379,7 +379,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
mutex_lock(&dev->struct_mutex);
pfn = (exynos_gem_obj->entry->paddr >> PAGE_SHIFT) + page_offset;
pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
PAGE_SHIFT) + page_offset;
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
......
......@@ -29,14 +29,30 @@
#define to_exynos_gem_obj(x) container_of(x,\
struct exynos_drm_gem_obj, base)
/*
* exynos drm gem buffer structure.
*
* @kvaddr: kernel virtual address to allocated memory region.
* @dma_addr: bus address(accessed by dma) to allocated memory region.
* - this address could be physical address without IOMMU and
* device address with IOMMU.
* @size: size of allocated memory region.
*/
struct exynos_drm_gem_buf {
void __iomem *kvaddr;
dma_addr_t dma_addr;
unsigned long size;
};
/*
* exynos drm buffer structure.
*
* @base: a gem object.
* - a new handle to this gem object would be created
* by drm_gem_handle_create().
* @entry: pointer to exynos drm buffer entry object.
* - containing the information to physically
* @buffer: a pointer to exynos_drm_gem_buffer object.
* - contain the information to memory region allocated
* by user request or at framebuffer creation.
* continuous memory region allocated by user request
* or at framebuffer creation.
*
......@@ -45,7 +61,7 @@
*/
struct exynos_drm_gem_obj {
struct drm_gem_object base;
struct exynos_drm_buf_entry *entry;
struct exynos_drm_gem_buf *buffer;
};
/* create a new buffer and get a new gem handle. */
......
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