You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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
...
This commit is contained in:
@@ -3,10 +3,9 @@
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
|
||||
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
|
||||
exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
|
||||
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
|
||||
exynos_drm_plane.o exynos_drm_dmabuf.o
|
||||
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \
|
||||
exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \
|
||||
exynos_drm_plane.o
|
||||
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||
|
||||
@@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
|
||||
#define OFFSIZE(x) (((x) & 0x3fff) << 14)
|
||||
#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;
|
||||
|
||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||
val &= ~WINCONx_BPPMODE_MASK;
|
||||
|
||||
switch (plane->pixel_format) {
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_XRGB1555:
|
||||
val |= WINCONx_BPPMODE_16BPP_I1555;
|
||||
val |= WINCONx_HAWSWP_F;
|
||||
@@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
|
||||
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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
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_8WORD;
|
||||
}
|
||||
@@ -219,17 +219,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
|
||||
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 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;
|
||||
|
||||
if (win < 0 || win >= WINDOWS_NR)
|
||||
return;
|
||||
|
||||
plane = &ctx->planes[win];
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
@@ -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);
|
||||
writel(val, ctx->addr + DECON_VIDOSDxA(win));
|
||||
|
||||
val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) |
|
||||
COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1);
|
||||
val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) |
|
||||
COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
|
||||
writel(val, ctx->addr + DECON_VIDOSDxB(win));
|
||||
|
||||
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)
|
||||
|
||||
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));
|
||||
|
||||
val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3))
|
||||
| PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3));
|
||||
val = OFFSIZE(pitch - plane->crtc_w * bpp)
|
||||
| PAGEWIDTH(plane->crtc_w * bpp);
|
||||
writel(val, ctx->addr + DECON_VIDW0xADD2(win));
|
||||
|
||||
decon_win_set_pixfmt(ctx, win);
|
||||
decon_win_set_pixfmt(ctx, win, state->fb);
|
||||
|
||||
/* window enable */
|
||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||
@@ -277,17 +276,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
|
||||
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 exynos_drm_plane *plane;
|
||||
unsigned int win = plane->zpos;
|
||||
u32 val;
|
||||
|
||||
if (win < 0 || win >= WINDOWS_NR)
|
||||
return;
|
||||
|
||||
plane = &ctx->planes[win];
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
@@ -378,7 +373,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
||||
* a destroyed buffer later.
|
||||
*/
|
||||
for (i = 0; i < WINDOWS_NR; i++)
|
||||
decon_win_disable(crtc, i);
|
||||
decon_disable_plane(crtc, &ctx->planes[i]);
|
||||
|
||||
decon_swreset(ctx);
|
||||
|
||||
@@ -407,7 +402,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
|
||||
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)
|
||||
@@ -460,10 +455,9 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
.disable_vblank = decon_disable_vblank,
|
||||
.commit = decon_commit,
|
||||
.win_commit = decon_win_commit,
|
||||
.win_disable = decon_win_disable,
|
||||
.update_plane = decon_update_plane,
|
||||
.disable_plane = decon_disable_plane,
|
||||
.te_handler = decon_te_irq_handler,
|
||||
.clear_channels = decon_clear_channels,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
goto err;
|
||||
|
||||
@@ -514,8 +510,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
|
||||
decon_disable(ctx->crtc);
|
||||
|
||||
/* 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 = {
|
||||
@@ -533,7 +528,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
|
||||
|
||||
val = readl(ctx->addr + DECON_VIDINTCON1);
|
||||
if (val & VIDINTCON1_INTFRMPEND) {
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
drm_crtc_handle_vblank(&ctx->crtc->base);
|
||||
|
||||
/* clear */
|
||||
writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
|
||||
@@ -553,7 +548,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
|
||||
|
||||
val = readl(ctx->addr + DECON_VIDINTCON1);
|
||||
if (val & VIDINTCON1_INTFRMDONEPEND) {
|
||||
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
|
||||
exynos_drm_crtc_finish_pageflip(ctx->crtc);
|
||||
|
||||
/* clear */
|
||||
writel(VIDINTCON1_INTFRMDONEPEND,
|
||||
|
||||
@@ -61,7 +61,7 @@ struct decon_context {
|
||||
atomic_t wait_vsync_event;
|
||||
|
||||
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[] = {
|
||||
@@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx,
|
||||
ctx->drm_dev = drm_dev;
|
||||
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)
|
||||
priv->pipe--;
|
||||
|
||||
@@ -136,8 +138,7 @@ static int decon_ctx_initialize(struct decon_context *ctx,
|
||||
static void decon_ctx_remove(struct decon_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);
|
||||
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
|
||||
}
|
||||
|
||||
static u32 decon_calc_clkdiv(struct decon_context *ctx,
|
||||
@@ -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;
|
||||
int padding;
|
||||
|
||||
val = readl(ctx->regs + WINCON(win));
|
||||
val &= ~WINCONx_BPPMODE_MASK;
|
||||
|
||||
switch (plane->pixel_format) {
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_RGB565:
|
||||
val |= WINCONx_BPPMODE_16BPP_565;
|
||||
val |= WINCONx_BURSTLEN_16WORD;
|
||||
@@ -329,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
|
||||
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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
|
||||
if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
|
||||
padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width;
|
||||
if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
|
||||
val &= ~WINCONx_BURSTLEN_MASK;
|
||||
val |= WINCONx_BURSTLEN_8WORD;
|
||||
}
|
||||
@@ -382,23 +383,19 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
|
||||
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 drm_display_mode *mode = &crtc->base.state->adjusted_mode;
|
||||
struct exynos_drm_plane *plane;
|
||||
struct drm_plane_state *state = plane->base.state;
|
||||
int padding;
|
||||
unsigned long val, alpha;
|
||||
unsigned int last_x;
|
||||
unsigned int last_y;
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
if (win < 0 || win >= WINDOWS_NR)
|
||||
return;
|
||||
|
||||
plane = &ctx->planes[win];
|
||||
unsigned int win = plane->zpos;
|
||||
unsigned int bpp = state->fb->bits_per_pixel >> 3;
|
||||
unsigned int pitch = state->fb->pitches[0];
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
@@ -420,11 +417,11 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
|
||||
val = (unsigned long)plane->dma_addr[0];
|
||||
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 */
|
||||
writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win));
|
||||
writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
|
||||
writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
|
||||
writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win));
|
||||
|
||||
/* offset from the start of the buffer to read */
|
||||
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)
|
||||
DRM_DEBUG_KMS("start addr = 0x%lx\n",
|
||||
(unsigned long)val);
|
||||
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
|
||||
plane->crtc_width, plane->crtc_height);
|
||||
plane->crtc_w, plane->crtc_h);
|
||||
|
||||
/*
|
||||
* OSD position.
|
||||
* In case the window layout goes of LCD layout, DECON fails.
|
||||
*/
|
||||
if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay)
|
||||
plane->crtc_x = mode->hdisplay - plane->crtc_width;
|
||||
if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay)
|
||||
plane->crtc_y = mode->vdisplay - plane->crtc_height;
|
||||
if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay)
|
||||
plane->crtc_x = mode->hdisplay - plane->crtc_w;
|
||||
if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay)
|
||||
plane->crtc_y = mode->vdisplay - plane->crtc_h;
|
||||
|
||||
val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
|
||||
VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
|
||||
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)
|
||||
last_x--;
|
||||
last_y = plane->crtc_y + plane->crtc_height;
|
||||
last_y = plane->crtc_y + plane->crtc_h;
|
||||
if (last_y)
|
||||
last_y--;
|
||||
|
||||
@@ -475,7 +472,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int 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. */
|
||||
if (win != 0)
|
||||
@@ -495,17 +492,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
|
||||
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 exynos_drm_plane *plane;
|
||||
unsigned int win = plane->zpos;
|
||||
u32 val;
|
||||
|
||||
if (win < 0 || win >= WINDOWS_NR)
|
||||
return;
|
||||
|
||||
plane = &ctx->planes[win];
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
@@ -601,7 +594,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
||||
* a destroyed buffer later.
|
||||
*/
|
||||
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->eclk);
|
||||
@@ -621,9 +614,8 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
.disable_vblank = decon_disable_vblank,
|
||||
.wait_for_vblank = decon_wait_for_vblank,
|
||||
.win_commit = decon_win_commit,
|
||||
.win_disable = decon_win_disable,
|
||||
.clear_channels = decon_clear_channels,
|
||||
.update_plane = decon_update_plane,
|
||||
.disable_plane = decon_disable_plane,
|
||||
};
|
||||
|
||||
|
||||
@@ -643,8 +635,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
|
||||
goto out;
|
||||
|
||||
if (!ctx->i80_if) {
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
|
||||
drm_crtc_handle_vblank(&ctx->crtc->base);
|
||||
exynos_drm_crtc_finish_pageflip(ctx->crtc);
|
||||
|
||||
/* set wait vsync event to zero and wake up queue. */
|
||||
if (atomic_read(&ctx->wait_vsync_event)) {
|
||||
@@ -689,8 +681,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
||||
return PTR_ERR(ctx->crtc);
|
||||
}
|
||||
|
||||
if (ctx->display)
|
||||
exynos_drm_create_enc_conn(drm_dev, ctx->display);
|
||||
if (ctx->encoder)
|
||||
exynos_dpi_bind(drm_dev, ctx->encoder);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -703,8 +695,8 @@ static void decon_unbind(struct device *dev, struct device *master,
|
||||
|
||||
decon_disable(ctx->crtc);
|
||||
|
||||
if (ctx->display)
|
||||
exynos_dpi_remove(ctx->display);
|
||||
if (ctx->encoder)
|
||||
exynos_dpi_remove(ctx->encoder);
|
||||
|
||||
decon_ctx_remove(ctx);
|
||||
}
|
||||
@@ -789,9 +781,9 @@ static int decon_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ctx->display = exynos_dpi_probe(dev);
|
||||
if (IS_ERR(ctx->display)) {
|
||||
ret = PTR_ERR(ctx->display);
|
||||
ctx->encoder = exynos_dpi_probe(dev);
|
||||
if (IS_ERR(ctx->encoder)) {
|
||||
ret = PTR_ERR(ctx->encoder);
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,19 +32,20 @@
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "exynos_dp_core.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
|
||||
#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \
|
||||
connector)
|
||||
|
||||
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 *
|
||||
display_to_dp(struct exynos_drm_display *d)
|
||||
static inline struct exynos_dp_device *encoder_to_dp(
|
||||
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 {
|
||||
@@ -795,9 +796,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp)
|
||||
/* Configure video slave mode */
|
||||
exynos_dp_enable_video_master(dp, 0);
|
||||
|
||||
/* Enable video */
|
||||
exynos_dp_start_video(dp);
|
||||
|
||||
timeout_loop = 0;
|
||||
|
||||
for (;;) {
|
||||
@@ -891,9 +889,9 @@ static void exynos_dp_hotplug(struct work_struct *work)
|
||||
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;
|
||||
|
||||
/* Keep the panel disabled while we configure video */
|
||||
@@ -938,6 +936,9 @@ static void exynos_dp_commit(struct exynos_drm_display *display)
|
||||
if (drm_panel_enable(dp->panel))
|
||||
DRM_ERROR("failed to enable the panel\n");
|
||||
}
|
||||
|
||||
/* Enable video */
|
||||
exynos_dp_start_video(dp);
|
||||
}
|
||||
|
||||
static enum drm_connector_status exynos_dp_detect(
|
||||
@@ -994,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder(
|
||||
{
|
||||
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 = {
|
||||
@@ -1019,15 +1020,12 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_dp_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
static int exynos_dp_create_connector(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;
|
||||
int ret;
|
||||
|
||||
dp->encoder = encoder;
|
||||
|
||||
/* Pre-empt DP connector creation if there's a bridge */
|
||||
if (dp->bridge) {
|
||||
ret = exynos_drm_attach_lcd_bridge(dp, encoder);
|
||||
@@ -1054,20 +1052,22 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
|
||||
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)
|
||||
phy_power_on(dp->phy);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (dp->dpms_mode == DRM_MODE_DPMS_ON)
|
||||
@@ -1084,14 +1084,17 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
|
||||
crtc->ops->clock_enable(dp_to_crtc(dp), true);
|
||||
|
||||
clk_prepare_enable(dp->clock);
|
||||
exynos_dp_phy_init(dp);
|
||||
phy_power_on(dp->phy);
|
||||
exynos_dp_init_dp(dp);
|
||||
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);
|
||||
|
||||
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
|
||||
@@ -1106,7 +1109,7 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
|
||||
|
||||
disable_irq(dp->irq);
|
||||
flush_work(&dp->hotplug_work);
|
||||
exynos_dp_phy_exit(dp);
|
||||
phy_power_off(dp->phy);
|
||||
clk_disable_unprepare(dp->clock);
|
||||
|
||||
if (crtc->ops->clock_enable)
|
||||
@@ -1116,31 +1119,19 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
|
||||
if (drm_panel_unprepare(dp->panel))
|
||||
DRM_ERROR("failed to turnoff the panel\n");
|
||||
}
|
||||
|
||||
dp->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
}
|
||||
|
||||
static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
|
||||
.mode_fixup = exynos_dp_mode_fixup,
|
||||
.mode_set = exynos_dp_mode_set,
|
||||
.enable = exynos_dp_enable,
|
||||
.disable = exynos_dp_disable,
|
||||
};
|
||||
|
||||
switch (mode) {
|
||||
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 = {
|
||||
.create_connector = exynos_dp_create_connector,
|
||||
.dpms = exynos_dp_dpms,
|
||||
.commit = exynos_dp_commit,
|
||||
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)
|
||||
@@ -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 platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct drm_encoder *encoder = &dp->encoder;
|
||||
struct resource *res;
|
||||
unsigned int irq_flags;
|
||||
int ret = 0;
|
||||
int pipe, ret = 0;
|
||||
|
||||
dp->dev = &pdev->dev;
|
||||
dp->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
@@ -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);
|
||||
|
||||
exynos_dp_phy_init(dp);
|
||||
phy_power_on(dp->phy);
|
||||
|
||||
exynos_dp_init_dp(dp);
|
||||
|
||||
@@ -1311,7 +1303,28 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
||||
|
||||
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,
|
||||
@@ -1319,7 +1332,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
|
||||
{
|
||||
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 = {
|
||||
@@ -1338,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
||||
if (!dp)
|
||||
return -ENOMEM;
|
||||
|
||||
dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
dp->display.ops = &exynos_dp_display_ops;
|
||||
platform_set_drvdata(pdev, dp);
|
||||
|
||||
panel_node = of_parse_phandle(dev->of_node, "panel", 0);
|
||||
@@ -1377,7 +1388,7 @@ static int exynos_dp_suspend(struct device *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;
|
||||
}
|
||||
|
||||
@@ -1385,7 +1396,7 @@ static int exynos_dp_resume(struct device *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;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -147,11 +147,10 @@ struct link_train {
|
||||
};
|
||||
|
||||
struct exynos_dp_device {
|
||||
struct exynos_drm_display display;
|
||||
struct drm_encoder encoder;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
struct clk *clock;
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/* 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);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* 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 @@
|
||||
#include <drm/drmP.h>
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
#include "exynos_drm_fbdev.h"
|
||||
|
||||
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)
|
||||
{
|
||||
if (!subdrv)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
#include "exynos_drm_plane.h"
|
||||
|
||||
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)
|
||||
return -EPERM;
|
||||
|
||||
if (exynos_crtc->ops->enable_vblank)
|
||||
exynos_crtc->ops->enable_vblank(exynos_crtc);
|
||||
return exynos_crtc->ops->enable_vblank(exynos_crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -195,24 +194,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
|
||||
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 *drm_crtc = dev_priv->crtc[pipe];
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
|
||||
struct drm_crtc *crtc = &exynos_crtc->base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
if (exynos_crtc->event) {
|
||||
|
||||
drm_send_vblank_event(dev, -1, exynos_crtc->event);
|
||||
drm_vblank_put(dev, pipe);
|
||||
drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
wake_up(&exynos_crtc->pending_flip_queue);
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -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,
|
||||
unsigned int out_type)
|
||||
enum exynos_drm_output_type out_type)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
||||
void *context);
|
||||
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_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);
|
||||
|
||||
/* 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,
|
||||
unsigned int out_type);
|
||||
enum exynos_drm_output_type out_type);
|
||||
|
||||
/*
|
||||
* This function calls the crtc device(manager)'s te_handler() callback
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
/* 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);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/* 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 @@
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
|
||||
struct exynos_dpi {
|
||||
struct exynos_drm_display display;
|
||||
struct drm_encoder encoder;
|
||||
struct device *dev;
|
||||
struct device_node *panel_node;
|
||||
|
||||
struct drm_panel *panel;
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
struct videomode *vm;
|
||||
int dpms_mode;
|
||||
};
|
||||
|
||||
#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
|
||||
@@ -99,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *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 = {
|
||||
@@ -107,15 +105,12 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
|
||||
.best_encoder = exynos_dpi_best_encoder,
|
||||
};
|
||||
|
||||
static int exynos_dpi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
static int exynos_dpi_create_connector(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;
|
||||
int ret;
|
||||
|
||||
ctx->encoder = encoder;
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
ret = drm_connector_init(encoder->dev, connector,
|
||||
@@ -133,46 +128,48 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display,
|
||||
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) {
|
||||
drm_panel_prepare(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) {
|
||||
drm_panel_disable(ctx->panel);
|
||||
drm_panel_unprepare(ctx->panel);
|
||||
}
|
||||
}
|
||||
|
||||
static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct exynos_dpi *ctx = display_to_dpi(display);
|
||||
static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
|
||||
.mode_fixup = exynos_dpi_mode_fixup,
|
||||
.mode_set = exynos_dpi_mode_set,
|
||||
.enable = exynos_dpi_enable,
|
||||
.disable = exynos_dpi_disable,
|
||||
};
|
||||
|
||||
switch (mode) {
|
||||
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 = {
|
||||
.create_connector = exynos_dpi_create_connector,
|
||||
.dpms = exynos_dpi_dpms
|
||||
static struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
/* 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)
|
||||
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;
|
||||
int ret;
|
||||
@@ -308,10 +332,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
|
||||
if (!ctx)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
ctx->display.ops = &exynos_dpi_display_ops;
|
||||
ctx->dev = dev;
|
||||
ctx->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
ret = exynos_dpi_parse_dt(ctx);
|
||||
if (ret < 0) {
|
||||
@@ -325,14 +346,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
|
||||
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)
|
||||
drm_panel_detach(ctx->panel);
|
||||
|
||||
@@ -21,13 +21,11 @@
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
#include "exynos_drm_fbdev.h"
|
||||
#include "exynos_drm_fb.h"
|
||||
#include "exynos_drm_gem.h"
|
||||
#include "exynos_drm_plane.h"
|
||||
#include "exynos_drm_vidi.h"
|
||||
#include "exynos_drm_dmabuf.h"
|
||||
#include "exynos_drm_g2d.h"
|
||||
#include "exynos_drm_ipp.h"
|
||||
#include "exynos_drm_iommu.h"
|
||||
@@ -41,7 +39,9 @@
|
||||
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
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);
|
||||
if (!private)
|
||||
@@ -67,7 +67,13 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
||||
exynos_drm_mode_config_init(dev);
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -297,8 +303,12 @@ static struct drm_driver exynos_drm_driver = {
|
||||
.dumb_destroy = drm_gem_dumb_destroy,
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_export = exynos_dmabuf_prime_export,
|
||||
.gem_prime_import = exynos_dmabuf_prime_import,
|
||||
.gem_prime_export = drm_gem_prime_export,
|
||||
.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,
|
||||
.num_ioctls = ARRAY_SIZE(exynos_ioctls),
|
||||
.fops = &exynos_drm_driver_fops,
|
||||
@@ -345,9 +355,6 @@ static struct platform_driver exynos_drm_platform_driver;
|
||||
* because connector requires pipe number of its crtc during initialization.
|
||||
*/
|
||||
static struct platform_driver *const exynos_drm_kms_drivers[] = {
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
&vidi_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
&fimd_driver,
|
||||
#endif
|
||||
@@ -370,6 +377,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
|
||||
&mixer_driver,
|
||||
&hdmi_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
&vidi_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
|
||||
|
||||
@@ -44,23 +44,14 @@ enum exynos_drm_output_type {
|
||||
* - the unit is screen coordinates.
|
||||
* @src_y: offset y on a framebuffer to be displayed.
|
||||
* - the unit is screen coordinates.
|
||||
* @src_width: width of a partial image to be displayed from framebuffer.
|
||||
* @src_height: height of a partial image to be displayed from framebuffer.
|
||||
* @fb_width: width of a framebuffer.
|
||||
* @fb_height: height of a framebuffer.
|
||||
* @src_w: width of a partial image to be displayed from framebuffer.
|
||||
* @src_h: height of a partial image to be displayed from framebuffer.
|
||||
* @crtc_x: offset x on hardware screen.
|
||||
* @crtc_y: offset y on hardware screen.
|
||||
* @crtc_width: window width to be displayed (hardware screen).
|
||||
* @crtc_height: window height to be displayed (hardware screen).
|
||||
* @mode_width: width of screen mode.
|
||||
* @mode_height: height of screen mode.
|
||||
* @crtc_w: window width to be displayed (hardware screen).
|
||||
* @crtc_h: window height to be displayed (hardware screen).
|
||||
* @h_ratio: horizontal 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
|
||||
* allocated for a overlay.
|
||||
* @zpos: order of overlay layer(z position).
|
||||
@@ -73,75 +64,18 @@ struct exynos_drm_plane {
|
||||
struct drm_plane base;
|
||||
unsigned int src_x;
|
||||
unsigned int src_y;
|
||||
unsigned int src_width;
|
||||
unsigned int src_height;
|
||||
unsigned int fb_width;
|
||||
unsigned int fb_height;
|
||||
unsigned int src_w;
|
||||
unsigned int src_h;
|
||||
unsigned int crtc_x;
|
||||
unsigned int crtc_y;
|
||||
unsigned int crtc_width;
|
||||
unsigned int crtc_height;
|
||||
unsigned int mode_width;
|
||||
unsigned int mode_height;
|
||||
unsigned int crtc_w;
|
||||
unsigned int crtc_h;
|
||||
unsigned int h_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];
|
||||
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
|
||||
*
|
||||
@@ -153,8 +87,8 @@ struct exynos_drm_display {
|
||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||
* @wait_for_vblank: wait for vblank interrupt to make sure that
|
||||
* hardware overlay is updated.
|
||||
* @win_commit: apply hardware specific overlay data to registers.
|
||||
* @win_disable: disable hardware specific overlay.
|
||||
* @update_plane: apply hardware specific overlay data to registers.
|
||||
* @disable_plane: disable hardware specific overlay.
|
||||
* @te_handler: trigger to transfer video image at the tearing effect
|
||||
* synchronization signal if there is a page flip request.
|
||||
* @clock_enable: optional function enabling/disabling display domain clock,
|
||||
@@ -173,11 +107,12 @@ struct exynos_drm_crtc_ops {
|
||||
int (*enable_vblank)(struct exynos_drm_crtc *crtc);
|
||||
void (*disable_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 (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos);
|
||||
void (*update_plane)(struct exynos_drm_crtc *crtc,
|
||||
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 (*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);
|
||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DPI
|
||||
struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
|
||||
int exynos_dpi_remove(struct exynos_drm_display *display);
|
||||
struct drm_encoder *exynos_dpi_probe(struct device *dev);
|
||||
int exynos_dpi_remove(struct drm_encoder *encoder);
|
||||
int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder);
|
||||
#else
|
||||
static inline struct exynos_drm_display *
|
||||
static inline struct drm_encoder *
|
||||
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;
|
||||
}
|
||||
#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 exynos5433_decon_driver;
|
||||
|
||||
@@ -259,7 +259,7 @@ struct exynos_dsi_driver_data {
|
||||
};
|
||||
|
||||
struct exynos_dsi {
|
||||
struct exynos_drm_display display;
|
||||
struct drm_encoder encoder;
|
||||
struct mipi_dsi_host dsi_host;
|
||||
struct drm_connector connector;
|
||||
struct device_node *panel_node;
|
||||
@@ -295,9 +295,9 @@ struct exynos_dsi {
|
||||
#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)
|
||||
|
||||
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 {
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
exynos_drm_crtc_te_handler(encoder->crtc);
|
||||
@@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
|
||||
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;
|
||||
|
||||
if (dsi->state & DSIM_STATE_ENABLED)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
ret = exynos_dsi_poweron(dsi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return;
|
||||
|
||||
dsi->state |= DSIM_STATE_ENABLED;
|
||||
|
||||
@@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
|
||||
if (ret < 0) {
|
||||
dsi->state &= ~DSIM_STATE_ENABLED;
|
||||
exynos_dsi_poweroff(dsi);
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
exynos_dsi_set_display_mode(dsi);
|
||||
@@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
|
||||
exynos_dsi_set_display_enable(dsi, false);
|
||||
drm_panel_unprepare(dsi->panel);
|
||||
exynos_dsi_poweroff(dsi);
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
@@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *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
|
||||
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)
|
||||
drm_panel_attach(dsi->panel, &dsi->connector);
|
||||
} else if (!dsi->panel_node) {
|
||||
struct exynos_drm_display *display;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
display = platform_get_drvdata(to_platform_device(dsi->dev));
|
||||
exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
|
||||
encoder = platform_get_drvdata(to_platform_device(dsi->dev));
|
||||
exynos_dsi_disable(encoder);
|
||||
drm_panel_detach(dsi->panel);
|
||||
dsi->panel = NULL;
|
||||
}
|
||||
@@ -1647,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *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 = {
|
||||
@@ -1655,10 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
|
||||
.best_encoder = exynos_dsi_best_encoder,
|
||||
};
|
||||
|
||||
static int exynos_dsi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
static int exynos_dsi_create_connector(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;
|
||||
int ret;
|
||||
|
||||
@@ -1679,26 +1659,40 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_dsi_mode_set(struct exynos_drm_display *display,
|
||||
struct drm_display_mode *mode)
|
||||
static bool exynos_dsi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct videomode *vm = &dsi->vm;
|
||||
|
||||
vm->hactive = mode->hdisplay;
|
||||
vm->vactive = mode->vdisplay;
|
||||
vm->vfront_porch = mode->vsync_start - mode->vdisplay;
|
||||
vm->vback_porch = mode->vtotal - mode->vsync_end;
|
||||
vm->vsync_len = mode->vsync_end - mode->vsync_start;
|
||||
vm->hfront_porch = mode->hsync_start - mode->hdisplay;
|
||||
vm->hback_porch = mode->htotal - mode->hsync_end;
|
||||
vm->hsync_len = mode->hsync_end - mode->hsync_start;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct exynos_drm_display_ops exynos_dsi_display_ops = {
|
||||
.create_connector = exynos_dsi_create_connector,
|
||||
static void exynos_dsi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
|
||||
struct videomode *vm = &dsi->vm;
|
||||
struct drm_display_mode *m = adjusted_mode;
|
||||
|
||||
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 drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
|
||||
.mode_fixup = exynos_dsi_mode_fixup,
|
||||
.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);
|
||||
@@ -1821,22 +1815,35 @@ end:
|
||||
static int exynos_dsi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_drm_display *display = dev_get_drvdata(dev);
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct drm_encoder *encoder = dev_get_drvdata(dev);
|
||||
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct drm_bridge *bridge;
|
||||
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) {
|
||||
DRM_ERROR("Encoder create [%d] failed with %d\n",
|
||||
display->type, ret);
|
||||
DRM_ERROR("failed to create connector ret = %d\n", ret);
|
||||
drm_encoder_cleanup(encoder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bridge = of_drm_find_bridge(dsi->bridge_node);
|
||||
if (bridge) {
|
||||
display->encoder->bridge = bridge;
|
||||
drm_bridge_attach(drm_dev, bridge);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_drm_display *display = dev_get_drvdata(dev);
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct drm_encoder *encoder = dev_get_drvdata(dev);
|
||||
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);
|
||||
}
|
||||
@@ -1870,9 +1877,6 @@ static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
if (!dsi)
|
||||
return -ENOMEM;
|
||||
|
||||
dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
dsi->display.ops = &exynos_dsi_display_ops;
|
||||
|
||||
/* To be checked as invalid one */
|
||||
dsi->te_gpio = -ENOENT;
|
||||
|
||||
@@ -1948,7 +1952,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, &dsi->display);
|
||||
platform_set_drvdata(pdev, &dsi->encoder);
|
||||
|
||||
return component_add(dev, &exynos_dsi_component_ops);
|
||||
}
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* 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 @@ err_free:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
|
||||
int index)
|
||||
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
|
||||
int index)
|
||||
{
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
buffer = exynos_fb->exynos_gem_obj[index]->buffer;
|
||||
if (!buffer)
|
||||
obj = exynos_fb->exynos_gem_obj[index];
|
||||
if (!obj)
|
||||
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)
|
||||
|
||||
@@ -19,8 +19,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
|
||||
/* get memory information of a drm framebuffer */
|
||||
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
|
||||
/* get gem object of a drm framebuffer */
|
||||
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
|
||||
int index);
|
||||
|
||||
void exynos_drm_mode_config_init(struct drm_device *dev);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user