Commit 7ebdb0dd authored by Dave Airlie's avatar Dave Airlie

Merge tag 'exynos-drm-next-for-v4.14' of...

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

Summary:
- Provide NV12MT pixel format support of Mixer driver in generic way.
- Refactor Exynos KMS drivers
  . Refactoring to panel detection way
  . Refactoring to setting up possible_crtcs
  . Refactoring to video and command mode support
- Some cleanups

* tag 'exynos-drm-next-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos: simplify set_pixfmt() in DECON and FIMD drivers
  drm/exynos: consistent use of cpp
  drm/exynos: mixer: remove src offset from mixer_graph_buffer()
  drm/exynos: mixer: simplify mixer_graph_buffer()
  drm/exynos: mixer: simplify vp_video_buffer()
  drm/exynos: mixer: enable NV12MT support for the video plane
  drm/exynos: mixer: fix chroma comment in vp_video_buffer()
  arm64: dts: exynos: remove i80-if-timings nodes
  dt-bindings: exynos5433-decon: remove i80-if-timings property
  drm/exynos/decon5433: use mode info stored in CRTC to detect i80 mode
  drm/exynos: add mode_valid callback to exynos_drm
  drm/exynos/decon5433: refactor irq requesting code
  drm/exynos/mic: use mode info stored in CRTC to detect i80 mode
  drm/exynos/dsi: propagate info about command mode from panel
  drm/exynos/dsi: refactor panel detection logic
  drm/exynos: use helper to set possible crtcs
  drm/exynos/decon5433: use readl_poll_timeout helpers
parents 095e2d04 5b7b1b7f
...@@ -25,12 +25,6 @@ Required properties: ...@@ -25,12 +25,6 @@ Required properties:
size-cells must 1 and 0, respectively. size-cells must 1 and 0, respectively.
- port: contains an endpoint node which is connected to the endpoint in the mic - port: contains an endpoint node which is connected to the endpoint in the mic
node. The reg value muset be 0. node. The reg value muset be 0.
- i80-if-timings: specify whether the panel which is connected to decon uses
i80 lcd interface or mipi video interface. This node contains
no timing information as that of fimd does. Because there is
no register in decon to specify i80 interface timing value,
it is not needed, but make it remain to use same kind of node
in fimd and exynos7 decon.
Example: Example:
SoC specific DT entry: SoC specific DT entry:
...@@ -59,9 +53,3 @@ decon: decon@13800000 { ...@@ -59,9 +53,3 @@ decon: decon@13800000 {
}; };
}; };
}; };
Board specific DT entry:
&decon {
i80-if-timings {
};
};
...@@ -280,9 +280,6 @@ &cpu4 { ...@@ -280,9 +280,6 @@ &cpu4 {
&decon { &decon {
status = "okay"; status = "okay";
i80-if-timings {
};
}; };
&decon_tv { &decon_tv {
...@@ -1116,9 +1113,6 @@ &pwm { ...@@ -1116,9 +1113,6 @@ &pwm {
&mic { &mic {
status = "okay"; status = "okay";
i80-if-timings {
};
}; };
&pmu_system_controller { &pmu_system_controller {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
...@@ -33,9 +34,8 @@ ...@@ -33,9 +34,8 @@
#define WINDOWS_NR 3 #define WINDOWS_NR 3
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define IFTYPE_I80 (1 << 0) #define I80_HW_TRG (1 << 0)
#define I80_HW_TRG (1 << 1) #define IFTYPE_HDMI (1 << 1)
#define IFTYPE_HDMI (1 << 2)
static const char * const decon_clks_name[] = { static const char * const decon_clks_name[] = {
"pclk", "pclk",
...@@ -57,6 +57,8 @@ struct decon_context { ...@@ -57,6 +57,8 @@ struct decon_context {
struct regmap *sysreg; struct regmap *sysreg;
struct clk *clks[ARRAY_SIZE(decon_clks_name)]; struct clk *clks[ARRAY_SIZE(decon_clks_name)];
unsigned int irq; unsigned int irq;
unsigned int irq_vsync;
unsigned int irq_lcd_sys;
unsigned int te_irq; unsigned int te_irq;
unsigned long out_type; unsigned long out_type;
int first_win; int first_win;
...@@ -90,7 +92,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) ...@@ -90,7 +92,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
u32 val; u32 val;
val = VIDINTCON0_INTEN; val = VIDINTCON0_INTEN;
if (ctx->out_type & IFTYPE_I80) if (crtc->i80_mode)
val |= VIDINTCON0_FRAMEDONE; val |= VIDINTCON0_FRAMEDONE;
else else
val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP;
...@@ -139,7 +141,7 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end) ...@@ -139,7 +141,7 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) { switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) {
case VIDCON1_VSTATUS_VS: case VIDCON1_VSTATUS_VS:
if (!(ctx->out_type & IFTYPE_I80)) if (!(ctx->crtc->i80_mode))
--frm; --frm;
break; break;
case VIDCON1_VSTATUS_BP: case VIDCON1_VSTATUS_BP:
...@@ -166,7 +168,7 @@ static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc) ...@@ -166,7 +168,7 @@ static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc)
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->crtc->i80_mode && !(ctx->out_type & I80_HW_TRG))
return; return;
if (!(ctx->out_type & I80_HW_TRG)) { if (!(ctx->out_type & I80_HW_TRG)) {
...@@ -206,7 +208,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -206,7 +208,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
val = VIDOUT_LCD_ON; val = VIDOUT_LCD_ON;
if (interlaced) if (interlaced)
val |= VIDOUT_INTERLACE_EN_F; val |= VIDOUT_INTERLACE_EN_F;
if (ctx->out_type & IFTYPE_I80) { if (crtc->i80_mode) {
val |= VIDOUT_COMMAND_IF; val |= VIDOUT_COMMAND_IF;
} else { } else {
val |= VIDOUT_RGB_IF; val |= VIDOUT_RGB_IF;
...@@ -222,7 +224,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -222,7 +224,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
VIDTCON2_HOZVAL(m->hdisplay - 1); VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2); writel(val, ctx->addr + DECON_VIDTCON2);
if (!(ctx->out_type & IFTYPE_I80)) { if (!crtc->i80_mode) {
int vbp = m->crtc_vtotal - m->crtc_vsync_end; int vbp = m->crtc_vtotal - m->crtc_vsync_end;
int vfp = m->crtc_vsync_start - m->crtc_vdisplay; int vfp = m->crtc_vsync_start - m->crtc_vdisplay;
...@@ -277,16 +279,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, ...@@ -277,16 +279,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ARGB8888:
default:
val |= WINCONx_BPPMODE_32BPP_A8888; val |= WINCONx_BPPMODE_32BPP_A8888;
val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F;
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
default:
DRM_ERROR("Proper pixel format is not set\n");
return;
} }
DRM_DEBUG_KMS("bpp = %u\n", fb->format->cpp[0] * 8); DRM_DEBUG_KMS("cpp = %u\n", fb->format->cpp[0]);
/* /*
* In case of exynos, setting dma-burst to 16Word causes permanent * In case of exynos, setting dma-burst to 16Word causes permanent
...@@ -329,7 +329,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -329,7 +329,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct drm_framebuffer *fb = state->base.fb; struct drm_framebuffer *fb = state->base.fb;
unsigned int win = plane->index; unsigned int win = plane->index;
unsigned int bpp = fb->format->cpp[0]; unsigned int cpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0]; unsigned int pitch = fb->pitches[0];
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;
...@@ -365,11 +365,11 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -365,11 +365,11 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
if (!(ctx->out_type & IFTYPE_HDMI)) if (!(ctx->out_type & IFTYPE_HDMI))
val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) val = BIT_VAL(pitch - state->crtc.w * cpp, 27, 14)
| BIT_VAL(state->crtc.w * bpp, 13, 0); | BIT_VAL(state->crtc.w * cpp, 13, 0);
else else
val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15) val = BIT_VAL(pitch - state->crtc.w * cpp, 29, 15)
| BIT_VAL(state->crtc.w * bpp, 14, 0); | BIT_VAL(state->crtc.w * cpp, 14, 0);
writel(val, ctx->addr + DECON_VIDW0xADD2(win)); writel(val, ctx->addr + DECON_VIDW0xADD2(win));
decon_win_set_pixfmt(ctx, win, fb); decon_win_set_pixfmt(ctx, win, fb);
...@@ -407,24 +407,19 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) ...@@ -407,24 +407,19 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
static void decon_swreset(struct decon_context *ctx) static void decon_swreset(struct decon_context *ctx)
{ {
unsigned int tries;
unsigned long flags; unsigned long flags;
u32 val;
int ret;
writel(0, ctx->addr + DECON_VIDCON0); writel(0, ctx->addr + DECON_VIDCON0);
for (tries = 2000; tries; --tries) { readl_poll_timeout(ctx->addr + DECON_VIDCON0, val,
if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) ~val & VIDCON0_STOP_STATUS, 12, 20000);
break;
udelay(10);
}
writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0);
for (tries = 2000; tries; --tries) { ret = readl_poll_timeout(ctx->addr + DECON_VIDCON0, val,
if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) ~val & VIDCON0_SWRESET, 12, 20000);
break;
udelay(10);
}
WARN(tries == 0, "failed to software reset DECON\n"); WARN(ret < 0, "failed to software reset DECON\n");
spin_lock_irqsave(&ctx->vblank_lock, flags); spin_lock_irqsave(&ctx->vblank_lock, flags);
ctx->frame_id = 0; ctx->frame_id = 0;
...@@ -515,6 +510,22 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -515,6 +510,22 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
clk_disable_unprepare(ctx->clks[i]); clk_disable_unprepare(ctx->clks[i]);
} }
static enum drm_mode_status decon_mode_valid(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct decon_context *ctx = crtc->ctx;
ctx->irq = crtc->i80_mode ? ctx->irq_lcd_sys : ctx->irq_vsync;
if (ctx->irq)
return MODE_OK;
dev_info(ctx->dev, "Sink requires %s mode, but appropriate interrupt is not provided.\n",
crtc->i80_mode ? "command" : "video");
return MODE_BAD;
}
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,
...@@ -524,6 +535,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { ...@@ -524,6 +535,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.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,
.mode_valid = decon_mode_valid,
.atomic_flush = decon_atomic_flush, .atomic_flush = decon_atomic_flush,
}; };
...@@ -674,20 +686,23 @@ static const struct of_device_id exynos5433_decon_driver_dt_match[] = { ...@@ -674,20 +686,23 @@ 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, static int decon_conf_irq(struct decon_context *ctx, const char *name,
irq_handler_t handler, unsigned long int flags, bool required) irq_handler_t handler, unsigned long int flags)
{ {
struct platform_device *pdev = to_platform_device(ctx->dev); struct platform_device *pdev = to_platform_device(ctx->dev);
int ret, irq = platform_get_irq_byname(pdev, name); int ret, irq = platform_get_irq_byname(pdev, name);
if (irq < 0) { if (irq < 0) {
if (irq == -EPROBE_DEFER) switch (irq) {
case -EPROBE_DEFER:
return irq; return irq;
if (required) case -ENODATA:
dev_err(ctx->dev, "cannot get %s IRQ\n", name); case -ENXIO:
else return 0;
irq = 0; default:
dev_err(ctx->dev, "IRQ %s get failed, %d\n", name, irq);
return irq; return irq;
} }
}
irq_set_status_flags(irq, IRQ_NOAUTOEN); irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx); ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx);
if (ret < 0) { if (ret < 0) {
...@@ -714,11 +729,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -714,11 +729,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
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);
if (ctx->out_type & IFTYPE_HDMI) { if (ctx->out_type & IFTYPE_HDMI)
ctx->first_win = 1; ctx->first_win = 1;
} else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) {
ctx->out_type |= IFTYPE_I80;
}
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;
...@@ -742,26 +754,24 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -742,26 +754,24 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
return PTR_ERR(ctx->addr); return PTR_ERR(ctx->addr);
} }
if (ctx->out_type & IFTYPE_I80) { ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0);
ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
ctx->irq = ret; ctx->irq_vsync = ret;
ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0);
if (ret < 0)
return ret;
ctx->irq_lcd_sys = ret;
ret = decon_conf_irq(ctx, "te", decon_te_irq_handler, ret = decon_conf_irq(ctx, "te", decon_te_irq_handler,
IRQF_TRIGGER_RISING, false); IRQF_TRIGGER_RISING);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret) { if (ret) {
ctx->te_irq = ret; ctx->te_irq = ret;
ctx->out_type &= ~I80_HW_TRG; 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;
}
if (ctx->out_type & I80_HW_TRG) { if (ctx->out_type & I80_HW_TRG) {
ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
......
...@@ -309,19 +309,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, ...@@ -309,19 +309,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
case DRM_FORMAT_BGRA8888: case DRM_FORMAT_BGRA8888:
default:
val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX | val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX |
WINCONx_ALPHA_SEL; WINCONx_ALPHA_SEL;
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
default:
DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
val |= WINCONx_BPPMODE_24BPP_xRGB;
val |= WINCONx_BURSTLEN_16WORD;
break;
} }
DRM_DEBUG_KMS("bpp = %d\n", fb->format->cpp[0] * 8); DRM_DEBUG_KMS("cpp = %d\n", fb->format->cpp[0]);
/* /*
* In case of exynos, setting dma-burst to 16Word causes permanent * In case of exynos, setting dma-burst to 16Word causes permanent
...@@ -398,7 +393,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -398,7 +393,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
unsigned int last_x; unsigned int last_x;
unsigned int last_y; unsigned int last_y;
unsigned int win = plane->index; unsigned int win = plane->index;
unsigned int bpp = fb->format->cpp[0]; unsigned int cpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0]; unsigned int pitch = fb->pitches[0];
if (ctx->suspended) if (ctx->suspended)
...@@ -418,7 +413,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -418,7 +413,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val = (unsigned long)exynos_drm_fb_dma_addr(fb, 0); val = (unsigned long)exynos_drm_fb_dma_addr(fb, 0);
writel(val, ctx->regs + VIDW_BUF_START(win)); writel(val, ctx->regs + VIDW_BUF_START(win));
padding = (pitch / bpp) - fb->width; padding = (pitch / cpp) - fb->width;
/* buffer size */ /* buffer size */
writel(fb->width + padding, ctx->regs + VIDW_WHOLE_X(win)); writel(fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
......
...@@ -155,7 +155,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) ...@@ -155,7 +155,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
struct exynos_dp_device *dp = dev_get_drvdata(dev); struct exynos_dp_device *dp = dev_get_drvdata(dev);
struct drm_encoder *encoder = &dp->encoder; struct drm_encoder *encoder = &dp->encoder;
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
int pipe, ret; int ret;
/* /*
* Just like the probe function said, we don't need the * Just like the probe function said, we don't need the
...@@ -179,20 +179,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) ...@@ -179,20 +179,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
return ret; return ret;
} }
pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_LCD);
if (pipe < 0)
return pipe;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL); DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
dp->plat_data.encoder = encoder; dp->plat_data.encoder = encoder;
return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
*/ */
#include <drm/drmP.h> #include <drm/drmP.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_encoder.h>
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
...@@ -83,7 +84,19 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -83,7 +84,19 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
exynos_crtc->ops->atomic_flush(exynos_crtc); exynos_crtc->ops->atomic_flush(exynos_crtc);
} }
static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->ops->mode_valid)
return exynos_crtc->ops->mode_valid(exynos_crtc, mode);
return MODE_OK;
}
static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.mode_valid = exynos_crtc_mode_valid,
.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,
...@@ -191,16 +204,30 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, ...@@ -191,16 +204,30 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
enum exynos_drm_output_type out_type) enum exynos_drm_output_type out_type)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
drm_for_each_crtc(crtc, drm_dev) drm_for_each_crtc(crtc, drm_dev)
if (to_exynos_crtc(crtc)->type == out_type) if (to_exynos_crtc(crtc)->type == out_type)
return drm_crtc_index(crtc); return to_exynos_crtc(crtc);
return ERR_PTR(-EPERM);
}
int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
enum exynos_drm_output_type out_type)
{
struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev,
out_type);
return -EPERM; if (IS_ERR(crtc))
return PTR_ERR(crtc);
encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
return 0;
} }
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
......
...@@ -15,19 +15,23 @@ ...@@ -15,19 +15,23 @@
#ifndef _EXYNOS_DRM_CRTC_H_ #ifndef _EXYNOS_DRM_CRTC_H_
#define _EXYNOS_DRM_CRTC_H_ #define _EXYNOS_DRM_CRTC_H_
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
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,
enum exynos_drm_output_type type, enum exynos_drm_output_type out_type,
const struct exynos_drm_crtc_ops *ops, const struct exynos_drm_crtc_ops *ops,
void *context); void *context);
void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
struct exynos_drm_plane *exynos_plane); struct exynos_drm_plane *exynos_plane);
/* This function gets pipe value to crtc device matched with out_type. */ /* This function gets crtc device matched with out_type. */
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
enum exynos_drm_output_type out_type);
int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
enum exynos_drm_output_type out_type); enum exynos_drm_output_type out_type);
/* /*
......
...@@ -202,19 +202,15 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder) ...@@ -202,19 +202,15 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
{ {
int ret; int ret;
ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
encoder->possible_crtcs = 1 << ret;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs, drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL); DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs); drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
ret = exynos_dpi_create_connector(encoder); ret = exynos_dpi_create_connector(encoder);
if (ret) { if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret); DRM_ERROR("failed to create connector ret = %d\n", ret);
......
...@@ -91,6 +91,7 @@ struct exynos_drm_plane { ...@@ -91,6 +91,7 @@ struct exynos_drm_plane {
#define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) #define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0)
#define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) #define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1)
#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) #define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2)
#define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3)
/* /*
* Exynos DRM plane configuration structure. * Exynos DRM plane configuration structure.
...@@ -117,6 +118,7 @@ struct exynos_drm_plane_config { ...@@ -117,6 +118,7 @@ struct exynos_drm_plane_config {
* @disable: disable the device * @disable: disable the device
* @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.
* @mode_valid: specific driver callback for mode validation
* @atomic_check: validate state * @atomic_check: validate state
* @atomic_begin: prepare device to receive an update * @atomic_begin: prepare device to receive an update
* @atomic_flush: mark the end of device update * @atomic_flush: mark the end of device update
...@@ -132,6 +134,8 @@ struct exynos_drm_crtc_ops { ...@@ -132,6 +134,8 @@ struct exynos_drm_crtc_ops {
int (*enable_vblank)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc); u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc);
enum drm_mode_status (*mode_valid)(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode);
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);
...@@ -162,6 +166,7 @@ struct exynos_drm_crtc { ...@@ -162,6 +166,7 @@ struct exynos_drm_crtc {
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;
bool i80_mode : 1;
}; };
static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,
......
...@@ -254,7 +254,6 @@ struct exynos_dsi { ...@@ -254,7 +254,6 @@ struct exynos_dsi {
struct drm_encoder encoder; struct drm_encoder encoder;
struct mipi_dsi_host dsi_host; struct mipi_dsi_host dsi_host;
struct drm_connector connector; struct drm_connector connector;
struct device_node *panel_node;
struct drm_panel *panel; struct drm_panel *panel;
struct device *dev; struct device *dev;
...@@ -1329,12 +1328,13 @@ static int exynos_dsi_init(struct exynos_dsi *dsi) ...@@ -1329,12 +1328,13 @@ static int exynos_dsi_init(struct exynos_dsi *dsi)
return 0; return 0;
} }
static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi,
struct device *panel)
{ {
int ret; int ret;
int te_gpio_irq; int te_gpio_irq;
dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0); dsi->te_gpio = of_get_named_gpio(panel->of_node, "te-gpios", 0);
if (dsi->te_gpio == -ENOENT) if (dsi->te_gpio == -ENOENT)
return 0; return 0;
...@@ -1374,85 +1374,6 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) ...@@ -1374,85 +1374,6 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
} }
} }
static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
dsi->lanes = device->lanes;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
dsi->panel_node = device->dev.of_node;
/*
* This is a temporary solution and should be made by more generic way.
*
* If attached panel device is for command mode one, dsi should register
* TE interrupt handler.
*/
if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
int ret = exynos_dsi_register_te_irq(dsi);
if (ret)
return ret;
}
if (dsi->connector.dev)
drm_helper_hpd_irq_event(dsi->connector.dev);
return 0;
}
static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
exynos_dsi_unregister_te_irq(dsi);
dsi->panel_node = NULL;
if (dsi->connector.dev)
drm_helper_hpd_irq_event(dsi->connector.dev);
return 0;
}
static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct exynos_dsi *dsi = host_to_dsi(host);
struct exynos_dsi_transfer xfer;
int ret;
if (!(dsi->state & DSIM_STATE_ENABLED))
return -EINVAL;
if (!(dsi->state & DSIM_STATE_INITIALIZED)) {
ret = exynos_dsi_init(dsi);
if (ret)
return ret;
dsi->state |= DSIM_STATE_INITIALIZED;
}
ret = mipi_dsi_create_packet(&xfer.packet, msg);
if (ret < 0)
return ret;
xfer.rx_len = msg->rx_len;
xfer.rx_payload = msg->rx_buf;
xfer.flags = msg->flags;
ret = exynos_dsi_transfer(dsi, &xfer);
return (ret < 0) ? ret : xfer.rx_done;
}
static const struct mipi_dsi_host_ops exynos_dsi_ops = {
.attach = exynos_dsi_host_attach,
.detach = exynos_dsi_host_detach,
.transfer = exynos_dsi_host_transfer,
};
static void exynos_dsi_enable(struct drm_encoder *encoder) static void exynos_dsi_enable(struct drm_encoder *encoder)
{ {
struct exynos_dsi *dsi = encoder_to_dsi(encoder); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
...@@ -1508,25 +1429,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) ...@@ -1508,25 +1429,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
static enum drm_connector_status static enum drm_connector_status
exynos_dsi_detect(struct drm_connector *connector, bool force) exynos_dsi_detect(struct drm_connector *connector, bool force)
{ {
struct exynos_dsi *dsi = connector_to_dsi(connector); return connector->status;
if (!dsi->panel) {
dsi->panel = of_drm_find_panel(dsi->panel_node);
if (dsi->panel)
drm_panel_attach(dsi->panel, &dsi->connector);
} else if (!dsi->panel_node) {
struct drm_encoder *encoder;
encoder = platform_get_drvdata(to_platform_device(dsi->dev));
exynos_dsi_disable(encoder);
drm_panel_detach(dsi->panel);
dsi->panel = NULL;
}
if (dsi->panel)
return connector_status_connected;
return connector_status_disconnected;
} }
static void exynos_dsi_connector_destroy(struct drm_connector *connector) static void exynos_dsi_connector_destroy(struct drm_connector *connector)
...@@ -1575,6 +1478,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) ...@@ -1575,6 +1478,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
return ret; return ret;
} }
connector->status = connector_status_disconnected;
drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
...@@ -1611,6 +1515,105 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = { ...@@ -1611,6 +1515,105 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
struct drm_device *drm = dsi->connector.dev;
/*
* This is a temporary solution and should be made by more generic way.
*
* If attached panel device is for command mode one, dsi should register
* TE interrupt handler.
*/
if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) {
int ret = exynos_dsi_register_te_irq(dsi, &device->dev);
if (ret)
return ret;
}
mutex_lock(&drm->mode_config.mutex);
dsi->lanes = device->lanes;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
dsi->panel = of_drm_find_panel(device->dev.of_node);
if (dsi->panel) {
drm_panel_attach(dsi->panel, &dsi->connector);
dsi->connector.status = connector_status_connected;
}
exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
mutex_unlock(&drm->mode_config.mutex);
if (drm->mode_config.poll_enabled)
drm_kms_helper_hotplug_event(drm);
return 0;
}
static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
struct drm_device *drm = dsi->connector.dev;
mutex_lock(&drm->mode_config.mutex);
if (dsi->panel) {
exynos_dsi_disable(&dsi->encoder);
drm_panel_detach(dsi->panel);
dsi->panel = NULL;
dsi->connector.status = connector_status_disconnected;
}
mutex_unlock(&drm->mode_config.mutex);
if (drm->mode_config.poll_enabled)
drm_kms_helper_hotplug_event(drm);
exynos_dsi_unregister_te_irq(dsi);
return 0;
}
static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct exynos_dsi *dsi = host_to_dsi(host);
struct exynos_dsi_transfer xfer;
int ret;
if (!(dsi->state & DSIM_STATE_ENABLED))
return -EINVAL;
if (!(dsi->state & DSIM_STATE_INITIALIZED)) {
ret = exynos_dsi_init(dsi);
if (ret)
return ret;
dsi->state |= DSIM_STATE_INITIALIZED;
}
ret = mipi_dsi_create_packet(&xfer.packet, msg);
if (ret < 0)
return ret;
xfer.rx_len = msg->rx_len;
xfer.rx_payload = msg->rx_buf;
xfer.flags = msg->flags;
ret = exynos_dsi_transfer(dsi, &xfer);
return (ret < 0) ? ret : xfer.rx_done;
}
static const struct mipi_dsi_host_ops exynos_dsi_ops = {
.attach = exynos_dsi_host_attach,
.detach = exynos_dsi_host_detach,
.transfer = exynos_dsi_host_transfer,
};
static int exynos_dsi_of_read_u32(const struct device_node *np, static int exynos_dsi_of_read_u32(const struct device_node *np,
const char *propname, u32 *out_value) const char *propname, u32 *out_value)
{ {
...@@ -1662,20 +1665,15 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, ...@@ -1662,20 +1665,15 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
struct drm_bridge *bridge; struct drm_bridge *bridge;
int ret; int ret;
ret = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
encoder->possible_crtcs = 1 << ret;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs, drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL); DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
ret = exynos_dsi_create_connector(encoder); ret = exynos_dsi_create_connector(encoder);
if (ret) { if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret); DRM_ERROR("failed to create connector ret = %d\n", ret);
......
...@@ -225,4 +225,6 @@ void exynos_drm_mode_config_init(struct drm_device *dev) ...@@ -225,4 +225,6 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
dev->mode_config.funcs = &exynos_drm_mode_config_funcs; dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
dev->mode_config.helper_private = &exynos_drm_mode_config_helpers; dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
dev->mode_config.allow_fb_modifiers = true;
} }
...@@ -583,18 +583,12 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, ...@@ -583,18 +583,12 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ARGB8888:
default:
val |= WINCON1_BPPMODE_25BPP_A1888 val |= WINCON1_BPPMODE_25BPP_A1888
| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
val |= WINCONx_WSWP; val |= WINCONx_WSWP;
val |= WINCONx_BURSTLEN_16WORD; val |= WINCONx_BURSTLEN_16WORD;
break; break;
default:
DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
val |= WINCON0_BPPMODE_24BPP_888;
val |= WINCONx_WSWP;
val |= WINCONx_BURSTLEN_16WORD;
break;
} }
/* /*
...@@ -718,13 +712,13 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, ...@@ -718,13 +712,13 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
unsigned long val, size, offset; unsigned long val, size, offset;
unsigned int last_x, last_y, buf_offsize, line_size; unsigned int last_x, last_y, buf_offsize, line_size;
unsigned int win = plane->index; unsigned int win = plane->index;
unsigned int bpp = fb->format->cpp[0]; unsigned int cpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0]; unsigned int pitch = fb->pitches[0];
if (ctx->suspended) if (ctx->suspended)
return; return;
offset = state->src.x * bpp; offset = state->src.x * cpp;
offset += state->src.y * pitch; offset += state->src.y * pitch;
/* buffer start address */ /* buffer start address */
...@@ -743,8 +737,8 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, ...@@ -743,8 +737,8 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
state->crtc.w, state->crtc.h); state->crtc.w, state->crtc.h);
/* buffer size */ /* buffer size */
buf_offsize = pitch - (state->crtc.w * bpp); buf_offsize = pitch - (state->crtc.w * cpp);
line_size = state->crtc.w * bpp; line_size = state->crtc.w * cpp;
val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
VIDW_BUF_SIZE_PAGEWIDTH(line_size) | VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
......
...@@ -21,9 +21,12 @@ ...@@ -21,9 +21,12 @@
#include <linux/component.h> #include <linux/component.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_encoder.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include "exynos_drm_drv.h"
/* Sysreg registers for MIC */ /* Sysreg registers for MIC */
#define DSD_CFG_MUX 0x1004 #define DSD_CFG_MUX 0x1004
#define MIC0_RGB_MUX (1 << 0) #define MIC0_RGB_MUX (1 << 0)
...@@ -85,12 +88,6 @@ ...@@ -85,12 +88,6 @@
#define MIC_BS_SIZE_2D(x) ((x) & 0x3fff) #define MIC_BS_SIZE_2D(x) ((x) & 0x3fff)
enum {
ENDPOINT_DECON_NODE,
ENDPOINT_DSI_NODE,
NUM_ENDPOINTS
};
static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" }; static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" };
#define NUM_CLKS ARRAY_SIZE(clk_names) #define NUM_CLKS ARRAY_SIZE(clk_names)
static DEFINE_MUTEX(mic_mutex); static DEFINE_MUTEX(mic_mutex);
...@@ -229,36 +226,6 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable) ...@@ -229,36 +226,6 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable)
writel(reg, mic->reg + MIC_OP); writel(reg, mic->reg + MIC_OP);
} }
static int parse_dt(struct exynos_mic *mic)
{
int ret = 0, i, j;
struct device_node *remote_node;
struct device_node *nodes[3];
/*
* The order of endpoints does matter.
* The first node must be for decon and the second one must be for dsi.
*/
for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) {
remote_node = of_graph_get_remote_node(mic->dev->of_node, i, 0);
if (!remote_node) {
ret = -EPIPE;
goto exit;
}
nodes[j++] = remote_node;
if (i == ENDPOINT_DECON_NODE &&
of_get_child_by_name(remote_node, "i80-if-timings"))
mic->i80_mode = 1;
}
exit:
while (--j > -1)
of_node_put(nodes[j]);
return ret;
}
static void mic_disable(struct drm_bridge *bridge) { } static void mic_disable(struct drm_bridge *bridge) { }
static void mic_post_disable(struct drm_bridge *bridge) static void mic_post_disable(struct drm_bridge *bridge)
...@@ -286,6 +253,7 @@ static void mic_mode_set(struct drm_bridge *bridge, ...@@ -286,6 +253,7 @@ static void mic_mode_set(struct drm_bridge *bridge,
mutex_lock(&mic_mutex); mutex_lock(&mic_mutex);
drm_display_mode_to_videomode(mode, &mic->vm); drm_display_mode_to_videomode(mode, &mic->vm);
mic->i80_mode = to_exynos_crtc(bridge->encoder->crtc)->i80_mode;
mutex_unlock(&mic_mutex); mutex_unlock(&mic_mutex);
} }
...@@ -417,10 +385,6 @@ static int exynos_mic_probe(struct platform_device *pdev) ...@@ -417,10 +385,6 @@ static int exynos_mic_probe(struct platform_device *pdev)
mic->dev = dev; mic->dev = dev;
ret = parse_dt(mic);
if (ret)
goto err;
ret = of_address_to_resource(dev->of_node, 0, &res); ret = of_address_to_resource(dev->of_node, 0, &res);
if (ret) { if (ret) {
DRM_ERROR("mic: Failed to get mem region for MIC\n"); DRM_ERROR("mic: Failed to get mem region for MIC\n");
......
...@@ -178,6 +178,29 @@ static struct drm_plane_funcs exynos_plane_funcs = { ...@@ -178,6 +178,29 @@ static struct drm_plane_funcs exynos_plane_funcs = {
.atomic_destroy_state = exynos_drm_plane_destroy_state, .atomic_destroy_state = exynos_drm_plane_destroy_state,
}; };
static int
exynos_drm_plane_check_format(const struct exynos_drm_plane_config *config,
struct exynos_drm_plane_state *state)
{
struct drm_framebuffer *fb = state->base.fb;
switch (fb->modifier) {
case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
if (!(config->capabilities & EXYNOS_DRM_PLANE_CAP_TILE))
return -ENOTSUPP;
break;
case DRM_FORMAT_MOD_LINEAR:
break;
default:
DRM_ERROR("unsupported pixel format modifier");
return -ENOTSUPP;
}
return 0;
}
static int static int
exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config,
struct exynos_drm_plane_state *state) struct exynos_drm_plane_state *state)
...@@ -222,6 +245,10 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, ...@@ -222,6 +245,10 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
/* translate state into exynos_state */ /* translate state into exynos_state */
exynos_plane_mode_set(exynos_state); exynos_plane_mode_set(exynos_state);
ret = exynos_drm_plane_check_format(exynos_plane->config, exynos_state);
if (ret)
return ret;
ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state); ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state);
return ret; return ret;
} }
......
...@@ -381,7 +381,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -381,7 +381,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
struct exynos_drm_plane_config plane_config = { 0 }; struct exynos_drm_plane_config plane_config = { 0 };
unsigned int i; unsigned int i;
int pipe, ret; int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
...@@ -406,20 +406,15 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -406,20 +406,15 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
} }
pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_VIDI);
if (pipe < 0)
return pipe;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL); DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs); drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_VIDI);
if (ret < 0)
return ret;
ret = vidi_create_connector(encoder); ret = vidi_create_connector(encoder);
if (ret) { if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret); DRM_ERROR("failed to create connector ret = %d\n", ret);
......
...@@ -1697,32 +1697,25 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -1697,32 +1697,25 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct hdmi_context *hdata = dev_get_drvdata(dev); struct hdmi_context *hdata = dev_get_drvdata(dev);
struct drm_encoder *encoder = &hdata->encoder; struct drm_encoder *encoder = &hdata->encoder;
struct exynos_drm_crtc *exynos_crtc; struct exynos_drm_crtc *crtc;
struct drm_crtc *crtc; int ret;
int ret, pipe;
hdata->drm_dev = drm_dev; hdata->drm_dev = drm_dev;
pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
EXYNOS_DISPLAY_TYPE_HDMI);
if (pipe < 0)
return pipe;
hdata->phy_clk.enable = hdmiphy_clk_enable; hdata->phy_clk.enable = hdmiphy_clk_enable;
crtc = drm_crtc_from_index(drm_dev, pipe);
exynos_crtc = to_exynos_crtc(crtc);
exynos_crtc->pipe_clk = &hdata->phy_clk;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs, drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL); DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs); drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_HDMI);
if (ret < 0)
return ret;
crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI);
crtc->pipe_clk = &hdata->phy_clk;
ret = hdmi_create_connector(encoder); ret = hdmi_create_connector(encoder);
if (ret) { if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret); DRM_ERROR("failed to create connector ret = %d\n", ret);
......
...@@ -148,7 +148,8 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = { ...@@ -148,7 +148,8 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
.pixel_formats = vp_formats, .pixel_formats = vp_formats,
.num_pixel_formats = ARRAY_SIZE(vp_formats), .num_pixel_formats = ARRAY_SIZE(vp_formats),
.capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
EXYNOS_DRM_PLANE_CAP_ZPOS, EXYNOS_DRM_PLANE_CAP_ZPOS |
EXYNOS_DRM_PLANE_CAP_TILE,
}, },
}; };
...@@ -483,29 +484,18 @@ static void vp_video_buffer(struct mixer_context *ctx, ...@@ -483,29 +484,18 @@ static void vp_video_buffer(struct mixer_context *ctx,
unsigned int priority = state->base.normalized_zpos + 1; unsigned int priority = state->base.normalized_zpos + 1;
unsigned long flags; unsigned long flags;
dma_addr_t luma_addr[2], chroma_addr[2]; dma_addr_t luma_addr[2], chroma_addr[2];
bool tiled_mode = false; bool is_tiled, is_nv21;
bool crcb_mode = false;
u32 val; u32 val;
switch (fb->format->format) { is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
case DRM_FORMAT_NV12: is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
crcb_mode = false;
break;
case DRM_FORMAT_NV21:
crcb_mode = true;
break;
default:
DRM_ERROR("pixel format for vp is wrong [%d].\n",
fb->format->format);
return;
}
luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0); luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1); chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
if (mode->flags & DRM_MODE_FLAG_INTERLACE) { if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
__set_bit(MXR_BIT_INTERLACE, &ctx->flags); __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
if (tiled_mode) { if (is_tiled) {
luma_addr[1] = luma_addr[0] + 0x40; luma_addr[1] = luma_addr[0] + 0x40;
chroma_addr[1] = chroma_addr[0] + 0x40; chroma_addr[1] = chroma_addr[0] + 0x40;
} else { } else {
...@@ -525,14 +515,14 @@ static void vp_video_buffer(struct mixer_context *ctx, ...@@ -525,14 +515,14 @@ static void vp_video_buffer(struct mixer_context *ctx,
vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP); vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
/* setup format */ /* setup format */
val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12); val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR); val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
/* setting size of input image */ /* setting size of input image */
vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
VP_IMG_VSIZE(fb->height)); VP_IMG_VSIZE(fb->height));
/* chroma height has to reduced by 2 to avoid chroma distorions */ /* chroma plane for NV12/NV21 is half the height of the luma plane */
vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
VP_IMG_VSIZE(fb->height / 2)); VP_IMG_VSIZE(fb->height / 2));
...@@ -594,7 +584,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ...@@ -594,7 +584,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
unsigned long flags; unsigned long flags;
unsigned int win = plane->index; unsigned int win = plane->index;
unsigned int x_ratio = 0, y_ratio = 0; unsigned int x_ratio = 0, y_ratio = 0;
unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; unsigned int dst_x_offset, dst_y_offset;
dma_addr_t dma_addr; dma_addr_t dma_addr;
unsigned int fmt; unsigned int fmt;
u32 val; u32 val;
...@@ -616,12 +606,9 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ...@@ -616,12 +606,9 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ARGB8888:
default:
fmt = MXR_FORMAT_ARGB8888; fmt = MXR_FORMAT_ARGB8888;
break; break;
default:
DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
return;
} }
/* ratio is already checked by common plane code */ /* ratio is already checked by common plane code */
...@@ -631,12 +618,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ...@@ -631,12 +618,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
dst_x_offset = state->crtc.x; dst_x_offset = state->crtc.x;
dst_y_offset = state->crtc.y; dst_y_offset = state->crtc.y;
/* converting dma address base and source offset */ /* translate dma address base s.t. the source image offset is zero */
dma_addr = exynos_drm_fb_dma_addr(fb, 0) dma_addr = exynos_drm_fb_dma_addr(fb, 0)
+ (state->src.x * fb->format->cpp[0]) + (state->src.x * fb->format->cpp[0])
+ (state->src.y * fb->pitches[0]); + (state->src.y * fb->pitches[0]);
src_x_offset = 0;
src_y_offset = 0;
if (mode->flags & DRM_MODE_FLAG_INTERLACE) if (mode->flags & DRM_MODE_FLAG_INTERLACE)
__set_bit(MXR_BIT_INTERLACE, &ctx->flags); __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
...@@ -667,11 +652,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ...@@ -667,11 +652,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
val |= MXR_GRP_WH_V_SCALE(y_ratio); val |= MXR_GRP_WH_V_SCALE(y_ratio);
mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
/* setup offsets in source image */
val = MXR_GRP_SXY_SX(src_x_offset);
val |= MXR_GRP_SXY_SY(src_y_offset);
mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
/* setup offsets in display image */ /* setup offsets in display image */
val = MXR_GRP_DXY_DX(dst_x_offset); val = MXR_GRP_DXY_DX(dst_x_offset);
val |= MXR_GRP_DXY_DY(dst_y_offset); val |= MXR_GRP_DXY_DY(dst_y_offset);
...@@ -748,6 +728,10 @@ static void mixer_win_reset(struct mixer_context *ctx) ...@@ -748,6 +728,10 @@ static void mixer_win_reset(struct mixer_context *ctx)
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
/* set all source image offsets to zero */
mixer_reg_write(res, MXR_GRAPHIC_SXY(0), 0);
mixer_reg_write(res, MXR_GRAPHIC_SXY(1), 0);
spin_unlock_irqrestore(&res->reg_slock, flags); spin_unlock_irqrestore(&res->reg_slock, flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment