forked from Minki/linux
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. -----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:
commit
c9f0726ff3
@ -8,12 +8,13 @@ Required properties:
|
||||
- compatible: value should be one of:
|
||||
"samsung,exynos5433-decon", "samsung,exynos5433-decon-tv";
|
||||
- reg: physical base address and length of the DECON registers set.
|
||||
- interrupts: should contain a list of all DECON IP block interrupts in the
|
||||
order: VSYNC, LCD_SYSTEM. The interrupt specifier format
|
||||
depends on the interrupt controller used.
|
||||
- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys"
|
||||
in the same order as they were listed in the interrupts
|
||||
property.
|
||||
- interrupt-names: should contain the interrupt names depending on mode of work:
|
||||
video mode: "vsync",
|
||||
command mode: "lcd_sys",
|
||||
command mode with software trigger: "lcd_sys", "te".
|
||||
- interrupts or interrupts-extended: list of interrupt specifiers corresponding
|
||||
to names privided in interrupt-names, as described in
|
||||
interrupt-controller/interrupts.txt
|
||||
- clocks: must include clock specifiers corresponding to entries in the
|
||||
clock-names property.
|
||||
- clock-names: list of clock names sorted in the same order as the clocks
|
||||
|
@ -47,14 +47,6 @@ static const char * const decon_clks_name[] = {
|
||||
"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 device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
@ -64,8 +56,8 @@ struct decon_context {
|
||||
void __iomem *addr;
|
||||
struct regmap *sysreg;
|
||||
struct clk *clks[ARRAY_SIZE(decon_clks_name)];
|
||||
int pipe;
|
||||
unsigned long flags;
|
||||
unsigned int irq;
|
||||
unsigned int te_irq;
|
||||
unsigned long out_type;
|
||||
int first_win;
|
||||
spinlock_t vblank_lock;
|
||||
@ -97,18 +89,17 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
u32 val;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return -EPERM;
|
||||
val = VIDINTCON0_INTEN;
|
||||
if (ctx->out_type & IFTYPE_I80)
|
||||
val |= VIDINTCON0_FRAMEDONE;
|
||||
else
|
||||
val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP;
|
||||
|
||||
if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
|
||||
val = VIDINTCON0_INTEN;
|
||||
if (ctx->out_type & IFTYPE_I80)
|
||||
val |= VIDINTCON0_FRAMEDONE;
|
||||
else
|
||||
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;
|
||||
}
|
||||
@ -117,11 +108,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
if (!(ctx->out_type & I80_HW_TRG))
|
||||
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);
|
||||
}
|
||||
|
||||
/* return number of starts/ends of frame transmissions since reset */
|
||||
@ -166,6 +157,13 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
u32 val;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
if (ctx->out_type & IFTYPE_HDMI) {
|
||||
m->crtc_hsync_start = m->crtc_hdisplay + 10;
|
||||
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));
|
||||
}
|
||||
|
||||
static void decon_shadow_protect_win(struct decon_context *ctx, int win,
|
||||
bool protect)
|
||||
static void decon_shadow_protect(struct decon_context *ctx, bool protect)
|
||||
{
|
||||
decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win),
|
||||
decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_PROTECT_MASK,
|
||||
protect ? ~0 : 0);
|
||||
}
|
||||
|
||||
static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
int i;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
for (i = ctx->first_win; i < WINDOWS_NR; i++)
|
||||
decon_shadow_protect_win(ctx, i, true);
|
||||
decon_shadow_protect(ctx, true);
|
||||
}
|
||||
|
||||
#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);
|
||||
u32 val;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
val = COORDINATE_X(state->crtc.x) |
|
||||
COORDINATE_Y(state->crtc.y / 2);
|
||||
@ -390,7 +376,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
|
||||
|
||||
/* window enable */
|
||||
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,
|
||||
@ -399,32 +384,19 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
unsigned int win = plane->index;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ctx->vblank_lock, flags);
|
||||
|
||||
for (i = ctx->first_win; i < WINDOWS_NR; i++)
|
||||
decon_shadow_protect_win(ctx, i, false);
|
||||
decon_shadow_protect(ctx, false);
|
||||
|
||||
if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags))
|
||||
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
||||
|
||||
if (ctx->out_type & IFTYPE_I80)
|
||||
set_bit(BIT_WIN_UPDATED, &ctx->flags);
|
||||
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
||||
|
||||
ctx->frame_id = decon_get_frame_count(ctx, true);
|
||||
|
||||
@ -473,21 +445,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
|
||||
{
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
|
||||
if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
|
||||
pm_runtime_get_sync(ctx->dev);
|
||||
|
||||
exynos_drm_pipe_clk_enable(crtc, true);
|
||||
|
||||
set_bit(BIT_CLKS_ENABLED, &ctx->flags);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -496,8 +459,9 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
|
||||
struct decon_context *ctx = crtc->ctx;
|
||||
int i;
|
||||
|
||||
if (test_bit(BIT_SUSPENDED, &ctx->flags))
|
||||
return;
|
||||
if (!(ctx->out_type & I80_HW_TRG))
|
||||
synchronize_irq(ctx->te_irq);
|
||||
synchronize_irq(ctx->irq);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
|
||||
|
||||
exynos_drm_pipe_clk_enable(crtc, false);
|
||||
|
||||
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;
|
||||
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
|
||||
|
||||
if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
|
||||
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (win = 0; win < WINDOWS_NR; win++) {
|
||||
decon_shadow_protect_win(ctx, win, true);
|
||||
decon_shadow_protect(ctx, true);
|
||||
for (win = 0; win < WINDOWS_NR; win++)
|
||||
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);
|
||||
|
||||
@ -564,25 +520,24 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
|
||||
.disable = decon_disable,
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
.disable_vblank = decon_disable_vblank,
|
||||
.get_vblank_counter = decon_get_vblank_counter,
|
||||
.atomic_begin = decon_atomic_begin,
|
||||
.update_plane = decon_update_plane,
|
||||
.disable_plane = decon_disable_plane,
|
||||
.atomic_flush = decon_atomic_flush,
|
||||
.te_handler = decon_te_irq_handler,
|
||||
};
|
||||
|
||||
static int decon_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct decon_context *ctx = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
struct exynos_drm_plane *exynos_plane;
|
||||
enum exynos_drm_output_type out_type;
|
||||
unsigned int win;
|
||||
int ret;
|
||||
|
||||
ctx->drm_dev = drm_dev;
|
||||
ctx->pipe = priv->pipe++;
|
||||
drm_dev->max_vblank_count = 0xffffffff;
|
||||
|
||||
for (win = ctx->first_win; win < WINDOWS_NR; 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];
|
||||
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
|
||||
1 << ctx->pipe, &ctx->configs[win]);
|
||||
&ctx->configs[win]);
|
||||
if (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
|
||||
: EXYNOS_DISPLAY_TYPE_LCD;
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, out_type,
|
||||
&decon_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc)) {
|
||||
ret = PTR_ERR(ctx->crtc);
|
||||
goto err;
|
||||
}
|
||||
out_type, &decon_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc))
|
||||
return PTR_ERR(ctx->crtc);
|
||||
|
||||
decon_clear_channels(ctx->crtc);
|
||||
|
||||
ret = drm_iommu_attach_device(drm_dev, dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return ret;
|
||||
err:
|
||||
priv->pipe--;
|
||||
return ret;
|
||||
return drm_iommu_attach_device(drm_dev, dev);
|
||||
}
|
||||
|
||||
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;
|
||||
u32 val;
|
||||
|
||||
if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
|
||||
goto out;
|
||||
|
||||
val = readl(ctx->addr + DECON_VIDINTCON1);
|
||||
val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
|
||||
|
||||
@ -677,7 +619,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
|
||||
decon_handle_vblank(ctx);
|
||||
}
|
||||
|
||||
out:
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -744,7 +710,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
__set_bit(BIT_SUSPENDED, &ctx->flags);
|
||||
ctx->dev = dev;
|
||||
ctx->out_type = (unsigned long)of_device_get_match_data(dev);
|
||||
spin_lock_init(&ctx->vblank_lock);
|
||||
@ -755,15 +720,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
|
||||
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++) {
|
||||
struct clk *clk;
|
||||
|
||||
@ -786,18 +742,34 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(ctx->addr);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
(ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync");
|
||||
if (!res) {
|
||||
dev_err(dev, "cannot find IRQ resource\n");
|
||||
return -ENXIO;
|
||||
if (ctx->out_type & IFTYPE_I80) {
|
||||
ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
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,
|
||||
"drm_decon", ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "lcd_sys irq request failed\n");
|
||||
return ret;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
@ -55,7 +55,6 @@ struct decon_context {
|
||||
unsigned long irq_flags;
|
||||
bool i80_if;
|
||||
bool suspended;
|
||||
int pipe;
|
||||
wait_queue_head_t wait_vsync_queue;
|
||||
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,
|
||||
struct drm_device *drm_dev)
|
||||
{
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ctx->drm_dev = drm_dev;
|
||||
ctx->pipe = priv->pipe++;
|
||||
|
||||
decon_clear_channels(ctx->crtc);
|
||||
|
||||
ret = drm_iommu_attach_device(drm_dev, ctx->dev);
|
||||
if (ret)
|
||||
priv->pipe--;
|
||||
|
||||
return ret;
|
||||
return drm_iommu_attach_device(drm_dev, ctx->dev);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.enable = decon_enable,
|
||||
.disable = decon_disable,
|
||||
.commit = decon_commit,
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
.disable_vblank = decon_disable_vblank,
|
||||
.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);
|
||||
|
||||
/* check the crtc is detached already from encoder */
|
||||
if (ctx->pipe < 0 || !ctx->drm_dev)
|
||||
if (!ctx->drm_dev)
|
||||
goto out;
|
||||
|
||||
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];
|
||||
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
|
||||
1 << ctx->pipe, &ctx->configs[i]);
|
||||
&ctx->configs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
|
||||
&decon_crtc_ops, ctx);
|
||||
EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc)) {
|
||||
decon_ctx_remove(ctx);
|
||||
return PTR_ERR(ctx->crtc);
|
||||
|
@ -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,
|
||||
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 = {
|
||||
.enable = exynos_drm_crtc_enable,
|
||||
.disable = exynos_drm_crtc_disable,
|
||||
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
|
||||
.atomic_check = exynos_crtc_atomic_check,
|
||||
.atomic_begin = exynos_crtc_atomic_begin,
|
||||
.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;
|
||||
unsigned long flags;
|
||||
|
||||
if (event) {
|
||||
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);
|
||||
}
|
||||
if (!event)
|
||||
return;
|
||||
crtc->state->event = NULL;
|
||||
|
||||
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)
|
||||
@ -143,6 +132,16 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *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 = {
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.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,
|
||||
.enable_vblank = exynos_drm_crtc_enable_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 drm_plane *plane,
|
||||
int pipe,
|
||||
enum exynos_drm_output_type type,
|
||||
const struct exynos_drm_crtc_ops *ops,
|
||||
void *ctx)
|
||||
@ -169,7 +168,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
||||
if (!exynos_crtc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
exynos_crtc->pipe = pipe;
|
||||
exynos_crtc->type = type;
|
||||
exynos_crtc->ops = ops;
|
||||
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;
|
||||
|
||||
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
|
||||
struct exynos_drm_crtc *exynos_crtc;
|
||||
|
||||
exynos_crtc = to_exynos_crtc(crtc);
|
||||
if (exynos_crtc->type == out_type)
|
||||
return exynos_crtc->pipe;
|
||||
}
|
||||
drm_for_each_crtc(crtc, drm_dev)
|
||||
if (to_exynos_crtc(crtc)->type == out_type)
|
||||
return drm_crtc_index(crtc);
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
||||
struct drm_plane *plane,
|
||||
int pipe,
|
||||
enum exynos_drm_output_type type,
|
||||
const struct exynos_drm_crtc_ops *ops,
|
||||
void *context);
|
||||
|
@ -115,7 +115,6 @@ struct exynos_drm_plane_config {
|
||||
*
|
||||
* @enable: enable the device
|
||||
* @disable: disable the device
|
||||
* @commit: set current hw specific display mode to hw.
|
||||
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||
* @atomic_check: validate state
|
||||
@ -130,9 +129,9 @@ struct exynos_drm_crtc;
|
||||
struct exynos_drm_crtc_ops {
|
||||
void (*enable)(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);
|
||||
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,
|
||||
struct drm_crtc_state *state);
|
||||
void (*atomic_begin)(struct exynos_drm_crtc *crtc);
|
||||
@ -153,24 +152,13 @@ struct exynos_drm_clk {
|
||||
*
|
||||
* @base: crtc object.
|
||||
* @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
|
||||
* @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 drm_crtc base;
|
||||
enum exynos_drm_output_type type;
|
||||
unsigned int pipe;
|
||||
const struct exynos_drm_crtc_ops *ops;
|
||||
void *ctx;
|
||||
struct exynos_drm_clk *pipe_clk;
|
||||
@ -203,7 +191,6 @@ struct drm_exynos_file_private {
|
||||
* otherwise default one.
|
||||
* @da_space_size: size of device address space.
|
||||
* 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
|
||||
* @lock: protect access to @pending
|
||||
* @wait: wait an atomic commit to finish
|
||||
@ -214,8 +201,6 @@ struct exynos_drm_private {
|
||||
struct device *dma_dev;
|
||||
void *mapping;
|
||||
|
||||
unsigned int pipe;
|
||||
|
||||
/* for atomic commit */
|
||||
u32 pending;
|
||||
spinlock_t lock;
|
||||
|
@ -1633,7 +1633,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
|
||||
{
|
||||
struct device *dev = dsi->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ep;
|
||||
int ret;
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0);
|
||||
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",
|
||||
ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency",
|
||||
&dsi->burst_clk_rate);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
return ret;
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0);
|
||||
dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
|
||||
if (!dsi->bridge_node)
|
||||
return -EINVAL;
|
||||
|
||||
end:
|
||||
of_node_put(ep);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
|
||||
|
||||
of_node_put(dsi->bridge_node);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
component_del(&pdev->dev, &exynos_dsi_component_ops);
|
||||
|
@ -179,7 +179,6 @@ struct fimd_context {
|
||||
u32 i80ifcon;
|
||||
bool i80_if;
|
||||
bool suspended;
|
||||
int pipe;
|
||||
wait_queue_head_t wait_vsync_queue;
|
||||
atomic_t wait_vsync_event;
|
||||
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 */
|
||||
if (ch_enabled) {
|
||||
int pipe = ctx->pipe;
|
||||
|
||||
/* ensure that vblank interrupt won't be reported to core */
|
||||
ctx->suspended = false;
|
||||
ctx->pipe = -1;
|
||||
|
||||
fimd_enable_vblank(ctx->crtc);
|
||||
fimd_wait_for_vblank(ctx->crtc);
|
||||
fimd_disable_vblank(ctx->crtc);
|
||||
|
||||
ctx->suspended = true;
|
||||
ctx->pipe = pipe;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Checks the crtc is detached already from encoder */
|
||||
if (ctx->pipe < 0 || !ctx->drm_dev)
|
||||
if (!ctx->drm_dev)
|
||||
return;
|
||||
|
||||
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 = {
|
||||
.enable = fimd_enable,
|
||||
.disable = fimd_disable,
|
||||
.commit = fimd_commit,
|
||||
.enable_vblank = fimd_enable_vblank,
|
||||
.disable_vblank = fimd_disable_vblank,
|
||||
.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);
|
||||
|
||||
/* check the crtc is detached already from encoder */
|
||||
if (ctx->pipe < 0 || !ctx->drm_dev)
|
||||
if (!ctx->drm_dev)
|
||||
goto out;
|
||||
|
||||
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 drm_device *drm_dev = data;
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
struct exynos_drm_plane *exynos_plane;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ctx->drm_dev = drm_dev;
|
||||
ctx->pipe = priv->pipe++;
|
||||
|
||||
for (i = 0; i < WINDOWS_NR; i++) {
|
||||
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].type = fimd_win_types[i];
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
|
||||
1 << ctx->pipe, &ctx->configs[i]);
|
||||
&ctx->configs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
|
||||
&fimd_crtc_ops, ctx);
|
||||
EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx);
|
||||
if (IS_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))
|
||||
fimd_clear_channels(ctx->crtc);
|
||||
|
||||
ret = drm_iommu_attach_device(drm_dev, dev);
|
||||
if (ret)
|
||||
priv->pipe--;
|
||||
|
||||
return ret;
|
||||
return drm_iommu_attach_device(drm_dev, dev);
|
||||
}
|
||||
|
||||
static void fimd_unbind(struct device *dev, struct device *master,
|
||||
|
@ -273,14 +273,13 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
|
||||
}
|
||||
|
||||
int exynos_plane_init(struct drm_device *dev,
|
||||
struct exynos_drm_plane *exynos_plane,
|
||||
unsigned int index, unsigned long possible_crtcs,
|
||||
struct exynos_drm_plane *exynos_plane, unsigned int index,
|
||||
const struct exynos_drm_plane_config *config)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = drm_universal_plane_init(dev, &exynos_plane->base,
|
||||
possible_crtcs,
|
||||
1 << dev->mode_config.num_crtc,
|
||||
&exynos_plane_funcs,
|
||||
config->pixel_formats,
|
||||
config->num_pixel_formats,
|
||||
|
@ -11,5 +11,4 @@
|
||||
|
||||
int exynos_plane_init(struct drm_device *dev,
|
||||
struct exynos_drm_plane *exynos_plane, unsigned int index,
|
||||
unsigned long possible_crtcs,
|
||||
const struct exynos_drm_plane_config *config);
|
||||
|
@ -51,7 +51,6 @@ struct vidi_context {
|
||||
bool suspended;
|
||||
struct timer_list timer;
|
||||
struct mutex lock;
|
||||
int pipe;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.enable = vidi_enable,
|
||||
.disable = vidi_disable,
|
||||
@ -177,9 +165,6 @@ static void vidi_fake_vblank_timer(unsigned long arg)
|
||||
{
|
||||
struct vidi_context *ctx = (void *)arg;
|
||||
|
||||
if (ctx->pipe < 0)
|
||||
return;
|
||||
|
||||
if (drm_crtc_handle_vblank(&ctx->crtc->base))
|
||||
mod_timer(&ctx->timer,
|
||||
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;
|
||||
int pipe, ret;
|
||||
|
||||
vidi_ctx_initialize(ctx, drm_dev);
|
||||
ctx->drm_dev = drm_dev;
|
||||
|
||||
plane_config.pixel_formats = 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];
|
||||
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
|
||||
1 << ctx->pipe, &plane_config);
|
||||
&plane_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
&vidi_crtc_ops, ctx);
|
||||
EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc)) {
|
||||
DRM_ERROR("failed to create crtc.\n");
|
||||
return PTR_ERR(ctx->crtc);
|
||||
|
@ -1486,8 +1486,6 @@ static void hdmi_enable(struct drm_encoder *encoder)
|
||||
static void hdmi_disable(struct drm_encoder *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)
|
||||
return;
|
||||
@ -1498,16 +1496,11 @@ static void hdmi_disable(struct drm_encoder *encoder)
|
||||
* to disable TV Subsystem should be as following,
|
||||
* VP -> Mixer -> HDMI
|
||||
*
|
||||
* Below codes will try to disable Mixer and VP(if used)
|
||||
* prior to disabling HDMI.
|
||||
* To achieve such sequence HDMI is disabled together with HDMI PHY, via
|
||||
* 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);
|
||||
cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
|
||||
|
||||
hdmiphy_disable(hdata);
|
||||
}
|
||||
|
@ -45,6 +45,22 @@
|
||||
#define MIXER_WIN_NR 3
|
||||
#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. */
|
||||
#define MXR_FORMAT_RGB565 4
|
||||
#define MXR_FORMAT_ARGB1555 5
|
||||
@ -99,7 +115,6 @@ struct mixer_context {
|
||||
struct drm_device *drm_dev;
|
||||
struct exynos_drm_crtc *crtc;
|
||||
struct exynos_drm_plane planes[MIXER_WIN_NR];
|
||||
int pipe;
|
||||
unsigned long flags;
|
||||
|
||||
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;
|
||||
u32 val;
|
||||
|
||||
if (height == 480) {
|
||||
switch (height) {
|
||||
case 480:
|
||||
case 576:
|
||||
val = MXR_CFG_RGB601_0_255;
|
||||
} else if (height == 576) {
|
||||
val = MXR_CFG_RGB601_0_255;
|
||||
} else if (height == 720) {
|
||||
break;
|
||||
case 720:
|
||||
case 1080:
|
||||
default:
|
||||
val = MXR_CFG_RGB709_16_235;
|
||||
/* Configure the BT.709 CSC matrix for full range RGB. */
|
||||
mixer_reg_write(res, MXR_CM_COEFF_Y,
|
||||
(1 << 30) | (94 << 20) | (314 << 10) |
|
||||
(32 << 0));
|
||||
MXR_CSC_CT( 0.184, 0.614, 0.063) |
|
||||
MXR_CM_COEFF_RGB_FULL);
|
||||
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,
|
||||
(225 << 20) | (820 << 10) | (1004 << 0));
|
||||
} else if (height == 1080) {
|
||||
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));
|
||||
MXR_CSC_CT( 0.440, -0.399, -0.040));
|
||||
break;
|
||||
}
|
||||
|
||||
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 */
|
||||
mixer_reg_write(res, MXR_LAYER_CFG, 0);
|
||||
|
||||
/* setting background color */
|
||||
mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
|
||||
mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
|
||||
mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
|
||||
/* set all background colors to RGB (0,0,0) */
|
||||
mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
|
||||
mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
|
||||
mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
|
||||
|
||||
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
|
||||
/* configuration of Video Processor Registers */
|
||||
@ -900,7 +902,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
|
||||
priv = drm_dev->dev_private;
|
||||
|
||||
mixer_ctx->drm_dev = drm_dev;
|
||||
mixer_ctx->pipe = priv->pipe++;
|
||||
|
||||
/* acquire resources: regs, irqs, clocks */
|
||||
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);
|
||||
if (ret)
|
||||
priv->pipe--;
|
||||
|
||||
return ret;
|
||||
return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
|
||||
1 << ctx->pipe, &plane_configs[i]);
|
||||
&plane_configs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos_plane = &ctx->planes[DEFAULT_WIN];
|
||||
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
|
||||
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
&mixer_crtc_ops, ctx);
|
||||
EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
|
||||
if (IS_ERR(ctx->crtc)) {
|
||||
mixer_ctx_remove(ctx);
|
||||
ret = PTR_ERR(ctx->crtc);
|
||||
|
@ -140,11 +140,11 @@
|
||||
#define MXR_INT_EN_VSYNC (1 << 11)
|
||||
#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_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_MASK MXR_LAYER_CFG_GRP1_VAL(~0)
|
||||
#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_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 */
|
||||
|
||||
|
@ -118,6 +118,7 @@
|
||||
#define WINCONx_ENWIN_F (1 << 0)
|
||||
|
||||
/* SHADOWCON */
|
||||
#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
|
||||
#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
|
||||
|
||||
/* VIDOSDxD */
|
||||
|
Loading…
Reference in New Issue
Block a user