- Rework vblank handling
   . This patch series adds frame counter callback and removes
     unnecessary pipe relevnt fields and simplifies event handling.
 - clean up and fix up sw-trigger relevant code
   . This patch series moves TE relevant code from Panel and HDMI
     to DECON driver to fix a race between interrupt handlers and
     DECON disable, and to fix timeout issue at wait-for-vblank.
   . It removes unnecessary flags and check code specific to Exynos driver.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZNPyAAAoJEFc4NIkMQxK4haQP/jqsPKffmy54xOmTssR587cA
 e6pCCJVDnRXmCSf504pMpHJNPq+7k5dCbv5r4eEqyFmJd9g4+B94+/4MOXSoy/bS
 6GMcWFRPxmmfdCZSUJKBQS+OoGIT0S+AFLkME+PouIXSDX9uE59cQwMeRzP0oflB
 5wUrTPFIYygt6hQp1JH+ofQUEj5d/gu7O7xJWe4MPZ2Xd+j7K97J4wpVKykUiAG0
 BS+ELCUJhSFO/LZMb9/sPCdhhIjQCQ61+8H0Ep0ciRDjIFb31jmLrMSvPI+c7C2r
 EEEkvFKVLoMJzI4+sOuD7O56mOiGZW2RQXXZXTTPVPv+2EeREv4ATUb0fd4Ep2SY
 +4uKbKJFgkaIN8Rq4P43TeznzHJpM671AJoOhb4KiJqC97IKZ7w779WP/oEkyqeJ
 ZbIV9neG+W+185oC9Lwxcuw4HO4Ub7LF2w/AuwlKTS0v7+673QUpCrcYkJluZIj2
 M6bcQiv0txouzUbnnuIf/cU20JAy1FieqjEsPFyaY+CJdfJSiYsGc++ZNl7DH6xH
 AEUu/XYis+TyzfWkI7HcM2aYihhBjQMkPNXwBW9BcFRAwplhpreLJBO5Q6DwhJDs
 8uVlsZQdV/1SxxMkT0JnqYEWv5lUvecGe4eGVeopKsms4DcDytEfEYxvrJVtRr5S
 hp8o4iNfvIGFSbIXvN7V
 =rgX/
 -----END PGP SIGNATURE-----

Merge tag 'exynos-drm-next-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

Summary:
- Rework vblank handling
  . This patch series adds frame counter callback and removes
    unnecessary pipe relevnt fields and simplifies event handling.
- clean up and fix up sw-trigger relevant code
  . This patch series moves TE relevant code from Panel and HDMI
    to DECON driver to fix a race between interrupt handlers and
    DECON disable, and to fix timeout issue at wait-for-vblank.
  . It removes unnecessary flags and check code specific to Exynos driver.

* tag 'exynos-drm-next-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (27 commits)
  drm/exynos/decon5433: remove useless check
  drm/exynos/decon5433: kill BIT_SUSPENDED flag
  drm/exynos/decon5433: kill BIT_WIN_UPDATED flag
  drm/exynos/decon5433: kill BIT_CLKS_ENABLED flag
  drm/exynos/decon5433: kill BIT_IRQS_ENABLED flag
  drm/exynos/decon5433: move TE handling to DECON
  dt-bindings: exynos5433-decon: add TE interrupt binding
  dt-bindings: exynos5433-decon: fix interrupts bindings
  drm/exynos/decon5433: always do sw-trigger when vblanks enabled
  drm/exynos: mixer: document YCbCr magic numbers
  drm/exynos: mixer: simplify mixer_cfg_rgb_fmt()
  drm/exynos/dsi: fix bridge_node DT parsing
  drm/exynos/hdmi: fix pipeline disable order
  drm/exynos/decon5433: simplify shadow protect code
  drm/exynos/decon5433: kill BIT_IRQS_ENABLED
  drm/exynos/decon5433: kill DECON_UPDATE workaround
  drm/exynos: kill mode_set_nofb callback
  drm/exynos: kill pipe field from drivers contexts
  drm/exynos: set plane possible_crtcs in exynos_plane_init
  drm/exynos: kill exynos_drm_private::pipe
  ...
This commit is contained in:
Dave Airlie 2017-06-06 16:54:27 +10:00
commit c9f0726ff3
15 changed files with 195 additions and 302 deletions

View File

@ -8,12 +8,13 @@ Required properties:
- compatible: value should be one of: - compatible: value should be one of:
"samsung,exynos5433-decon", "samsung,exynos5433-decon-tv"; "samsung,exynos5433-decon", "samsung,exynos5433-decon-tv";
- reg: physical base address and length of the DECON registers set. - reg: physical base address and length of the DECON registers set.
- interrupts: should contain a list of all DECON IP block interrupts in the - interrupt-names: should contain the interrupt names depending on mode of work:
order: VSYNC, LCD_SYSTEM. The interrupt specifier format video mode: "vsync",
depends on the interrupt controller used. command mode: "lcd_sys",
- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys" command mode with software trigger: "lcd_sys", "te".
in the same order as they were listed in the interrupts - interrupts or interrupts-extended: list of interrupt specifiers corresponding
property. to names privided in interrupt-names, as described in
interrupt-controller/interrupts.txt
- clocks: must include clock specifiers corresponding to entries in the - clocks: must include clock specifiers corresponding to entries in the
clock-names property. clock-names property.
- clock-names: list of clock names sorted in the same order as the clocks - clock-names: list of clock names sorted in the same order as the clocks

View File

@ -47,14 +47,6 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk", "sclk_decon_eclk",
}; };
enum decon_flag_bits {
BIT_CLKS_ENABLED,
BIT_IRQS_ENABLED,
BIT_WIN_UPDATED,
BIT_SUSPENDED,
BIT_REQUEST_UPDATE
};
struct decon_context { struct decon_context {
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
@ -64,8 +56,8 @@ struct decon_context {
void __iomem *addr; void __iomem *addr;
struct regmap *sysreg; struct regmap *sysreg;
struct clk *clks[ARRAY_SIZE(decon_clks_name)]; struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe; unsigned int irq;
unsigned long flags; unsigned int te_irq;
unsigned long out_type; unsigned long out_type;
int first_win; int first_win;
spinlock_t vblank_lock; spinlock_t vblank_lock;
@ -97,10 +89,6 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
u32 val; u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return -EPERM;
if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN; val = VIDINTCON0_INTEN;
if (ctx->out_type & IFTYPE_I80) if (ctx->out_type & IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE; val |= VIDINTCON0_FRAMEDONE;
@ -108,7 +96,10 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP;
writel(val, ctx->addr + DECON_VIDINTCON0); writel(val, ctx->addr + DECON_VIDINTCON0);
}
enable_irq(ctx->irq);
if (!(ctx->out_type & I80_HW_TRG))
enable_irq(ctx->te_irq);
return 0; return 0;
} }
@ -117,10 +108,10 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (!(ctx->out_type & I80_HW_TRG))
return; disable_irq_nosync(ctx->te_irq);
disable_irq_nosync(ctx->irq);
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
writel(0, ctx->addr + DECON_VIDINTCON0); writel(0, ctx->addr + DECON_VIDINTCON0);
} }
@ -166,6 +157,13 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
return frm; return frm;
} }
static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
return decon_get_frame_count(ctx, false);
}
static void decon_setup_trigger(struct decon_context *ctx) static void decon_setup_trigger(struct decon_context *ctx)
{ {
if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))) if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)))
@ -193,9 +191,6 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
bool interlaced = false; bool interlaced = false;
u32 val; u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
if (ctx->out_type & IFTYPE_HDMI) { if (ctx->out_type & IFTYPE_HDMI) {
m->crtc_hsync_start = m->crtc_hdisplay + 10; m->crtc_hsync_start = m->crtc_hdisplay + 10;
m->crtc_hsync_end = m->crtc_htotal - 92; m->crtc_hsync_end = m->crtc_htotal - 92;
@ -309,23 +304,17 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
writel(val, ctx->addr + DECON_WINCONx(win)); writel(val, ctx->addr + DECON_WINCONx(win));
} }
static void decon_shadow_protect_win(struct decon_context *ctx, int win, static void decon_shadow_protect(struct decon_context *ctx, bool protect)
bool protect)
{ {
decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_PROTECT_MASK,
protect ? ~0 : 0); protect ? ~0 : 0);
} }
static void decon_atomic_begin(struct exynos_drm_crtc *crtc) static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
int i;
if (test_bit(BIT_SUSPENDED, &ctx->flags)) decon_shadow_protect(ctx, true);
return;
for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_shadow_protect_win(ctx, i, true);
} }
#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s))
@ -345,9 +334,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0);
u32 val; u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) { if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) {
val = COORDINATE_X(state->crtc.x) | val = COORDINATE_X(state->crtc.x) |
COORDINATE_Y(state->crtc.y / 2); COORDINATE_Y(state->crtc.y / 2);
@ -390,7 +376,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
/* window enable */ /* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
} }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, static void decon_disable_plane(struct exynos_drm_crtc *crtc,
@ -399,33 +384,20 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
unsigned int win = plane->index; unsigned int win = plane->index;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
} }
static void decon_atomic_flush(struct exynos_drm_crtc *crtc) static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
unsigned long flags; unsigned long flags;
int i;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
spin_lock_irqsave(&ctx->vblank_lock, flags); spin_lock_irqsave(&ctx->vblank_lock, flags);
for (i = ctx->first_win; i < WINDOWS_NR; i++) decon_shadow_protect(ctx, false);
decon_shadow_protect_win(ctx, i, false);
if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags))
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
if (ctx->out_type & IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags);
ctx->frame_id = decon_get_frame_count(ctx, true); ctx->frame_id = decon_get_frame_count(ctx, true);
exynos_crtc_handle_event(crtc); exynos_crtc_handle_event(crtc);
@ -473,21 +445,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
return;
pm_runtime_get_sync(ctx->dev); pm_runtime_get_sync(ctx->dev);
exynos_drm_pipe_clk_enable(crtc, true); exynos_drm_pipe_clk_enable(crtc, true);
set_bit(BIT_CLKS_ENABLED, &ctx->flags);
decon_swreset(ctx); decon_swreset(ctx);
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
decon_enable_vblank(ctx->crtc);
decon_commit(ctx->crtc); decon_commit(ctx->crtc);
} }
@ -496,8 +459,9 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
int i; int i;
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (!(ctx->out_type & I80_HW_TRG))
return; synchronize_irq(ctx->te_irq);
synchronize_irq(ctx->irq);
/* /*
* We need to make sure that all windows are disabled before we * We need to make sure that all windows are disabled before we
@ -509,25 +473,18 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
decon_swreset(ctx); decon_swreset(ctx);
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
exynos_drm_pipe_clk_enable(crtc, false); exynos_drm_pipe_clk_enable(crtc, false);
pm_runtime_put_sync(ctx->dev); pm_runtime_put_sync(ctx->dev);
set_bit(BIT_SUSPENDED, &ctx->flags);
} }
static void decon_te_irq_handler(struct exynos_drm_crtc *crtc) static irqreturn_t decon_te_irq_handler(int irq, void *dev_id)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = dev_id;
if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) ||
(ctx->out_type & I80_HW_TRG))
return;
if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
return IRQ_HANDLED;
} }
static void decon_clear_channels(struct exynos_drm_crtc *crtc) static void decon_clear_channels(struct exynos_drm_crtc *crtc)
@ -543,11 +500,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
goto err; goto err;
} }
for (win = 0; win < WINDOWS_NR; win++) { decon_shadow_protect(ctx, true);
decon_shadow_protect_win(ctx, win, true); for (win = 0; win < WINDOWS_NR; win++)
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false); decon_shadow_protect(ctx, false);
}
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
@ -564,25 +520,24 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.disable = decon_disable, .disable = decon_disable,
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.get_vblank_counter = decon_get_vblank_counter,
.atomic_begin = decon_atomic_begin, .atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane, .update_plane = decon_update_plane,
.disable_plane = decon_disable_plane, .disable_plane = decon_disable_plane,
.atomic_flush = decon_atomic_flush, .atomic_flush = decon_atomic_flush,
.te_handler = decon_te_irq_handler,
}; };
static int decon_bind(struct device *dev, struct device *master, void *data) static int decon_bind(struct device *dev, struct device *master, void *data)
{ {
struct decon_context *ctx = dev_get_drvdata(dev); struct decon_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
enum exynos_drm_output_type out_type; enum exynos_drm_output_type out_type;
unsigned int win; unsigned int win;
int ret; int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++; drm_dev->max_vblank_count = 0xffffffff;
for (win = ctx->first_win; win < WINDOWS_NR; win++) { for (win = ctx->first_win; win < WINDOWS_NR; win++) {
int tmp = (win == ctx->first_win) ? 0 : win; int tmp = (win == ctx->first_win) ? 0 : win;
@ -593,7 +548,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
ctx->configs[win].type = decon_win_types[tmp]; ctx->configs[win].type = decon_win_types[tmp];
ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
1 << ctx->pipe, &ctx->configs[win]); &ctx->configs[win]);
if (ret) if (ret)
return ret; return ret;
} }
@ -602,23 +557,13 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI
: EXYNOS_DISPLAY_TYPE_LCD; : EXYNOS_DISPLAY_TYPE_LCD;
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, out_type, out_type, &decon_crtc_ops, ctx);
&decon_crtc_ops, ctx); if (IS_ERR(ctx->crtc))
if (IS_ERR(ctx->crtc)) { return PTR_ERR(ctx->crtc);
ret = PTR_ERR(ctx->crtc);
goto err;
}
decon_clear_channels(ctx->crtc); decon_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, dev); return drm_iommu_attach_device(drm_dev, dev);
if (ret)
goto err;
return ret;
err:
priv->pipe--;
return ret;
} }
static void decon_unbind(struct device *dev, struct device *master, void *data) static void decon_unbind(struct device *dev, struct device *master, void *data)
@ -659,9 +604,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
struct decon_context *ctx = dev_id; struct decon_context *ctx = dev_id;
u32 val; u32 val;
if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
goto out;
val = readl(ctx->addr + DECON_VIDINTCON1); val = readl(ctx->addr + DECON_VIDINTCON1);
val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
@ -677,7 +619,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
decon_handle_vblank(ctx); decon_handle_vblank(ctx);
} }
out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -732,6 +673,31 @@ static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
}; };
MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
static int decon_conf_irq(struct decon_context *ctx, const char *name,
irq_handler_t handler, unsigned long int flags, bool required)
{
struct platform_device *pdev = to_platform_device(ctx->dev);
int ret, irq = platform_get_irq_byname(pdev, name);
if (irq < 0) {
if (irq == -EPROBE_DEFER)
return irq;
if (required)
dev_err(ctx->dev, "cannot get %s IRQ\n", name);
else
irq = 0;
return irq;
}
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx);
if (ret < 0) {
dev_err(ctx->dev, "IRQ %s request failed\n", name);
return ret;
}
return irq;
}
static int exynos5433_decon_probe(struct platform_device *pdev) static int exynos5433_decon_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -744,7 +710,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
__set_bit(BIT_SUSPENDED, &ctx->flags);
ctx->dev = dev; ctx->dev = dev;
ctx->out_type = (unsigned long)of_device_get_match_data(dev); ctx->out_type = (unsigned long)of_device_get_match_data(dev);
spin_lock_init(&ctx->vblank_lock); spin_lock_init(&ctx->vblank_lock);
@ -755,15 +720,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
ctx->out_type |= IFTYPE_I80; ctx->out_type |= IFTYPE_I80;
} }
if (ctx->out_type & I80_HW_TRG) {
ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,disp-sysreg");
if (IS_ERR(ctx->sysreg)) {
dev_err(dev, "failed to get system register\n");
return PTR_ERR(ctx->sysreg);
}
}
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk; struct clk *clk;
@ -786,18 +742,34 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
return PTR_ERR(ctx->addr); return PTR_ERR(ctx->addr);
} }
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, if (ctx->out_type & IFTYPE_I80) {
(ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync"); ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0, true);
if (!res) { if (ret < 0)
dev_err(dev, "cannot find IRQ resource\n"); return ret;
return -ENXIO; ctx->irq = ret;
ret = decon_conf_irq(ctx, "te", decon_te_irq_handler,
IRQF_TRIGGER_RISING, false);
if (ret < 0)
return ret;
if (ret) {
ctx->te_irq = ret;
ctx->out_type &= ~I80_HW_TRG;
}
} else {
ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0, true);
if (ret < 0)
return ret;
ctx->irq = ret;
} }
ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, if (ctx->out_type & I80_HW_TRG) {
"drm_decon", ctx); ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
if (ret < 0) { "samsung,disp-sysreg");
dev_err(dev, "lcd_sys irq request failed\n"); if (IS_ERR(ctx->sysreg)) {
return ret; dev_err(dev, "failed to get system register\n");
return PTR_ERR(ctx->sysreg);
}
} }
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);

View File

@ -55,7 +55,6 @@ struct decon_context {
unsigned long irq_flags; unsigned long irq_flags;
bool i80_if; bool i80_if;
bool suspended; bool suspended;
int pipe;
wait_queue_head_t wait_vsync_queue; wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
@ -130,19 +129,11 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
static int decon_ctx_initialize(struct decon_context *ctx, static int decon_ctx_initialize(struct decon_context *ctx,
struct drm_device *drm_dev) struct drm_device *drm_dev)
{ {
struct exynos_drm_private *priv = drm_dev->dev_private;
int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
decon_clear_channels(ctx->crtc); decon_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, ctx->dev); return drm_iommu_attach_device(drm_dev, ctx->dev);
if (ret)
priv->pipe--;
return ret;
} }
static void decon_ctx_remove(struct decon_context *ctx) static void decon_ctx_remove(struct decon_context *ctx)
@ -590,7 +581,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
static const struct exynos_drm_crtc_ops decon_crtc_ops = { static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable = decon_enable, .enable = decon_enable,
.disable = decon_disable, .disable = decon_disable,
.commit = decon_commit,
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.atomic_begin = decon_atomic_begin, .atomic_begin = decon_atomic_begin,
@ -612,7 +602,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
writel(clear_bit, ctx->regs + VIDINTCON1); writel(clear_bit, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */ /* check the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
goto out; goto out;
if (!ctx->i80_if) { if (!ctx->i80_if) {
@ -649,15 +639,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
ctx->configs[i].type = decon_win_types[i]; ctx->configs[i].type = decon_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &ctx->configs[i]); &ctx->configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx);
&decon_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
decon_ctx_remove(ctx); decon_ctx_remove(ctx);
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);

View File

@ -49,15 +49,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
} }
} }
static void
exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->ops->commit)
exynos_crtc->ops->commit(exynos_crtc);
}
static int exynos_crtc_atomic_check(struct drm_crtc *crtc, static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
@ -93,7 +84,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.enable = exynos_drm_crtc_enable, .enable = exynos_drm_crtc_enable,
.disable = exynos_drm_crtc_disable, .disable = exynos_drm_crtc_disable,
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
.atomic_check = exynos_crtc_atomic_check, .atomic_check = exynos_crtc_atomic_check,
.atomic_begin = exynos_crtc_atomic_begin, .atomic_begin = exynos_crtc_atomic_begin,
.atomic_flush = exynos_crtc_atomic_flush, .atomic_flush = exynos_crtc_atomic_flush,
@ -105,16 +95,15 @@ void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
struct drm_pending_vblank_event *event = crtc->state->event; struct drm_pending_vblank_event *event = crtc->state->event;
unsigned long flags; unsigned long flags;
if (event) { if (!event)
return;
crtc->state->event = NULL; crtc->state->event = NULL;
spin_lock_irqsave(&crtc->dev->event_lock, flags);
if (drm_crtc_vblank_get(crtc) == 0)
drm_crtc_arm_vblank_event(crtc, event);
else
drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_arm_vblank_event(crtc, event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
} }
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
@ -143,6 +132,16 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
exynos_crtc->ops->disable_vblank(exynos_crtc); exynos_crtc->ops->disable_vblank(exynos_crtc);
} }
static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->ops->get_vblank_counter)
return exynos_crtc->ops->get_vblank_counter(exynos_crtc);
return 0;
}
static const struct drm_crtc_funcs exynos_crtc_funcs = { static const struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
@ -152,11 +151,11 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = exynos_drm_crtc_enable_vblank, .enable_vblank = exynos_drm_crtc_enable_vblank,
.disable_vblank = exynos_drm_crtc_disable_vblank, .disable_vblank = exynos_drm_crtc_disable_vblank,
.get_vblank_counter = exynos_drm_crtc_get_vblank_counter,
}; };
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_plane *plane, struct drm_plane *plane,
int pipe,
enum exynos_drm_output_type type, enum exynos_drm_output_type type,
const struct exynos_drm_crtc_ops *ops, const struct exynos_drm_crtc_ops *ops,
void *ctx) void *ctx)
@ -169,7 +168,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
if (!exynos_crtc) if (!exynos_crtc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
exynos_crtc->pipe = pipe;
exynos_crtc->type = type; exynos_crtc->type = type;
exynos_crtc->ops = ops; exynos_crtc->ops = ops;
exynos_crtc->ctx = ctx; exynos_crtc->ctx = ctx;
@ -196,13 +194,9 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { drm_for_each_crtc(crtc, drm_dev)
struct exynos_drm_crtc *exynos_crtc; if (to_exynos_crtc(crtc)->type == out_type)
return drm_crtc_index(crtc);
exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->type == out_type)
return exynos_crtc->pipe;
}
return -EPERM; return -EPERM;
} }

View File

@ -19,7 +19,6 @@
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_plane *plane, struct drm_plane *plane,
int pipe,
enum exynos_drm_output_type type, enum exynos_drm_output_type type,
const struct exynos_drm_crtc_ops *ops, const struct exynos_drm_crtc_ops *ops,
void *context); void *context);

View File

@ -115,7 +115,6 @@ struct exynos_drm_plane_config {
* *
* @enable: enable the device * @enable: enable the device
* @disable: disable the device * @disable: disable the device
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt. * @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt.
* @atomic_check: validate state * @atomic_check: validate state
@ -130,9 +129,9 @@ struct exynos_drm_crtc;
struct exynos_drm_crtc_ops { struct exynos_drm_crtc_ops {
void (*enable)(struct exynos_drm_crtc *crtc); void (*enable)(struct exynos_drm_crtc *crtc);
void (*disable)(struct exynos_drm_crtc *crtc); void (*disable)(struct exynos_drm_crtc *crtc);
void (*commit)(struct exynos_drm_crtc *crtc);
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);
u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc);
int (*atomic_check)(struct exynos_drm_crtc *crtc, int (*atomic_check)(struct exynos_drm_crtc *crtc,
struct drm_crtc_state *state); struct drm_crtc_state *state);
void (*atomic_begin)(struct exynos_drm_crtc *crtc); void (*atomic_begin)(struct exynos_drm_crtc *crtc);
@ -153,24 +152,13 @@ struct exynos_drm_clk {
* *
* @base: crtc object. * @base: crtc object.
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @pipe: a crtc index created at load() with a new crtc object creation
* and the crtc object would be set to private->crtc array
* to get a crtc object corresponding to this pipe from private->crtc
* array when irq interrupt occurred. the reason of using this pipe is that
* drm framework doesn't support multiple irq yet.
* we can refer to the crtc to current hardware interrupt occurred through
* this pipe value.
* @enabled: if the crtc is enabled or not
* @event: vblank event that is currently queued for flip
* @wait_update: wait all pending planes updates to finish
* @pending_update: number of pending plane updates in this crtc
* @ops: pointer to callbacks for exynos drm specific functionality * @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the crtc's implementation specific context * @ctx: A pointer to the crtc's implementation specific context
* @pipe_clk: A pointer to the crtc's pipeline clock.
*/ */
struct exynos_drm_crtc { struct exynos_drm_crtc {
struct drm_crtc base; struct drm_crtc base;
enum exynos_drm_output_type type; enum exynos_drm_output_type type;
unsigned int pipe;
const struct exynos_drm_crtc_ops *ops; const struct exynos_drm_crtc_ops *ops;
void *ctx; void *ctx;
struct exynos_drm_clk *pipe_clk; struct exynos_drm_clk *pipe_clk;
@ -203,7 +191,6 @@ struct drm_exynos_file_private {
* otherwise default one. * otherwise default one.
* @da_space_size: size of device address space. * @da_space_size: size of device address space.
* if 0 then default value is used for it. * if 0 then default value is used for it.
* @pipe: the pipe number for this crtc/manager.
* @pending: the crtcs that have pending updates to finish * @pending: the crtcs that have pending updates to finish
* @lock: protect access to @pending * @lock: protect access to @pending
* @wait: wait an atomic commit to finish * @wait: wait an atomic commit to finish
@ -214,8 +201,6 @@ struct exynos_drm_private {
struct device *dma_dev; struct device *dma_dev;
void *mapping; void *mapping;
unsigned int pipe;
/* for atomic commit */ /* for atomic commit */
u32 pending; u32 pending;
spinlock_t lock; spinlock_t lock;

View File

@ -1633,7 +1633,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
{ {
struct device *dev = dsi->dev; struct device *dev = dsi->dev;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct device_node *ep;
int ret; int ret;
ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
@ -1641,32 +1640,21 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0) if (ret < 0)
return ret; return ret;
ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0); ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency",
if (!ep) {
dev_err(dev, "no output port with endpoint specified\n");
return -EINVAL;
}
ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency",
&dsi->burst_clk_rate); &dsi->burst_clk_rate);
if (ret < 0) if (ret < 0)
goto end; return ret;
ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency", ret = exynos_dsi_of_read_u32(node, "samsung,esc-clock-frequency",
&dsi->esc_clk_rate); &dsi->esc_clk_rate);
if (ret < 0) if (ret < 0)
goto end; return ret;
of_node_put(ep); dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0);
if (!dsi->bridge_node) if (!dsi->bridge_node)
return -EINVAL; return -EINVAL;
end: return 0;
of_node_put(ep);
return ret;
} }
static int exynos_dsi_bind(struct device *dev, struct device *master, static int exynos_dsi_bind(struct device *dev, struct device *master,
@ -1817,6 +1805,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
static int exynos_dsi_remove(struct platform_device *pdev) static int exynos_dsi_remove(struct platform_device *pdev)
{ {
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
of_node_put(dsi->bridge_node);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &exynos_dsi_component_ops); component_del(&pdev->dev, &exynos_dsi_component_ops);

View File

@ -179,7 +179,6 @@ struct fimd_context {
u32 i80ifcon; u32 i80ifcon;
bool i80_if; bool i80_if;
bool suspended; bool suspended;
int pipe;
wait_queue_head_t wait_vsync_queue; wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
atomic_t win_updated; atomic_t win_updated;
@ -354,18 +353,13 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
/* Wait for vsync, as disable channel takes effect at next vsync */ /* Wait for vsync, as disable channel takes effect at next vsync */
if (ch_enabled) { if (ch_enabled) {
int pipe = ctx->pipe;
/* ensure that vblank interrupt won't be reported to core */
ctx->suspended = false; ctx->suspended = false;
ctx->pipe = -1;
fimd_enable_vblank(ctx->crtc); fimd_enable_vblank(ctx->crtc);
fimd_wait_for_vblank(ctx->crtc); fimd_wait_for_vblank(ctx->crtc);
fimd_disable_vblank(ctx->crtc); fimd_disable_vblank(ctx->crtc);
ctx->suspended = true; ctx->suspended = true;
ctx->pipe = pipe;
} }
clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->lcd_clk);
@ -899,7 +893,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
u32 trg_type = ctx->driver_data->trg_type; u32 trg_type = ctx->driver_data->trg_type;
/* Checks the crtc is detached already from encoder */ /* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
return; return;
if (trg_type == I80_HW_TRG) if (trg_type == I80_HW_TRG)
@ -934,7 +928,6 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
static const struct exynos_drm_crtc_ops fimd_crtc_ops = { static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
.enable = fimd_enable, .enable = fimd_enable,
.disable = fimd_disable, .disable = fimd_disable,
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank, .enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank, .disable_vblank = fimd_disable_vblank,
.atomic_begin = fimd_atomic_begin, .atomic_begin = fimd_atomic_begin,
@ -957,7 +950,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
writel(clear_bit, ctx->regs + VIDINTCON1); writel(clear_bit, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */ /* check the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
goto out; goto out;
if (!ctx->i80_if) if (!ctx->i80_if)
@ -982,13 +975,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
{ {
struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
unsigned int i; unsigned int i;
int ret; int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
for (i = 0; i < WINDOWS_NR; i++) { for (i = 0; i < WINDOWS_NR; i++) {
ctx->configs[i].pixel_formats = fimd_formats; ctx->configs[i].pixel_formats = fimd_formats;
@ -996,15 +987,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
ctx->configs[i].zpos = i; ctx->configs[i].zpos = i;
ctx->configs[i].type = fimd_win_types[i]; ctx->configs[i].type = fimd_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &ctx->configs[i]); &ctx->configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx);
&fimd_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
@ -1019,11 +1009,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
if (is_drm_iommu_supported(drm_dev)) if (is_drm_iommu_supported(drm_dev))
fimd_clear_channels(ctx->crtc); fimd_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, dev); return drm_iommu_attach_device(drm_dev, dev);
if (ret)
priv->pipe--;
return ret;
} }
static void fimd_unbind(struct device *dev, struct device *master, static void fimd_unbind(struct device *dev, struct device *master,

View File

@ -273,14 +273,13 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
} }
int exynos_plane_init(struct drm_device *dev, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, struct exynos_drm_plane *exynos_plane, unsigned int index,
unsigned int index, unsigned long possible_crtcs,
const struct exynos_drm_plane_config *config) const struct exynos_drm_plane_config *config)
{ {
int err; int err;
err = drm_universal_plane_init(dev, &exynos_plane->base, err = drm_universal_plane_init(dev, &exynos_plane->base,
possible_crtcs, 1 << dev->mode_config.num_crtc,
&exynos_plane_funcs, &exynos_plane_funcs,
config->pixel_formats, config->pixel_formats,
config->num_pixel_formats, config->num_pixel_formats,

View File

@ -11,5 +11,4 @@
int exynos_plane_init(struct drm_device *dev, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, unsigned int index, struct exynos_drm_plane *exynos_plane, unsigned int index,
unsigned long possible_crtcs,
const struct exynos_drm_plane_config *config); const struct exynos_drm_plane_config *config);

View File

@ -51,7 +51,6 @@ struct vidi_context {
bool suspended; bool suspended;
struct timer_list timer; struct timer_list timer;
struct mutex lock; struct mutex lock;
int pipe;
}; };
static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
@ -153,17 +152,6 @@ static void vidi_disable(struct exynos_drm_crtc *crtc)
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
} }
static int vidi_ctx_initialize(struct vidi_context *ctx,
struct drm_device *drm_dev)
{
struct exynos_drm_private *priv = drm_dev->dev_private;
ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
return 0;
}
static const struct exynos_drm_crtc_ops vidi_crtc_ops = { static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
.enable = vidi_enable, .enable = vidi_enable,
.disable = vidi_disable, .disable = vidi_disable,
@ -177,9 +165,6 @@ static void vidi_fake_vblank_timer(unsigned long arg)
{ {
struct vidi_context *ctx = (void *)arg; struct vidi_context *ctx = (void *)arg;
if (ctx->pipe < 0)
return;
if (drm_crtc_handle_vblank(&ctx->crtc->base)) if (drm_crtc_handle_vblank(&ctx->crtc->base))
mod_timer(&ctx->timer, mod_timer(&ctx->timer,
jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1); jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
@ -399,7 +384,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
unsigned int i; unsigned int i;
int pipe, ret; int pipe, ret;
vidi_ctx_initialize(ctx, drm_dev); ctx->drm_dev = drm_dev;
plane_config.pixel_formats = formats; plane_config.pixel_formats = formats;
plane_config.num_pixel_formats = ARRAY_SIZE(formats); plane_config.num_pixel_formats = ARRAY_SIZE(formats);
@ -409,15 +394,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
plane_config.type = vidi_win_types[i]; plane_config.type = vidi_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &plane_config); &plane_config);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx);
&vidi_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
DRM_ERROR("failed to create crtc.\n"); DRM_ERROR("failed to create crtc.\n");
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);

View File

@ -1486,8 +1486,6 @@ static void hdmi_enable(struct drm_encoder *encoder)
static void hdmi_disable(struct drm_encoder *encoder) static void hdmi_disable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
struct drm_crtc *crtc = encoder->crtc;
const struct drm_crtc_helper_funcs *funcs = NULL;
if (!hdata->powered) if (!hdata->powered)
return; return;
@ -1498,16 +1496,11 @@ static void hdmi_disable(struct drm_encoder *encoder)
* to disable TV Subsystem should be as following, * to disable TV Subsystem should be as following,
* VP -> Mixer -> HDMI * VP -> Mixer -> HDMI
* *
* Below codes will try to disable Mixer and VP(if used) * To achieve such sequence HDMI is disabled together with HDMI PHY, via
* prior to disabling HDMI. * pipe clock callback.
*/ */
if (crtc)
funcs = crtc->helper_private;
if (funcs && funcs->disable)
(*funcs->disable)(crtc);
cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
cancel_delayed_work(&hdata->hotplug_work); cancel_delayed_work(&hdata->hotplug_work);
cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
hdmiphy_disable(hdata); hdmiphy_disable(hdata);
} }

View File

@ -45,6 +45,22 @@
#define MIXER_WIN_NR 3 #define MIXER_WIN_NR 3
#define VP_DEFAULT_WIN 2 #define VP_DEFAULT_WIN 2
/*
* Mixer color space conversion coefficient triplet.
* Used for CSC from RGB to YCbCr.
* Each coefficient is a 10-bit fixed point number with
* sign and no integer part, i.e.
* [0:8] = fractional part (representing a value y = x / 2^9)
* [9] = sign
* Negative values are encoded with two's complement.
*/
#define MXR_CSC_C(x) ((int)((x) * 512.0) & 0x3ff)
#define MXR_CSC_CT(a0, a1, a2) \
((MXR_CSC_C(a0) << 20) | (MXR_CSC_C(a1) << 10) | (MXR_CSC_C(a2) << 0))
/* YCbCr value, used for mixer background color configuration. */
#define MXR_YCBCR_VAL(y, cb, cr) (((y) << 16) | ((cb) << 8) | ((cr) << 0))
/* The pixelformats that are natively supported by the mixer. */ /* The pixelformats that are natively supported by the mixer. */
#define MXR_FORMAT_RGB565 4 #define MXR_FORMAT_RGB565 4
#define MXR_FORMAT_ARGB1555 5 #define MXR_FORMAT_ARGB1555 5
@ -99,7 +115,6 @@ struct mixer_context {
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc; struct exynos_drm_crtc *crtc;
struct exynos_drm_plane planes[MIXER_WIN_NR]; struct exynos_drm_plane planes[MIXER_WIN_NR];
int pipe;
unsigned long flags; unsigned long flags;
struct mixer_resources mixer_res; struct mixer_resources mixer_res;
@ -382,37 +397,24 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
u32 val; u32 val;
if (height == 480) { switch (height) {
case 480:
case 576:
val = MXR_CFG_RGB601_0_255; val = MXR_CFG_RGB601_0_255;
} else if (height == 576) { break;
val = MXR_CFG_RGB601_0_255; case 720:
} else if (height == 720) { case 1080:
default:
val = MXR_CFG_RGB709_16_235; val = MXR_CFG_RGB709_16_235;
/* Configure the BT.709 CSC matrix for full range RGB. */
mixer_reg_write(res, MXR_CM_COEFF_Y, mixer_reg_write(res, MXR_CM_COEFF_Y,
(1 << 30) | (94 << 20) | (314 << 10) | MXR_CSC_CT( 0.184, 0.614, 0.063) |
(32 << 0)); MXR_CM_COEFF_RGB_FULL);
mixer_reg_write(res, MXR_CM_COEFF_CB, mixer_reg_write(res, MXR_CM_COEFF_CB,
(972 << 20) | (851 << 10) | (225 << 0)); MXR_CSC_CT(-0.102, -0.338, 0.440));
mixer_reg_write(res, MXR_CM_COEFF_CR, mixer_reg_write(res, MXR_CM_COEFF_CR,
(225 << 20) | (820 << 10) | (1004 << 0)); MXR_CSC_CT( 0.440, -0.399, -0.040));
} else if (height == 1080) { break;
val = MXR_CFG_RGB709_16_235;
mixer_reg_write(res, MXR_CM_COEFF_Y,
(1 << 30) | (94 << 20) | (314 << 10) |
(32 << 0));
mixer_reg_write(res, MXR_CM_COEFF_CB,
(972 << 20) | (851 << 10) | (225 << 0));
mixer_reg_write(res, MXR_CM_COEFF_CR,
(225 << 20) | (820 << 10) | (1004 << 0));
} else {
val = MXR_CFG_RGB709_16_235;
mixer_reg_write(res, MXR_CM_COEFF_Y,
(1 << 30) | (94 << 20) | (314 << 10) |
(32 << 0));
mixer_reg_write(res, MXR_CM_COEFF_CB,
(972 << 20) | (851 << 10) | (225 << 0));
mixer_reg_write(res, MXR_CM_COEFF_CR,
(225 << 20) | (820 << 10) | (1004 << 0));
} }
mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK); mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
@ -729,10 +731,10 @@ static void mixer_win_reset(struct mixer_context *ctx)
/* reset default layer priority */ /* reset default layer priority */
mixer_reg_write(res, MXR_LAYER_CFG, 0); mixer_reg_write(res, MXR_LAYER_CFG, 0);
/* setting background color */ /* set all background colors to RGB (0,0,0) */
mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) { if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
/* configuration of Video Processor Registers */ /* configuration of Video Processor Registers */
@ -900,7 +902,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
priv = drm_dev->dev_private; priv = drm_dev->dev_private;
mixer_ctx->drm_dev = drm_dev; mixer_ctx->drm_dev = drm_dev;
mixer_ctx->pipe = priv->pipe++;
/* acquire resources: regs, irqs, clocks */ /* acquire resources: regs, irqs, clocks */
ret = mixer_resources_init(mixer_ctx); ret = mixer_resources_init(mixer_ctx);
@ -918,11 +919,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
} }
} }
ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev); return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
if (ret)
priv->pipe--;
return ret;
} }
static void mixer_ctx_remove(struct mixer_context *mixer_ctx) static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
@ -1158,15 +1155,14 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
continue; continue;
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &plane_configs[i]); &plane_configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
&mixer_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
mixer_ctx_remove(ctx); mixer_ctx_remove(ctx);
ret = PTR_ERR(ctx->crtc); ret = PTR_ERR(ctx->crtc);

View File

@ -140,11 +140,11 @@
#define MXR_INT_EN_VSYNC (1 << 11) #define MXR_INT_EN_VSYNC (1 << 11)
#define MXR_INT_EN_ALL (0x0f << 8) #define MXR_INT_EN_ALL (0x0f << 8)
/* bit for MXR_INT_STATUS */ /* bits for MXR_INT_STATUS */
#define MXR_INT_CLEAR_VSYNC (1 << 11) #define MXR_INT_CLEAR_VSYNC (1 << 11)
#define MXR_INT_STATUS_VSYNC (1 << 0) #define MXR_INT_STATUS_VSYNC (1 << 0)
/* bit for MXR_LAYER_CFG */ /* bits for MXR_LAYER_CFG */
#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8) #define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0) #define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0)
#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4) #define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
@ -152,5 +152,8 @@
#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0) #define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
#define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0) #define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0)
/* bits for MXR_CM_COEFF_Y */
#define MXR_CM_COEFF_RGB_FULL (1 << 30)
#endif /* SAMSUNG_REGS_MIXER_H */ #endif /* SAMSUNG_REGS_MIXER_H */

View File

@ -118,6 +118,7 @@
#define WINCONx_ENWIN_F (1 << 0) #define WINCONx_ENWIN_F (1 << 0)
/* SHADOWCON */ /* SHADOWCON */
#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n))) #define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
/* VIDOSDxD */ /* VIDOSDxD */