Commit 3ff8e509 authored by Dave Airlie's avatar Dave Airlie

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

Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

Summary:
- Clean up HDMI and MIXER parts
- Clean up legacy structures specific to Exynos DRM
  . This patch series removes existing exyons_drm_display and
    exynos_drm_encoder structures specific to Exynos DRM, and
    makes them to replace with common drm_encoder structure.
    With cleanup patch, we removes exynos_drm_encoder module.
- Clean up gem, dmabuf and buffer modules
  . This patch series replaces existing Exynos DRM dmabuf codes
    with common drm prime ones, and embeds all codes of exynos_drm_buf
    into exynos_drm_gem module.
    With cleanup patch, we removes exynos_drm_buf and exynos_drm_dmabuf
    modules.
- And some fixups.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (53 commits)
  drm/exynos: merge exynos_drm_buf.c to exynos_drm_gem.c
  drm/exynos: use prime helpers
  drm/exynos: remove function roundup_gem_size
  drm/exynos: remove function update_vm_cache_attr
  drm/exynos: remove function check_gem_flags
  drm/exynos: use ERR_PTR instead of NULL in exynos_drm_gem_init
  drm/exynos: remove unused fields of struct exynos_drm_gem_buf
  drm/exynos: stop copying sg table
  drm/exynos: remove function exynos_drm_gem_map_buf
  drm/exynos: remove mutex locking in pagefault handler
  drm/exynos: remove function convert_to_vm_err_msg
  drm/exynos: stop using sgtable in page fault handler
  drm/exynos: remove struct exynos_drm_encoder layer
  drm/exynos: fold encoder setup into exynos_drm_load()
  drm/exynos: remove exynos_drm_create_enc_conn()
  drm/exynos: remove exynos_encoder's .commit() op
  drm/exynos: remove extra call to exynos_dp_commit()
  drm/exynos: remove extra call to hdmi_commit()
  drm/exynos: remove struct exynos_drm_display
  drm/exynos: simplify calculation of possible CRTCs
  ...
parents 3be66711 2a8cb489
...@@ -3,10 +3,9 @@ ...@@ -3,10 +3,9 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \ exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \
exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \ exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \ exynos_drm_plane.o
exynos_drm_plane.o exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
......
...@@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
#define OFFSIZE(x) (((x) & 0x3fff) << 14) #define OFFSIZE(x) (((x) & 0x3fff) << 14)
#define PAGEWIDTH(x) ((x) & 0x3fff) #define PAGEWIDTH(x) ((x) & 0x3fff)
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
struct drm_framebuffer *fb)
{ {
struct exynos_drm_plane *plane = &ctx->planes[win];
unsigned long val; unsigned long val;
val = readl(ctx->addr + DECON_WINCONx(win)); val = readl(ctx->addr + DECON_WINCONx(win));
val &= ~WINCONx_BPPMODE_MASK; val &= ~WINCONx_BPPMODE_MASK;
switch (plane->pixel_format) { switch (fb->pixel_format) {
case DRM_FORMAT_XRGB1555: case DRM_FORMAT_XRGB1555:
val |= WINCONx_BPPMODE_16BPP_I1555; val |= WINCONx_BPPMODE_16BPP_I1555;
val |= WINCONx_HAWSWP_F; val |= WINCONx_HAWSWP_F;
...@@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) ...@@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
return; return;
} }
DRM_DEBUG_KMS("bpp = %u\n", plane->bpp); DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel);
/* /*
* In case of exynos, setting dma-burst to 16Word causes permanent * In case of exynos, setting dma-burst to 16Word causes permanent
...@@ -196,7 +196,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) ...@@ -196,7 +196,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
* movement causes unstable DMA which results into iommu crash/tear. * movement causes unstable DMA which results into iommu crash/tear.
*/ */
if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK; val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_8WORD; val |= WINCONx_BURSTLEN_8WORD;
} }
...@@ -219,17 +219,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, ...@@ -219,17 +219,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
writel(val, ctx->addr + DECON_SHADOWCON); writel(val, ctx->addr + DECON_SHADOWCON);
} }
static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane; struct drm_plane_state *state = plane->base.state;
unsigned int win = plane->zpos;
unsigned int bpp = state->fb->bits_per_pixel >> 3;
unsigned int pitch = state->fb->pitches[0];
u32 val; u32 val;
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -238,8 +237,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -238,8 +237,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
writel(val, ctx->addr + DECON_VIDOSDxA(win)); writel(val, ctx->addr + DECON_VIDOSDxA(win));
val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) | val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) |
COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1); COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
writel(val, ctx->addr + DECON_VIDOSDxB(win)); writel(val, ctx->addr + DECON_VIDOSDxB(win));
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
...@@ -252,14 +251,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -252,14 +251,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win));
val = plane->dma_addr[0] + plane->pitch * plane->crtc_height; val = plane->dma_addr[0] + pitch * plane->crtc_h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3)) val = OFFSIZE(pitch - plane->crtc_w * bpp)
| PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3)); | PAGEWIDTH(plane->crtc_w * bpp);
writel(val, ctx->addr + DECON_VIDW0xADD2(win)); writel(val, ctx->addr + DECON_VIDW0xADD2(win));
decon_win_set_pixfmt(ctx, win); decon_win_set_pixfmt(ctx, win, state->fb);
/* window enable */ /* window enable */
val = readl(ctx->addr + DECON_WINCONx(win)); val = readl(ctx->addr + DECON_WINCONx(win));
...@@ -277,17 +276,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -277,17 +276,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
atomic_set(&ctx->win_updated, 1); atomic_set(&ctx->win_updated, 1);
} }
static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) static void decon_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane; unsigned int win = plane->zpos;
u32 val; u32 val;
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -378,7 +373,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -378,7 +373,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
* a destroyed buffer later. * a destroyed buffer later.
*/ */
for (i = 0; i < WINDOWS_NR; i++) for (i = 0; i < WINDOWS_NR; i++)
decon_win_disable(crtc, i); decon_disable_plane(crtc, &ctx->planes[i]);
decon_swreset(ctx); decon_swreset(ctx);
...@@ -407,7 +402,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc) ...@@ -407,7 +402,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
writel(val, ctx->addr + DECON_TRIGCON); writel(val, ctx->addr + DECON_TRIGCON);
} }
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
} }
static void decon_clear_channels(struct exynos_drm_crtc *crtc) static void decon_clear_channels(struct exynos_drm_crtc *crtc)
...@@ -460,10 +455,9 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { ...@@ -460,10 +455,9 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.commit = decon_commit, .commit = decon_commit,
.win_commit = decon_win_commit, .update_plane = decon_update_plane,
.win_disable = decon_win_disable, .disable_plane = decon_disable_plane,
.te_handler = decon_te_irq_handler, .te_handler = decon_te_irq_handler,
.clear_channels = decon_clear_channels,
}; };
static int decon_bind(struct device *dev, struct device *master, void *data) static int decon_bind(struct device *dev, struct device *master, void *data)
...@@ -497,7 +491,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -497,7 +491,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
goto err; goto err;
} }
ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); decon_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, dev);
if (ret) if (ret)
goto err; goto err;
...@@ -514,8 +510,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data) ...@@ -514,8 +510,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
decon_disable(ctx->crtc); decon_disable(ctx->crtc);
/* detach this sub driver from iommu mapping if supported. */ /* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev)) drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
} }
static const struct component_ops decon_component_ops = { static const struct component_ops decon_component_ops = {
...@@ -533,7 +528,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) ...@@ -533,7 +528,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
val = readl(ctx->addr + DECON_VIDINTCON1); val = readl(ctx->addr + DECON_VIDINTCON1);
if (val & VIDINTCON1_INTFRMPEND) { if (val & VIDINTCON1_INTFRMPEND) {
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
/* clear */ /* clear */
writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
...@@ -553,7 +548,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) ...@@ -553,7 +548,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
val = readl(ctx->addr + DECON_VIDINTCON1); val = readl(ctx->addr + DECON_VIDINTCON1);
if (val & VIDINTCON1_INTFRMDONEPEND) { if (val & VIDINTCON1_INTFRMDONEPEND) {
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); exynos_drm_crtc_finish_pageflip(ctx->crtc);
/* clear */ /* clear */
writel(VIDINTCON1_INTFRMDONEPEND, writel(VIDINTCON1_INTFRMDONEPEND,
......
...@@ -61,7 +61,7 @@ struct decon_context { ...@@ -61,7 +61,7 @@ struct decon_context {
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
struct exynos_drm_panel_info panel; struct exynos_drm_panel_info panel;
struct exynos_drm_display *display; struct drm_encoder *encoder;
}; };
static const struct of_device_id decon_driver_dt_match[] = { static const struct of_device_id decon_driver_dt_match[] = {
...@@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx, ...@@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx,
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++; ctx->pipe = priv->pipe++;
ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); decon_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, ctx->dev);
if (ret) if (ret)
priv->pipe--; priv->pipe--;
...@@ -136,8 +138,7 @@ static int decon_ctx_initialize(struct decon_context *ctx, ...@@ -136,8 +138,7 @@ static int decon_ctx_initialize(struct decon_context *ctx,
static void decon_ctx_remove(struct decon_context *ctx) static void decon_ctx_remove(struct decon_context *ctx)
{ {
/* detach this sub driver from iommu mapping if supported. */ /* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev)) drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
} }
static u32 decon_calc_clkdiv(struct decon_context *ctx, static u32 decon_calc_clkdiv(struct decon_context *ctx,
...@@ -271,16 +272,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) ...@@ -271,16 +272,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
} }
} }
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
struct drm_framebuffer *fb)
{ {
struct exynos_drm_plane *plane = &ctx->planes[win];
unsigned long val; unsigned long val;
int padding; int padding;
val = readl(ctx->regs + WINCON(win)); val = readl(ctx->regs + WINCON(win));
val &= ~WINCONx_BPPMODE_MASK; val &= ~WINCONx_BPPMODE_MASK;
switch (plane->pixel_format) { switch (fb->pixel_format) {
case DRM_FORMAT_RGB565: case DRM_FORMAT_RGB565:
val |= WINCONx_BPPMODE_16BPP_565; val |= WINCONx_BPPMODE_16BPP_565;
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
...@@ -329,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) ...@@ -329,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
break; break;
} }
DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
/* /*
* In case of exynos, setting dma-burst to 16Word causes permanent * In case of exynos, setting dma-burst to 16Word causes permanent
...@@ -339,8 +340,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) ...@@ -339,8 +340,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
* movement causes unstable DMA which results into iommu crash/tear. * movement causes unstable DMA which results into iommu crash/tear.
*/ */
padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width;
if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK; val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_8WORD; val |= WINCONx_BURSTLEN_8WORD;
} }
...@@ -382,23 +383,19 @@ static void decon_shadow_protect_win(struct decon_context *ctx, ...@@ -382,23 +383,19 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
writel(val, ctx->regs + SHADOWCON); writel(val, ctx->regs + SHADOWCON);
} }
static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
struct exynos_drm_plane *plane; struct drm_plane_state *state = plane->base.state;
int padding; int padding;
unsigned long val, alpha; unsigned long val, alpha;
unsigned int last_x; unsigned int last_x;
unsigned int last_y; unsigned int last_y;
unsigned int win = plane->zpos;
if (ctx->suspended) unsigned int bpp = state->fb->bits_per_pixel >> 3;
return; unsigned int pitch = state->fb->pitches[0];
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -420,11 +417,11 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -420,11 +417,11 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
val = (unsigned long)plane->dma_addr[0]; val = (unsigned long)plane->dma_addr[0];
writel(val, ctx->regs + VIDW_BUF_START(win)); writel(val, ctx->regs + VIDW_BUF_START(win));
padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; padding = (pitch / bpp) - state->fb->width;
/* buffer size */ /* buffer size */
writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win)); writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win)); writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win));
/* offset from the start of the buffer to read */ /* offset from the start of the buffer to read */
writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win)); writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
...@@ -433,25 +430,25 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -433,25 +430,25 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
DRM_DEBUG_KMS("start addr = 0x%lx\n", DRM_DEBUG_KMS("start addr = 0x%lx\n",
(unsigned long)val); (unsigned long)val);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
plane->crtc_width, plane->crtc_height); plane->crtc_w, plane->crtc_h);
/* /*
* OSD position. * OSD position.
* In case the window layout goes of LCD layout, DECON fails. * In case the window layout goes of LCD layout, DECON fails.
*/ */
if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay) if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay)
plane->crtc_x = mode->hdisplay - plane->crtc_width; plane->crtc_x = mode->hdisplay - plane->crtc_w;
if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay) if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay)
plane->crtc_y = mode->vdisplay - plane->crtc_height; plane->crtc_y = mode->vdisplay - plane->crtc_h;
val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
VIDOSDxA_TOPLEFT_Y(plane->crtc_y); VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
writel(val, ctx->regs + VIDOSD_A(win)); writel(val, ctx->regs + VIDOSD_A(win));
last_x = plane->crtc_x + plane->crtc_width; last_x = plane->crtc_x + plane->crtc_w;
if (last_x) if (last_x)
last_x--; last_x--;
last_y = plane->crtc_y + plane->crtc_height; last_y = plane->crtc_y + plane->crtc_h;
if (last_y) if (last_y)
last_y--; last_y--;
...@@ -475,7 +472,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -475,7 +472,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
writel(alpha, ctx->regs + VIDOSD_D(win)); writel(alpha, ctx->regs + VIDOSD_D(win));
decon_win_set_pixfmt(ctx, win); decon_win_set_pixfmt(ctx, win, state->fb);
/* hardware window 0 doesn't support color key. */ /* hardware window 0 doesn't support color key. */
if (win != 0) if (win != 0)
...@@ -495,17 +492,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -495,17 +492,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
writel(val, ctx->regs + DECON_UPDATE); writel(val, ctx->regs + DECON_UPDATE);
} }
static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) static void decon_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane; unsigned int win = plane->zpos;
u32 val; u32 val;
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -601,7 +594,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -601,7 +594,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
* a destroyed buffer later. * a destroyed buffer later.
*/ */
for (i = 0; i < WINDOWS_NR; i++) for (i = 0; i < WINDOWS_NR; i++)
decon_win_disable(crtc, i); decon_disable_plane(crtc, &ctx->planes[i]);
clk_disable_unprepare(ctx->vclk); clk_disable_unprepare(ctx->vclk);
clk_disable_unprepare(ctx->eclk); clk_disable_unprepare(ctx->eclk);
...@@ -621,9 +614,8 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { ...@@ -621,9 +614,8 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.wait_for_vblank = decon_wait_for_vblank, .wait_for_vblank = decon_wait_for_vblank,
.win_commit = decon_win_commit, .update_plane = decon_update_plane,
.win_disable = decon_win_disable, .disable_plane = decon_disable_plane,
.clear_channels = decon_clear_channels,
}; };
...@@ -643,8 +635,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) ...@@ -643,8 +635,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
goto out; goto out;
if (!ctx->i80_if) { if (!ctx->i80_if) {
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); exynos_drm_crtc_finish_pageflip(ctx->crtc);
/* set wait vsync event to zero and wake up queue. */ /* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) { if (atomic_read(&ctx->wait_vsync_event)) {
...@@ -689,8 +681,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -689,8 +681,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
} }
if (ctx->display) if (ctx->encoder)
exynos_drm_create_enc_conn(drm_dev, ctx->display); exynos_dpi_bind(drm_dev, ctx->encoder);
return 0; return 0;
...@@ -703,8 +695,8 @@ static void decon_unbind(struct device *dev, struct device *master, ...@@ -703,8 +695,8 @@ static void decon_unbind(struct device *dev, struct device *master,
decon_disable(ctx->crtc); decon_disable(ctx->crtc);
if (ctx->display) if (ctx->encoder)
exynos_dpi_remove(ctx->display); exynos_dpi_remove(ctx->encoder);
decon_ctx_remove(ctx); decon_ctx_remove(ctx);
} }
...@@ -789,9 +781,9 @@ static int decon_probe(struct platform_device *pdev) ...@@ -789,9 +781,9 @@ static int decon_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
ctx->display = exynos_dpi_probe(dev); ctx->encoder = exynos_dpi_probe(dev);
if (IS_ERR(ctx->display)) { if (IS_ERR(ctx->encoder)) {
ret = PTR_ERR(ctx->display); ret = PTR_ERR(ctx->encoder);
goto err_iounmap; goto err_iounmap;
} }
......
...@@ -32,19 +32,20 @@ ...@@ -32,19 +32,20 @@
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include "exynos_dp_core.h" #include "exynos_dp_core.h"
#include "exynos_drm_crtc.h"
#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \
connector) connector)
static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp)
{ {
return to_exynos_crtc(dp->encoder->crtc); return to_exynos_crtc(dp->encoder.crtc);
} }
static inline struct exynos_dp_device * static inline struct exynos_dp_device *encoder_to_dp(
display_to_dp(struct exynos_drm_display *d) struct drm_encoder *e)
{ {
return container_of(d, struct exynos_dp_device, display); return container_of(e, struct exynos_dp_device, encoder);
} }
struct bridge_init { struct bridge_init {
...@@ -795,9 +796,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp) ...@@ -795,9 +796,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp)
/* Configure video slave mode */ /* Configure video slave mode */
exynos_dp_enable_video_master(dp, 0); exynos_dp_enable_video_master(dp, 0);
/* Enable video */
exynos_dp_start_video(dp);
timeout_loop = 0; timeout_loop = 0;
for (;;) { for (;;) {
...@@ -891,9 +889,9 @@ static void exynos_dp_hotplug(struct work_struct *work) ...@@ -891,9 +889,9 @@ static void exynos_dp_hotplug(struct work_struct *work)
drm_helper_hpd_irq_event(dp->drm_dev); drm_helper_hpd_irq_event(dp->drm_dev);
} }
static void exynos_dp_commit(struct exynos_drm_display *display) static void exynos_dp_commit(struct drm_encoder *encoder)
{ {
struct exynos_dp_device *dp = display_to_dp(display); struct exynos_dp_device *dp = encoder_to_dp(encoder);
int ret; int ret;
/* Keep the panel disabled while we configure video */ /* Keep the panel disabled while we configure video */
...@@ -938,6 +936,9 @@ static void exynos_dp_commit(struct exynos_drm_display *display) ...@@ -938,6 +936,9 @@ static void exynos_dp_commit(struct exynos_drm_display *display)
if (drm_panel_enable(dp->panel)) if (drm_panel_enable(dp->panel))
DRM_ERROR("failed to enable the panel\n"); DRM_ERROR("failed to enable the panel\n");
} }
/* Enable video */
exynos_dp_start_video(dp);
} }
static enum drm_connector_status exynos_dp_detect( static enum drm_connector_status exynos_dp_detect(
...@@ -994,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder( ...@@ -994,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder(
{ {
struct exynos_dp_device *dp = ctx_from_connector(connector); struct exynos_dp_device *dp = ctx_from_connector(connector);
return dp->encoder; return &dp->encoder;
} }
static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
...@@ -1019,15 +1020,12 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, ...@@ -1019,15 +1020,12 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
return 0; return 0;
} }
static int exynos_dp_create_connector(struct exynos_drm_display *display, static int exynos_dp_create_connector(struct drm_encoder *encoder)
struct drm_encoder *encoder)
{ {
struct exynos_dp_device *dp = display_to_dp(display); struct exynos_dp_device *dp = encoder_to_dp(encoder);
struct drm_connector *connector = &dp->connector; struct drm_connector *connector = &dp->connector;
int ret; int ret;
dp->encoder = encoder;
/* Pre-empt DP connector creation if there's a bridge */ /* Pre-empt DP connector creation if there's a bridge */
if (dp->bridge) { if (dp->bridge) {
ret = exynos_drm_attach_lcd_bridge(dp, encoder); ret = exynos_drm_attach_lcd_bridge(dp, encoder);
...@@ -1054,20 +1052,22 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, ...@@ -1054,20 +1052,22 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
return ret; return ret;
} }
static void exynos_dp_phy_init(struct exynos_dp_device *dp) static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{ {
if (dp->phy) return true;
phy_power_on(dp->phy);
} }
static void exynos_dp_phy_exit(struct exynos_dp_device *dp) static void exynos_dp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{ {
if (dp->phy)
phy_power_off(dp->phy);
} }
static void exynos_dp_poweron(struct exynos_dp_device *dp) static void exynos_dp_enable(struct drm_encoder *encoder)
{ {
struct exynos_dp_device *dp = encoder_to_dp(encoder);
struct exynos_drm_crtc *crtc = dp_to_crtc(dp); struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode == DRM_MODE_DPMS_ON) if (dp->dpms_mode == DRM_MODE_DPMS_ON)
...@@ -1084,14 +1084,17 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) ...@@ -1084,14 +1084,17 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
crtc->ops->clock_enable(dp_to_crtc(dp), true); crtc->ops->clock_enable(dp_to_crtc(dp), true);
clk_prepare_enable(dp->clock); clk_prepare_enable(dp->clock);
exynos_dp_phy_init(dp); phy_power_on(dp->phy);
exynos_dp_init_dp(dp); exynos_dp_init_dp(dp);
enable_irq(dp->irq); enable_irq(dp->irq);
exynos_dp_commit(&dp->display); exynos_dp_commit(&dp->encoder);
dp->dpms_mode = DRM_MODE_DPMS_ON;
} }
static void exynos_dp_poweroff(struct exynos_dp_device *dp) static void exynos_dp_disable(struct drm_encoder *encoder)
{ {
struct exynos_dp_device *dp = encoder_to_dp(encoder);
struct exynos_drm_crtc *crtc = dp_to_crtc(dp); struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode != DRM_MODE_DPMS_ON) if (dp->dpms_mode != DRM_MODE_DPMS_ON)
...@@ -1106,7 +1109,7 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) ...@@ -1106,7 +1109,7 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
disable_irq(dp->irq); disable_irq(dp->irq);
flush_work(&dp->hotplug_work); flush_work(&dp->hotplug_work);
exynos_dp_phy_exit(dp); phy_power_off(dp->phy);
clk_disable_unprepare(dp->clock); clk_disable_unprepare(dp->clock);
if (crtc->ops->clock_enable) if (crtc->ops->clock_enable)
...@@ -1116,31 +1119,19 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) ...@@ -1116,31 +1119,19 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
if (drm_panel_unprepare(dp->panel)) if (drm_panel_unprepare(dp->panel))
DRM_ERROR("failed to turnoff the panel\n"); DRM_ERROR("failed to turnoff the panel\n");
} }
}
static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
{
struct exynos_dp_device *dp = display_to_dp(display);
switch (mode) { dp->dpms_mode = DRM_MODE_DPMS_OFF;
case DRM_MODE_DPMS_ON:
exynos_dp_poweron(dp);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
exynos_dp_poweroff(dp);
break;
default:
break;
}
dp->dpms_mode = mode;
} }
static struct exynos_drm_display_ops exynos_dp_display_ops = { static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
.create_connector = exynos_dp_create_connector, .mode_fixup = exynos_dp_mode_fixup,
.dpms = exynos_dp_dpms, .mode_set = exynos_dp_mode_set,
.commit = exynos_dp_commit, .enable = exynos_dp_enable,
.disable = exynos_dp_disable,
};
static struct drm_encoder_funcs exynos_dp_encoder_funcs = {
.destroy = drm_encoder_cleanup,
}; };
static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
...@@ -1219,9 +1210,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) ...@@ -1219,9 +1210,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
struct exynos_dp_device *dp = dev_get_drvdata(dev); struct exynos_dp_device *dp = dev_get_drvdata(dev);
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct drm_encoder *encoder = &dp->encoder;
struct resource *res; struct resource *res;
unsigned int irq_flags; unsigned int irq_flags;
int ret = 0; int pipe, ret = 0;
dp->dev = &pdev->dev; dp->dev = &pdev->dev;
dp->dpms_mode = DRM_MODE_DPMS_OFF; dp->dpms_mode = DRM_MODE_DPMS_OFF;
...@@ -1297,7 +1289,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) ...@@ -1297,7 +1289,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
exynos_dp_phy_init(dp); phy_power_on(dp->phy);
exynos_dp_init_dp(dp); exynos_dp_init_dp(dp);
...@@ -1311,7 +1303,28 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) ...@@ -1311,7 +1303,28 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
dp->drm_dev = drm_dev; dp->drm_dev = drm_dev;
return exynos_drm_create_enc_conn(drm_dev, &dp->display); pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_LCD);
if (pipe < 0)
return pipe;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
ret = exynos_dp_create_connector(encoder);
if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret);
drm_encoder_cleanup(encoder);
return ret;
}
return 0;
} }
static void exynos_dp_unbind(struct device *dev, struct device *master, static void exynos_dp_unbind(struct device *dev, struct device *master,
...@@ -1319,7 +1332,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master, ...@@ -1319,7 +1332,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
{ {
struct exynos_dp_device *dp = dev_get_drvdata(dev); struct exynos_dp_device *dp = dev_get_drvdata(dev);
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); exynos_dp_disable(&dp->encoder);
} }
static const struct component_ops exynos_dp_ops = { static const struct component_ops exynos_dp_ops = {
...@@ -1338,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev) ...@@ -1338,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
if (!dp) if (!dp)
return -ENOMEM; return -ENOMEM;
dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
dp->display.ops = &exynos_dp_display_ops;
platform_set_drvdata(pdev, dp); platform_set_drvdata(pdev, dp);
panel_node = of_parse_phandle(dev->of_node, "panel", 0); panel_node = of_parse_phandle(dev->of_node, "panel", 0);
...@@ -1377,7 +1388,7 @@ static int exynos_dp_suspend(struct device *dev) ...@@ -1377,7 +1388,7 @@ static int exynos_dp_suspend(struct device *dev)
{ {
struct exynos_dp_device *dp = dev_get_drvdata(dev); struct exynos_dp_device *dp = dev_get_drvdata(dev);
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); exynos_dp_disable(&dp->encoder);
return 0; return 0;
} }
...@@ -1385,7 +1396,7 @@ static int exynos_dp_resume(struct device *dev) ...@@ -1385,7 +1396,7 @@ static int exynos_dp_resume(struct device *dev)
{ {
struct exynos_dp_device *dp = dev_get_drvdata(dev); struct exynos_dp_device *dp = dev_get_drvdata(dev);
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON); exynos_dp_enable(&dp->encoder);
return 0; return 0;
} }
#endif #endif
......
...@@ -147,11 +147,10 @@ struct link_train { ...@@ -147,11 +147,10 @@ struct link_train {
}; };
struct exynos_dp_device { struct exynos_dp_device {
struct exynos_drm_display display; struct drm_encoder encoder;
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder *encoder;
struct drm_panel *panel; struct drm_panel *panel;
struct drm_bridge *bridge; struct drm_bridge *bridge;
struct clk *clock; struct clk *clock;
......
/* exynos_drm_buf.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#include "exynos_drm_iommu.h"
static int lowlevel_buffer_allocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
int ret = 0;
enum dma_attr attr;
unsigned int nr_pages;
if (buf->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
}
init_dma_attrs(&buf->dma_attrs);
/*
* if EXYNOS_BO_CONTIG, fully physically contiguous memory
* region will be allocated else physically contiguous
* as possible.
*/
if (!(flags & EXYNOS_BO_NONCONTIG))
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
/*
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
* else cachable mapping.
*/
if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE))
attr = DMA_ATTR_WRITE_COMBINE;
else
attr = DMA_ATTR_NON_CONSISTENT;
dma_set_attr(attr, &buf->dma_attrs);
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
nr_pages = buf->size >> PAGE_SHIFT;
if (!is_drm_iommu_supported(dev)) {
dma_addr_t start_addr;
unsigned int i = 0;
buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
if (!buf->pages) {
DRM_ERROR("failed to allocate pages.\n");
return -ENOMEM;
}
buf->cookie = dma_alloc_attrs(dev->dev,
buf->size,
&buf->dma_addr, GFP_KERNEL,
&buf->dma_attrs);
if (!buf->cookie) {
DRM_ERROR("failed to allocate buffer.\n");
ret = -ENOMEM;
goto err_free;
}
start_addr = buf->dma_addr;
while (i < nr_pages) {
buf->pages[i] = phys_to_page(start_addr);
start_addr += PAGE_SIZE;
i++;
}
} else {
buf->pages = dma_alloc_attrs(dev->dev, buf->size,
&buf->dma_addr, GFP_KERNEL,
&buf->dma_attrs);
if (!buf->pages) {
DRM_ERROR("failed to allocate buffer.\n");
return -ENOMEM;
}
}
buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
if (IS_ERR(buf->sgt)) {
DRM_ERROR("failed to get sg table.\n");
ret = PTR_ERR(buf->sgt);
goto err_free_attrs;
}
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)buf->dma_addr,
buf->size);
return ret;
err_free_attrs:
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
err_free:
if (!is_drm_iommu_supported(dev))
drm_free_large(buf->pages);
return ret;
}
static void lowlevel_buffer_deallocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
if (!buf->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
}
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)buf->dma_addr,
buf->size);
sg_free_table(buf->sgt);
kfree(buf->sgt);
buf->sgt = NULL;
if (!is_drm_iommu_supported(dev)) {
dma_free_attrs(dev->dev, buf->size, buf->cookie,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
drm_free_large(buf->pages);
} else
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
}
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
unsigned int size)
{
struct exynos_drm_gem_buf *buffer;
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return NULL;
buffer->size = size;
return buffer;
}
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer)
{
kfree(buffer);
buffer = NULL;
}
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf, unsigned int flags)
{
/*
* allocate memory region and set the memory information
* to vaddr and dma_addr of a buffer object.
*/
if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
return -ENOMEM;
return 0;
}
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buffer)
{
lowlevel_buffer_deallocate(dev, flags, buffer);
}
/* exynos_drm_buf.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_BUF_H_
#define _EXYNOS_DRM_BUF_H_
/* create and initialize buffer object. */
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
unsigned int size);
/* destroy buffer object. */
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer);
/* allocate physical memory region and setup sgt. */
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf,
unsigned int flags);
/* release physical memory region, and sgt. */
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags,
struct exynos_drm_gem_buf *buffer);
#endif
...@@ -15,46 +15,10 @@ ...@@ -15,46 +15,10 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_fbdev.h" #include "exynos_drm_fbdev.h"
static LIST_HEAD(exynos_drm_subdrv_list); static LIST_HEAD(exynos_drm_subdrv_list);
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display)
{
struct drm_encoder *encoder;
int ret;
unsigned long possible_crtcs = 0;
ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
if (ret < 0)
return ret;
possible_crtcs |= 1 << ret;
/* create and initialize a encoder for this sub driver. */
encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
if (!encoder) {
DRM_ERROR("failed to create encoder\n");
return -EFAULT;
}
display->encoder = encoder;
ret = display->ops->create_connector(display, encoder);
if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret);
goto err_destroy_encoder;
}
return 0;
err_destroy_encoder:
encoder->funcs->destroy(encoder);
return ret;
}
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{ {
if (!subdrv) if (!subdrv)
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
static void exynos_drm_crtc_enable(struct drm_crtc *crtc) static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
...@@ -177,7 +176,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) ...@@ -177,7 +176,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
return -EPERM; return -EPERM;
if (exynos_crtc->ops->enable_vblank) if (exynos_crtc->ops->enable_vblank)
exynos_crtc->ops->enable_vblank(exynos_crtc); return exynos_crtc->ops->enable_vblank(exynos_crtc);
return 0; return 0;
} }
...@@ -195,24 +194,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) ...@@ -195,24 +194,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
exynos_crtc->ops->disable_vblank(exynos_crtc); exynos_crtc->ops->disable_vblank(exynos_crtc);
} }
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc)
{ {
struct exynos_drm_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = &exynos_crtc->base;
struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&crtc->dev->event_lock, flags);
if (exynos_crtc->event) { if (exynos_crtc->event) {
drm_send_vblank_event(dev, -1, exynos_crtc->event); drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
drm_vblank_put(dev, pipe); drm_crtc_vblank_put(crtc);
wake_up(&exynos_crtc->pending_flip_queue); wake_up(&exynos_crtc->pending_flip_queue);
} }
exynos_crtc->event = NULL; exynos_crtc->event = NULL;
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
} }
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
...@@ -239,7 +236,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) ...@@ -239,7 +236,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
} }
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
unsigned int out_type) enum exynos_drm_output_type out_type)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
......
...@@ -25,12 +25,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, ...@@ -25,12 +25,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
void *context); void *context);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
/* This function gets pipe value to crtc device matched with out_type. */ /* This function gets pipe value to crtc device matched with out_type. */
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
unsigned int out_type); enum exynos_drm_output_type out_type);
/* /*
* This function calls the crtc device(manager)'s te_handler() callback * This function calls the crtc device(manager)'s te_handler() callback
......
/* exynos_drm_dmabuf.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_dmabuf.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include <linux/dma-buf.h>
struct exynos_drm_dmabuf_attachment {
struct sg_table sgt;
enum dma_data_direction dir;
bool is_mapped;
};
static struct exynos_drm_gem_obj *dma_buf_to_obj(struct dma_buf *buf)
{
return to_exynos_gem_obj(buf->priv);
}
static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf,
struct device *dev,
struct dma_buf_attachment *attach)
{
struct exynos_drm_dmabuf_attachment *exynos_attach;
exynos_attach = kzalloc(sizeof(*exynos_attach), GFP_KERNEL);
if (!exynos_attach)
return -ENOMEM;
exynos_attach->dir = DMA_NONE;
attach->priv = exynos_attach;
return 0;
}
static void exynos_gem_detach_dma_buf(struct dma_buf *dmabuf,
struct dma_buf_attachment *attach)
{
struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
struct sg_table *sgt;
if (!exynos_attach)
return;
sgt = &exynos_attach->sgt;
if (exynos_attach->dir != DMA_NONE)
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
exynos_attach->dir);
sg_free_table(sgt);
kfree(exynos_attach);
attach->priv = NULL;
}
static struct sg_table *
exynos_gem_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
{
struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
struct exynos_drm_gem_obj *gem_obj = dma_buf_to_obj(attach->dmabuf);
struct drm_device *dev = gem_obj->base.dev;
struct exynos_drm_gem_buf *buf;
struct scatterlist *rd, *wr;
struct sg_table *sgt = NULL;
unsigned int i;
int nents, ret;
/* just return current sgt if already requested. */
if (exynos_attach->dir == dir && exynos_attach->is_mapped)
return &exynos_attach->sgt;
buf = gem_obj->buffer;
if (!buf) {
DRM_ERROR("buffer is null.\n");
return ERR_PTR(-ENOMEM);
}
sgt = &exynos_attach->sgt;
ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
if (ret) {
DRM_ERROR("failed to alloc sgt.\n");
return ERR_PTR(-ENOMEM);
}
mutex_lock(&dev->struct_mutex);
rd = buf->sgt->sgl;
wr = sgt->sgl;
for (i = 0; i < sgt->orig_nents; ++i) {
sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
rd = sg_next(rd);
wr = sg_next(wr);
}
if (dir != DMA_NONE) {
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
if (!nents) {
DRM_ERROR("failed to map sgl with iommu.\n");
sg_free_table(sgt);
sgt = ERR_PTR(-EIO);
goto err_unlock;
}
}
exynos_attach->is_mapped = true;
exynos_attach->dir = dir;
attach->priv = exynos_attach;
DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
err_unlock:
mutex_unlock(&dev->struct_mutex);
return sgt;
}
static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
struct sg_table *sgt,
enum dma_data_direction dir)
{
/* Nothing to do. */
}
static void *exynos_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
unsigned long page_num)
{
/* TODO */
return NULL;
}
static void exynos_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
unsigned long page_num,
void *addr)
{
/* TODO */
}
static void *exynos_gem_dmabuf_kmap(struct dma_buf *dma_buf,
unsigned long page_num)
{
/* TODO */
return NULL;
}
static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
unsigned long page_num, void *addr)
{
/* TODO */
}
static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf,
struct vm_area_struct *vma)
{
return -ENOTTY;
}
static struct dma_buf_ops exynos_dmabuf_ops = {
.attach = exynos_gem_attach_dma_buf,
.detach = exynos_gem_detach_dma_buf,
.map_dma_buf = exynos_gem_map_dma_buf,
.unmap_dma_buf = exynos_gem_unmap_dma_buf,
.kmap = exynos_gem_dmabuf_kmap,
.kmap_atomic = exynos_gem_dmabuf_kmap_atomic,
.kunmap = exynos_gem_dmabuf_kunmap,
.kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic,
.mmap = exynos_gem_dmabuf_mmap,
.release = drm_gem_dmabuf_release,
};
struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
struct drm_gem_object *obj, int flags)
{
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.ops = &exynos_dmabuf_ops;
exp_info.size = exynos_gem_obj->base.size;
exp_info.flags = flags;
exp_info.priv = obj;
return dma_buf_export(&exp_info);
}
struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct dma_buf *dma_buf)
{
struct dma_buf_attachment *attach;
struct sg_table *sgt;
struct scatterlist *sgl;
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buffer;
int ret;
/* is this one of own objects? */
if (dma_buf->ops == &exynos_dmabuf_ops) {
struct drm_gem_object *obj;
obj = dma_buf->priv;
/* is it from our device? */
if (obj->dev == drm_dev) {
/*
* Importing dmabuf exported from out own gem increases
* refcount on gem itself instead of f_count of dmabuf.
*/
drm_gem_object_reference(obj);
return obj;
}
}
attach = dma_buf_attach(dma_buf, drm_dev->dev);
if (IS_ERR(attach))
return ERR_PTR(-EINVAL);
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto err_buf_detach;
}
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto err_unmap_attach;
}
exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size);
if (!exynos_gem_obj) {
ret = -ENOMEM;
goto err_free_buffer;
}
sgl = sgt->sgl;
buffer->size = dma_buf->size;
buffer->dma_addr = sg_dma_address(sgl);
if (sgt->nents == 1) {
/* always physically continuous memory if sgt->nents is 1. */
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
} else {
/*
* this case could be CONTIG or NONCONTIG type but for now
* sets NONCONTIG.
* TODO. we have to find a way that exporter can notify
* the type of its own buffer to importer.
*/
exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
}
exynos_gem_obj->buffer = buffer;
buffer->sgt = sgt;
exynos_gem_obj->base.import_attach = attach;
DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,
buffer->size);
return &exynos_gem_obj->base;
err_free_buffer:
kfree(buffer);
buffer = NULL;
err_unmap_attach:
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
err_buf_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
return ERR_PTR(ret);
}
/* exynos_drm_dmabuf.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_DMABUF_H_
#define _EXYNOS_DRM_DMABUF_H_
struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
struct drm_gem_object *obj, int flags);
struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct dma_buf *dma_buf);
#endif
...@@ -20,26 +20,24 @@ ...@@ -20,26 +20,24 @@
#include <video/of_videomode.h> #include <video/of_videomode.h>
#include <video/videomode.h> #include <video/videomode.h>
#include "exynos_drm_drv.h" #include "exynos_drm_crtc.h"
struct exynos_dpi { struct exynos_dpi {
struct exynos_drm_display display; struct drm_encoder encoder;
struct device *dev; struct device *dev;
struct device_node *panel_node; struct device_node *panel_node;
struct drm_panel *panel; struct drm_panel *panel;
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder *encoder;
struct videomode *vm; struct videomode *vm;
int dpms_mode;
}; };
#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d) static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
{ {
return container_of(d, struct exynos_dpi, display); return container_of(e, struct exynos_dpi, encoder);
} }
static enum drm_connector_status static enum drm_connector_status
...@@ -99,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector) ...@@ -99,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector)
{ {
struct exynos_dpi *ctx = connector_to_dpi(connector); struct exynos_dpi *ctx = connector_to_dpi(connector);
return ctx->encoder; return &ctx->encoder;
} }
static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
...@@ -107,15 +105,12 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { ...@@ -107,15 +105,12 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
.best_encoder = exynos_dpi_best_encoder, .best_encoder = exynos_dpi_best_encoder,
}; };
static int exynos_dpi_create_connector(struct exynos_drm_display *display, static int exynos_dpi_create_connector(struct drm_encoder *encoder)
struct drm_encoder *encoder)
{ {
struct exynos_dpi *ctx = display_to_dpi(display); struct exynos_dpi *ctx = encoder_to_dpi(encoder);
struct drm_connector *connector = &ctx->connector; struct drm_connector *connector = &ctx->connector;
int ret; int ret;
ctx->encoder = encoder;
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(encoder->dev, connector, ret = drm_connector_init(encoder->dev, connector,
...@@ -133,46 +128,48 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, ...@@ -133,46 +128,48 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display,
return 0; return 0;
} }
static void exynos_dpi_poweron(struct exynos_dpi *ctx) static bool exynos_dpi_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_dpi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{ {
}
static void exynos_dpi_enable(struct drm_encoder *encoder)
{
struct exynos_dpi *ctx = encoder_to_dpi(encoder);
if (ctx->panel) { if (ctx->panel) {
drm_panel_prepare(ctx->panel); drm_panel_prepare(ctx->panel);
drm_panel_enable(ctx->panel); drm_panel_enable(ctx->panel);
} }
} }
static void exynos_dpi_poweroff(struct exynos_dpi *ctx) static void exynos_dpi_disable(struct drm_encoder *encoder)
{ {
struct exynos_dpi *ctx = encoder_to_dpi(encoder);
if (ctx->panel) { if (ctx->panel) {
drm_panel_disable(ctx->panel); drm_panel_disable(ctx->panel);
drm_panel_unprepare(ctx->panel); drm_panel_unprepare(ctx->panel);
} }
} }
static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
{ .mode_fixup = exynos_dpi_mode_fixup,
struct exynos_dpi *ctx = display_to_dpi(display); .mode_set = exynos_dpi_mode_set,
.enable = exynos_dpi_enable,
switch (mode) { .disable = exynos_dpi_disable,
case DRM_MODE_DPMS_ON: };
if (ctx->dpms_mode != DRM_MODE_DPMS_ON)
exynos_dpi_poweron(ctx);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (ctx->dpms_mode == DRM_MODE_DPMS_ON)
exynos_dpi_poweroff(ctx);
break;
default:
break;
}
ctx->dpms_mode = mode;
}
static struct exynos_drm_display_ops exynos_dpi_display_ops = { static struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
.create_connector = exynos_dpi_create_connector, .destroy = drm_encoder_cleanup,
.dpms = exynos_dpi_dpms
}; };
/* of_* functions will be removed after merge of of_graph patches */ /* of_* functions will be removed after merge of of_graph patches */
...@@ -299,7 +296,34 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) ...@@ -299,7 +296,34 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
return 0; return 0;
} }
struct exynos_drm_display *exynos_dpi_probe(struct device *dev) int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
{
int ret;
ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
encoder->possible_crtcs = 1 << ret;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
ret = exynos_dpi_create_connector(encoder);
if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret);
drm_encoder_cleanup(encoder);
return ret;
}
return 0;
}
struct drm_encoder *exynos_dpi_probe(struct device *dev)
{ {
struct exynos_dpi *ctx; struct exynos_dpi *ctx;
int ret; int ret;
...@@ -308,10 +332,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) ...@@ -308,10 +332,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
if (!ctx) if (!ctx)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD;
ctx->display.ops = &exynos_dpi_display_ops;
ctx->dev = dev; ctx->dev = dev;
ctx->dpms_mode = DRM_MODE_DPMS_OFF;
ret = exynos_dpi_parse_dt(ctx); ret = exynos_dpi_parse_dt(ctx);
if (ret < 0) { if (ret < 0) {
...@@ -325,14 +346,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) ...@@ -325,14 +346,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
} }
return &ctx->display; return &ctx->encoder;
} }
int exynos_dpi_remove(struct exynos_drm_display *display) int exynos_dpi_remove(struct drm_encoder *encoder)
{ {
struct exynos_dpi *ctx = display_to_dpi(display); struct exynos_dpi *ctx = encoder_to_dpi(encoder);
exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF); exynos_dpi_disable(&ctx->encoder);
if (ctx->panel) if (ctx->panel)
drm_panel_detach(ctx->panel); drm_panel_detach(ctx->panel);
......
...@@ -21,13 +21,11 @@ ...@@ -21,13 +21,11 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_fbdev.h" #include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h" #include "exynos_drm_vidi.h"
#include "exynos_drm_dmabuf.h"
#include "exynos_drm_g2d.h" #include "exynos_drm_g2d.h"
#include "exynos_drm_ipp.h" #include "exynos_drm_ipp.h"
#include "exynos_drm_iommu.h" #include "exynos_drm_iommu.h"
...@@ -41,7 +39,9 @@ ...@@ -41,7 +39,9 @@
static int exynos_drm_load(struct drm_device *dev, unsigned long flags) static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{ {
struct exynos_drm_private *private; struct exynos_drm_private *private;
int ret; struct drm_encoder *encoder;
unsigned int clone_mask;
int cnt, ret;
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
if (!private) if (!private)
...@@ -67,7 +67,13 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) ...@@ -67,7 +67,13 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
exynos_drm_mode_config_init(dev); exynos_drm_mode_config_init(dev);
/* setup possible_clones. */ /* setup possible_clones. */
exynos_drm_encoder_setup(dev); cnt = 0;
clone_mask = 0;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
clone_mask |= (1 << (cnt++));
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
encoder->possible_clones = clone_mask;
platform_set_drvdata(dev->platformdev, dev); platform_set_drvdata(dev->platformdev, dev);
...@@ -297,8 +303,12 @@ static struct drm_driver exynos_drm_driver = { ...@@ -297,8 +303,12 @@ static struct drm_driver exynos_drm_driver = {
.dumb_destroy = drm_gem_dumb_destroy, .dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = exynos_dmabuf_prime_export, .gem_prime_export = drm_gem_prime_export,
.gem_prime_import = exynos_dmabuf_prime_import, .gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = exynos_drm_gem_prime_get_sg_table,
.gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table,
.gem_prime_vmap = exynos_drm_gem_prime_vmap,
.gem_prime_vunmap = exynos_drm_gem_prime_vunmap,
.ioctls = exynos_ioctls, .ioctls = exynos_ioctls,
.num_ioctls = ARRAY_SIZE(exynos_ioctls), .num_ioctls = ARRAY_SIZE(exynos_ioctls),
.fops = &exynos_drm_driver_fops, .fops = &exynos_drm_driver_fops,
...@@ -345,9 +355,6 @@ static struct platform_driver exynos_drm_platform_driver; ...@@ -345,9 +355,6 @@ static struct platform_driver exynos_drm_platform_driver;
* because connector requires pipe number of its crtc during initialization. * because connector requires pipe number of its crtc during initialization.
*/ */
static struct platform_driver *const exynos_drm_kms_drivers[] = { static struct platform_driver *const exynos_drm_kms_drivers[] = {
#ifdef CONFIG_DRM_EXYNOS_VIDI
&vidi_driver,
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMD #ifdef CONFIG_DRM_EXYNOS_FIMD
&fimd_driver, &fimd_driver,
#endif #endif
...@@ -370,6 +377,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = { ...@@ -370,6 +377,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
&mixer_driver, &mixer_driver,
&hdmi_driver, &hdmi_driver,
#endif #endif
#ifdef CONFIG_DRM_EXYNOS_VIDI
&vidi_driver,
#endif
}; };
static struct platform_driver *const exynos_drm_non_kms_drivers[] = { static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
......
...@@ -44,23 +44,14 @@ enum exynos_drm_output_type { ...@@ -44,23 +44,14 @@ enum exynos_drm_output_type {
* - the unit is screen coordinates. * - the unit is screen coordinates.
* @src_y: offset y on a framebuffer to be displayed. * @src_y: offset y on a framebuffer to be displayed.
* - the unit is screen coordinates. * - the unit is screen coordinates.
* @src_width: width of a partial image to be displayed from framebuffer. * @src_w: width of a partial image to be displayed from framebuffer.
* @src_height: height of a partial image to be displayed from framebuffer. * @src_h: height of a partial image to be displayed from framebuffer.
* @fb_width: width of a framebuffer.
* @fb_height: height of a framebuffer.
* @crtc_x: offset x on hardware screen. * @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen. * @crtc_y: offset y on hardware screen.
* @crtc_width: window width to be displayed (hardware screen). * @crtc_w: window width to be displayed (hardware screen).
* @crtc_height: window height to be displayed (hardware screen). * @crtc_h: window height to be displayed (hardware screen).
* @mode_width: width of screen mode.
* @mode_height: height of screen mode.
* @h_ratio: horizontal scaling ratio, 16.16 fixed point * @h_ratio: horizontal scaling ratio, 16.16 fixed point
* @v_ratio: vertical scaling ratio, 16.16 fixed point * @v_ratio: vertical scaling ratio, 16.16 fixed point
* @refresh: refresh rate.
* @scan_flag: interlace or progressive way.
* (it could be DRM_MODE_FLAG_*)
* @bpp: pixel size.(in bit)
* @pixel_format: fourcc pixel format of this overlay
* @dma_addr: array of bus(accessed by dma) address to the memory region * @dma_addr: array of bus(accessed by dma) address to the memory region
* allocated for a overlay. * allocated for a overlay.
* @zpos: order of overlay layer(z position). * @zpos: order of overlay layer(z position).
...@@ -73,75 +64,18 @@ struct exynos_drm_plane { ...@@ -73,75 +64,18 @@ struct exynos_drm_plane {
struct drm_plane base; struct drm_plane base;
unsigned int src_x; unsigned int src_x;
unsigned int src_y; unsigned int src_y;
unsigned int src_width; unsigned int src_w;
unsigned int src_height; unsigned int src_h;
unsigned int fb_width;
unsigned int fb_height;
unsigned int crtc_x; unsigned int crtc_x;
unsigned int crtc_y; unsigned int crtc_y;
unsigned int crtc_width; unsigned int crtc_w;
unsigned int crtc_height; unsigned int crtc_h;
unsigned int mode_width;
unsigned int mode_height;
unsigned int h_ratio; unsigned int h_ratio;
unsigned int v_ratio; unsigned int v_ratio;
unsigned int refresh;
unsigned int scan_flag;
unsigned int bpp;
unsigned int pitch;
uint32_t pixel_format;
dma_addr_t dma_addr[MAX_FB_BUFFER]; dma_addr_t dma_addr[MAX_FB_BUFFER];
unsigned int zpos; unsigned int zpos;
}; };
/*
* Exynos DRM Display Structure.
* - this structure is common to analog tv, digital tv and lcd panel.
*
* @create_connector: initialize and register a new connector
* @remove: cleans up the display for removal
* @mode_fixup: fix mode data comparing to hw specific display mode.
* @mode_set: convert drm_display_mode to hw specific display mode and
* would be called by encoder->mode_set().
* @check_mode: check if mode is valid or not.
* @dpms: display device on or off.
* @commit: apply changes to hw
*/
struct exynos_drm_display;
struct exynos_drm_display_ops {
int (*create_connector)(struct exynos_drm_display *display,
struct drm_encoder *encoder);
void (*remove)(struct exynos_drm_display *display);
void (*mode_fixup)(struct exynos_drm_display *display,
struct drm_connector *connector,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
void (*mode_set)(struct exynos_drm_display *display,
struct drm_display_mode *mode);
int (*check_mode)(struct exynos_drm_display *display,
struct drm_display_mode *mode);
void (*dpms)(struct exynos_drm_display *display, int mode);
void (*commit)(struct exynos_drm_display *display);
};
/*
* Exynos drm display structure, maps 1:1 with an encoder/connector
*
* @list: the list entry for this manager
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @encoder: encoder object this display maps to
* @connector: connector object this display maps to
* @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the display's implementation specific context
*/
struct exynos_drm_display {
struct list_head list;
enum exynos_drm_output_type type;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct exynos_drm_display_ops *ops;
};
/* /*
* Exynos drm crtc ops * Exynos drm crtc ops
* *
...@@ -153,8 +87,8 @@ struct exynos_drm_display { ...@@ -153,8 +87,8 @@ struct exynos_drm_display {
* @disable_vblank: specific driver callback for disabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that * @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated. * hardware overlay is updated.
* @win_commit: apply hardware specific overlay data to registers. * @update_plane: apply hardware specific overlay data to registers.
* @win_disable: disable hardware specific overlay. * @disable_plane: disable hardware specific overlay.
* @te_handler: trigger to transfer video image at the tearing effect * @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request. * synchronization signal if there is a page flip request.
* @clock_enable: optional function enabling/disabling display domain clock, * @clock_enable: optional function enabling/disabling display domain clock,
...@@ -173,11 +107,12 @@ struct exynos_drm_crtc_ops { ...@@ -173,11 +107,12 @@ struct exynos_drm_crtc_ops {
int (*enable_vblank)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*update_plane)(struct exynos_drm_crtc *crtc,
void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); struct exynos_drm_plane *plane);
void (*disable_plane)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane);
void (*te_handler)(struct exynos_drm_crtc *crtc); void (*te_handler)(struct exynos_drm_crtc *crtc);
void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
void (*clear_channels)(struct exynos_drm_crtc *crtc);
}; };
/* /*
...@@ -285,20 +220,23 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); ...@@ -285,20 +220,23 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
#ifdef CONFIG_DRM_EXYNOS_DPI #ifdef CONFIG_DRM_EXYNOS_DPI
struct exynos_drm_display * exynos_dpi_probe(struct device *dev); struct drm_encoder *exynos_dpi_probe(struct device *dev);
int exynos_dpi_remove(struct exynos_drm_display *display); int exynos_dpi_remove(struct drm_encoder *encoder);
int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder);
#else #else
static inline struct exynos_drm_display * static inline struct drm_encoder *
exynos_dpi_probe(struct device *dev) { return NULL; } exynos_dpi_probe(struct device *dev) { return NULL; }
static inline int exynos_dpi_remove(struct exynos_drm_display *display) static inline int exynos_dpi_remove(struct drm_encoder *encoder)
{
return 0;
}
static inline int exynos_dpi_bind(struct drm_device *dev,
struct drm_encoder *encoder)
{ {
return 0; return 0;
} }
#endif #endif
/* This function creates a encoder and a connector, and initializes them. */
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display);
extern struct platform_driver fimd_driver; extern struct platform_driver fimd_driver;
extern struct platform_driver exynos5433_decon_driver; extern struct platform_driver exynos5433_decon_driver;
......
...@@ -259,7 +259,7 @@ struct exynos_dsi_driver_data { ...@@ -259,7 +259,7 @@ struct exynos_dsi_driver_data {
}; };
struct exynos_dsi { struct exynos_dsi {
struct exynos_drm_display display; struct drm_encoder encoder;
struct mipi_dsi_host dsi_host; struct mipi_dsi_host dsi_host;
struct drm_connector connector; struct drm_connector connector;
struct device_node *panel_node; struct device_node *panel_node;
...@@ -295,9 +295,9 @@ struct exynos_dsi { ...@@ -295,9 +295,9 @@ struct exynos_dsi {
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d) static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
{ {
return container_of(d, struct exynos_dsi, display); return container_of(e, struct exynos_dsi, encoder);
} }
enum reg_idx { enum reg_idx {
...@@ -1272,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) ...@@ -1272,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
{ {
struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
struct drm_encoder *encoder = dsi->display.encoder; struct drm_encoder *encoder = &dsi->encoder;
if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)
exynos_drm_crtc_te_handler(encoder->crtc); exynos_drm_crtc_te_handler(encoder->crtc);
...@@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) ...@@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
dev_err(dsi->dev, "cannot disable regulators %d\n", ret); dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
} }
static int exynos_dsi_enable(struct exynos_dsi *dsi) static void exynos_dsi_enable(struct drm_encoder *encoder)
{ {
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
int ret; int ret;
if (dsi->state & DSIM_STATE_ENABLED) if (dsi->state & DSIM_STATE_ENABLED)
return 0; return;
ret = exynos_dsi_poweron(dsi); ret = exynos_dsi_poweron(dsi);
if (ret < 0) if (ret < 0)
return ret; return;
dsi->state |= DSIM_STATE_ENABLED; dsi->state |= DSIM_STATE_ENABLED;
...@@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) ...@@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
if (ret < 0) { if (ret < 0) {
dsi->state &= ~DSIM_STATE_ENABLED; dsi->state &= ~DSIM_STATE_ENABLED;
exynos_dsi_poweroff(dsi); exynos_dsi_poweroff(dsi);
return ret; return;
} }
exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_mode(dsi);
...@@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) ...@@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
exynos_dsi_set_display_enable(dsi, false); exynos_dsi_set_display_enable(dsi, false);
drm_panel_unprepare(dsi->panel); drm_panel_unprepare(dsi->panel);
exynos_dsi_poweroff(dsi); exynos_dsi_poweroff(dsi);
return ret; return;
} }
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
return 0;
} }
static void exynos_dsi_disable(struct exynos_dsi *dsi) static void exynos_dsi_disable(struct drm_encoder *encoder)
{ {
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
if (!(dsi->state & DSIM_STATE_ENABLED)) if (!(dsi->state & DSIM_STATE_ENABLED))
return; return;
...@@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) ...@@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
exynos_dsi_poweroff(dsi); exynos_dsi_poweroff(dsi);
} }
static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
{
struct exynos_dsi *dsi = display_to_dsi(display);
if (dsi->panel) {
switch (mode) {
case DRM_MODE_DPMS_ON:
exynos_dsi_enable(dsi);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
exynos_dsi_disable(dsi);
break;
default:
break;
}
}
}
static enum drm_connector_status static enum drm_connector_status
exynos_dsi_detect(struct drm_connector *connector, bool force) exynos_dsi_detect(struct drm_connector *connector, bool force)
{ {
...@@ -1601,10 +1582,10 @@ exynos_dsi_detect(struct drm_connector *connector, bool force) ...@@ -1601,10 +1582,10 @@ exynos_dsi_detect(struct drm_connector *connector, bool force)
if (dsi->panel) if (dsi->panel)
drm_panel_attach(dsi->panel, &dsi->connector); drm_panel_attach(dsi->panel, &dsi->connector);
} else if (!dsi->panel_node) { } else if (!dsi->panel_node) {
struct exynos_drm_display *display; struct drm_encoder *encoder;
display = platform_get_drvdata(to_platform_device(dsi->dev)); encoder = platform_get_drvdata(to_platform_device(dsi->dev));
exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); exynos_dsi_disable(encoder);
drm_panel_detach(dsi->panel); drm_panel_detach(dsi->panel);
dsi->panel = NULL; dsi->panel = NULL;
} }
...@@ -1647,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector) ...@@ -1647,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
{ {
struct exynos_dsi *dsi = connector_to_dsi(connector); struct exynos_dsi *dsi = connector_to_dsi(connector);
return dsi->display.encoder; return &dsi->encoder;
} }
static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
...@@ -1655,10 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { ...@@ -1655,10 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
.best_encoder = exynos_dsi_best_encoder, .best_encoder = exynos_dsi_best_encoder,
}; };
static int exynos_dsi_create_connector(struct exynos_drm_display *display, static int exynos_dsi_create_connector(struct drm_encoder *encoder)
struct drm_encoder *encoder)
{ {
struct exynos_dsi *dsi = display_to_dsi(display); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct drm_connector *connector = &dsi->connector; struct drm_connector *connector = &dsi->connector;
int ret; int ret;
...@@ -1679,26 +1659,40 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display, ...@@ -1679,26 +1659,40 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display,
return 0; return 0;
} }
static void exynos_dsi_mode_set(struct exynos_drm_display *display, static bool exynos_dsi_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode) const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{ {
struct exynos_dsi *dsi = display_to_dsi(display); return true;
struct videomode *vm = &dsi->vm; }
vm->hactive = mode->hdisplay; static void exynos_dsi_mode_set(struct drm_encoder *encoder,
vm->vactive = mode->vdisplay; struct drm_display_mode *mode,
vm->vfront_porch = mode->vsync_start - mode->vdisplay; struct drm_display_mode *adjusted_mode)
vm->vback_porch = mode->vtotal - mode->vsync_end; {
vm->vsync_len = mode->vsync_end - mode->vsync_start; struct exynos_dsi *dsi = encoder_to_dsi(encoder);
vm->hfront_porch = mode->hsync_start - mode->hdisplay; struct videomode *vm = &dsi->vm;
vm->hback_porch = mode->htotal - mode->hsync_end; struct drm_display_mode *m = adjusted_mode;
vm->hsync_len = mode->hsync_end - mode->hsync_start;
vm->hactive = m->hdisplay;
vm->vactive = m->vdisplay;
vm->vfront_porch = m->vsync_start - m->vdisplay;
vm->vback_porch = m->vtotal - m->vsync_end;
vm->vsync_len = m->vsync_end - m->vsync_start;
vm->hfront_porch = m->hsync_start - m->hdisplay;
vm->hback_porch = m->htotal - m->hsync_end;
vm->hsync_len = m->hsync_end - m->hsync_start;
} }
static struct exynos_drm_display_ops exynos_dsi_display_ops = { static struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
.create_connector = exynos_dsi_create_connector, .mode_fixup = exynos_dsi_mode_fixup,
.mode_set = exynos_dsi_mode_set, .mode_set = exynos_dsi_mode_set,
.dpms = exynos_dsi_dpms .enable = exynos_dsi_enable,
.disable = exynos_dsi_disable,
};
static struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
}; };
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
...@@ -1821,22 +1815,35 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ...@@ -1821,22 +1815,35 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
static int exynos_dsi_bind(struct device *dev, struct device *master, static int exynos_dsi_bind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct exynos_drm_display *display = dev_get_drvdata(dev); struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = display_to_dsi(display); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct drm_bridge *bridge; struct drm_bridge *bridge;
int ret; int ret;
ret = exynos_drm_create_enc_conn(drm_dev, display); ret = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
encoder->possible_crtcs = 1 << ret;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
ret = exynos_dsi_create_connector(encoder);
if (ret) { if (ret) {
DRM_ERROR("Encoder create [%d] failed with %d\n", DRM_ERROR("failed to create connector ret = %d\n", ret);
display->type, ret); drm_encoder_cleanup(encoder);
return ret; return ret;
} }
bridge = of_drm_find_bridge(dsi->bridge_node); bridge = of_drm_find_bridge(dsi->bridge_node);
if (bridge) { if (bridge) {
display->encoder->bridge = bridge;
drm_bridge_attach(drm_dev, bridge); drm_bridge_attach(drm_dev, bridge);
} }
...@@ -1846,10 +1853,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, ...@@ -1846,10 +1853,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
static void exynos_dsi_unbind(struct device *dev, struct device *master, static void exynos_dsi_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct exynos_drm_display *display = dev_get_drvdata(dev); struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = display_to_dsi(display); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); exynos_dsi_disable(encoder);
mipi_dsi_host_unregister(&dsi->dsi_host); mipi_dsi_host_unregister(&dsi->dsi_host);
} }
...@@ -1870,9 +1877,6 @@ static int exynos_dsi_probe(struct platform_device *pdev) ...@@ -1870,9 +1877,6 @@ static int exynos_dsi_probe(struct platform_device *pdev)
if (!dsi) if (!dsi)
return -ENOMEM; return -ENOMEM;
dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD;
dsi->display.ops = &exynos_dsi_display_ops;
/* To be checked as invalid one */ /* To be checked as invalid one */
dsi->te_gpio = -ENOENT; dsi->te_gpio = -ENOENT;
...@@ -1948,7 +1952,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) ...@@ -1948,7 +1952,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
return ret; return ret;
} }
platform_set_drvdata(pdev, &dsi->display); platform_set_drvdata(pdev, &dsi->encoder);
return component_add(dev, &exynos_dsi_component_ops); return component_add(dev, &exynos_dsi_component_ops);
} }
......
/* exynos_drm_encoder.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
drm_encoder)
/*
* exynos specific encoder structure.
*
* @drm_encoder: encoder object.
* @display: the display structure that maps to this encoder
*/
struct exynos_drm_encoder {
struct drm_encoder drm_encoder;
struct exynos_drm_display *display;
};
static bool
exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder != encoder)
continue;
if (display->ops->mode_fixup)
display->ops->mode_fixup(display, connector, mode,
adjusted_mode);
}
return true;
}
static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
if (display->ops->mode_set)
display->ops->mode_set(display, adjusted_mode);
}
static void exynos_drm_encoder_enable(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
if (display->ops->dpms)
display->ops->dpms(display, DRM_MODE_DPMS_ON);
if (display->ops->commit)
display->ops->commit(display);
}
static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
if (display->ops->dpms)
display->ops->dpms(display, DRM_MODE_DPMS_OFF);
}
static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
.mode_fixup = exynos_drm_encoder_mode_fixup,
.mode_set = exynos_drm_encoder_mode_set,
.enable = exynos_drm_encoder_enable,
.disable = exynos_drm_encoder_disable,
};
static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
drm_encoder_cleanup(encoder);
kfree(exynos_encoder);
}
static struct drm_encoder_funcs exynos_encoder_funcs = {
.destroy = exynos_drm_encoder_destroy,
};
static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
{
struct drm_encoder *clone;
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
unsigned int clone_mask = 0;
int cnt = 0;
list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
switch (display->type) {
case EXYNOS_DISPLAY_TYPE_LCD:
case EXYNOS_DISPLAY_TYPE_HDMI:
case EXYNOS_DISPLAY_TYPE_VIDI:
clone_mask |= (1 << (cnt++));
break;
default:
continue;
}
}
return clone_mask;
}
void exynos_drm_encoder_setup(struct drm_device *dev)
{
struct drm_encoder *encoder;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
encoder->possible_clones = exynos_drm_encoder_clones(encoder);
}
struct drm_encoder *
exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_display *display,
unsigned long possible_crtcs)
{
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
if (!possible_crtcs)
return NULL;
exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
if (!exynos_encoder)
return NULL;
exynos_encoder->display = display;
encoder = &exynos_encoder->drm_encoder;
encoder->possible_crtcs = possible_crtcs;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
DRM_DEBUG_KMS("encoder has been created\n");
return encoder;
}
struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
{
return to_exynos_encoder(encoder)->display;
}
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_ENCODER_H_
#define _EXYNOS_DRM_ENCODER_H_
void exynos_drm_encoder_setup(struct drm_device *dev);
struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_display *mgr,
unsigned long possible_crtcs);
struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
#endif
...@@ -238,22 +238,22 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, ...@@ -238,22 +238,22 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
int index) int index)
{ {
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_obj *obj;
if (index >= MAX_FB_BUFFER) if (index >= MAX_FB_BUFFER)
return NULL; return NULL;
buffer = exynos_fb->exynos_gem_obj[index]->buffer; obj = exynos_fb->exynos_gem_obj[index];
if (!buffer) if (!obj)
return NULL; return NULL;
DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr); DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr);
return buffer; return obj;
} }
static void exynos_drm_output_poll_changed(struct drm_device *dev) static void exynos_drm_output_poll_changed(struct drm_device *dev)
......
...@@ -19,8 +19,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev, ...@@ -19,8 +19,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd, struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj); struct drm_gem_object *obj);
/* get memory information of a drm framebuffer */ /* get gem object of a drm framebuffer */
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
int index); int index);
void exynos_drm_mode_config_init(struct drm_device *dev); void exynos_drm_mode_config_init(struct drm_device *dev);
......
...@@ -40,8 +40,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info, ...@@ -40,8 +40,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
{ {
struct drm_fb_helper *helper = info->par; struct drm_fb_helper *helper = info->par;
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj;
struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer;
unsigned long vm_size; unsigned long vm_size;
int ret; int ret;
...@@ -49,11 +48,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info, ...@@ -49,11 +48,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
vm_size = vma->vm_end - vma->vm_start; vm_size = vma->vm_end - vma->vm_start;
if (vm_size > buffer->size) if (vm_size > obj->size)
return -EINVAL; return -EINVAL;
ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages, ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr,
buffer->dma_addr, buffer->size, &buffer->dma_attrs); obj->size, &obj->dma_attrs);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to mmap.\n"); DRM_ERROR("failed to mmap.\n");
return ret; return ret;
...@@ -80,7 +79,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -80,7 +79,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
struct fb_info *fbi = helper->fbdev; struct fb_info *fbi = helper->fbdev;
struct exynos_drm_gem_buf *buffer; struct exynos_drm_gem_obj *obj;
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 int nr_pages; unsigned int nr_pages;
unsigned long offset; unsigned long offset;
...@@ -89,18 +88,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -89,18 +88,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
/* RGB formats use only one buffer */ /* RGB formats use only one buffer */
buffer = exynos_drm_fb_buffer(fb, 0); obj = exynos_drm_fb_gem_obj(fb, 0);
if (!buffer) { if (!obj) {
DRM_DEBUG_KMS("buffer is null.\n"); DRM_DEBUG_KMS("gem object is null.\n");
return -EFAULT; return -EFAULT;
} }
nr_pages = buffer->size >> PAGE_SHIFT; nr_pages = obj->size >> PAGE_SHIFT;
buffer->kvaddr = (void __iomem *) vmap(buffer->pages, obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,
nr_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL)); pgprot_writecombine(PAGE_KERNEL));
if (!buffer->kvaddr) { if (!obj->kvaddr) {
DRM_ERROR("failed to map pages to kernel space.\n"); DRM_ERROR("failed to map pages to kernel space.\n");
return -EIO; return -EIO;
} }
...@@ -111,7 +109,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -111,7 +109,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
offset += fbi->var.yoffset * fb->pitches[0]; offset += fbi->var.yoffset * fb->pitches[0];
fbi->screen_base = buffer->kvaddr + offset; fbi->screen_base = obj->kvaddr + offset;
fbi->screen_size = size; fbi->screen_size = size;
fbi->fix.smem_len = size; fbi->fix.smem_len = size;
...@@ -290,8 +288,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, ...@@ -290,8 +288,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
if (exynos_gem_obj->buffer->kvaddr) if (exynos_gem_obj->kvaddr)
vunmap(exynos_gem_obj->buffer->kvaddr); vunmap(exynos_gem_obj->kvaddr);
/* release drm framebuffer and real buffer */ /* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) { if (fb_helper->fb && fb_helper->fb->funcs) {
......
...@@ -169,7 +169,7 @@ struct fimd_context { ...@@ -169,7 +169,7 @@ struct fimd_context {
struct exynos_drm_panel_info panel; struct exynos_drm_panel_info panel;
struct fimd_driver_data *driver_data; struct fimd_driver_data *driver_data;
struct exynos_drm_display *display; struct drm_encoder *encoder;
}; };
static const struct of_device_id fimd_driver_dt_match[] = { static const struct of_device_id fimd_driver_dt_match[] = {
...@@ -348,13 +348,6 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -348,13 +348,6 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
pm_runtime_put(ctx->dev); pm_runtime_put(ctx->dev);
} }
static void fimd_iommu_detach_devices(struct fimd_context *ctx)
{
/* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev))
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
}
static u32 fimd_calc_clkdiv(struct fimd_context *ctx, static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
...@@ -486,9 +479,9 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) ...@@ -486,9 +479,9 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
} }
static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
struct drm_framebuffer *fb)
{ {
struct exynos_drm_plane *plane = &ctx->planes[win];
unsigned long val; unsigned long val;
val = WINCONx_ENWIN; val = WINCONx_ENWIN;
...@@ -498,11 +491,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) ...@@ -498,11 +491,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
* So the request format is ARGB8888 then change it to XRGB8888. * So the request format is ARGB8888 then change it to XRGB8888.
*/ */
if (ctx->driver_data->has_limited_fmt && !win) { if (ctx->driver_data->has_limited_fmt && !win) {
if (plane->pixel_format == DRM_FORMAT_ARGB8888) if (fb->pixel_format == DRM_FORMAT_ARGB8888)
plane->pixel_format = DRM_FORMAT_XRGB8888; fb->pixel_format = DRM_FORMAT_XRGB8888;
} }
switch (plane->pixel_format) { switch (fb->pixel_format) {
case DRM_FORMAT_C8: case DRM_FORMAT_C8:
val |= WINCON0_BPPMODE_8BPP_PALETTE; val |= WINCON0_BPPMODE_8BPP_PALETTE;
val |= WINCONx_BURSTLEN_8WORD; val |= WINCONx_BURSTLEN_8WORD;
...@@ -538,7 +531,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) ...@@ -538,7 +531,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
break; break;
} }
DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
/* /*
* In case of exynos, setting dma-burst to 16Word causes permanent * In case of exynos, setting dma-burst to 16Word causes permanent
...@@ -548,7 +541,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) ...@@ -548,7 +541,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
* movement causes unstable DMA which results into iommu crash/tear. * movement causes unstable DMA which results into iommu crash/tear.
*/ */
if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK; val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_4WORD; val |= WINCONx_BURSTLEN_4WORD;
} }
...@@ -614,21 +607,17 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, ...@@ -614,21 +607,17 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg); writel(val, ctx->regs + reg);
} }
static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) static void fimd_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane; struct drm_plane_state *state = plane->base.state;
dma_addr_t dma_addr; dma_addr_t dma_addr;
unsigned long val, size, offset; unsigned long val, size, offset;
unsigned int last_x, last_y, buf_offsize, line_size; unsigned int last_x, last_y, buf_offsize, line_size;
unsigned int win = plane->zpos;
if (ctx->suspended) unsigned int bpp = state->fb->bits_per_pixel >> 3;
return; unsigned int pitch = state->fb->pitches[0];
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -647,8 +636,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -647,8 +636,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
fimd_shadow_protect_win(ctx, win, true); fimd_shadow_protect_win(ctx, win, true);
offset = plane->src_x * (plane->bpp >> 3); offset = plane->src_x * bpp;
offset += plane->src_y * plane->pitch; offset += plane->src_y * pitch;
/* buffer start address */ /* buffer start address */
dma_addr = plane->dma_addr[0] + offset; dma_addr = plane->dma_addr[0] + offset;
...@@ -656,18 +645,18 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -656,18 +645,18 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
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 = plane->pitch * plane->crtc_height; size = pitch * plane->crtc_h;
val = (unsigned long)(dma_addr + size); val = (unsigned long)(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)dma_addr, val, size); (unsigned long)dma_addr, val, size);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
plane->crtc_width, plane->crtc_height); plane->crtc_w, plane->crtc_h);
/* buffer size */ /* buffer size */
buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); buf_offsize = pitch - (plane->crtc_w * bpp);
line_size = plane->crtc_width * (plane->bpp >> 3); line_size = plane->crtc_w * bpp;
val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
VIDW_BUF_SIZE_PAGEWIDTH(line_size) | VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
...@@ -681,10 +670,10 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -681,10 +670,10 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
writel(val, ctx->regs + VIDOSD_A(win)); writel(val, ctx->regs + VIDOSD_A(win));
last_x = plane->crtc_x + plane->crtc_width; last_x = plane->crtc_x + plane->crtc_w;
if (last_x) if (last_x)
last_x--; last_x--;
last_y = plane->crtc_y + plane->crtc_height; last_y = plane->crtc_y + plane->crtc_h;
if (last_y) if (last_y)
last_y--; last_y--;
...@@ -701,13 +690,13 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -701,13 +690,13 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
u32 offset = VIDOSD_D(win); u32 offset = VIDOSD_D(win);
if (win == 0) if (win == 0)
offset = VIDOSD_C(win); offset = VIDOSD_C(win);
val = plane->crtc_width * plane->crtc_height; val = plane->crtc_w * plane->crtc_h;
writel(val, ctx->regs + offset); writel(val, ctx->regs + offset);
DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
} }
fimd_win_set_pixfmt(ctx, win); fimd_win_set_pixfmt(ctx, win, state->fb);
/* hardware window 0 doesn't support color key. */ /* hardware window 0 doesn't support color key. */
if (win != 0) if (win != 0)
...@@ -725,15 +714,11 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) ...@@ -725,15 +714,11 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
atomic_set(&ctx->win_updated, 1); atomic_set(&ctx->win_updated, 1);
} }
static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane; unsigned int win = plane->zpos;
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
if (ctx->suspended) if (ctx->suspended)
return; return;
...@@ -795,7 +780,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) ...@@ -795,7 +780,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc)
* a destroyed buffer later. * a destroyed buffer later.
*/ */
for (i = 0; i < WINDOWS_NR; i++) for (i = 0; i < WINDOWS_NR; i++)
fimd_win_disable(crtc, i); fimd_disable_plane(crtc, &ctx->planes[i]);
fimd_enable_vblank(crtc); fimd_enable_vblank(crtc);
fimd_wait_for_vblank(crtc); fimd_wait_for_vblank(crtc);
...@@ -862,7 +847,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) ...@@ -862,7 +847,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
} }
if (test_bit(0, &ctx->irq_flags)) if (test_bit(0, &ctx->irq_flags))
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
} }
static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
...@@ -890,11 +875,10 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { ...@@ -890,11 +875,10 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
.enable_vblank = fimd_enable_vblank, .enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank, .disable_vblank = fimd_disable_vblank,
.wait_for_vblank = fimd_wait_for_vblank, .wait_for_vblank = fimd_wait_for_vblank,
.win_commit = fimd_win_commit, .update_plane = fimd_update_plane,
.win_disable = fimd_win_disable, .disable_plane = fimd_disable_plane,
.te_handler = fimd_te_handler, .te_handler = fimd_te_handler,
.clock_enable = fimd_dp_clock_enable, .clock_enable = fimd_dp_clock_enable,
.clear_channels = fimd_clear_channels,
}; };
static irqreturn_t fimd_irq_handler(int irq, void *dev_id) static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
...@@ -913,13 +897,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) ...@@ -913,13 +897,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
goto out; goto out;
if (ctx->i80_if) { if (ctx->i80_if) {
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); exynos_drm_crtc_finish_pageflip(ctx->crtc);
/* Exits triggering mode */ /* Exits triggering mode */
atomic_set(&ctx->triggering, 0); atomic_set(&ctx->triggering, 0);
} else { } else {
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); exynos_drm_crtc_finish_pageflip(ctx->crtc);
/* set wait vsync event to zero and wake up queue. */ /* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) { if (atomic_read(&ctx->wait_vsync_event)) {
...@@ -961,10 +945,13 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -961,10 +945,13 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(ctx->crtc)) if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
if (ctx->display) if (ctx->encoder)
exynos_drm_create_enc_conn(drm_dev, ctx->display); exynos_dpi_bind(drm_dev, ctx->encoder);
if (is_drm_iommu_supported(drm_dev))
fimd_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); ret = drm_iommu_attach_device(drm_dev, dev);
if (ret) if (ret)
priv->pipe--; priv->pipe--;
...@@ -978,10 +965,10 @@ static void fimd_unbind(struct device *dev, struct device *master, ...@@ -978,10 +965,10 @@ static void fimd_unbind(struct device *dev, struct device *master,
fimd_disable(ctx->crtc); fimd_disable(ctx->crtc);
fimd_iommu_detach_devices(ctx); drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
if (ctx->display) if (ctx->encoder)
exynos_dpi_remove(ctx->display); exynos_dpi_remove(ctx->encoder);
} }
static const struct component_ops fimd_component_ops = { static const struct component_ops fimd_component_ops = {
...@@ -1088,10 +1075,9 @@ static int fimd_probe(struct platform_device *pdev) ...@@ -1088,10 +1075,9 @@ static int fimd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
ctx->display = exynos_dpi_probe(dev); ctx->encoder = exynos_dpi_probe(dev);
if (IS_ERR(ctx->display)) { if (IS_ERR(ctx->encoder))
return PTR_ERR(ctx->display); return PTR_ERR(ctx->encoder);
}
pm_runtime_enable(dev); pm_runtime_enable(dev);
......
...@@ -1319,9 +1319,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) ...@@ -1319,9 +1319,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
return ret; return ret;
} }
if (!is_drm_iommu_supported(drm_dev))
return 0;
ret = drm_iommu_attach_device(drm_dev, dev); ret = drm_iommu_attach_device(drm_dev, dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to enable iommu.\n"); dev_err(dev, "failed to enable iommu.\n");
...@@ -1334,9 +1331,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) ...@@ -1334,9 +1331,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
{ {
if (!is_drm_iommu_supported(drm_dev))
return;
drm_iommu_detach_device(drm_dev, dev); drm_iommu_detach_device(drm_dev, dev);
} }
......
This diff is collapsed.
...@@ -19,35 +19,6 @@ ...@@ -19,35 +19,6 @@
#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) #define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG)
/*
* exynos drm gem buffer structure.
*
* @cookie: cookie returned by dma_alloc_attrs
* @kvaddr: kernel virtual address to allocated memory region.
* *userptr: user space address.
* @dma_addr: bus address(accessed by dma) to allocated memory region.
* - this address could be physical address without IOMMU and
* device address with IOMMU.
* @write: whether pages will be written to by the caller.
* @pages: Array of backing pages.
* @sgt: sg table to transfer page data.
* @size: size of allocated memory region.
* @pfnmap: indicate whether memory region from userptr is mmaped with
* VM_PFNMAP or not.
*/
struct exynos_drm_gem_buf {
void *cookie;
void __iomem *kvaddr;
unsigned long userptr;
dma_addr_t dma_addr;
struct dma_attrs dma_attrs;
unsigned int write;
struct page **pages;
struct sg_table *sgt;
unsigned long size;
bool pfnmap;
};
/* /*
* exynos drm buffer structure. * exynos drm buffer structure.
* *
...@@ -59,18 +30,28 @@ struct exynos_drm_gem_buf { ...@@ -59,18 +30,28 @@ 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.
* @flags: indicate memory type to allocated buffer and cache attruibute.
* @size: size requested from user, in bytes and this size is aligned * @size: size requested from user, in bytes and this size is aligned
* in page unit. * in page unit.
* @flags: indicate memory type to allocated buffer and cache attruibute. * @cookie: cookie returned by dma_alloc_attrs
* @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.
* @pages: Array of backing pages.
* *
* P.S. this object would be transferred to user as kms_bo.handle so * P.S. this object would be transferred to user as kms_bo.handle so
* user can access the buffer through kms_bo.handle. * user can access the buffer through kms_bo.handle.
*/ */
struct exynos_drm_gem_obj { struct exynos_drm_gem_obj {
struct drm_gem_object base; struct drm_gem_object base;
struct exynos_drm_gem_buf *buffer; unsigned int flags;
unsigned long size; unsigned long size;
unsigned int flags; void *cookie;
void __iomem *kvaddr;
dma_addr_t dma_addr;
struct dma_attrs dma_attrs;
struct page **pages;
}; };
struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
...@@ -177,4 +158,13 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, ...@@ -177,4 +158,13 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
struct sg_table *sgt, struct sg_table *sgt,
enum dma_data_direction dir); enum dma_data_direction dir);
/* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *
exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
struct sg_table *sgt);
void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj);
void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
#endif #endif
...@@ -582,9 +582,17 @@ static int gsc_src_set_transf(struct device *dev, ...@@ -582,9 +582,17 @@ static int gsc_src_set_transf(struct device *dev,
break; break;
case EXYNOS_DRM_DEGREE_180: case EXYNOS_DRM_DEGREE_180:
cfg |= GSC_IN_ROT_180; cfg |= GSC_IN_ROT_180;
if (flip & EXYNOS_DRM_FLIP_VERTICAL)
cfg &= ~GSC_IN_ROT_XFLIP;
if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
case EXYNOS_DRM_DEGREE_270: case EXYNOS_DRM_DEGREE_270:
cfg |= GSC_IN_ROT_270; cfg |= GSC_IN_ROT_270;
if (flip & EXYNOS_DRM_FLIP_VERTICAL)
cfg &= ~GSC_IN_ROT_XFLIP;
if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
...@@ -845,9 +853,17 @@ static int gsc_dst_set_transf(struct device *dev, ...@@ -845,9 +853,17 @@ static int gsc_dst_set_transf(struct device *dev,
break; break;
case EXYNOS_DRM_DEGREE_180: case EXYNOS_DRM_DEGREE_180:
cfg |= GSC_IN_ROT_180; cfg |= GSC_IN_ROT_180;
if (flip & EXYNOS_DRM_FLIP_VERTICAL)
cfg &= ~GSC_IN_ROT_XFLIP;
if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
case EXYNOS_DRM_DEGREE_270: case EXYNOS_DRM_DEGREE_270:
cfg |= GSC_IN_ROT_270; cfg |= GSC_IN_ROT_270;
if (flip & EXYNOS_DRM_FLIP_VERTICAL)
cfg &= ~GSC_IN_ROT_XFLIP;
if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
......
...@@ -87,10 +87,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, ...@@ -87,10 +87,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *dev = drm_dev->dev; struct device *dev = drm_dev->dev;
int ret; int ret;
if (!dev->archdata.mapping) { if (!dev->archdata.mapping)
DRM_ERROR("iommu_mapping is null.\n"); return 0;
return -EFAULT;
}
subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
sizeof(*subdrv_dev->dma_parms), sizeof(*subdrv_dev->dma_parms),
...@@ -144,17 +142,3 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, ...@@ -144,17 +142,3 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
iommu_detach_device(mapping->domain, subdrv_dev); iommu_detach_device(mapping->domain, subdrv_dev);
drm_release_iommu_mapping(drm_dev); drm_release_iommu_mapping(drm_dev);
} }
int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc,
struct drm_device *drm_dev, struct device *subdrv_dev)
{
int ret = 0;
if (is_drm_iommu_supported(drm_dev)) {
if (exynos_crtc->ops->clear_channels)
exynos_crtc->ops->clear_channels(exynos_crtc);
return drm_iommu_attach_device(drm_dev, subdrv_dev);
}
return ret;
}
...@@ -29,19 +29,11 @@ void drm_iommu_detach_device(struct drm_device *dev_dev, ...@@ -29,19 +29,11 @@ void drm_iommu_detach_device(struct drm_device *dev_dev,
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{ {
#ifdef CONFIG_ARM_DMA_USE_IOMMU
struct device *dev = drm_dev->dev; struct device *dev = drm_dev->dev;
return dev->archdata.mapping ? true : false; return dev->archdata.mapping ? true : false;
#else
return false;
#endif
} }
int drm_iommu_attach_device_if_possible(
struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev,
struct device *subdrv_dev);
#else #else
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
...@@ -69,12 +61,5 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) ...@@ -69,12 +61,5 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
return false; return false;
} }
static inline int drm_iommu_attach_device_if_possible(
struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev,
struct device *subdrv_dev)
{
return 0;
}
#endif #endif
#endif #endif
...@@ -1622,12 +1622,10 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) ...@@ -1622,12 +1622,10 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
INIT_LIST_HEAD(&ippdrv->cmd_list); INIT_LIST_HEAD(&ippdrv->cmd_list);
mutex_init(&ippdrv->cmd_lock); mutex_init(&ippdrv->cmd_lock);
if (is_drm_iommu_supported(drm_dev)) { ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);
ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); if (ret) {
if (ret) { DRM_ERROR("failed to activate iommu\n");
DRM_ERROR("failed to activate iommu\n"); goto err;
goto err;
}
} }
} }
...@@ -1637,8 +1635,7 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) ...@@ -1637,8 +1635,7 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
/* get ipp driver entry */ /* get ipp driver entry */
list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list,
drv_list) { drv_list) {
if (is_drm_iommu_supported(drm_dev)) drm_iommu_detach_device(drm_dev, ippdrv->dev);
drm_iommu_detach_device(drm_dev, ippdrv->dev);
ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
ippdrv->prop_list.ipp_id); ippdrv->prop_list.ipp_id);
...@@ -1654,8 +1651,7 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) ...@@ -1654,8 +1651,7 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
/* get ipp driver entry */ /* get ipp driver entry */
list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) {
if (is_drm_iommu_supported(drm_dev)) drm_iommu_detach_device(drm_dev, ippdrv->dev);
drm_iommu_detach_device(drm_dev, ippdrv->dev);
ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
ippdrv->prop_list.ipp_id); ippdrv->prop_list.ipp_id);
......
...@@ -97,29 +97,18 @@ static void exynos_plane_mode_set(struct drm_plane *plane, ...@@ -97,29 +97,18 @@ static void exynos_plane_mode_set(struct drm_plane *plane,
/* set drm framebuffer data. */ /* set drm framebuffer data. */
exynos_plane->src_x = src_x; exynos_plane->src_x = src_x;
exynos_plane->src_y = src_y; exynos_plane->src_y = src_y;
exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16; exynos_plane->src_w = (actual_w * exynos_plane->h_ratio) >> 16;
exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16; exynos_plane->src_h = (actual_h * exynos_plane->v_ratio) >> 16;
exynos_plane->fb_width = fb->width;
exynos_plane->fb_height = fb->height;
exynos_plane->bpp = fb->bits_per_pixel;
exynos_plane->pitch = fb->pitches[0];
exynos_plane->pixel_format = fb->pixel_format;
/* set plane range to be displayed. */ /* set plane range to be displayed. */
exynos_plane->crtc_x = crtc_x; exynos_plane->crtc_x = crtc_x;
exynos_plane->crtc_y = crtc_y; exynos_plane->crtc_y = crtc_y;
exynos_plane->crtc_width = actual_w; exynos_plane->crtc_w = actual_w;
exynos_plane->crtc_height = actual_h; exynos_plane->crtc_h = actual_h;
/* set drm mode data. */
exynos_plane->mode_width = mode->hdisplay;
exynos_plane->mode_height = mode->vdisplay;
exynos_plane->refresh = mode->vrefresh;
exynos_plane->scan_flag = mode->flags;
DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
exynos_plane->crtc_x, exynos_plane->crtc_y, exynos_plane->crtc_x, exynos_plane->crtc_y,
exynos_plane->crtc_width, exynos_plane->crtc_height); exynos_plane->crtc_w, exynos_plane->crtc_h);
plane->crtc = crtc; plane->crtc = crtc;
} }
...@@ -145,15 +134,15 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, ...@@ -145,15 +134,15 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
nr = exynos_drm_fb_get_buf_cnt(state->fb); nr = exynos_drm_fb_get_buf_cnt(state->fb);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
struct exynos_drm_gem_buf *buffer = struct exynos_drm_gem_obj *obj =
exynos_drm_fb_buffer(state->fb, i); exynos_drm_fb_gem_obj(state->fb, i);
if (!buffer) { if (!obj) {
DRM_DEBUG_KMS("buffer is null\n"); DRM_DEBUG_KMS("gem object is null\n");
return -EFAULT; return -EFAULT;
} }
exynos_plane->dma_addr[i] = buffer->dma_addr + exynos_plane->dma_addr[i] = obj->dma_addr +
state->fb->offsets[i]; state->fb->offsets[i];
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
...@@ -179,8 +168,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, ...@@ -179,8 +168,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
state->src_x >> 16, state->src_y >> 16, state->src_x >> 16, state->src_y >> 16,
state->src_w >> 16, state->src_h >> 16); state->src_w >> 16, state->src_h >> 16);
if (exynos_crtc->ops->win_commit) if (exynos_crtc->ops->update_plane)
exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
} }
static void exynos_plane_atomic_disable(struct drm_plane *plane, static void exynos_plane_atomic_disable(struct drm_plane *plane,
...@@ -192,9 +181,9 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane, ...@@ -192,9 +181,9 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane,
if (!old_state->crtc) if (!old_state->crtc)
return; return;
if (exynos_crtc->ops->win_disable) if (exynos_crtc->ops->disable_plane)
exynos_crtc->ops->win_disable(exynos_crtc, exynos_crtc->ops->disable_plane(exynos_crtc,
exynos_plane->zpos); exynos_plane);
} }
static const struct drm_plane_helper_funcs plane_helper_funcs = { static const struct drm_plane_helper_funcs plane_helper_funcs = {
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_vidi.h" #include "exynos_drm_vidi.h"
/* vidi has totally three virtual windows. */ /* vidi has totally three virtual windows. */
...@@ -35,11 +34,10 @@ ...@@ -35,11 +34,10 @@
connector) connector)
struct vidi_context { struct vidi_context {
struct exynos_drm_display display; struct drm_encoder encoder;
struct platform_device *pdev; struct platform_device *pdev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc; struct exynos_drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector connector; struct drm_connector connector;
struct exynos_drm_plane planes[WINDOWS_NR]; struct exynos_drm_plane planes[WINDOWS_NR];
struct edid *raw_edid; struct edid *raw_edid;
...@@ -55,9 +53,9 @@ struct vidi_context { ...@@ -55,9 +53,9 @@ struct vidi_context {
int pipe; int pipe;
}; };
static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d) static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
{ {
return container_of(d, struct vidi_context, display); return container_of(e, struct vidi_context, encoder);
} }
static const char fake_edid_info[] = { static const char fake_edid_info[] = {
...@@ -100,7 +98,7 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) ...@@ -100,7 +98,7 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
/* /*
* in case of page flip request, vidi_finish_pageflip function * in case of page flip request, vidi_finish_pageflip function
* will not be called because direct_vblank is true and then * will not be called because direct_vblank is true and then
* that function will be called by crtc_ops->win_commit callback * that function will be called by crtc_ops->update_plane callback
*/ */
schedule_work(&ctx->work); schedule_work(&ctx->work);
...@@ -118,19 +116,14 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) ...@@ -118,19 +116,14 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
ctx->vblank_on = false; ctx->vblank_on = false;
} }
static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) static void vidi_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{ {
struct vidi_context *ctx = crtc->ctx; struct vidi_context *ctx = crtc->ctx;
struct exynos_drm_plane *plane;
if (ctx->suspended) if (ctx->suspended)
return; return;
if (win < 0 || win >= WINDOWS_NR)
return;
plane = &ctx->planes[win];
DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr);
if (ctx->vblank_on) if (ctx->vblank_on)
...@@ -179,7 +172,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = { ...@@ -179,7 +172,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
.disable = vidi_disable, .disable = vidi_disable,
.enable_vblank = vidi_enable_vblank, .enable_vblank = vidi_enable_vblank,
.disable_vblank = vidi_disable_vblank, .disable_vblank = vidi_disable_vblank,
.win_commit = vidi_win_commit, .update_plane = vidi_update_plane,
}; };
static void vidi_fake_vblank_handler(struct work_struct *work) static void vidi_fake_vblank_handler(struct work_struct *work)
...@@ -196,7 +189,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) ...@@ -196,7 +189,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
mutex_lock(&ctx->lock); mutex_lock(&ctx->lock);
if (ctx->direct_vblank) { if (ctx->direct_vblank) {
drm_handle_vblank(ctx->drm_dev, ctx->pipe); drm_crtc_handle_vblank(&ctx->crtc->base);
ctx->direct_vblank = false; ctx->direct_vblank = false;
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
return; return;
...@@ -204,7 +197,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) ...@@ -204,7 +197,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); exynos_drm_crtc_finish_pageflip(ctx->crtc);
} }
static int vidi_show_connection(struct device *dev, static int vidi_show_connection(struct device *dev,
...@@ -259,9 +252,7 @@ static DEVICE_ATTR(connection, 0644, vidi_show_connection, ...@@ -259,9 +252,7 @@ static DEVICE_ATTR(connection, 0644, vidi_show_connection,
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct vidi_context *ctx = NULL; struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
struct drm_encoder *encoder;
struct exynos_drm_display *display;
struct drm_exynos_vidi_connection *vidi = data; struct drm_exynos_vidi_connection *vidi = data;
if (!vidi) { if (!vidi) {
...@@ -274,21 +265,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, ...@@ -274,21 +265,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
return -EINVAL; return -EINVAL;
} }
list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
head) {
display = exynos_drm_get_display(encoder);
if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
ctx = display_to_vidi(display);
break;
}
}
if (!ctx) {
DRM_DEBUG_KMS("not found virtual device type encoder.\n");
return -EINVAL;
}
if (ctx->connected == vidi->connection) { if (ctx->connected == vidi->connection) {
DRM_DEBUG_KMS("same connection request.\n"); DRM_DEBUG_KMS("same connection request.\n");
return -EINVAL; return -EINVAL;
...@@ -381,7 +357,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) ...@@ -381,7 +357,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
{ {
struct vidi_context *ctx = ctx_from_connector(connector); struct vidi_context *ctx = ctx_from_connector(connector);
return ctx->encoder; return &ctx->encoder;
} }
static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
...@@ -389,14 +365,12 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { ...@@ -389,14 +365,12 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
.best_encoder = vidi_best_encoder, .best_encoder = vidi_best_encoder,
}; };
static int vidi_create_connector(struct exynos_drm_display *display, static int vidi_create_connector(struct drm_encoder *encoder)
struct drm_encoder *encoder)
{ {
struct vidi_context *ctx = display_to_vidi(display); struct vidi_context *ctx = encoder_to_vidi(encoder);
struct drm_connector *connector = &ctx->connector; struct drm_connector *connector = &ctx->connector;
int ret; int ret;
ctx->encoder = encoder;
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(ctx->drm_dev, connector, ret = drm_connector_init(ctx->drm_dev, connector,
...@@ -413,19 +387,47 @@ static int vidi_create_connector(struct exynos_drm_display *display, ...@@ -413,19 +387,47 @@ static int vidi_create_connector(struct exynos_drm_display *display,
return 0; return 0;
} }
static bool exynos_vidi_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_vidi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
}
static struct exynos_drm_display_ops vidi_display_ops = { static void exynos_vidi_enable(struct drm_encoder *encoder)
.create_connector = vidi_create_connector, {
}
static void exynos_vidi_disable(struct drm_encoder *encoder)
{
}
static struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
.mode_fixup = exynos_vidi_mode_fixup,
.mode_set = exynos_vidi_mode_set,
.enable = exynos_vidi_enable,
.disable = exynos_vidi_disable,
};
static struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
}; };
static int vidi_bind(struct device *dev, struct device *master, void *data) static int vidi_bind(struct device *dev, struct device *master, void *data)
{ {
struct vidi_context *ctx = dev_get_drvdata(dev); struct vidi_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct drm_encoder *encoder = &ctx->encoder;
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
enum drm_plane_type type; enum drm_plane_type type;
unsigned int zpos; unsigned int zpos;
int ret; int pipe, ret;
vidi_ctx_initialize(ctx, drm_dev); vidi_ctx_initialize(ctx, drm_dev);
...@@ -447,9 +449,24 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -447,9 +449,24 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
} }
ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_VIDI);
if (pipe < 0)
return pipe;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
ret = vidi_create_connector(encoder);
if (ret) { if (ret) {
ctx->crtc->base.funcs->destroy(&ctx->crtc->base); DRM_ERROR("failed to create connector ret = %d\n", ret);
drm_encoder_cleanup(encoder);
return ret; return ret;
} }
...@@ -475,8 +492,6 @@ static int vidi_probe(struct platform_device *pdev) ...@@ -475,8 +492,6 @@ static int vidi_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
ctx->display.ops = &vidi_display_ops;
ctx->default_win = 0; ctx->default_win = 0;
ctx->pdev = pdev; ctx->pdev = pdev;
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment