Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull Exynos DRM changes from Dave Airlie: "So I totally missed Inki's pull request for -next, its fully exynos self contained." (I took just the actual commits, not Dave's two extraneous merges) * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (30 commits) drm/exynos: fixed exception to page allocation failure drm/exynos: use __free_page() to deallocate memory drm/exynos: fixed a comment to gem size. drm/exynos: removed unnecessary variable drm/exynos: do not release memory region from exporter. drm/exynos: set buffer type from exporter. drm/exynos: use alloc_page() to allocate pages. drm/exynos: fixed build warning. drm/exynos: fixed edid data setting at vidi connection request drm/exynos: check if raw edid data is fake or not for test drm/exynos: set edid fake data only for test. drm/exynos: removed unnecessary declaration. drm/exynos: fix buffer pitch calculation drm/exynos: check for null in return value of dma_buf_map_attachment() drm/exynos: return NULL if exynos_pages_to_sg fails drm/exynos: Use devm_* functions in exynos_mixer.c drm/exynos: Use devm_* functions in exynos_hdmi.c drm/exynos: Use devm_* functions in exynos_drm_fimd.c drm/exynos: Add missing static storage class specifier drm/exynos: add property for crtc mode ...
This commit is contained in:
@@ -196,7 +196,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
|
static struct drm_encoder *exynos_drm_best_encoder(
|
||||||
|
struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct exynos_drm_connector *exynos_connector =
|
struct exynos_drm_connector *exynos_connector =
|
||||||
|
@@ -33,7 +33,6 @@
|
|||||||
#include "exynos_drm_fbdev.h"
|
#include "exynos_drm_fbdev.h"
|
||||||
|
|
||||||
static LIST_HEAD(exynos_drm_subdrv_list);
|
static LIST_HEAD(exynos_drm_subdrv_list);
|
||||||
static struct drm_device *drm_dev;
|
|
||||||
|
|
||||||
static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
||||||
struct exynos_drm_subdrv *subdrv)
|
struct exynos_drm_subdrv *subdrv)
|
||||||
@@ -120,8 +119,6 @@ int exynos_drm_device_register(struct drm_device *dev)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
drm_dev = dev;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
||||||
subdrv->drm_dev = dev;
|
subdrv->drm_dev = dev;
|
||||||
err = exynos_drm_subdrv_probe(dev, subdrv);
|
err = exynos_drm_subdrv_probe(dev, subdrv);
|
||||||
@@ -149,8 +146,6 @@ int exynos_drm_device_unregister(struct drm_device *dev)
|
|||||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
|
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
|
||||||
exynos_drm_subdrv_remove(dev, subdrv);
|
exynos_drm_subdrv_remove(dev, subdrv);
|
||||||
|
|
||||||
drm_dev = NULL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
|
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
|
||||||
|
@@ -29,21 +29,23 @@
|
|||||||
#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_encoder.h"
|
#include "exynos_drm_encoder.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_plane.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)
|
||||||
|
|
||||||
|
enum exynos_crtc_mode {
|
||||||
|
CRTC_MODE_NORMAL, /* normal mode */
|
||||||
|
CRTC_MODE_BLANK, /* The private plane of crtc is blank */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exynos specific crtc structure.
|
* Exynos specific crtc structure.
|
||||||
*
|
*
|
||||||
* @drm_crtc: crtc object.
|
* @drm_crtc: crtc object.
|
||||||
* @overlay: contain information common to display controller and hdmi and
|
* @drm_plane: pointer of private plane object for this crtc
|
||||||
* contents of this overlay object would be copied to sub driver size.
|
|
||||||
* @pipe: a crtc index created at load() with a new crtc object creation
|
* @pipe: a crtc index created at load() with a new crtc object creation
|
||||||
* and the crtc object would be set to private->crtc array
|
* and the crtc object would be set to private->crtc array
|
||||||
* to get a crtc object corresponding to this pipe from private->crtc
|
* to get a crtc object corresponding to this pipe from private->crtc
|
||||||
@@ -52,115 +54,16 @@
|
|||||||
* we can refer to the crtc to current hardware interrupt occured through
|
* we can refer to the crtc to current hardware interrupt occured through
|
||||||
* this pipe value.
|
* this pipe value.
|
||||||
* @dpms: store the crtc dpms value
|
* @dpms: store the crtc dpms value
|
||||||
|
* @mode: store the crtc mode value
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_crtc {
|
struct exynos_drm_crtc {
|
||||||
struct drm_crtc drm_crtc;
|
struct drm_crtc drm_crtc;
|
||||||
struct exynos_drm_overlay overlay;
|
struct drm_plane *plane;
|
||||||
unsigned int pipe;
|
unsigned int pipe;
|
||||||
unsigned int dpms;
|
unsigned int dpms;
|
||||||
|
enum exynos_crtc_mode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
|
||||||
struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
|
|
||||||
|
|
||||||
exynos_drm_fn_encoder(crtc, overlay,
|
|
||||||
exynos_drm_encoder_crtc_mode_set);
|
|
||||||
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
|
||||||
exynos_drm_encoder_crtc_commit);
|
|
||||||
}
|
|
||||||
|
|
||||||
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_gem_buf *buffer;
|
|
||||||
unsigned int actual_w;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay->dma_addr[i] = buffer->dma_addr;
|
|
||||||
overlay->vaddr[i] = buffer->kvaddr;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
|
|
||||||
i, (unsigned long)overlay->vaddr[i],
|
|
||||||
(unsigned long)overlay->dma_addr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
|
|
||||||
actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
|
|
||||||
|
|
||||||
/* set drm framebuffer data. */
|
|
||||||
overlay->fb_x = pos->fb_x;
|
|
||||||
overlay->fb_y = pos->fb_y;
|
|
||||||
overlay->fb_width = fb->width;
|
|
||||||
overlay->fb_height = fb->height;
|
|
||||||
overlay->src_width = pos->src_w;
|
|
||||||
overlay->src_height = pos->src_h;
|
|
||||||
overlay->bpp = fb->bits_per_pixel;
|
|
||||||
overlay->pitch = fb->pitches[0];
|
|
||||||
overlay->pixel_format = fb->pixel_format;
|
|
||||||
|
|
||||||
/* set overlay range to be displayed. */
|
|
||||||
overlay->crtc_x = pos->crtc_x;
|
|
||||||
overlay->crtc_y = pos->crtc_y;
|
|
||||||
overlay->crtc_width = actual_w;
|
|
||||||
overlay->crtc_height = actual_h;
|
|
||||||
|
|
||||||
/* set drm mode data. */
|
|
||||||
overlay->mode_width = mode->hdisplay;
|
|
||||||
overlay->mode_height = mode->vdisplay;
|
|
||||||
overlay->refresh = mode->vrefresh;
|
|
||||||
overlay->scan_flag = mode->flags;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
|
|
||||||
overlay->crtc_x, overlay->crtc_y,
|
|
||||||
overlay->crtc_width, overlay->crtc_height);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos_drm_crtc_update(struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct exynos_drm_crtc *exynos_crtc;
|
|
||||||
struct exynos_drm_overlay *overlay;
|
|
||||||
struct exynos_drm_crtc_pos pos;
|
|
||||||
struct drm_display_mode *mode = &crtc->mode;
|
|
||||||
struct drm_framebuffer *fb = crtc->fb;
|
|
||||||
|
|
||||||
if (!mode || !fb)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
exynos_crtc = to_exynos_crtc(crtc);
|
|
||||||
overlay = &exynos_crtc->overlay;
|
|
||||||
|
|
||||||
memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
|
|
||||||
|
|
||||||
/* it means the offset of framebuffer to be displayed. */
|
|
||||||
pos.fb_x = crtc->x;
|
|
||||||
pos.fb_y = crtc->y;
|
|
||||||
|
|
||||||
/* OSD position to be displayed. */
|
|
||||||
pos.crtc_x = 0;
|
|
||||||
pos.crtc_y = 0;
|
|
||||||
pos.crtc_w = fb->width - crtc->x;
|
|
||||||
pos.crtc_h = fb->height - crtc->y;
|
|
||||||
pos.src_w = pos.crtc_w;
|
|
||||||
pos.src_h = pos.crtc_h;
|
|
||||||
|
|
||||||
return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
@@ -175,23 +78,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||||||
|
|
||||||
mutex_lock(&dev->struct_mutex);
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
|
||||||
switch (mode) {
|
exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
|
||||||
case DRM_MODE_DPMS_ON:
|
exynos_crtc->dpms = mode;
|
||||||
exynos_drm_fn_encoder(crtc, &mode,
|
|
||||||
exynos_drm_encoder_crtc_dpms);
|
|
||||||
exynos_crtc->dpms = mode;
|
|
||||||
break;
|
|
||||||
case DRM_MODE_DPMS_STANDBY:
|
|
||||||
case DRM_MODE_DPMS_SUSPEND:
|
|
||||||
case DRM_MODE_DPMS_OFF:
|
|
||||||
exynos_drm_fn_encoder(crtc, &mode,
|
|
||||||
exynos_drm_encoder_crtc_dpms);
|
|
||||||
exynos_crtc->dpms = mode;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DRM_ERROR("unspecified mode %d\n", mode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&dev->struct_mutex);
|
mutex_unlock(&dev->struct_mutex);
|
||||||
}
|
}
|
||||||
@@ -209,30 +97,8 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
/*
|
exynos_plane_commit(exynos_crtc->plane);
|
||||||
* when set_crtc is requested from user or at booting time,
|
exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
|
||||||
* crtc->commit would be called without dpms call so if dpms is
|
|
||||||
* no power on then crtc->dpms should be called
|
|
||||||
* with DRM_MODE_DPMS_ON for the hardware power to be on.
|
|
||||||
*/
|
|
||||||
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
|
|
||||||
int mode = DRM_MODE_DPMS_ON;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* enable hardware(power on) to all encoders hdmi connected
|
|
||||||
* to current crtc.
|
|
||||||
*/
|
|
||||||
exynos_drm_crtc_dpms(crtc, mode);
|
|
||||||
/*
|
|
||||||
* enable dma to all encoders connected to current crtc and
|
|
||||||
* lcd panel.
|
|
||||||
*/
|
|
||||||
exynos_drm_fn_encoder(crtc, &mode,
|
|
||||||
exynos_drm_encoder_dpms_from_crtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
|
|
||||||
exynos_drm_encoder_crtc_commit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -251,31 +117,61 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||||||
struct drm_display_mode *adjusted_mode, int x, int y,
|
struct drm_display_mode *adjusted_mode, int x, int y,
|
||||||
struct drm_framebuffer *old_fb)
|
struct drm_framebuffer *old_fb)
|
||||||
{
|
{
|
||||||
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
struct drm_plane *plane = exynos_crtc->plane;
|
||||||
|
unsigned int crtc_w;
|
||||||
|
unsigned int crtc_h;
|
||||||
|
int pipe = exynos_crtc->pipe;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy the mode data adjusted by mode_fixup() into crtc->mode
|
* copy the mode data adjusted by mode_fixup() into crtc->mode
|
||||||
* so that hardware can be seet to proper mode.
|
* so that hardware can be seet to proper mode.
|
||||||
*/
|
*/
|
||||||
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
|
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
|
||||||
|
|
||||||
return exynos_drm_crtc_update(crtc);
|
crtc_w = crtc->fb->width - x;
|
||||||
|
crtc_h = crtc->fb->height - y;
|
||||||
|
|
||||||
|
ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
|
||||||
|
x, y, crtc_w, crtc_h);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
plane->crtc = crtc;
|
||||||
|
plane->fb = crtc->fb;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||||
struct drm_framebuffer *old_fb)
|
struct drm_framebuffer *old_fb)
|
||||||
{
|
{
|
||||||
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
struct drm_plane *plane = exynos_crtc->plane;
|
||||||
|
unsigned int crtc_w;
|
||||||
|
unsigned int crtc_h;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
ret = exynos_drm_crtc_update(crtc);
|
crtc_w = crtc->fb->width - x;
|
||||||
|
crtc_h = crtc->fb->height - y;
|
||||||
|
|
||||||
|
ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
|
||||||
|
x, y, crtc_w, crtc_h);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
exynos_drm_crtc_apply(crtc);
|
exynos_drm_crtc_commit(crtc);
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
|
static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
|
||||||
@@ -284,6 +180,16 @@ static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
|
|||||||
/* drm framework doesn't check NULL */
|
/* drm framework doesn't check NULL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
|
||||||
|
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
||||||
.dpms = exynos_drm_crtc_dpms,
|
.dpms = exynos_drm_crtc_dpms,
|
||||||
.prepare = exynos_drm_crtc_prepare,
|
.prepare = exynos_drm_crtc_prepare,
|
||||||
@@ -292,6 +198,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
|||||||
.mode_set = exynos_drm_crtc_mode_set,
|
.mode_set = exynos_drm_crtc_mode_set,
|
||||||
.mode_set_base = exynos_drm_crtc_mode_set_base,
|
.mode_set_base = exynos_drm_crtc_mode_set_base,
|
||||||
.load_lut = exynos_drm_crtc_load_lut,
|
.load_lut = exynos_drm_crtc_load_lut,
|
||||||
|
.disable = exynos_drm_crtc_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
|
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
|
||||||
@@ -327,7 +234,8 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
|
|||||||
&dev_priv->pageflip_event_list);
|
&dev_priv->pageflip_event_list);
|
||||||
|
|
||||||
crtc->fb = fb;
|
crtc->fb = fb;
|
||||||
ret = exynos_drm_crtc_update(crtc);
|
ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
|
||||||
|
NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
crtc->fb = old_fb;
|
crtc->fb = old_fb;
|
||||||
drm_vblank_put(dev, exynos_crtc->pipe);
|
drm_vblank_put(dev, exynos_crtc->pipe);
|
||||||
@@ -335,14 +243,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
|
|||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* the values related to a buffer of the drm framebuffer
|
|
||||||
* to be applied should be set at here. because these values
|
|
||||||
* first, are set to shadow registers and then to
|
|
||||||
* real registers at vsync front porch period.
|
|
||||||
*/
|
|
||||||
exynos_drm_crtc_apply(crtc);
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&dev->struct_mutex);
|
mutex_unlock(&dev->struct_mutex);
|
||||||
@@ -362,18 +262,73 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
|
|||||||
kfree(exynos_crtc);
|
kfree(exynos_crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
|
||||||
|
struct drm_property *property,
|
||||||
|
uint64_t val)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||||
|
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __func__);
|
||||||
|
|
||||||
|
if (property == dev_priv->crtc_mode_property) {
|
||||||
|
enum exynos_crtc_mode mode = val;
|
||||||
|
|
||||||
|
if (mode == exynos_crtc->mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exynos_crtc->mode = mode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CRTC_MODE_NORMAL:
|
||||||
|
exynos_drm_crtc_commit(crtc);
|
||||||
|
break;
|
||||||
|
case CRTC_MODE_BLANK:
|
||||||
|
exynos_plane_dpms(exynos_crtc->plane,
|
||||||
|
DRM_MODE_DPMS_OFF);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct drm_crtc_funcs exynos_crtc_funcs = {
|
static struct drm_crtc_funcs exynos_crtc_funcs = {
|
||||||
.set_config = drm_crtc_helper_set_config,
|
.set_config = drm_crtc_helper_set_config,
|
||||||
.page_flip = exynos_drm_crtc_page_flip,
|
.page_flip = exynos_drm_crtc_page_flip,
|
||||||
.destroy = exynos_drm_crtc_destroy,
|
.destroy = exynos_drm_crtc_destroy,
|
||||||
|
.set_property = exynos_drm_crtc_set_property,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
|
static const struct drm_prop_enum_list mode_names[] = {
|
||||||
struct drm_crtc *crtc)
|
{ CRTC_MODE_NORMAL, "normal" },
|
||||||
{
|
{ CRTC_MODE_BLANK, "blank" },
|
||||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
};
|
||||||
|
|
||||||
return &exynos_crtc->overlay;
|
static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||||
|
struct drm_property *prop;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __func__);
|
||||||
|
|
||||||
|
prop = dev_priv->crtc_mode_property;
|
||||||
|
if (!prop) {
|
||||||
|
prop = drm_property_create_enum(dev, 0, "mode", mode_names,
|
||||||
|
ARRAY_SIZE(mode_names));
|
||||||
|
if (!prop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_priv->crtc_mode_property = prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_object_attach_property(&crtc->base, prop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
||||||
@@ -392,7 +347,12 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
|||||||
|
|
||||||
exynos_crtc->pipe = nr;
|
exynos_crtc->pipe = nr;
|
||||||
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
|
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
|
||||||
exynos_crtc->overlay.zpos = DEFAULT_ZPOS;
|
exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
|
||||||
|
if (!exynos_crtc->plane) {
|
||||||
|
kfree(exynos_crtc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
crtc = &exynos_crtc->drm_crtc;
|
crtc = &exynos_crtc->drm_crtc;
|
||||||
|
|
||||||
private->crtc[nr] = crtc;
|
private->crtc[nr] = crtc;
|
||||||
@@ -400,6 +360,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
|||||||
drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
|
drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
|
||||||
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
|
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
|
||||||
|
|
||||||
|
exynos_drm_crtc_attach_mode_property(crtc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,39 +29,8 @@
|
|||||||
#ifndef _EXYNOS_DRM_CRTC_H_
|
#ifndef _EXYNOS_DRM_CRTC_H_
|
||||||
#define _EXYNOS_DRM_CRTC_H_
|
#define _EXYNOS_DRM_CRTC_H_
|
||||||
|
|
||||||
struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
|
|
||||||
struct drm_crtc *crtc);
|
|
||||||
int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
|
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.
|
|
||||||
* @src_w: width of source area to be displayed from a framebuffer.
|
|
||||||
* @src_h: height of source area to be displayed from a framebuffer.
|
|
||||||
* @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 src_w;
|
|
||||||
unsigned int src_h;
|
|
||||||
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
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
|
#include "exynos_drm.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_gem.h"
|
||||||
|
|
||||||
@@ -86,6 +87,10 @@ static struct sg_table *
|
|||||||
npages = buf->size / buf->page_size;
|
npages = buf->size / buf->page_size;
|
||||||
|
|
||||||
sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
|
sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
|
||||||
|
if (!sgt) {
|
||||||
|
DRM_DEBUG_PRIME("exynos_pages_to_sg returned NULL!\n");
|
||||||
|
goto err_unlock;
|
||||||
|
}
|
||||||
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
|
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
|
||||||
|
|
||||||
DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
|
DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
|
||||||
@@ -186,7 +191,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
|
|||||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||||
struct exynos_drm_gem_buf *buffer;
|
struct exynos_drm_gem_buf *buffer;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int ret, i = 0;
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG_PRIME("%s\n", __FILE__);
|
DRM_DEBUG_PRIME("%s\n", __FILE__);
|
||||||
|
|
||||||
@@ -210,7 +215,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
|
|||||||
|
|
||||||
|
|
||||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||||
if (IS_ERR(sgt)) {
|
if (IS_ERR_OR_NULL(sgt)) {
|
||||||
ret = PTR_ERR(sgt);
|
ret = PTR_ERR(sgt);
|
||||||
goto err_buf_detach;
|
goto err_buf_detach;
|
||||||
}
|
}
|
||||||
@@ -236,13 +241,25 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sgl = sgt->sgl;
|
sgl = sgt->sgl;
|
||||||
buffer->dma_addr = sg_dma_address(sgl);
|
|
||||||
|
|
||||||
while (i < sgt->nents) {
|
if (sgt->nents == 1) {
|
||||||
buffer->pages[i] = sg_page(sgl);
|
buffer->dma_addr = sg_dma_address(sgt->sgl);
|
||||||
buffer->size += sg_dma_len(sgl);
|
buffer->size = sg_dma_len(sgt->sgl);
|
||||||
sgl = sg_next(sgl);
|
|
||||||
i++;
|
/* always physically continuous memory if sgt->nents is 1. */
|
||||||
|
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
|
||||||
|
} else {
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
buffer->dma_addr = sg_dma_address(sgl);
|
||||||
|
while (i < sgt->nents) {
|
||||||
|
buffer->pages[i] = sg_page(sgl);
|
||||||
|
buffer->size += sg_dma_len(sgl);
|
||||||
|
sgl = sg_next(sgl);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
exynos_gem_obj->buffer = buffer;
|
exynos_gem_obj->buffer = buffer;
|
||||||
|
@@ -85,8 +85,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (nr = 0; nr < MAX_PLANE; nr++) {
|
for (nr = 0; nr < MAX_PLANE; nr++) {
|
||||||
ret = exynos_plane_init(dev, nr);
|
struct drm_plane *plane;
|
||||||
if (ret)
|
unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
|
||||||
|
|
||||||
|
plane = exynos_plane_init(dev, possible_crtcs, false);
|
||||||
|
if (!plane)
|
||||||
goto err_crtc;
|
goto err_crtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,8 +224,6 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
|
|||||||
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||||
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
|
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
|
||||||
exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
|
exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
|
||||||
DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
|
|
||||||
DRM_UNLOCKED | DRM_AUTH),
|
|
||||||
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
|
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
|
||||||
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||||
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
|
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
|
||||||
|
@@ -59,12 +59,14 @@ enum exynos_drm_output_type {
|
|||||||
*
|
*
|
||||||
* @mode_set: copy drm overlay info to hw specific overlay info.
|
* @mode_set: copy drm overlay info to hw specific overlay info.
|
||||||
* @commit: apply hardware specific overlay data to registers.
|
* @commit: apply hardware specific overlay data to registers.
|
||||||
|
* @enable: enable hardware specific overlay.
|
||||||
* @disable: disable hardware specific overlay.
|
* @disable: disable hardware specific overlay.
|
||||||
*/
|
*/
|
||||||
struct exynos_drm_overlay_ops {
|
struct exynos_drm_overlay_ops {
|
||||||
void (*mode_set)(struct device *subdrv_dev,
|
void (*mode_set)(struct device *subdrv_dev,
|
||||||
struct exynos_drm_overlay *overlay);
|
struct exynos_drm_overlay *overlay);
|
||||||
void (*commit)(struct device *subdrv_dev, int zpos);
|
void (*commit)(struct device *subdrv_dev, int zpos);
|
||||||
|
void (*enable)(struct device *subdrv_dev, int zpos);
|
||||||
void (*disable)(struct device *subdrv_dev, int zpos);
|
void (*disable)(struct device *subdrv_dev, int zpos);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -235,6 +237,8 @@ struct exynos_drm_private {
|
|||||||
* this array is used to be aware of which crtc did it request vblank.
|
* this array is used to be aware of which crtc did it request vblank.
|
||||||
*/
|
*/
|
||||||
struct drm_crtc *crtc[MAX_CRTC];
|
struct drm_crtc *crtc[MAX_CRTC];
|
||||||
|
struct drm_property *plane_zpos_property;
|
||||||
|
struct drm_property *crtc_mode_property;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -30,7 +30,6 @@
|
|||||||
#include "drm_crtc_helper.h"
|
#include "drm_crtc_helper.h"
|
||||||
|
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_crtc.h"
|
|
||||||
#include "exynos_drm_encoder.h"
|
#include "exynos_drm_encoder.h"
|
||||||
|
|
||||||
#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
|
#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
|
||||||
@@ -136,21 +135,16 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
|
|||||||
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;
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
|
||||||
struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
|
|
||||||
encoder->crtc);
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
|
||||||
|
|
||||||
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)
|
||||||
if (manager_ops && manager_ops->mode_set)
|
if (manager_ops && manager_ops->mode_set)
|
||||||
manager_ops->mode_set(manager->dev,
|
manager_ops->mode_set(manager->dev,
|
||||||
adjusted_mode);
|
adjusted_mode);
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->mode_set)
|
|
||||||
overlay_ops->mode_set(manager->dev, overlay);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +304,8 @@ void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
|
|||||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
int crtc = *(int *)data;
|
int crtc = *(int *)data;
|
||||||
|
|
||||||
if (manager->pipe == -1)
|
if (manager->pipe != crtc)
|
||||||
manager->pipe = crtc;
|
return;
|
||||||
|
|
||||||
if (manager_ops->enable_vblank)
|
if (manager_ops->enable_vblank)
|
||||||
manager_ops->enable_vblank(manager->dev);
|
manager_ops->enable_vblank(manager->dev);
|
||||||
@@ -324,65 +318,18 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
|
|||||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
int crtc = *(int *)data;
|
int crtc = *(int *)data;
|
||||||
|
|
||||||
if (manager->pipe == -1)
|
if (manager->pipe != crtc)
|
||||||
manager->pipe = crtc;
|
return;
|
||||||
|
|
||||||
if (manager_ops->disable_vblank)
|
if (manager_ops->disable_vblank)
|
||||||
manager_ops->disable_vblank(manager->dev);
|
manager_ops->disable_vblank(manager->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct exynos_drm_manager *manager =
|
|
||||||
to_exynos_encoder(encoder)->manager;
|
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
|
||||||
int zpos = DEFAULT_ZPOS;
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
zpos = *(int *)data;
|
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->commit)
|
|
||||||
overlay_ops->commit(manager->dev, zpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
|
|
||||||
{
|
|
||||||
struct exynos_drm_manager *manager =
|
|
||||||
to_exynos_encoder(encoder)->manager;
|
|
||||||
int crtc = *(int *)data;
|
|
||||||
int zpos = DEFAULT_ZPOS;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* when crtc is detached from encoder, this pipe is used
|
|
||||||
* to select manager operation
|
|
||||||
*/
|
|
||||||
manager->pipe = crtc;
|
|
||||||
|
|
||||||
exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
|
|
||||||
{
|
|
||||||
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
|
|
||||||
int mode = *(int *)data;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
|
||||||
|
|
||||||
exynos_drm_encoder_dpms(encoder, mode);
|
|
||||||
|
|
||||||
exynos_encoder->dpms = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
|
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = encoder->dev;
|
|
||||||
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
|
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
|
||||||
struct exynos_drm_manager *manager = exynos_encoder->manager;
|
struct exynos_drm_manager *manager = exynos_encoder->manager;
|
||||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||||
struct drm_connector *connector;
|
|
||||||
int mode = *(int *)data;
|
int mode = *(int *)data;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
@@ -390,15 +337,6 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
|
|||||||
if (manager_ops && manager_ops->dpms)
|
if (manager_ops && manager_ops->dpms)
|
||||||
manager_ops->dpms(manager->dev, mode);
|
manager_ops->dpms(manager->dev, mode);
|
||||||
|
|
||||||
/*
|
|
||||||
* set current dpms mode to the connector connected to
|
|
||||||
* current encoder. connector->dpms would be checked
|
|
||||||
* at drm_helper_connector_dpms()
|
|
||||||
*/
|
|
||||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
|
||||||
if (connector->encoder == encoder)
|
|
||||||
connector->dpms = mode;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if this condition is ok then it means that the crtc is already
|
* if this condition is ok then it means that the crtc is already
|
||||||
* detached from encoder and last function for detaching is properly
|
* detached from encoder and last function for detaching is properly
|
||||||
@@ -410,25 +348,74 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
|
void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
|
||||||
|
{
|
||||||
|
struct exynos_drm_manager *manager =
|
||||||
|
to_exynos_encoder(encoder)->manager;
|
||||||
|
int pipe = *(int *)data;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* when crtc is detached from encoder, this pipe is used
|
||||||
|
* to select manager operation
|
||||||
|
*/
|
||||||
|
manager->pipe = pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_encoder_plane_mode_set(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;
|
||||||
struct exynos_drm_overlay *overlay = data;
|
struct exynos_drm_overlay *overlay = data;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
if (overlay_ops && overlay_ops->mode_set)
|
if (overlay_ops && overlay_ops->mode_set)
|
||||||
overlay_ops->mode_set(manager->dev, overlay);
|
overlay_ops->mode_set(manager->dev, overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
|
void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
|
||||||
{
|
{
|
||||||
struct exynos_drm_manager *manager =
|
struct exynos_drm_manager *manager =
|
||||||
to_exynos_encoder(encoder)->manager;
|
to_exynos_encoder(encoder)->manager;
|
||||||
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
int zpos = DEFAULT_ZPOS;
|
int zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("\n");
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
zpos = *(int *)data;
|
||||||
|
|
||||||
|
if (overlay_ops && overlay_ops->commit)
|
||||||
|
overlay_ops->commit(manager->dev, zpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
|
||||||
|
{
|
||||||
|
struct exynos_drm_manager *manager =
|
||||||
|
to_exynos_encoder(encoder)->manager;
|
||||||
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
|
int zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
zpos = *(int *)data;
|
||||||
|
|
||||||
|
if (overlay_ops && overlay_ops->enable)
|
||||||
|
overlay_ops->enable(manager->dev, zpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
|
||||||
|
{
|
||||||
|
struct exynos_drm_manager *manager =
|
||||||
|
to_exynos_encoder(encoder)->manager;
|
||||||
|
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||||
|
int zpos = DEFAULT_ZPOS;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
zpos = *(int *)data;
|
zpos = *(int *)data;
|
||||||
|
@@ -40,13 +40,11 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
|||||||
void (*fn)(struct drm_encoder *, void *));
|
void (*fn)(struct drm_encoder *, void *));
|
||||||
void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
|
void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
|
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
|
|
||||||
void *data);
|
|
||||||
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
|
|
||||||
void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
|
|
||||||
void *data);
|
|
||||||
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
|
||||||
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
|
void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
|
||||||
|
void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -78,7 +78,6 @@ struct fimd_context {
|
|||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
struct clk *bus_clk;
|
struct clk *bus_clk;
|
||||||
struct clk *lcd_clk;
|
struct clk *lcd_clk;
|
||||||
struct resource *regs_res;
|
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct fimd_win_data win_data[WINDOWS_NR];
|
struct fimd_win_data win_data[WINDOWS_NR];
|
||||||
unsigned int clkdiv;
|
unsigned int clkdiv;
|
||||||
@@ -813,7 +812,7 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -838,33 +837,26 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
|||||||
goto err_clk;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->regs_res = request_mem_region(res->start, resource_size(res),
|
ctx->regs = devm_request_and_ioremap(&pdev->dev, res);
|
||||||
dev_name(dev));
|
|
||||||
if (!ctx->regs_res) {
|
|
||||||
dev_err(dev, "failed to claim register region\n");
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto err_clk;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->regs = ioremap(res->start, resource_size(res));
|
|
||||||
if (!ctx->regs) {
|
if (!ctx->regs) {
|
||||||
dev_err(dev, "failed to map registers\n");
|
dev_err(dev, "failed to map registers\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto err_req_region_io;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dev_err(dev, "irq request failed.\n");
|
dev_err(dev, "irq request failed.\n");
|
||||||
goto err_req_region_irq;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->irq = res->start;
|
ctx->irq = res->start;
|
||||||
|
|
||||||
ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
|
ret = devm_request_irq(&pdev->dev, ctx->irq, fimd_irq_handler,
|
||||||
if (ret < 0) {
|
0, "drm_fimd", ctx);
|
||||||
|
if (ret) {
|
||||||
dev_err(dev, "irq request failed.\n");
|
dev_err(dev, "irq request failed.\n");
|
||||||
goto err_req_irq;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->vidcon0 = pdata->vidcon0;
|
ctx->vidcon0 = pdata->vidcon0;
|
||||||
@@ -899,14 +891,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_req_irq:
|
|
||||||
err_req_region_irq:
|
|
||||||
iounmap(ctx->regs);
|
|
||||||
|
|
||||||
err_req_region_io:
|
|
||||||
release_resource(ctx->regs_res);
|
|
||||||
kfree(ctx->regs_res);
|
|
||||||
|
|
||||||
err_clk:
|
err_clk:
|
||||||
clk_disable(ctx->lcd_clk);
|
clk_disable(ctx->lcd_clk);
|
||||||
clk_put(ctx->lcd_clk);
|
clk_put(ctx->lcd_clk);
|
||||||
@@ -916,7 +900,6 @@ err_bus_clk:
|
|||||||
clk_put(ctx->bus_clk);
|
clk_put(ctx->bus_clk);
|
||||||
|
|
||||||
err_clk_get:
|
err_clk_get:
|
||||||
kfree(ctx);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,13 +927,6 @@ out:
|
|||||||
clk_put(ctx->lcd_clk);
|
clk_put(ctx->lcd_clk);
|
||||||
clk_put(ctx->bus_clk);
|
clk_put(ctx->bus_clk);
|
||||||
|
|
||||||
iounmap(ctx->regs);
|
|
||||||
release_resource(ctx->regs_res);
|
|
||||||
kfree(ctx->regs_res);
|
|
||||||
free_irq(ctx->irq, ctx);
|
|
||||||
|
|
||||||
kfree(ctx);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -99,25 +99,17 @@ out:
|
|||||||
struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
|
struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
|
||||||
gfp_t gfpmask)
|
gfp_t gfpmask)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
|
||||||
struct address_space *mapping;
|
|
||||||
struct page *p, **pages;
|
struct page *p, **pages;
|
||||||
int i, npages;
|
int i, npages;
|
||||||
|
|
||||||
/* This is the shared memory object that backs the GEM resource */
|
|
||||||
inode = obj->filp->f_path.dentry->d_inode;
|
|
||||||
mapping = inode->i_mapping;
|
|
||||||
|
|
||||||
npages = obj->size >> PAGE_SHIFT;
|
npages = obj->size >> PAGE_SHIFT;
|
||||||
|
|
||||||
pages = drm_malloc_ab(npages, sizeof(struct page *));
|
pages = drm_malloc_ab(npages, sizeof(struct page *));
|
||||||
if (pages == NULL)
|
if (pages == NULL)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
gfpmask |= mapping_gfp_mask(mapping);
|
|
||||||
|
|
||||||
for (i = 0; i < npages; i++) {
|
for (i = 0; i < npages; i++) {
|
||||||
p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
|
p = alloc_page(gfpmask);
|
||||||
if (IS_ERR(p))
|
if (IS_ERR(p))
|
||||||
goto fail;
|
goto fail;
|
||||||
pages[i] = p;
|
pages[i] = p;
|
||||||
@@ -126,31 +118,22 @@ struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
|
|||||||
return pages;
|
return pages;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
while (i--)
|
while (--i)
|
||||||
page_cache_release(pages[i]);
|
__free_page(pages[i]);
|
||||||
|
|
||||||
drm_free_large(pages);
|
drm_free_large(pages);
|
||||||
return ERR_PTR(PTR_ERR(p));
|
return ERR_PTR(PTR_ERR(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_gem_put_pages(struct drm_gem_object *obj,
|
static void exynos_gem_put_pages(struct drm_gem_object *obj,
|
||||||
struct page **pages,
|
struct page **pages)
|
||||||
bool dirty, bool accessed)
|
|
||||||
{
|
{
|
||||||
int i, npages;
|
int npages;
|
||||||
|
|
||||||
npages = obj->size >> PAGE_SHIFT;
|
npages = obj->size >> PAGE_SHIFT;
|
||||||
|
|
||||||
for (i = 0; i < npages; i++) {
|
while (--npages >= 0)
|
||||||
if (dirty)
|
__free_page(pages[npages]);
|
||||||
set_page_dirty(pages[i]);
|
|
||||||
|
|
||||||
if (accessed)
|
|
||||||
mark_page_accessed(pages[i]);
|
|
||||||
|
|
||||||
/* Undo the reference we took when populating the table */
|
|
||||||
page_cache_release(pages[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
drm_free_large(pages);
|
drm_free_large(pages);
|
||||||
}
|
}
|
||||||
@@ -189,7 +172,7 @@ static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pages = exynos_gem_get_pages(obj, GFP_KERNEL);
|
pages = exynos_gem_get_pages(obj, GFP_HIGHUSER_MOVABLE);
|
||||||
if (IS_ERR(pages)) {
|
if (IS_ERR(pages)) {
|
||||||
DRM_ERROR("failed to get pages.\n");
|
DRM_ERROR("failed to get pages.\n");
|
||||||
return PTR_ERR(pages);
|
return PTR_ERR(pages);
|
||||||
@@ -230,7 +213,7 @@ err1:
|
|||||||
kfree(buf->sgt);
|
kfree(buf->sgt);
|
||||||
buf->sgt = NULL;
|
buf->sgt = NULL;
|
||||||
err:
|
err:
|
||||||
exynos_gem_put_pages(obj, pages, true, false);
|
exynos_gem_put_pages(obj, pages);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -248,7 +231,7 @@ static void exynos_drm_gem_put_pages(struct drm_gem_object *obj)
|
|||||||
kfree(buf->sgt);
|
kfree(buf->sgt);
|
||||||
buf->sgt = NULL;
|
buf->sgt = NULL;
|
||||||
|
|
||||||
exynos_gem_put_pages(obj, buf->pages, true, false);
|
exynos_gem_put_pages(obj, buf->pages);
|
||||||
buf->pages = NULL;
|
buf->pages = NULL;
|
||||||
|
|
||||||
/* add some codes for UNCACHED type here. TODO */
|
/* add some codes for UNCACHED type here. TODO */
|
||||||
@@ -291,11 +274,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
|
|||||||
if (!buf->pages)
|
if (!buf->pages)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* do not release memory region from exporter.
|
||||||
|
*
|
||||||
|
* the region will be released by exporter
|
||||||
|
* once dmabuf's refcount becomes 0.
|
||||||
|
*/
|
||||||
|
if (obj->import_attach)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
|
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
|
||||||
exynos_drm_gem_put_pages(obj);
|
exynos_drm_gem_put_pages(obj);
|
||||||
else
|
else
|
||||||
exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
|
exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
|
||||||
|
|
||||||
|
out:
|
||||||
exynos_drm_fini_buf(obj->dev, buf);
|
exynos_drm_fini_buf(obj->dev, buf);
|
||||||
exynos_gem_obj->buffer = NULL;
|
exynos_gem_obj->buffer = NULL;
|
||||||
|
|
||||||
@@ -668,7 +661,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
|||||||
* with DRM_IOCTL_MODE_CREATE_DUMB command.
|
* with DRM_IOCTL_MODE_CREATE_DUMB command.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
args->pitch = args->width * args->bpp >> 3;
|
args->pitch = args->width * ((args->bpp + 7) / 8);
|
||||||
args->size = PAGE_ALIGN(args->pitch * args->height);
|
args->size = PAGE_ALIGN(args->pitch * args->height);
|
||||||
|
|
||||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
||||||
|
@@ -63,7 +63,8 @@ struct exynos_drm_gem_buf {
|
|||||||
* by user request or at framebuffer creation.
|
* 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.
|
||||||
* @size: total memory size to physically non-continuous memory region.
|
* @size: size requested from user, in bytes and this size is aligned
|
||||||
|
* in page unit.
|
||||||
* @flags: indicate memory type to allocated buffer and cache attruibute.
|
* @flags: indicate memory type to allocated buffer and cache attruibute.
|
||||||
*
|
*
|
||||||
* P.S. this object would be transfered to user as kms_bo.handle so
|
* P.S. this object would be transfered to user as kms_bo.handle so
|
||||||
|
@@ -12,9 +12,12 @@
|
|||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
|
|
||||||
#include "exynos_drm.h"
|
#include "exynos_drm.h"
|
||||||
#include "exynos_drm_crtc.h"
|
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_encoder.h"
|
#include "exynos_drm_encoder.h"
|
||||||
|
#include "exynos_drm_fb.h"
|
||||||
|
#include "exynos_drm_gem.h"
|
||||||
|
|
||||||
|
#define to_exynos_plane(x) container_of(x, struct exynos_plane, base)
|
||||||
|
|
||||||
struct exynos_plane {
|
struct exynos_plane {
|
||||||
struct drm_plane base;
|
struct drm_plane base;
|
||||||
@@ -30,6 +33,108 @@ static const uint32_t formats[] = {
|
|||||||
DRM_FORMAT_NV12MT,
|
DRM_FORMAT_NV12MT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||||
|
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||||
|
unsigned int crtc_w, unsigned int crtc_h,
|
||||||
|
uint32_t src_x, uint32_t src_y,
|
||||||
|
uint32_t src_w, uint32_t src_h)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
|
||||||
|
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
||||||
|
unsigned int actual_w;
|
||||||
|
unsigned int actual_h;
|
||||||
|
int nr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
nr = exynos_drm_format_num_buffers(fb->pixel_format);
|
||||||
|
for (i = 0; i < nr; i++) {
|
||||||
|
struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
DRM_LOG_KMS("buffer is null\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay->dma_addr[i] = buffer->dma_addr;
|
||||||
|
overlay->vaddr[i] = buffer->kvaddr;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
|
||||||
|
i, (unsigned long)overlay->vaddr[i],
|
||||||
|
(unsigned long)overlay->dma_addr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w);
|
||||||
|
actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h);
|
||||||
|
|
||||||
|
/* set drm framebuffer data. */
|
||||||
|
overlay->fb_x = src_x;
|
||||||
|
overlay->fb_y = src_y;
|
||||||
|
overlay->fb_width = fb->width;
|
||||||
|
overlay->fb_height = fb->height;
|
||||||
|
overlay->src_width = src_w;
|
||||||
|
overlay->src_height = src_h;
|
||||||
|
overlay->bpp = fb->bits_per_pixel;
|
||||||
|
overlay->pitch = fb->pitches[0];
|
||||||
|
overlay->pixel_format = fb->pixel_format;
|
||||||
|
|
||||||
|
/* set overlay range to be displayed. */
|
||||||
|
overlay->crtc_x = crtc_x;
|
||||||
|
overlay->crtc_y = crtc_y;
|
||||||
|
overlay->crtc_width = actual_w;
|
||||||
|
overlay->crtc_height = actual_h;
|
||||||
|
|
||||||
|
/* set drm mode data. */
|
||||||
|
overlay->mode_width = crtc->mode.hdisplay;
|
||||||
|
overlay->mode_height = crtc->mode.vdisplay;
|
||||||
|
overlay->refresh = crtc->mode.vrefresh;
|
||||||
|
overlay->scan_flag = crtc->mode.flags;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
|
||||||
|
overlay->crtc_x, overlay->crtc_y,
|
||||||
|
overlay->crtc_width, overlay->crtc_height);
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_plane_commit(struct drm_plane *plane)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
|
||||||
|
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||||
|
exynos_drm_encoder_plane_commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_plane_dpms(struct drm_plane *plane, int mode)
|
||||||
|
{
|
||||||
|
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
|
||||||
|
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
if (mode == DRM_MODE_DPMS_ON) {
|
||||||
|
if (exynos_plane->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||||
|
exynos_drm_encoder_plane_enable);
|
||||||
|
|
||||||
|
exynos_plane->enabled = true;
|
||||||
|
} else {
|
||||||
|
if (!exynos_plane->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||||
|
exynos_drm_encoder_plane_disable);
|
||||||
|
|
||||||
|
exynos_plane->enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||||
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||||
@@ -37,64 +142,37 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|||||||
uint32_t src_x, uint32_t src_y,
|
uint32_t src_x, uint32_t src_y,
|
||||||
uint32_t src_w, uint32_t src_h)
|
uint32_t src_w, uint32_t src_h)
|
||||||
{
|
{
|
||||||
struct exynos_plane *exynos_plane =
|
|
||||||
container_of(plane, struct exynos_plane, base);
|
|
||||||
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
|
||||||
struct exynos_drm_crtc_pos pos;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
|
ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
|
||||||
pos.crtc_x = crtc_x;
|
crtc_w, crtc_h, src_x >> 16, src_y >> 16,
|
||||||
pos.crtc_y = crtc_y;
|
src_w >> 16, src_h >> 16);
|
||||||
pos.crtc_w = crtc_w;
|
|
||||||
pos.crtc_h = crtc_h;
|
|
||||||
|
|
||||||
/* considering 16.16 fixed point of source values */
|
|
||||||
pos.fb_x = src_x >> 16;
|
|
||||||
pos.fb_y = src_y >> 16;
|
|
||||||
pos.src_w = src_w >> 16;
|
|
||||||
pos.src_h = src_h >> 16;
|
|
||||||
|
|
||||||
ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
exynos_drm_fn_encoder(crtc, overlay,
|
plane->crtc = crtc;
|
||||||
exynos_drm_encoder_crtc_mode_set);
|
plane->fb = crtc->fb;
|
||||||
exynos_drm_fn_encoder(crtc, &overlay->zpos,
|
|
||||||
exynos_drm_encoder_crtc_plane_commit);
|
|
||||||
|
|
||||||
exynos_plane->enabled = true;
|
exynos_plane_commit(plane);
|
||||||
|
exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_disable_plane(struct drm_plane *plane)
|
static int exynos_disable_plane(struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
struct exynos_plane *exynos_plane =
|
|
||||||
container_of(plane, struct exynos_plane, base);
|
|
||||||
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
if (!exynos_plane->enabled)
|
exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
|
||||||
return 0;
|
|
||||||
|
|
||||||
exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
|
||||||
exynos_drm_encoder_crtc_disable);
|
|
||||||
|
|
||||||
exynos_plane->enabled = false;
|
|
||||||
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_plane_destroy(struct drm_plane *plane)
|
static void exynos_plane_destroy(struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
struct exynos_plane *exynos_plane =
|
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
|
||||||
container_of(plane, struct exynos_plane, base);
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
@@ -103,69 +181,79 @@ static void exynos_plane_destroy(struct drm_plane *plane)
|
|||||||
kfree(exynos_plane);
|
kfree(exynos_plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int exynos_plane_set_property(struct drm_plane *plane,
|
||||||
|
struct drm_property *property,
|
||||||
|
uint64_t val)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = plane->dev;
|
||||||
|
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
|
||||||
|
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
|
if (property == dev_priv->plane_zpos_property) {
|
||||||
|
exynos_plane->overlay.zpos = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct drm_plane_funcs exynos_plane_funcs = {
|
static struct drm_plane_funcs exynos_plane_funcs = {
|
||||||
.update_plane = exynos_update_plane,
|
.update_plane = exynos_update_plane,
|
||||||
.disable_plane = exynos_disable_plane,
|
.disable_plane = exynos_disable_plane,
|
||||||
.destroy = exynos_plane_destroy,
|
.destroy = exynos_plane_destroy,
|
||||||
|
.set_property = exynos_plane_set_property,
|
||||||
};
|
};
|
||||||
|
|
||||||
int exynos_plane_init(struct drm_device *dev, unsigned int nr)
|
static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
struct exynos_plane *exynos_plane;
|
struct drm_device *dev = plane->dev;
|
||||||
uint32_t possible_crtcs;
|
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||||
|
struct drm_property *prop;
|
||||||
exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
|
|
||||||
if (!exynos_plane)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* all CRTCs are available */
|
|
||||||
possible_crtcs = (1 << MAX_CRTC) - 1;
|
|
||||||
|
|
||||||
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
|
||||||
|
|
||||||
return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
|
|
||||||
&exynos_plane_funcs, formats, ARRAY_SIZE(formats),
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
|
|
||||||
struct drm_file *file_priv)
|
|
||||||
{
|
|
||||||
struct drm_exynos_plane_set_zpos *zpos_req = data;
|
|
||||||
struct drm_mode_object *obj;
|
|
||||||
struct drm_plane *plane;
|
|
||||||
struct exynos_plane *exynos_plane;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
prop = dev_priv->plane_zpos_property;
|
||||||
return -EINVAL;
|
if (!prop) {
|
||||||
|
prop = drm_property_create_range(dev, 0, "zpos", 0,
|
||||||
|
MAX_PLANE - 1);
|
||||||
|
if (!prop)
|
||||||
|
return;
|
||||||
|
|
||||||
if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
|
dev_priv->plane_zpos_property = prop;
|
||||||
if (zpos_req->zpos != DEFAULT_ZPOS) {
|
|
||||||
DRM_ERROR("zpos not within limits\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev->mode_config.mutex);
|
drm_object_attach_property(&plane->base, prop, 0);
|
||||||
|
}
|
||||||
obj = drm_mode_object_find(dev, zpos_req->plane_id,
|
|
||||||
DRM_MODE_OBJECT_PLANE);
|
struct drm_plane *exynos_plane_init(struct drm_device *dev,
|
||||||
if (!obj) {
|
unsigned int possible_crtcs, bool priv)
|
||||||
DRM_DEBUG_KMS("Unknown plane ID %d\n",
|
{
|
||||||
zpos_req->plane_id);
|
struct exynos_plane *exynos_plane;
|
||||||
ret = -EINVAL;
|
int err;
|
||||||
goto out;
|
|
||||||
}
|
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||||
|
|
||||||
plane = obj_to_plane(obj);
|
exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
|
||||||
exynos_plane = container_of(plane, struct exynos_plane, base);
|
if (!exynos_plane) {
|
||||||
|
DRM_ERROR("failed to allocate plane\n");
|
||||||
exynos_plane->overlay.zpos = zpos_req->zpos;
|
return NULL;
|
||||||
|
}
|
||||||
out:
|
|
||||||
mutex_unlock(&dev->mode_config.mutex);
|
err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
|
||||||
return ret;
|
&exynos_plane_funcs, formats, ARRAY_SIZE(formats),
|
||||||
|
priv);
|
||||||
|
if (err) {
|
||||||
|
DRM_ERROR("failed to initialize plane\n");
|
||||||
|
kfree(exynos_plane);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv)
|
||||||
|
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
||||||
|
else
|
||||||
|
exynos_plane_attach_zpos_property(&exynos_plane->base);
|
||||||
|
|
||||||
|
return &exynos_plane->base;
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int exynos_plane_init(struct drm_device *dev, unsigned int nr);
|
int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||||
int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
|
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||||
struct drm_file *file_priv);
|
unsigned int crtc_w, unsigned int crtc_h,
|
||||||
|
uint32_t src_x, uint32_t src_y,
|
||||||
|
uint32_t src_w, uint32_t src_h);
|
||||||
|
void exynos_plane_commit(struct drm_plane *plane);
|
||||||
|
void exynos_plane_dpms(struct drm_plane *plane, int mode);
|
||||||
|
struct drm_plane *exynos_plane_init(struct drm_device *dev,
|
||||||
|
unsigned int possible_crtcs, bool priv);
|
||||||
|
@@ -85,8 +85,6 @@ static const char fake_edid_info[] = {
|
|||||||
0x00, 0x00, 0x00, 0x06
|
0x00, 0x00, 0x00, 0x06
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vidi_fake_vblank_handler(struct work_struct *work);
|
|
||||||
|
|
||||||
static bool vidi_display_is_connected(struct device *dev)
|
static bool vidi_display_is_connected(struct device *dev)
|
||||||
{
|
{
|
||||||
struct vidi_context *ctx = get_vidi_context(dev);
|
struct vidi_context *ctx = get_vidi_context(dev);
|
||||||
@@ -531,6 +529,16 @@ static int vidi_store_connection(struct device *dev,
|
|||||||
if (ctx->connected > 1)
|
if (ctx->connected > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* use fake edid data for test. */
|
||||||
|
if (!ctx->raw_edid)
|
||||||
|
ctx->raw_edid = (struct edid *)fake_edid_info;
|
||||||
|
|
||||||
|
/* if raw_edid isn't same as fake data then it can't be tested. */
|
||||||
|
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
|
||||||
|
DRM_DEBUG_KMS("edid data is not fake data.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
DRM_DEBUG_KMS("requested connection.\n");
|
DRM_DEBUG_KMS("requested connection.\n");
|
||||||
|
|
||||||
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
||||||
@@ -549,6 +557,8 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
struct exynos_drm_manager *manager;
|
struct exynos_drm_manager *manager;
|
||||||
struct exynos_drm_display_ops *display_ops;
|
struct exynos_drm_display_ops *display_ops;
|
||||||
struct drm_exynos_vidi_connection *vidi = data;
|
struct drm_exynos_vidi_connection *vidi = data;
|
||||||
|
struct edid *raw_edid;
|
||||||
|
int edid_len;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||||
|
|
||||||
@@ -557,11 +567,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vidi->edid) {
|
|
||||||
DRM_DEBUG_KMS("edid data is null.\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vidi->connection > 1) {
|
if (vidi->connection > 1) {
|
||||||
DRM_DEBUG_KMS("connection should be 0 or 1.\n");
|
DRM_DEBUG_KMS("connection should be 0 or 1.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -588,8 +593,30 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vidi->connection)
|
if (vidi->connection) {
|
||||||
ctx->raw_edid = (struct edid *)vidi->edid;
|
if (!vidi->edid) {
|
||||||
|
DRM_DEBUG_KMS("edid data is null.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
raw_edid = (struct edid *)(uint32_t)vidi->edid;
|
||||||
|
edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
|
||||||
|
ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL);
|
||||||
|
if (!ctx->raw_edid) {
|
||||||
|
DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memcpy(ctx->raw_edid, raw_edid, edid_len);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* with connection = 0, free raw_edid
|
||||||
|
* only if raw edid data isn't same as fake data.
|
||||||
|
*/
|
||||||
|
if (ctx->raw_edid && ctx->raw_edid !=
|
||||||
|
(struct edid *)fake_edid_info) {
|
||||||
|
kfree(ctx->raw_edid);
|
||||||
|
ctx->raw_edid = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx->connected = vidi->connection;
|
ctx->connected = vidi->connection;
|
||||||
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
||||||
@@ -614,9 +641,6 @@ static int __devinit vidi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
|
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
|
||||||
|
|
||||||
/* for test */
|
|
||||||
ctx->raw_edid = (struct edid *)fake_edid_info;
|
|
||||||
|
|
||||||
subdrv = &ctx->subdrv;
|
subdrv = &ctx->subdrv;
|
||||||
subdrv->dev = dev;
|
subdrv->dev = dev;
|
||||||
subdrv->manager = &vidi_manager;
|
subdrv->manager = &vidi_manager;
|
||||||
@@ -644,6 +668,11 @@ static int __devexit vidi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
||||||
|
|
||||||
|
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
|
||||||
|
kfree(ctx->raw_edid);
|
||||||
|
ctx->raw_edid = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -63,7 +63,6 @@ struct hdmi_context {
|
|||||||
bool dvi_mode;
|
bool dvi_mode;
|
||||||
struct mutex hdmi_mutex;
|
struct mutex hdmi_mutex;
|
||||||
|
|
||||||
struct resource *regs_res;
|
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
unsigned int external_irq;
|
unsigned int external_irq;
|
||||||
unsigned int internal_irq;
|
unsigned int internal_irq;
|
||||||
@@ -2280,16 +2279,17 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
|
drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!drm_hdmi_ctx) {
|
if (!drm_hdmi_ctx) {
|
||||||
DRM_ERROR("failed to allocate common hdmi context.\n");
|
DRM_ERROR("failed to allocate common hdmi context.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
|
hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!hdata) {
|
if (!hdata) {
|
||||||
DRM_ERROR("out of memory\n");
|
DRM_ERROR("out of memory\n");
|
||||||
kfree(drm_hdmi_ctx);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2318,26 +2318,18 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
|
|||||||
goto err_resource;
|
goto err_resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdata->regs_res = request_mem_region(res->start, resource_size(res),
|
hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
|
||||||
dev_name(dev));
|
|
||||||
if (!hdata->regs_res) {
|
|
||||||
DRM_ERROR("failed to claim register region\n");
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto err_resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdata->regs = ioremap(res->start, resource_size(res));
|
|
||||||
if (!hdata->regs) {
|
if (!hdata->regs) {
|
||||||
DRM_ERROR("failed to map registers\n");
|
DRM_ERROR("failed to map registers\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto err_req_region;
|
goto err_resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DDC i2c driver */
|
/* DDC i2c driver */
|
||||||
if (i2c_add_driver(&ddc_driver)) {
|
if (i2c_add_driver(&ddc_driver)) {
|
||||||
DRM_ERROR("failed to register ddc i2c driver\n");
|
DRM_ERROR("failed to register ddc i2c driver\n");
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto err_iomap;
|
goto err_resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdata->ddc_port = hdmi_ddc;
|
hdata->ddc_port = hdmi_ddc;
|
||||||
@@ -2398,16 +2390,9 @@ err_hdmiphy:
|
|||||||
i2c_del_driver(&hdmiphy_driver);
|
i2c_del_driver(&hdmiphy_driver);
|
||||||
err_ddc:
|
err_ddc:
|
||||||
i2c_del_driver(&ddc_driver);
|
i2c_del_driver(&ddc_driver);
|
||||||
err_iomap:
|
|
||||||
iounmap(hdata->regs);
|
|
||||||
err_req_region:
|
|
||||||
release_mem_region(hdata->regs_res->start,
|
|
||||||
resource_size(hdata->regs_res));
|
|
||||||
err_resource:
|
err_resource:
|
||||||
hdmi_resources_cleanup(hdata);
|
hdmi_resources_cleanup(hdata);
|
||||||
err_data:
|
err_data:
|
||||||
kfree(hdata);
|
|
||||||
kfree(drm_hdmi_ctx);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2425,18 +2410,11 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
hdmi_resources_cleanup(hdata);
|
hdmi_resources_cleanup(hdata);
|
||||||
|
|
||||||
iounmap(hdata->regs);
|
|
||||||
|
|
||||||
release_mem_region(hdata->regs_res->start,
|
|
||||||
resource_size(hdata->regs_res));
|
|
||||||
|
|
||||||
/* hdmiphy i2c driver */
|
/* hdmiphy i2c driver */
|
||||||
i2c_del_driver(&hdmiphy_driver);
|
i2c_del_driver(&hdmiphy_driver);
|
||||||
/* DDC i2c driver */
|
/* DDC i2c driver */
|
||||||
i2c_del_driver(&ddc_driver);
|
i2c_del_driver(&ddc_driver);
|
||||||
|
|
||||||
kfree(hdata);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -956,7 +956,8 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
|
|||||||
|
|
||||||
clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
|
clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
|
||||||
|
|
||||||
mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
|
mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
|
||||||
|
resource_size(res));
|
||||||
if (mixer_res->mixer_regs == NULL) {
|
if (mixer_res->mixer_regs == NULL) {
|
||||||
dev_err(dev, "register mapping failed.\n");
|
dev_err(dev, "register mapping failed.\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
@@ -967,38 +968,34 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
|
|||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
dev_err(dev, "get memory resource failed.\n");
|
dev_err(dev, "get memory resource failed.\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto fail_mixer_regs;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer_res->vp_regs = ioremap(res->start, resource_size(res));
|
mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
|
||||||
|
resource_size(res));
|
||||||
if (mixer_res->vp_regs == NULL) {
|
if (mixer_res->vp_regs == NULL) {
|
||||||
dev_err(dev, "register mapping failed.\n");
|
dev_err(dev, "register mapping failed.\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto fail_mixer_regs;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
|
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
dev_err(dev, "get interrupt resource failed.\n");
|
dev_err(dev, "get interrupt resource failed.\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto fail_vp_regs;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
|
ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
|
||||||
|
0, "drm_mixer", ctx);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "request interrupt failed.\n");
|
dev_err(dev, "request interrupt failed.\n");
|
||||||
goto fail_vp_regs;
|
goto fail;
|
||||||
}
|
}
|
||||||
mixer_res->irq = res->start;
|
mixer_res->irq = res->start;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_vp_regs:
|
|
||||||
iounmap(mixer_res->vp_regs);
|
|
||||||
|
|
||||||
fail_mixer_regs:
|
|
||||||
iounmap(mixer_res->mixer_regs);
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
|
if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
|
||||||
clk_put(mixer_res->sclk_dac);
|
clk_put(mixer_res->sclk_dac);
|
||||||
@@ -1013,16 +1010,6 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mixer_resources_cleanup(struct mixer_context *ctx)
|
|
||||||
{
|
|
||||||
struct mixer_resources *res = &ctx->mixer_res;
|
|
||||||
|
|
||||||
free_irq(res->irq, ctx);
|
|
||||||
|
|
||||||
iounmap(res->vp_regs);
|
|
||||||
iounmap(res->mixer_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __devinit mixer_probe(struct platform_device *pdev)
|
static int __devinit mixer_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
@@ -1032,16 +1019,16 @@ static int __devinit mixer_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dev_info(dev, "probe start\n");
|
dev_info(dev, "probe start\n");
|
||||||
|
|
||||||
drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
|
drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!drm_hdmi_ctx) {
|
if (!drm_hdmi_ctx) {
|
||||||
DRM_ERROR("failed to allocate common hdmi context.\n");
|
DRM_ERROR("failed to allocate common hdmi context.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
DRM_ERROR("failed to alloc mixer context.\n");
|
DRM_ERROR("failed to alloc mixer context.\n");
|
||||||
kfree(drm_hdmi_ctx);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,17 +1059,10 @@ fail:
|
|||||||
|
|
||||||
static int mixer_remove(struct platform_device *pdev)
|
static int mixer_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
dev_info(&pdev->dev, "remove successful\n");
|
||||||
struct exynos_drm_hdmi_context *drm_hdmi_ctx =
|
|
||||||
platform_get_drvdata(pdev);
|
|
||||||
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
|
|
||||||
|
|
||||||
dev_info(dev, "remove successful\n");
|
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
mixer_resources_cleanup(ctx);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -107,11 +107,6 @@ struct drm_exynos_vidi_connection {
|
|||||||
uint64_t edid;
|
uint64_t edid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drm_exynos_plane_set_zpos {
|
|
||||||
__u32 plane_id;
|
|
||||||
__s32 zpos;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* memory type definitions. */
|
/* memory type definitions. */
|
||||||
enum e_drm_exynos_gem_mem_type {
|
enum e_drm_exynos_gem_mem_type {
|
||||||
/* Physically Continuous memory and used as default. */
|
/* Physically Continuous memory and used as default. */
|
||||||
@@ -164,7 +159,6 @@ struct drm_exynos_g2d_exec {
|
|||||||
#define DRM_EXYNOS_GEM_MMAP 0x02
|
#define DRM_EXYNOS_GEM_MMAP 0x02
|
||||||
/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
|
/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
|
||||||
#define DRM_EXYNOS_GEM_GET 0x04
|
#define DRM_EXYNOS_GEM_GET 0x04
|
||||||
#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06
|
|
||||||
#define DRM_EXYNOS_VIDI_CONNECTION 0x07
|
#define DRM_EXYNOS_VIDI_CONNECTION 0x07
|
||||||
|
|
||||||
/* G2D */
|
/* G2D */
|
||||||
@@ -184,9 +178,6 @@ struct drm_exynos_g2d_exec {
|
|||||||
#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
|
#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
|
||||||
DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info)
|
DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info)
|
||||||
|
|
||||||
#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \
|
|
||||||
DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
|
|
||||||
|
|
||||||
#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
|
#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
|
||||||
DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
|
DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user