mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-16 23:45:31 +08:00
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux: drm/exynos: fixed wrong err ptr usage and destroy call in exeception drm/exynos: Add disable of manager drm/exynos: include linux/module.h drm/exynos: fix vblank bug. drm/exynos: changed buffer structure. drm/exynos: removed unnecessary variable. drm/exynos: use gem create function generically drm/exynos: checked for null pointer drm/exynos: added crtc dpms for disable crtc drm/exynos: removed meaningless parameter from fbdev update drm/exynos: restored kernel_fb_list when reiniting fb_helper drm/exynos: changed exynos_drm_display to exynos_drm_display_ops drm/exynos: added manager object to connector drm/exynos: fixed converting between display mode and timing drm/exynos: fixed connector flag with hpd and interlace scan for hdmi drm/exynos: added kms poll for handling hpd event
This commit is contained in:
commit
4244cb482e
@ -27,82 +27,84 @@
|
|||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
|
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
|
#include "exynos_drm_gem.h"
|
||||||
#include "exynos_drm_buf.h"
|
#include "exynos_drm_buf.h"
|
||||||
|
|
||||||
static DEFINE_MUTEX(exynos_drm_buf_lock);
|
|
||||||
|
|
||||||
static int lowlevel_buffer_allocate(struct drm_device *dev,
|
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__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
entry->vaddr = dma_alloc_writecombine(dev->dev, entry->size,
|
buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size,
|
||||||
(dma_addr_t *)&entry->paddr, GFP_KERNEL);
|
&buffer->dma_addr, GFP_KERNEL);
|
||||||
if (!entry->paddr) {
|
if (!buffer->kvaddr) {
|
||||||
DRM_ERROR("failed to allocate buffer.\n");
|
DRM_ERROR("failed to allocate buffer.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRM_DEBUG_KMS("allocated : vaddr(0x%x), paddr(0x%x), size(0x%x)\n",
|
DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
|
||||||
(unsigned int)entry->vaddr, entry->paddr, entry->size);
|
(unsigned long)buffer->kvaddr,
|
||||||
|
(unsigned long)buffer->dma_addr,
|
||||||
|
buffer->size);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lowlevel_buffer_deallocate(struct drm_device *dev,
|
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__);
|
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||||
|
|
||||||
if (entry->paddr && entry->vaddr && entry->size)
|
if (buffer->dma_addr && buffer->size)
|
||||||
dma_free_writecombine(dev->dev, entry->size, entry->vaddr,
|
dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
|
||||||
entry->paddr);
|
(dma_addr_t)buffer->dma_addr);
|
||||||
else
|
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)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
struct exynos_drm_buf_entry *entry;
|
struct exynos_drm_gem_buf *buffer;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||||
|
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
|
||||||
|
|
||||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||||
if (!entry) {
|
if (!buffer) {
|
||||||
DRM_ERROR("failed to allocate exynos_drm_buf_entry.\n");
|
DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->size = size;
|
buffer->size = size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate memory region with size and set the memory information
|
* 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) {
|
if (lowlevel_buffer_allocate(dev, buffer) < 0) {
|
||||||
kfree(entry);
|
kfree(buffer);
|
||||||
entry = NULL;
|
buffer = NULL;
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_drm_buf_destroy(struct drm_device *dev,
|
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__);
|
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||||
|
|
||||||
if (!entry) {
|
if (!buffer) {
|
||||||
DRM_DEBUG_KMS("entry is null.\n");
|
DRM_DEBUG_KMS("buffer is null.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lowlevel_buffer_deallocate(dev, entry);
|
lowlevel_buffer_deallocate(dev, buffer);
|
||||||
|
|
||||||
kfree(entry);
|
kfree(buffer);
|
||||||
entry = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||||
|
@ -26,28 +26,15 @@
|
|||||||
#ifndef _EXYNOS_DRM_BUF_H_
|
#ifndef _EXYNOS_DRM_BUF_H_
|
||||||
#define _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. */
|
/* 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);
|
unsigned int size);
|
||||||
|
|
||||||
/* get physical memory information of a drm framebuffer. */
|
/* get memory information of a drm framebuffer. */
|
||||||
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);
|
||||||
|
|
||||||
/* 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_buf_entry *entry);
|
struct exynos_drm_gem_buf *buffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
struct exynos_drm_connector {
|
struct exynos_drm_connector {
|
||||||
struct drm_connector drm_connector;
|
struct drm_connector drm_connector;
|
||||||
|
uint32_t encoder_id;
|
||||||
|
struct exynos_drm_manager *manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* convert exynos_video_timings to drm_display_mode */
|
/* convert exynos_video_timings to drm_display_mode */
|
||||||
@ -47,6 +49,7 @@ convert_to_display_mode(struct drm_display_mode *mode,
|
|||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
mode->clock = timing->pixclock / 1000;
|
mode->clock = timing->pixclock / 1000;
|
||||||
|
mode->vrefresh = timing->refresh;
|
||||||
|
|
||||||
mode->hdisplay = timing->xres;
|
mode->hdisplay = timing->xres;
|
||||||
mode->hsync_start = mode->hdisplay + timing->left_margin;
|
mode->hsync_start = mode->hdisplay + timing->left_margin;
|
||||||
@ -57,6 +60,12 @@ convert_to_display_mode(struct drm_display_mode *mode,
|
|||||||
mode->vsync_start = mode->vdisplay + timing->upper_margin;
|
mode->vsync_start = mode->vdisplay + timing->upper_margin;
|
||||||
mode->vsync_end = mode->vsync_start + timing->vsync_len;
|
mode->vsync_end = mode->vsync_start + timing->vsync_len;
|
||||||
mode->vtotal = mode->vsync_end + timing->lower_margin;
|
mode->vtotal = mode->vsync_end + timing->lower_margin;
|
||||||
|
|
||||||
|
if (timing->vmode & FB_VMODE_INTERLACED)
|
||||||
|
mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
||||||
|
|
||||||
|
if (timing->vmode & FB_VMODE_DOUBLE)
|
||||||
|
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert drm_display_mode to exynos_video_timings */
|
/* convert drm_display_mode to exynos_video_timings */
|
||||||
@ -69,7 +78,7 @@ convert_to_video_timing(struct fb_videomode *timing,
|
|||||||
memset(timing, 0, sizeof(*timing));
|
memset(timing, 0, sizeof(*timing));
|
||||||
|
|
||||||
timing->pixclock = mode->clock * 1000;
|
timing->pixclock = mode->clock * 1000;
|
||||||
timing->refresh = mode->vrefresh;
|
timing->refresh = drm_mode_vrefresh(mode);
|
||||||
|
|
||||||
timing->xres = mode->hdisplay;
|
timing->xres = mode->hdisplay;
|
||||||
timing->left_margin = mode->hsync_start - mode->hdisplay;
|
timing->left_margin = mode->hsync_start - mode->hdisplay;
|
||||||
@ -92,15 +101,16 @@ convert_to_video_timing(struct fb_videomode *timing,
|
|||||||
|
|
||||||
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct exynos_drm_manager *manager =
|
struct exynos_drm_connector *exynos_connector =
|
||||||
exynos_drm_get_manager(connector->encoder);
|
to_exynos_connector(connector);
|
||||||
struct exynos_drm_display *display = manager->display;
|
struct exynos_drm_manager *manager = exynos_connector->manager;
|
||||||
|
struct exynos_drm_display_ops *display_ops = manager->display_ops;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
if (!display) {
|
if (!display_ops) {
|
||||||
DRM_DEBUG_KMS("display is null.\n");
|
DRM_DEBUG_KMS("display_ops is null.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +122,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
|||||||
* P.S. in case of lcd panel, count is always 1 if success
|
* P.S. in case of lcd panel, count is always 1 if success
|
||||||
* because lcd panel has only one mode.
|
* because lcd panel has only one mode.
|
||||||
*/
|
*/
|
||||||
if (display->get_edid) {
|
if (display_ops->get_edid) {
|
||||||
int ret;
|
int ret;
|
||||||
void *edid;
|
void *edid;
|
||||||
|
|
||||||
@ -122,7 +132,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = display->get_edid(manager->dev, connector,
|
ret = display_ops->get_edid(manager->dev, connector,
|
||||||
edid, MAX_EDID);
|
edid, MAX_EDID);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
DRM_ERROR("failed to get edid data.\n");
|
DRM_ERROR("failed to get edid data.\n");
|
||||||
@ -140,8 +150,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
|||||||
struct drm_display_mode *mode = drm_mode_create(connector->dev);
|
struct drm_display_mode *mode = drm_mode_create(connector->dev);
|
||||||
struct fb_videomode *timing;
|
struct fb_videomode *timing;
|
||||||
|
|
||||||
if (display->get_timing)
|
if (display_ops->get_timing)
|
||||||
timing = display->get_timing(manager->dev);
|
timing = display_ops->get_timing(manager->dev);
|
||||||
else {
|
else {
|
||||||
drm_mode_destroy(connector->dev, mode);
|
drm_mode_destroy(connector->dev, mode);
|
||||||
return 0;
|
return 0;
|
||||||
@ -162,9 +172,10 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
|||||||
static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
||||||
struct drm_display_mode *mode)
|
struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
struct exynos_drm_manager *manager =
|
struct exynos_drm_connector *exynos_connector =
|
||||||
exynos_drm_get_manager(connector->encoder);
|
to_exynos_connector(connector);
|
||||||
struct exynos_drm_display *display = manager->display;
|
struct exynos_drm_manager *manager = exynos_connector->manager;
|
||||||
|
struct exynos_drm_display_ops *display_ops = manager->display_ops;
|
||||||
struct fb_videomode timing;
|
struct fb_videomode timing;
|
||||||
int ret = MODE_BAD;
|
int ret = MODE_BAD;
|
||||||
|
|
||||||
@ -172,8 +183,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
|||||||
|
|
||||||
convert_to_video_timing(&timing, mode);
|
convert_to_video_timing(&timing, mode);
|
||||||
|
|
||||||
if (display && display->check_timing)
|
if (display_ops && display_ops->check_timing)
|
||||||
if (!display->check_timing(manager->dev, (void *)&timing))
|
if (!display_ops->check_timing(manager->dev, (void *)&timing))
|
||||||
ret = MODE_OK;
|
ret = MODE_OK;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -181,9 +192,25 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
|||||||
|
|
||||||
struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
|
struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
|
struct drm_device *dev = connector->dev;
|
||||||
|
struct exynos_drm_connector *exynos_connector =
|
||||||
|
to_exynos_connector(connector);
|
||||||
|
struct drm_mode_object *obj;
|
||||||
|
struct drm_encoder *encoder;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
return connector->encoder;
|
obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
|
||||||
|
DRM_MODE_OBJECT_ENCODER);
|
||||||
|
if (!obj) {
|
||||||
|
DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
|
||||||
|
exynos_connector->encoder_id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder = obj_to_encoder(obj);
|
||||||
|
|
||||||
|
return encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
|
static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
|
||||||
@ -196,15 +223,17 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
|
|||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
|
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
|
||||||
{
|
{
|
||||||
struct exynos_drm_manager *manager =
|
struct exynos_drm_connector *exynos_connector =
|
||||||
exynos_drm_get_manager(connector->encoder);
|
to_exynos_connector(connector);
|
||||||
struct exynos_drm_display *display = manager->display;
|
struct exynos_drm_manager *manager = exynos_connector->manager;
|
||||||
|
struct exynos_drm_display_ops *display_ops =
|
||||||
|
manager->display_ops;
|
||||||
enum drm_connector_status status = connector_status_disconnected;
|
enum drm_connector_status status = connector_status_disconnected;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
if (display && display->is_connected) {
|
if (display_ops && display_ops->is_connected) {
|
||||||
if (display->is_connected(manager->dev))
|
if (display_ops->is_connected(manager->dev))
|
||||||
status = connector_status_connected;
|
status = connector_status_connected;
|
||||||
else
|
else
|
||||||
status = connector_status_disconnected;
|
status = connector_status_disconnected;
|
||||||
@ -251,9 +280,11 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
|||||||
|
|
||||||
connector = &exynos_connector->drm_connector;
|
connector = &exynos_connector->drm_connector;
|
||||||
|
|
||||||
switch (manager->display->type) {
|
switch (manager->display_ops->type) {
|
||||||
case EXYNOS_DISPLAY_TYPE_HDMI:
|
case EXYNOS_DISPLAY_TYPE_HDMI:
|
||||||
type = DRM_MODE_CONNECTOR_HDMIA;
|
type = DRM_MODE_CONNECTOR_HDMIA;
|
||||||
|
connector->interlace_allowed = true;
|
||||||
|
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = DRM_MODE_CONNECTOR_Unknown;
|
type = DRM_MODE_CONNECTOR_Unknown;
|
||||||
@ -267,7 +298,10 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_connector;
|
goto err_connector;
|
||||||
|
|
||||||
|
exynos_connector->encoder_id = encoder->base.id;
|
||||||
|
exynos_connector->manager = manager;
|
||||||
connector->encoder = encoder;
|
connector->encoder = encoder;
|
||||||
|
|
||||||
err = drm_mode_connector_attach_encoder(connector, encoder);
|
err = drm_mode_connector_attach_encoder(connector, encoder);
|
||||||
if (err) {
|
if (err) {
|
||||||
DRM_ERROR("failed to attach a connector to a encoder\n");
|
DRM_ERROR("failed to attach a connector to a encoder\n");
|
||||||
|
@ -29,35 +29,16 @@
|
|||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm_crtc_helper.h"
|
#include "drm_crtc_helper.h"
|
||||||
|
|
||||||
|
#include "exynos_drm_crtc.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#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_buf.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)
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
* Exynos specific crtc structure.
|
||||||
*
|
*
|
||||||
@ -85,30 +66,31 @@ static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
exynos_drm_fn_encoder(crtc, overlay,
|
exynos_drm_fn_encoder(crtc, overlay,
|
||||||
exynos_drm_encoder_crtc_mode_set);
|
exynos_drm_encoder_crtc_mode_set);
|
||||||
exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
|
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
||||||
|
exynos_drm_encoder_crtc_commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
|
int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
|
||||||
struct drm_framebuffer *fb,
|
struct drm_framebuffer *fb,
|
||||||
struct drm_display_mode *mode,
|
struct drm_display_mode *mode,
|
||||||
struct exynos_drm_crtc_pos *pos)
|
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_w;
|
||||||
unsigned int actual_h;
|
unsigned int actual_h;
|
||||||
|
|
||||||
entry = exynos_drm_fb_get_buf(fb);
|
buffer = exynos_drm_fb_get_buf(fb);
|
||||||
if (!entry) {
|
if (!buffer) {
|
||||||
DRM_LOG_KMS("entry is null.\n");
|
DRM_LOG_KMS("buffer is null.\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay->paddr = entry->paddr;
|
overlay->dma_addr = buffer->dma_addr;
|
||||||
overlay->vaddr = entry->vaddr;
|
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->vaddr,
|
||||||
(unsigned long)overlay->paddr);
|
(unsigned long)overlay->dma_addr);
|
||||||
|
|
||||||
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);
|
||||||
@ -171,9 +153,26 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||||
{
|
{
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
|
||||||
/* TODO */
|
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case DRM_MODE_DPMS_ON:
|
||||||
|
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
||||||
|
exynos_drm_encoder_crtc_commit);
|
||||||
|
break;
|
||||||
|
case DRM_MODE_DPMS_STANDBY:
|
||||||
|
case DRM_MODE_DPMS_SUSPEND:
|
||||||
|
case DRM_MODE_DPMS_OFF:
|
||||||
|
/* TODO */
|
||||||
|
exynos_drm_fn_encoder(crtc, NULL,
|
||||||
|
exynos_drm_encoder_crtc_disable);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
|
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
|
||||||
@ -185,9 +184,12 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
|
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
/* drm framework doesn't check NULL. */
|
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
||||||
|
exynos_drm_encoder_crtc_commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -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);
|
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
|
||||||
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
|
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
#endif
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
|
#include "drm_crtc_helper.h"
|
||||||
|
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
|
|
||||||
@ -61,6 +62,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
|||||||
|
|
||||||
drm_mode_config_init(dev);
|
drm_mode_config_init(dev);
|
||||||
|
|
||||||
|
/* init kms poll for handling hpd */
|
||||||
|
drm_kms_helper_poll_init(dev);
|
||||||
|
|
||||||
exynos_drm_mode_config_init(dev);
|
exynos_drm_mode_config_init(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -116,6 +120,7 @@ static int exynos_drm_unload(struct drm_device *dev)
|
|||||||
exynos_drm_fbdev_fini(dev);
|
exynos_drm_fbdev_fini(dev);
|
||||||
exynos_drm_device_unregister(dev);
|
exynos_drm_device_unregister(dev);
|
||||||
drm_vblank_cleanup(dev);
|
drm_vblank_cleanup(dev);
|
||||||
|
drm_kms_helper_poll_fini(dev);
|
||||||
drm_mode_config_cleanup(dev);
|
drm_mode_config_cleanup(dev);
|
||||||
kfree(dev->dev_private);
|
kfree(dev->dev_private);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#ifndef _EXYNOS_DRM_DRV_H_
|
#ifndef _EXYNOS_DRM_DRV_H_
|
||||||
#define _EXYNOS_DRM_DRV_H_
|
#define _EXYNOS_DRM_DRV_H_
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
|
|
||||||
#define MAX_CRTC 2
|
#define MAX_CRTC 2
|
||||||
@ -79,8 +80,8 @@ 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)
|
||||||
* @paddr: bus(accessed by dma) physical memory address to this overlay
|
* @dma_addr: bus(accessed by dma) address to the memory region allocated
|
||||||
* and this is physically continuous.
|
* for a overlay.
|
||||||
* @vaddr: virtual memory addresss to this overlay.
|
* @vaddr: virtual memory addresss to this overlay.
|
||||||
* @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.
|
||||||
@ -108,7 +109,7 @@ 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 paddr;
|
dma_addr_t dma_addr;
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
|
|
||||||
bool default_win;
|
bool default_win;
|
||||||
@ -130,7 +131,7 @@ struct exynos_drm_overlay {
|
|||||||
* @check_timing: check if timing is valid or not.
|
* @check_timing: check if timing is valid or not.
|
||||||
* @power_on: display device on or off.
|
* @power_on: display device on or off.
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_display {
|
struct exynos_drm_display_ops {
|
||||||
enum exynos_drm_output_type type;
|
enum exynos_drm_output_type type;
|
||||||
bool (*is_connected)(struct device *dev);
|
bool (*is_connected)(struct device *dev);
|
||||||
int (*get_edid)(struct device *dev, struct drm_connector *connector,
|
int (*get_edid)(struct device *dev, struct drm_connector *connector,
|
||||||
@ -146,12 +147,14 @@ struct exynos_drm_display {
|
|||||||
* @mode_set: convert drm_display_mode to hw specific display mode and
|
* @mode_set: convert drm_display_mode to hw specific display mode and
|
||||||
* would be called by encoder->mode_set().
|
* would be called by encoder->mode_set().
|
||||||
* @commit: set current hw specific display mode to hw.
|
* @commit: set current hw specific display mode to hw.
|
||||||
|
* @disable: disable hardware specific display mode.
|
||||||
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
||||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_manager_ops {
|
struct exynos_drm_manager_ops {
|
||||||
void (*mode_set)(struct device *subdrv_dev, void *mode);
|
void (*mode_set)(struct device *subdrv_dev, void *mode);
|
||||||
void (*commit)(struct device *subdrv_dev);
|
void (*commit)(struct device *subdrv_dev);
|
||||||
|
void (*disable)(struct device *subdrv_dev);
|
||||||
int (*enable_vblank)(struct device *subdrv_dev);
|
int (*enable_vblank)(struct device *subdrv_dev);
|
||||||
void (*disable_vblank)(struct device *subdrv_dev);
|
void (*disable_vblank)(struct device *subdrv_dev);
|
||||||
};
|
};
|
||||||
@ -178,7 +181,7 @@ struct exynos_drm_manager {
|
|||||||
int pipe;
|
int pipe;
|
||||||
struct exynos_drm_manager_ops *ops;
|
struct exynos_drm_manager_ops *ops;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops;
|
struct exynos_drm_overlay_ops *overlay_ops;
|
||||||
struct exynos_drm_display *display;
|
struct exynos_drm_display_ops *display_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -53,15 +53,36 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||||||
struct drm_device *dev = encoder->dev;
|
struct drm_device *dev = encoder->dev;
|
||||||
struct drm_connector *connector;
|
struct drm_connector *connector;
|
||||||
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
||||||
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
|
DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case DRM_MODE_DPMS_ON:
|
||||||
|
if (manager_ops && manager_ops->commit)
|
||||||
|
manager_ops->commit(manager->dev);
|
||||||
|
break;
|
||||||
|
case DRM_MODE_DPMS_STANDBY:
|
||||||
|
case DRM_MODE_DPMS_SUSPEND:
|
||||||
|
case DRM_MODE_DPMS_OFF:
|
||||||
|
/* TODO */
|
||||||
|
if (manager_ops && manager_ops->disable)
|
||||||
|
manager_ops->disable(manager->dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("unspecified mode %d\n", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||||
if (connector->encoder == encoder) {
|
if (connector->encoder == encoder) {
|
||||||
struct exynos_drm_display *display = manager->display;
|
struct exynos_drm_display_ops *display_ops =
|
||||||
|
manager->display_ops;
|
||||||
|
|
||||||
if (display && display->power_on)
|
DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
|
||||||
display->power_on(manager->dev, mode);
|
connector->base.id, mode);
|
||||||
|
if (display_ops && display_ops->power_on)
|
||||||
|
display_ops->power_on(manager->dev, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,15 +137,11 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
|
|||||||
{
|
{
|
||||||
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
||||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
if (manager_ops && manager_ops->commit)
|
if (manager_ops && manager_ops->commit)
|
||||||
manager_ops->commit(manager->dev);
|
manager_ops->commit(manager->dev);
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->commit)
|
|
||||||
overlay_ops->commit(manager->dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct drm_crtc *
|
static struct drm_crtc *
|
||||||
@ -208,10 +225,23 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
|||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
|
struct exynos_drm_private *private = dev->dev_private;
|
||||||
|
struct exynos_drm_manager *manager;
|
||||||
|
|
||||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||||
if (encoder->crtc != crtc)
|
/*
|
||||||
continue;
|
* if crtc is detached from encoder, check pipe,
|
||||||
|
* otherwise check crtc attached to encoder
|
||||||
|
*/
|
||||||
|
if (!encoder->crtc) {
|
||||||
|
manager = to_exynos_encoder(encoder)->manager;
|
||||||
|
if (manager->pipe < 0 ||
|
||||||
|
private->crtc[manager->pipe] != crtc)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (encoder->crtc != crtc)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
fn(encoder, data);
|
fn(encoder, data);
|
||||||
}
|
}
|
||||||
@ -250,8 +280,18 @@ void exynos_drm_encoder_crtc_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 crtc = *(int *)data;
|
||||||
|
|
||||||
overlay_ops->commit(manager->dev);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* when crtc is detached from encoder, this pipe is used
|
||||||
|
* to select manager operation
|
||||||
|
*/
|
||||||
|
manager->pipe = crtc;
|
||||||
|
|
||||||
|
if (overlay_ops && overlay_ops->commit)
|
||||||
|
overlay_ops->commit(manager->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
|
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
|
||||||
@ -261,7 +301,28 @@ void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
|
|||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
struct exynos_drm_overlay *overlay = data;
|
struct exynos_drm_overlay *overlay = data;
|
||||||
|
|
||||||
overlay_ops->mode_set(manager->dev, overlay);
|
if (overlay_ops && overlay_ops->mode_set)
|
||||||
|
overlay_ops->mode_set(manager->dev, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
|
||||||
|
{
|
||||||
|
struct exynos_drm_manager *manager =
|
||||||
|
to_exynos_encoder(encoder)->manager;
|
||||||
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("\n");
|
||||||
|
|
||||||
|
if (overlay_ops && overlay_ops->disable)
|
||||||
|
overlay_ops->disable(manager->dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crtc is already detached from encoder and last
|
||||||
|
* function for detaching is properly done, so
|
||||||
|
* clear pipe from manager to prevent repeated call
|
||||||
|
*/
|
||||||
|
if (!encoder->crtc)
|
||||||
|
manager->pipe = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||||
|
@ -41,5 +41,6 @@ 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_commit(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,7 +29,9 @@
|
|||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm_crtc.h"
|
#include "drm_crtc.h"
|
||||||
#include "drm_crtc_helper.h"
|
#include "drm_crtc_helper.h"
|
||||||
|
#include "drm_fb_helper.h"
|
||||||
|
|
||||||
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_buf.h"
|
#include "exynos_drm_buf.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_gem.h"
|
||||||
@ -41,14 +43,14 @@
|
|||||||
*
|
*
|
||||||
* @fb: drm framebuffer obejct.
|
* @fb: drm framebuffer obejct.
|
||||||
* @exynos_gem_obj: exynos specific gem object containing a gem object.
|
* @exynos_gem_obj: exynos specific gem object containing a gem object.
|
||||||
* @entry: pointer to exynos drm buffer entry object.
|
* @buffer: pointer to exynos_drm_gem_buffer object.
|
||||||
* - containing only the information to physically continuous memory
|
* - contain the memory information to memory region allocated
|
||||||
* region allocated at default framebuffer creation.
|
* 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;
|
||||||
struct exynos_drm_buf_entry *entry;
|
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)
|
||||||
@ -63,8 +65,8 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
|
|||||||
* default framebuffer has no gem object so
|
* default framebuffer has no gem object so
|
||||||
* a buffer of the default framebuffer should be released at here.
|
* a buffer of the default framebuffer should be released at here.
|
||||||
*/
|
*/
|
||||||
if (!exynos_fb->exynos_gem_obj && exynos_fb->entry)
|
if (!exynos_fb->exynos_gem_obj && exynos_fb->buffer)
|
||||||
exynos_drm_buf_destroy(fb->dev, exynos_fb->entry);
|
exynos_drm_buf_destroy(fb->dev, exynos_fb->buffer);
|
||||||
|
|
||||||
kfree(exynos_fb);
|
kfree(exynos_fb);
|
||||||
exynos_fb = NULL;
|
exynos_fb = NULL;
|
||||||
@ -143,29 +145,29 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
|
|||||||
*/
|
*/
|
||||||
if (!mode_cmd->handle) {
|
if (!mode_cmd->handle) {
|
||||||
if (!file_priv) {
|
if (!file_priv) {
|
||||||
struct exynos_drm_buf_entry *entry;
|
struct exynos_drm_gem_buf *buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in case that file_priv is NULL, it allocates
|
* in case that file_priv is NULL, it allocates
|
||||||
* only buffer and this buffer would be used
|
* only buffer and this buffer would be used
|
||||||
* for default framebuffer.
|
* for default framebuffer.
|
||||||
*/
|
*/
|
||||||
entry = exynos_drm_buf_create(dev, size);
|
buffer = exynos_drm_buf_create(dev, size);
|
||||||
if (IS_ERR(entry)) {
|
if (IS_ERR(buffer)) {
|
||||||
ret = PTR_ERR(entry);
|
ret = PTR_ERR(buffer);
|
||||||
goto 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",
|
DRM_LOG_KMS("default: dma_addr = 0x%lx, size = 0x%x\n",
|
||||||
(unsigned long)entry->paddr, size);
|
(unsigned long)buffer->dma_addr, size);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
exynos_gem_obj = exynos_drm_gem_create(file_priv, dev,
|
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
|
||||||
size,
|
&mode_cmd->handle,
|
||||||
&mode_cmd->handle);
|
size);
|
||||||
if (IS_ERR(exynos_gem_obj)) {
|
if (IS_ERR(exynos_gem_obj)) {
|
||||||
ret = PTR_ERR(exynos_gem_obj);
|
ret = PTR_ERR(exynos_gem_obj);
|
||||||
goto err_buffer;
|
goto err_buffer;
|
||||||
@ -189,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,
|
* so that default framebuffer has no its own gem object,
|
||||||
* only its own buffer 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",
|
DRM_LOG_KMS("dma_addr = 0x%lx, size = 0x%x, gem object = 0x%x\n",
|
||||||
(unsigned long)exynos_fb->entry->paddr, size,
|
(unsigned long)exynos_fb->buffer->dma_addr, size,
|
||||||
(unsigned int)&exynos_gem_obj->base);
|
(unsigned int)&exynos_gem_obj->base);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -220,26 +222,36 @@ struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
|
|||||||
return exynos_drm_fb_init(file_priv, dev, mode_cmd);
|
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_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__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
entry = exynos_fb->entry;
|
buffer = exynos_fb->buffer;
|
||||||
if (!entry)
|
if (!buffer)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
|
DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n",
|
||||||
(unsigned long)entry->vaddr,
|
(unsigned long)buffer->kvaddr,
|
||||||
(unsigned long)entry->paddr);
|
(unsigned long)buffer->dma_addr);
|
||||||
|
|
||||||
return entry;
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exynos_drm_output_poll_changed(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *private = dev->dev_private;
|
||||||
|
struct drm_fb_helper *fb_helper = private->fb_helper;
|
||||||
|
|
||||||
|
if (fb_helper)
|
||||||
|
drm_fb_helper_hotplug_event(fb_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_drm_fb_create,
|
||||||
|
.output_poll_changed = exynos_drm_output_poll_changed,
|
||||||
};
|
};
|
||||||
|
|
||||||
void exynos_drm_mode_config_init(struct drm_device *dev)
|
void exynos_drm_mode_config_init(struct drm_device *dev)
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#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_buf.h"
|
#include "exynos_drm_buf.h"
|
||||||
|
|
||||||
#define MAX_CONNECTOR 4
|
#define MAX_CONNECTOR 4
|
||||||
@ -85,15 +86,13 @@ static struct fb_ops exynos_drm_fb_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
||||||
struct drm_framebuffer *fb,
|
struct drm_framebuffer *fb)
|
||||||
unsigned int fb_width,
|
|
||||||
unsigned int fb_height)
|
|
||||||
{
|
{
|
||||||
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_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 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__);
|
||||||
@ -101,20 +100,20 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
|
|||||||
exynos_fb->fb = fb;
|
exynos_fb->fb = fb;
|
||||||
|
|
||||||
drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
|
drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
|
||||||
drm_fb_helper_fill_var(fbi, helper, fb_width, fb_height);
|
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
|
||||||
|
|
||||||
entry = exynos_drm_fb_get_buf(fb);
|
buffer = exynos_drm_fb_get_buf(fb);
|
||||||
if (!entry) {
|
if (!buffer) {
|
||||||
DRM_LOG_KMS("entry is null.\n");
|
DRM_LOG_KMS("buffer is null.\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
|
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
|
||||||
offset += fbi->var.yoffset * fb->pitch;
|
offset += fbi->var.yoffset * fb->pitch;
|
||||||
|
|
||||||
dev->mode_config.fb_base = entry->paddr;
|
dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
|
||||||
fbi->screen_base = entry->vaddr + offset;
|
fbi->screen_base = buffer->kvaddr + offset;
|
||||||
fbi->fix.smem_start = entry->paddr + offset;
|
fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset);
|
||||||
fbi->screen_size = size;
|
fbi->screen_size = size;
|
||||||
fbi->fix.smem_len = size;
|
fbi->fix.smem_len = size;
|
||||||
|
|
||||||
@ -171,8 +170,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
|
ret = exynos_drm_fbdev_update(helper, helper->fb);
|
||||||
sizes->fb_height);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
fb_dealloc_cmap(&fbi->cmap);
|
fb_dealloc_cmap(&fbi->cmap);
|
||||||
|
|
||||||
@ -235,8 +233,7 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
|
|||||||
}
|
}
|
||||||
|
|
||||||
helper->fb = exynos_fbdev->fb;
|
helper->fb = exynos_fbdev->fb;
|
||||||
return exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
|
return exynos_drm_fbdev_update(helper, helper->fb);
|
||||||
sizes->fb_height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
|
static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
|
||||||
@ -405,6 +402,18 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev)
|
|||||||
fb_helper = private->fb_helper;
|
fb_helper = private->fb_helper;
|
||||||
|
|
||||||
if (fb_helper) {
|
if (fb_helper) {
|
||||||
|
struct list_head temp_list;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&temp_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fb_helper is reintialized but kernel fb is reused
|
||||||
|
* so kernel_fb_list need to be backuped and restored
|
||||||
|
*/
|
||||||
|
if (!list_empty(&fb_helper->kernel_fb_list))
|
||||||
|
list_replace_init(&fb_helper->kernel_fb_list,
|
||||||
|
&temp_list);
|
||||||
|
|
||||||
drm_fb_helper_fini(fb_helper);
|
drm_fb_helper_fini(fb_helper);
|
||||||
|
|
||||||
ret = drm_fb_helper_init(dev, fb_helper,
|
ret = drm_fb_helper_init(dev, fb_helper,
|
||||||
@ -414,6 +423,9 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&temp_list))
|
||||||
|
list_replace(&temp_list, &fb_helper->kernel_fb_list);
|
||||||
|
|
||||||
ret = drm_fb_helper_single_add_all_connectors(fb_helper);
|
ret = drm_fb_helper_single_add_all_connectors(fb_helper);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
DRM_ERROR("failed to add fb helper to connectors\n");
|
DRM_ERROR("failed to add fb helper to connectors\n");
|
||||||
|
@ -64,7 +64,7 @@ struct fimd_win_data {
|
|||||||
unsigned int fb_width;
|
unsigned int fb_width;
|
||||||
unsigned int fb_height;
|
unsigned int fb_height;
|
||||||
unsigned int bpp;
|
unsigned int bpp;
|
||||||
dma_addr_t paddr;
|
dma_addr_t dma_addr;
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
unsigned int buf_offsize;
|
unsigned int buf_offsize;
|
||||||
unsigned int line_size; /* bytes */
|
unsigned int line_size; /* bytes */
|
||||||
@ -124,7 +124,7 @@ static int fimd_display_power_on(struct device *dev, int mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct exynos_drm_display fimd_display = {
|
static struct exynos_drm_display_ops fimd_display_ops = {
|
||||||
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
||||||
.is_connected = fimd_display_is_connected,
|
.is_connected = fimd_display_is_connected,
|
||||||
.get_timing = fimd_get_timing,
|
.get_timing = fimd_get_timing,
|
||||||
@ -177,6 +177,40 @@ static void fimd_commit(struct device *dev)
|
|||||||
writel(val, ctx->regs + VIDCON0);
|
writel(val, ctx->regs + VIDCON0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fimd_disable(struct device *dev)
|
||||||
|
{
|
||||||
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
|
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
|
||||||
|
struct drm_device *drm_dev = subdrv->drm_dev;
|
||||||
|
struct exynos_drm_manager *manager = &subdrv->manager;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
/* fimd dma off */
|
||||||
|
val = readl(ctx->regs + VIDCON0);
|
||||||
|
val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F);
|
||||||
|
writel(val, ctx->regs + VIDCON0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if vblank is enabled status with dma off then
|
||||||
|
* it disables vsync interrupt.
|
||||||
|
*/
|
||||||
|
if (drm_dev->vblank_enabled[manager->pipe] &&
|
||||||
|
atomic_read(&drm_dev->vblank_refcount[manager->pipe])) {
|
||||||
|
drm_vblank_put(drm_dev, manager->pipe);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if vblank_disable_allowed is 0 then disable
|
||||||
|
* vsync interrupt right now else the vsync interrupt
|
||||||
|
* would be disabled by drm timer once a current process
|
||||||
|
* gives up ownershop of vblank event.
|
||||||
|
*/
|
||||||
|
if (!drm_dev->vblank_disable_allowed)
|
||||||
|
drm_vblank_off(drm_dev, manager->pipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int fimd_enable_vblank(struct device *dev)
|
static int fimd_enable_vblank(struct device *dev)
|
||||||
{
|
{
|
||||||
struct fimd_context *ctx = get_fimd_context(dev);
|
struct fimd_context *ctx = get_fimd_context(dev);
|
||||||
@ -220,6 +254,7 @@ static void fimd_disable_vblank(struct device *dev)
|
|||||||
|
|
||||||
static struct exynos_drm_manager_ops fimd_manager_ops = {
|
static struct exynos_drm_manager_ops fimd_manager_ops = {
|
||||||
.commit = fimd_commit,
|
.commit = fimd_commit,
|
||||||
|
.disable = fimd_disable,
|
||||||
.enable_vblank = fimd_enable_vblank,
|
.enable_vblank = fimd_enable_vblank,
|
||||||
.disable_vblank = fimd_disable_vblank,
|
.disable_vblank = fimd_disable_vblank,
|
||||||
};
|
};
|
||||||
@ -251,7 +286,7 @@ 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->paddr = overlay->paddr + offset;
|
win_data->dma_addr = overlay->dma_addr + offset;
|
||||||
win_data->vaddr = overlay->vaddr + offset;
|
win_data->vaddr = overlay->vaddr + 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) *
|
||||||
@ -263,7 +298,7 @@ static void fimd_win_mode_set(struct device *dev,
|
|||||||
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
|
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
|
||||||
win_data->ovl_width, win_data->ovl_height);
|
win_data->ovl_width, win_data->ovl_height);
|
||||||
DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
|
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);
|
(unsigned long)win_data->vaddr);
|
||||||
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
|
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
|
||||||
overlay->fb_width, overlay->crtc_width);
|
overlay->fb_width, overlay->crtc_width);
|
||||||
@ -376,16 +411,16 @@ static void fimd_win_commit(struct device *dev)
|
|||||||
writel(val, ctx->regs + SHADOWCON);
|
writel(val, ctx->regs + SHADOWCON);
|
||||||
|
|
||||||
/* buffer start address */
|
/* buffer start address */
|
||||||
val = win_data->paddr;
|
val = (unsigned long)win_data->dma_addr;
|
||||||
writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
|
writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
|
||||||
|
|
||||||
/* buffer end address */
|
/* buffer end address */
|
||||||
size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
|
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));
|
writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
|
||||||
|
|
||||||
DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
|
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",
|
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
|
||||||
win_data->ovl_width, win_data->ovl_height);
|
win_data->ovl_width, win_data->ovl_height);
|
||||||
|
|
||||||
@ -447,7 +482,6 @@ static void fimd_win_commit(struct device *dev)
|
|||||||
static void fimd_win_disable(struct device *dev)
|
static void fimd_win_disable(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;
|
|
||||||
int win = ctx->default_win;
|
int win = ctx->default_win;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
@ -456,8 +490,6 @@ static void fimd_win_disable(struct device *dev)
|
|||||||
if (win < 0 || win > WINDOWS_NR)
|
if (win < 0 || win > WINDOWS_NR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
win_data = &ctx->win_data[win];
|
|
||||||
|
|
||||||
/* protect windows */
|
/* protect windows */
|
||||||
val = readl(ctx->regs + SHADOWCON);
|
val = readl(ctx->regs + SHADOWCON);
|
||||||
val |= SHADOWCON_WINx_PROTECT(win);
|
val |= SHADOWCON_WINx_PROTECT(win);
|
||||||
@ -528,6 +560,16 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
|
|||||||
/* VSYNC interrupt */
|
/* VSYNC interrupt */
|
||||||
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
|
writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in case that vblank_disable_allowed is 1, it could induce
|
||||||
|
* the problem that manager->pipe could be -1 because with
|
||||||
|
* disable callback, vsync interrupt isn't disabled and at this moment,
|
||||||
|
* vsync interrupt could occur. the vsync interrupt would be disabled
|
||||||
|
* by timer handler later.
|
||||||
|
*/
|
||||||
|
if (manager->pipe == -1)
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
drm_handle_vblank(drm_dev, manager->pipe);
|
drm_handle_vblank(drm_dev, manager->pipe);
|
||||||
fimd_finish_pageflip(drm_dev, manager->pipe);
|
fimd_finish_pageflip(drm_dev, manager->pipe);
|
||||||
|
|
||||||
@ -548,13 +590,6 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
|||||||
*/
|
*/
|
||||||
drm_dev->irq_enabled = 1;
|
drm_dev->irq_enabled = 1;
|
||||||
|
|
||||||
/*
|
|
||||||
* with vblank_disable_allowed = 1, vblank interrupt will be disabled
|
|
||||||
* by drm timer once a current process gives up ownership of
|
|
||||||
* vblank event.(drm_vblank_put function was called)
|
|
||||||
*/
|
|
||||||
drm_dev->vblank_disable_allowed = 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +766,7 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
|||||||
subdrv->manager.pipe = -1;
|
subdrv->manager.pipe = -1;
|
||||||
subdrv->manager.ops = &fimd_manager_ops;
|
subdrv->manager.ops = &fimd_manager_ops;
|
||||||
subdrv->manager.overlay_ops = &fimd_overlay_ops;
|
subdrv->manager.overlay_ops = &fimd_overlay_ops;
|
||||||
subdrv->manager.display = &fimd_display;
|
subdrv->manager.display_ops = &fimd_display_ops;
|
||||||
subdrv->manager.dev = dev;
|
subdrv->manager.dev = dev;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ctx);
|
platform_set_drvdata(pdev, ctx);
|
||||||
|
@ -62,40 +62,28 @@ static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
|
|||||||
return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
|
return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv,
|
static struct exynos_drm_gem_obj
|
||||||
struct drm_device *dev, unsigned int size,
|
*exynos_drm_gem_init(struct drm_device *drm_dev,
|
||||||
unsigned int *handle)
|
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 exynos_drm_buf_entry *entry;
|
|
||||||
struct drm_gem_object *obj;
|
struct drm_gem_object *obj;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
|
||||||
|
|
||||||
size = roundup(size, PAGE_SIZE);
|
|
||||||
|
|
||||||
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 ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate the new buffer object and memory region. */
|
|
||||||
entry = exynos_drm_buf_create(dev, size);
|
|
||||||
if (!entry) {
|
|
||||||
kfree(exynos_gem_obj);
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
exynos_gem_obj->entry = entry;
|
|
||||||
|
|
||||||
obj = &exynos_gem_obj->base;
|
obj = &exynos_gem_obj->base;
|
||||||
|
|
||||||
ret = drm_gem_object_init(dev, obj, size);
|
ret = drm_gem_object_init(drm_dev, obj, size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
DRM_ERROR("failed to initailize gem object.\n");
|
DRM_ERROR("failed to initialize gem object.\n");
|
||||||
goto err_obj_init;
|
ret = -EINVAL;
|
||||||
|
goto err_object_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -127,24 +115,50 @@ err_handle_create:
|
|||||||
err_create_mmap_offset:
|
err_create_mmap_offset:
|
||||||
drm_gem_object_release(obj);
|
drm_gem_object_release(obj);
|
||||||
|
|
||||||
err_obj_init:
|
err_object_init:
|
||||||
exynos_drm_buf_destroy(dev, exynos_gem_obj->entry);
|
|
||||||
|
|
||||||
kfree(exynos_gem_obj);
|
kfree(exynos_gem_obj);
|
||||||
|
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||||
|
struct drm_file *file_priv,
|
||||||
|
unsigned int *handle, unsigned long size)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
|
||||||
|
struct exynos_drm_gem_buf *buffer;
|
||||||
|
|
||||||
|
size = roundup(size, PAGE_SIZE);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
|
||||||
|
|
||||||
|
buffer = exynos_drm_buf_create(dev, size);
|
||||||
|
if (IS_ERR(buffer)) {
|
||||||
|
return ERR_CAST(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size);
|
||||||
|
if (IS_ERR(exynos_gem_obj)) {
|
||||||
|
exynos_drm_buf_destroy(dev, buffer);
|
||||||
|
return exynos_gem_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
exynos_gem_obj->buffer = buffer;
|
||||||
|
|
||||||
|
return exynos_gem_obj;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
struct exynos_drm_gem_obj *exynos_gem_obj = NULL;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s : size = 0x%x\n", __FILE__, args->size);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size,
|
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv,
|
||||||
&args->handle);
|
&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);
|
||||||
|
|
||||||
@ -175,7 +189,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
|||||||
{
|
{
|
||||||
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);
|
||||||
struct exynos_drm_buf_entry *entry;
|
struct exynos_drm_gem_buf *buffer;
|
||||||
unsigned long pfn, vm_size;
|
unsigned long pfn, vm_size;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
@ -187,20 +201,20 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
|||||||
|
|
||||||
vm_size = vma->vm_end - vma->vm_start;
|
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.
|
* 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. */
|
/* check if user-requested size is valid. */
|
||||||
if (vm_size > entry->size)
|
if (vm_size > buffer->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get page frame number to physical memory to be mapped
|
* get page frame number to physical memory to be mapped
|
||||||
* to user space.
|
* 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);
|
DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
|
||||||
|
|
||||||
@ -281,7 +295,7 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj)
|
|||||||
|
|
||||||
exynos_gem_obj = to_exynos_gem_obj(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);
|
kfree(exynos_gem_obj);
|
||||||
}
|
}
|
||||||
@ -302,8 +316,8 @@ 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(file_priv, dev, args->size,
|
exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle,
|
||||||
&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);
|
||||||
|
|
||||||
@ -360,7 +374,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
|
|
||||||
mutex_lock(&dev->struct_mutex);
|
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);
|
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||||
|
|
||||||
|
@ -29,14 +29,30 @@
|
|||||||
#define to_exynos_gem_obj(x) container_of(x,\
|
#define to_exynos_gem_obj(x) container_of(x,\
|
||||||
struct exynos_drm_gem_obj, base)
|
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.
|
* exynos drm buffer structure.
|
||||||
*
|
*
|
||||||
* @base: a gem object.
|
* @base: a gem object.
|
||||||
* - a new handle to this gem object would be created
|
* - a new handle to this gem object would be created
|
||||||
* by drm_gem_handle_create().
|
* by drm_gem_handle_create().
|
||||||
* @entry: pointer to exynos drm buffer entry object.
|
* @buffer: a pointer to exynos_drm_gem_buffer object.
|
||||||
* - containing the information to physically
|
* - contain the information to memory region allocated
|
||||||
|
* by user request or at framebuffer creation.
|
||||||
* continuous memory region allocated by user request
|
* continuous memory region allocated by user request
|
||||||
* or at framebuffer creation.
|
* or at framebuffer creation.
|
||||||
*
|
*
|
||||||
@ -45,13 +61,13 @@
|
|||||||
*/
|
*/
|
||||||
struct exynos_drm_gem_obj {
|
struct exynos_drm_gem_obj {
|
||||||
struct drm_gem_object base;
|
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. */
|
/* create a new buffer and get a new gem handle. */
|
||||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv,
|
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||||
struct drm_device *dev, unsigned int size,
|
struct drm_file *file_priv,
|
||||||
unsigned int *handle);
|
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
|
||||||
|
@ -32,17 +32,16 @@
|
|||||||
/**
|
/**
|
||||||
* User-desired buffer creation information structure.
|
* User-desired buffer creation information structure.
|
||||||
*
|
*
|
||||||
* @size: requested size for the object.
|
* @size: user-desired memory allocation size.
|
||||||
* - this size value would be page-aligned internally.
|
* - this size value would be page-aligned internally.
|
||||||
* @flags: user request for setting memory type or cache attributes.
|
* @flags: user request for setting memory type or cache attributes.
|
||||||
* @handle: returned handle for the object.
|
* @handle: returned a handle to created gem object.
|
||||||
* @pad: just padding to be 64-bit aligned.
|
* - this handle will be set by gem module of kernel side.
|
||||||
*/
|
*/
|
||||||
struct drm_exynos_gem_create {
|
struct drm_exynos_gem_create {
|
||||||
unsigned int size;
|
uint64_t size;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int handle;
|
unsigned int handle;
|
||||||
unsigned int pad;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user