Commit c9f0726f authored by Dave Airlie's avatar Dave Airlie

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

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
  ...
parents 55f5b0bf ce42cf4b
...@@ -8,12 +8,13 @@ Required properties: ...@@ -8,12 +8,13 @@ Required properties:
- compatible: value should be one of: - compatible: value should be one of:
"samsung,exynos5433-decon", "samsung,exynos5433-decon-tv"; "samsung,exynos5433-decon", "samsung,exynos5433-decon-tv";
- reg: physical base address and length of the DECON registers set. - reg: physical base address and length of the DECON registers set.
- interrupts: should contain a list of all DECON IP block interrupts in the - interrupt-names: should contain the interrupt names depending on mode of work:
order: VSYNC, LCD_SYSTEM. The interrupt specifier format video mode: "vsync",
depends on the interrupt controller used. command mode: "lcd_sys",
- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys" command mode with software trigger: "lcd_sys", "te".
in the same order as they were listed in the interrupts - interrupts or interrupts-extended: list of interrupt specifiers corresponding
property. to names privided in interrupt-names, as described in
interrupt-controller/interrupts.txt
- clocks: must include clock specifiers corresponding to entries in the - clocks: must include clock specifiers corresponding to entries in the
clock-names property. clock-names property.
- clock-names: list of clock names sorted in the same order as the clocks - clock-names: list of clock names sorted in the same order as the clocks
......
...@@ -55,7 +55,6 @@ struct decon_context { ...@@ -55,7 +55,6 @@ struct decon_context {
unsigned long irq_flags; unsigned long irq_flags;
bool i80_if; bool i80_if;
bool suspended; bool suspended;
int pipe;
wait_queue_head_t wait_vsync_queue; wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
...@@ -130,19 +129,11 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -130,19 +129,11 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
static int decon_ctx_initialize(struct decon_context *ctx, static int decon_ctx_initialize(struct decon_context *ctx,
struct drm_device *drm_dev) struct drm_device *drm_dev)
{ {
struct exynos_drm_private *priv = drm_dev->dev_private;
int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
decon_clear_channels(ctx->crtc); decon_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, ctx->dev); return drm_iommu_attach_device(drm_dev, ctx->dev);
if (ret)
priv->pipe--;
return ret;
} }
static void decon_ctx_remove(struct decon_context *ctx) static void decon_ctx_remove(struct decon_context *ctx)
...@@ -590,7 +581,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -590,7 +581,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
static const struct exynos_drm_crtc_ops decon_crtc_ops = { static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable = decon_enable, .enable = decon_enable,
.disable = decon_disable, .disable = decon_disable,
.commit = decon_commit,
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.atomic_begin = decon_atomic_begin, .atomic_begin = decon_atomic_begin,
...@@ -612,7 +602,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) ...@@ -612,7 +602,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
writel(clear_bit, ctx->regs + VIDINTCON1); writel(clear_bit, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */ /* check the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
goto out; goto out;
if (!ctx->i80_if) { if (!ctx->i80_if) {
...@@ -649,15 +639,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -649,15 +639,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
ctx->configs[i].type = decon_win_types[i]; ctx->configs[i].type = decon_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &ctx->configs[i]); &ctx->configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx);
&decon_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
decon_ctx_remove(ctx); decon_ctx_remove(ctx);
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
......
...@@ -49,15 +49,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *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, static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
...@@ -93,7 +84,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -93,7 +84,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.enable = exynos_drm_crtc_enable, .enable = exynos_drm_crtc_enable,
.disable = exynos_drm_crtc_disable, .disable = exynos_drm_crtc_disable,
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
.atomic_check = exynos_crtc_atomic_check, .atomic_check = exynos_crtc_atomic_check,
.atomic_begin = exynos_crtc_atomic_begin, .atomic_begin = exynos_crtc_atomic_begin,
.atomic_flush = exynos_crtc_atomic_flush, .atomic_flush = exynos_crtc_atomic_flush,
...@@ -105,16 +95,15 @@ void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) ...@@ -105,16 +95,15 @@ void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
struct drm_pending_vblank_event *event = crtc->state->event; struct drm_pending_vblank_event *event = crtc->state->event;
unsigned long flags; unsigned long flags;
if (event) { if (!event)
crtc->state->event = NULL; return;
spin_lock_irqsave(&crtc->dev->event_lock, flags); crtc->state->event = NULL;
if (drm_crtc_vblank_get(crtc) == 0)
drm_crtc_arm_vblank_event(crtc, event);
else
drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_arm_vblank_event(crtc, event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
} }
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
...@@ -143,6 +132,16 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) ...@@ -143,6 +132,16 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
exynos_crtc->ops->disable_vblank(exynos_crtc); exynos_crtc->ops->disable_vblank(exynos_crtc);
} }
static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->ops->get_vblank_counter)
return exynos_crtc->ops->get_vblank_counter(exynos_crtc);
return 0;
}
static const struct drm_crtc_funcs exynos_crtc_funcs = { static const struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
...@@ -152,11 +151,11 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = { ...@@ -152,11 +151,11 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = exynos_drm_crtc_enable_vblank, .enable_vblank = exynos_drm_crtc_enable_vblank,
.disable_vblank = exynos_drm_crtc_disable_vblank, .disable_vblank = exynos_drm_crtc_disable_vblank,
.get_vblank_counter = exynos_drm_crtc_get_vblank_counter,
}; };
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_plane *plane, struct drm_plane *plane,
int pipe,
enum exynos_drm_output_type type, enum exynos_drm_output_type type,
const struct exynos_drm_crtc_ops *ops, const struct exynos_drm_crtc_ops *ops,
void *ctx) void *ctx)
...@@ -169,7 +168,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, ...@@ -169,7 +168,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
if (!exynos_crtc) if (!exynos_crtc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
exynos_crtc->pipe = pipe;
exynos_crtc->type = type; exynos_crtc->type = type;
exynos_crtc->ops = ops; exynos_crtc->ops = ops;
exynos_crtc->ctx = ctx; exynos_crtc->ctx = ctx;
...@@ -196,13 +194,9 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, ...@@ -196,13 +194,9 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { drm_for_each_crtc(crtc, drm_dev)
struct exynos_drm_crtc *exynos_crtc; if (to_exynos_crtc(crtc)->type == out_type)
return drm_crtc_index(crtc);
exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->type == out_type)
return exynos_crtc->pipe;
}
return -EPERM; return -EPERM;
} }
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
struct drm_plane *plane, struct drm_plane *plane,
int pipe,
enum exynos_drm_output_type type, enum exynos_drm_output_type type,
const struct exynos_drm_crtc_ops *ops, const struct exynos_drm_crtc_ops *ops,
void *context); void *context);
......
...@@ -115,7 +115,6 @@ struct exynos_drm_plane_config { ...@@ -115,7 +115,6 @@ struct exynos_drm_plane_config {
* *
* @enable: enable the device * @enable: enable the device
* @disable: disable the device * @disable: disable the device
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt. * @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt.
* @atomic_check: validate state * @atomic_check: validate state
...@@ -130,9 +129,9 @@ struct exynos_drm_crtc; ...@@ -130,9 +129,9 @@ struct exynos_drm_crtc;
struct exynos_drm_crtc_ops { struct exynos_drm_crtc_ops {
void (*enable)(struct exynos_drm_crtc *crtc); void (*enable)(struct exynos_drm_crtc *crtc);
void (*disable)(struct exynos_drm_crtc *crtc); void (*disable)(struct exynos_drm_crtc *crtc);
void (*commit)(struct exynos_drm_crtc *crtc);
int (*enable_vblank)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc);
int (*atomic_check)(struct exynos_drm_crtc *crtc, int (*atomic_check)(struct exynos_drm_crtc *crtc,
struct drm_crtc_state *state); struct drm_crtc_state *state);
void (*atomic_begin)(struct exynos_drm_crtc *crtc); void (*atomic_begin)(struct exynos_drm_crtc *crtc);
...@@ -153,24 +152,13 @@ struct exynos_drm_clk { ...@@ -153,24 +152,13 @@ struct exynos_drm_clk {
* *
* @base: crtc object. * @base: crtc object.
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @pipe: a crtc index created at load() with a new crtc object creation
* and the crtc object would be set to private->crtc array
* to get a crtc object corresponding to this pipe from private->crtc
* array when irq interrupt occurred. the reason of using this pipe is that
* drm framework doesn't support multiple irq yet.
* we can refer to the crtc to current hardware interrupt occurred through
* this pipe value.
* @enabled: if the crtc is enabled or not
* @event: vblank event that is currently queued for flip
* @wait_update: wait all pending planes updates to finish
* @pending_update: number of pending plane updates in this crtc
* @ops: pointer to callbacks for exynos drm specific functionality * @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the crtc's implementation specific context * @ctx: A pointer to the crtc's implementation specific context
* @pipe_clk: A pointer to the crtc's pipeline clock.
*/ */
struct exynos_drm_crtc { struct exynos_drm_crtc {
struct drm_crtc base; struct drm_crtc base;
enum exynos_drm_output_type type; enum exynos_drm_output_type type;
unsigned int pipe;
const struct exynos_drm_crtc_ops *ops; const struct exynos_drm_crtc_ops *ops;
void *ctx; void *ctx;
struct exynos_drm_clk *pipe_clk; struct exynos_drm_clk *pipe_clk;
...@@ -203,7 +191,6 @@ struct drm_exynos_file_private { ...@@ -203,7 +191,6 @@ struct drm_exynos_file_private {
* otherwise default one. * otherwise default one.
* @da_space_size: size of device address space. * @da_space_size: size of device address space.
* if 0 then default value is used for it. * if 0 then default value is used for it.
* @pipe: the pipe number for this crtc/manager.
* @pending: the crtcs that have pending updates to finish * @pending: the crtcs that have pending updates to finish
* @lock: protect access to @pending * @lock: protect access to @pending
* @wait: wait an atomic commit to finish * @wait: wait an atomic commit to finish
...@@ -214,8 +201,6 @@ struct exynos_drm_private { ...@@ -214,8 +201,6 @@ struct exynos_drm_private {
struct device *dma_dev; struct device *dma_dev;
void *mapping; void *mapping;
unsigned int pipe;
/* for atomic commit */ /* for atomic commit */
u32 pending; u32 pending;
spinlock_t lock; spinlock_t lock;
......
...@@ -1633,7 +1633,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ...@@ -1633,7 +1633,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
{ {
struct device *dev = dsi->dev; struct device *dev = dsi->dev;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct device_node *ep;
int ret; int ret;
ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
...@@ -1641,32 +1640,21 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ...@@ -1641,32 +1640,21 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0) if (ret < 0)
return ret; return ret;
ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0); ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency",
if (!ep) {
dev_err(dev, "no output port with endpoint specified\n");
return -EINVAL;
}
ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency",
&dsi->burst_clk_rate); &dsi->burst_clk_rate);
if (ret < 0) if (ret < 0)
goto end; return ret;
ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency", ret = exynos_dsi_of_read_u32(node, "samsung,esc-clock-frequency",
&dsi->esc_clk_rate); &dsi->esc_clk_rate);
if (ret < 0) if (ret < 0)
goto end; return ret;
of_node_put(ep);
dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0); dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
if (!dsi->bridge_node) if (!dsi->bridge_node)
return -EINVAL; return -EINVAL;
end: return 0;
of_node_put(ep);
return ret;
} }
static int exynos_dsi_bind(struct device *dev, struct device *master, static int exynos_dsi_bind(struct device *dev, struct device *master,
...@@ -1817,6 +1805,10 @@ static int exynos_dsi_probe(struct platform_device *pdev) ...@@ -1817,6 +1805,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
static int exynos_dsi_remove(struct platform_device *pdev) static int exynos_dsi_remove(struct platform_device *pdev)
{ {
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
of_node_put(dsi->bridge_node);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &exynos_dsi_component_ops); component_del(&pdev->dev, &exynos_dsi_component_ops);
......
...@@ -179,7 +179,6 @@ struct fimd_context { ...@@ -179,7 +179,6 @@ struct fimd_context {
u32 i80ifcon; u32 i80ifcon;
bool i80_if; bool i80_if;
bool suspended; bool suspended;
int pipe;
wait_queue_head_t wait_vsync_queue; wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event; atomic_t wait_vsync_event;
atomic_t win_updated; atomic_t win_updated;
...@@ -354,18 +353,13 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -354,18 +353,13 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
/* Wait for vsync, as disable channel takes effect at next vsync */ /* Wait for vsync, as disable channel takes effect at next vsync */
if (ch_enabled) { if (ch_enabled) {
int pipe = ctx->pipe;
/* ensure that vblank interrupt won't be reported to core */
ctx->suspended = false; ctx->suspended = false;
ctx->pipe = -1;
fimd_enable_vblank(ctx->crtc); fimd_enable_vblank(ctx->crtc);
fimd_wait_for_vblank(ctx->crtc); fimd_wait_for_vblank(ctx->crtc);
fimd_disable_vblank(ctx->crtc); fimd_disable_vblank(ctx->crtc);
ctx->suspended = true; ctx->suspended = true;
ctx->pipe = pipe;
} }
clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->lcd_clk);
...@@ -899,7 +893,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) ...@@ -899,7 +893,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
u32 trg_type = ctx->driver_data->trg_type; u32 trg_type = ctx->driver_data->trg_type;
/* Checks the crtc is detached already from encoder */ /* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
return; return;
if (trg_type == I80_HW_TRG) if (trg_type == I80_HW_TRG)
...@@ -934,7 +928,6 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable) ...@@ -934,7 +928,6 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
static const struct exynos_drm_crtc_ops fimd_crtc_ops = { static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
.enable = fimd_enable, .enable = fimd_enable,
.disable = fimd_disable, .disable = fimd_disable,
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank, .enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank, .disable_vblank = fimd_disable_vblank,
.atomic_begin = fimd_atomic_begin, .atomic_begin = fimd_atomic_begin,
...@@ -957,7 +950,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) ...@@ -957,7 +950,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
writel(clear_bit, ctx->regs + VIDINTCON1); writel(clear_bit, ctx->regs + VIDINTCON1);
/* check the crtc is detached already from encoder */ /* check the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (!ctx->drm_dev)
goto out; goto out;
if (!ctx->i80_if) if (!ctx->i80_if)
...@@ -982,13 +975,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -982,13 +975,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
{ {
struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
unsigned int i; unsigned int i;
int ret; int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
for (i = 0; i < WINDOWS_NR; i++) { for (i = 0; i < WINDOWS_NR; i++) {
ctx->configs[i].pixel_formats = fimd_formats; ctx->configs[i].pixel_formats = fimd_formats;
...@@ -996,15 +987,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -996,15 +987,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
ctx->configs[i].zpos = i; ctx->configs[i].zpos = i;
ctx->configs[i].type = fimd_win_types[i]; ctx->configs[i].type = fimd_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &ctx->configs[i]); &ctx->configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx);
&fimd_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
...@@ -1019,11 +1009,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -1019,11 +1009,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
if (is_drm_iommu_supported(drm_dev)) if (is_drm_iommu_supported(drm_dev))
fimd_clear_channels(ctx->crtc); fimd_clear_channels(ctx->crtc);
ret = drm_iommu_attach_device(drm_dev, dev); return drm_iommu_attach_device(drm_dev, dev);
if (ret)
priv->pipe--;
return ret;
} }
static void fimd_unbind(struct device *dev, struct device *master, static void fimd_unbind(struct device *dev, struct device *master,
......
...@@ -273,14 +273,13 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, ...@@ -273,14 +273,13 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
} }
int exynos_plane_init(struct drm_device *dev, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, struct exynos_drm_plane *exynos_plane, unsigned int index,
unsigned int index, unsigned long possible_crtcs,
const struct exynos_drm_plane_config *config) const struct exynos_drm_plane_config *config)
{ {
int err; int err;
err = drm_universal_plane_init(dev, &exynos_plane->base, err = drm_universal_plane_init(dev, &exynos_plane->base,
possible_crtcs, 1 << dev->mode_config.num_crtc,
&exynos_plane_funcs, &exynos_plane_funcs,
config->pixel_formats, config->pixel_formats,
config->num_pixel_formats, config->num_pixel_formats,
......
...@@ -11,5 +11,4 @@ ...@@ -11,5 +11,4 @@
int exynos_plane_init(struct drm_device *dev, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, unsigned int index, struct exynos_drm_plane *exynos_plane, unsigned int index,
unsigned long possible_crtcs,
const struct exynos_drm_plane_config *config); const struct exynos_drm_plane_config *config);
...@@ -51,7 +51,6 @@ struct vidi_context { ...@@ -51,7 +51,6 @@ struct vidi_context {
bool suspended; bool suspended;
struct timer_list timer; struct timer_list timer;
struct mutex lock; struct mutex lock;
int pipe;
}; };
static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
...@@ -153,17 +152,6 @@ static void vidi_disable(struct exynos_drm_crtc *crtc) ...@@ -153,17 +152,6 @@ static void vidi_disable(struct exynos_drm_crtc *crtc)
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
} }
static int vidi_ctx_initialize(struct vidi_context *ctx,
struct drm_device *drm_dev)
{
struct exynos_drm_private *priv = drm_dev->dev_private;
ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
return 0;
}
static const struct exynos_drm_crtc_ops vidi_crtc_ops = { static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
.enable = vidi_enable, .enable = vidi_enable,
.disable = vidi_disable, .disable = vidi_disable,
...@@ -177,9 +165,6 @@ static void vidi_fake_vblank_timer(unsigned long arg) ...@@ -177,9 +165,6 @@ static void vidi_fake_vblank_timer(unsigned long arg)
{ {
struct vidi_context *ctx = (void *)arg; struct vidi_context *ctx = (void *)arg;
if (ctx->pipe < 0)
return;
if (drm_crtc_handle_vblank(&ctx->crtc->base)) if (drm_crtc_handle_vblank(&ctx->crtc->base))
mod_timer(&ctx->timer, mod_timer(&ctx->timer,
jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1); jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
...@@ -399,7 +384,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -399,7 +384,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
unsigned int i; unsigned int i;
int pipe, ret; int pipe, ret;
vidi_ctx_initialize(ctx, drm_dev); ctx->drm_dev = drm_dev;
plane_config.pixel_formats = formats; plane_config.pixel_formats = formats;
plane_config.num_pixel_formats = ARRAY_SIZE(formats); plane_config.num_pixel_formats = ARRAY_SIZE(formats);
...@@ -409,15 +394,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -409,15 +394,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
plane_config.type = vidi_win_types[i]; plane_config.type = vidi_win_types[i];
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &plane_config); &plane_config);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx);
&vidi_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
DRM_ERROR("failed to create crtc.\n"); DRM_ERROR("failed to create crtc.\n");
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
......
...@@ -1486,8 +1486,6 @@ static void hdmi_enable(struct drm_encoder *encoder) ...@@ -1486,8 +1486,6 @@ static void hdmi_enable(struct drm_encoder *encoder)
static void hdmi_disable(struct drm_encoder *encoder) static void hdmi_disable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
struct drm_crtc *crtc = encoder->crtc;
const struct drm_crtc_helper_funcs *funcs = NULL;
if (!hdata->powered) if (!hdata->powered)
return; return;
...@@ -1498,16 +1496,11 @@ static void hdmi_disable(struct drm_encoder *encoder) ...@@ -1498,16 +1496,11 @@ static void hdmi_disable(struct drm_encoder *encoder)
* to disable TV Subsystem should be as following, * to disable TV Subsystem should be as following,
* VP -> Mixer -> HDMI * VP -> Mixer -> HDMI
* *
* Below codes will try to disable Mixer and VP(if used) * To achieve such sequence HDMI is disabled together with HDMI PHY, via
* prior to disabling HDMI. * pipe clock callback.
*/ */
if (crtc)
funcs = crtc->helper_private;
if (funcs && funcs->disable)
(*funcs->disable)(crtc);
cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
cancel_delayed_work(&hdata->hotplug_work); cancel_delayed_work(&hdata->hotplug_work);
cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
hdmiphy_disable(hdata); hdmiphy_disable(hdata);
} }
......
...@@ -45,6 +45,22 @@ ...@@ -45,6 +45,22 @@
#define MIXER_WIN_NR 3 #define MIXER_WIN_NR 3
#define VP_DEFAULT_WIN 2 #define VP_DEFAULT_WIN 2
/*
* Mixer color space conversion coefficient triplet.
* Used for CSC from RGB to YCbCr.
* Each coefficient is a 10-bit fixed point number with
* sign and no integer part, i.e.
* [0:8] = fractional part (representing a value y = x / 2^9)
* [9] = sign
* Negative values are encoded with two's complement.
*/
#define MXR_CSC_C(x) ((int)((x) * 512.0) & 0x3ff)
#define MXR_CSC_CT(a0, a1, a2) \
((MXR_CSC_C(a0) << 20) | (MXR_CSC_C(a1) << 10) | (MXR_CSC_C(a2) << 0))
/* YCbCr value, used for mixer background color configuration. */
#define MXR_YCBCR_VAL(y, cb, cr) (((y) << 16) | ((cb) << 8) | ((cr) << 0))
/* The pixelformats that are natively supported by the mixer. */ /* The pixelformats that are natively supported by the mixer. */
#define MXR_FORMAT_RGB565 4 #define MXR_FORMAT_RGB565 4
#define MXR_FORMAT_ARGB1555 5 #define MXR_FORMAT_ARGB1555 5
...@@ -99,7 +115,6 @@ struct mixer_context { ...@@ -99,7 +115,6 @@ struct mixer_context {
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc; struct exynos_drm_crtc *crtc;
struct exynos_drm_plane planes[MIXER_WIN_NR]; struct exynos_drm_plane planes[MIXER_WIN_NR];
int pipe;
unsigned long flags; unsigned long flags;
struct mixer_resources mixer_res; struct mixer_resources mixer_res;
...@@ -382,37 +397,24 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height) ...@@ -382,37 +397,24 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
u32 val; u32 val;
if (height == 480) { switch (height) {
val = MXR_CFG_RGB601_0_255; case 480:
} else if (height == 576) { case 576:
val = MXR_CFG_RGB601_0_255; val = MXR_CFG_RGB601_0_255;
} else if (height == 720) { break;
val = MXR_CFG_RGB709_16_235; case 720:
mixer_reg_write(res, MXR_CM_COEFF_Y, case 1080:
(1 << 30) | (94 << 20) | (314 << 10) | default:
(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 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; val = MXR_CFG_RGB709_16_235;
/* Configure the BT.709 CSC matrix for full range RGB. */
mixer_reg_write(res, MXR_CM_COEFF_Y, mixer_reg_write(res, MXR_CM_COEFF_Y,
(1 << 30) | (94 << 20) | (314 << 10) | MXR_CSC_CT( 0.184, 0.614, 0.063) |
(32 << 0)); MXR_CM_COEFF_RGB_FULL);
mixer_reg_write(res, MXR_CM_COEFF_CB, mixer_reg_write(res, MXR_CM_COEFF_CB,
(972 << 20) | (851 << 10) | (225 << 0)); MXR_CSC_CT(-0.102, -0.338, 0.440));
mixer_reg_write(res, MXR_CM_COEFF_CR, mixer_reg_write(res, MXR_CM_COEFF_CR,
(225 << 20) | (820 << 10) | (1004 << 0)); MXR_CSC_CT( 0.440, -0.399, -0.040));
break;
} }
mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK); mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
...@@ -729,10 +731,10 @@ static void mixer_win_reset(struct mixer_context *ctx) ...@@ -729,10 +731,10 @@ static void mixer_win_reset(struct mixer_context *ctx)
/* reset default layer priority */ /* reset default layer priority */
mixer_reg_write(res, MXR_LAYER_CFG, 0); mixer_reg_write(res, MXR_LAYER_CFG, 0);
/* setting background color */ /* set all background colors to RGB (0,0,0) */
mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) { if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
/* configuration of Video Processor Registers */ /* configuration of Video Processor Registers */
...@@ -900,7 +902,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, ...@@ -900,7 +902,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
priv = drm_dev->dev_private; priv = drm_dev->dev_private;
mixer_ctx->drm_dev = drm_dev; mixer_ctx->drm_dev = drm_dev;
mixer_ctx->pipe = priv->pipe++;
/* acquire resources: regs, irqs, clocks */ /* acquire resources: regs, irqs, clocks */
ret = mixer_resources_init(mixer_ctx); ret = mixer_resources_init(mixer_ctx);
...@@ -918,11 +919,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, ...@@ -918,11 +919,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
} }
} }
ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev); return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
if (ret)
priv->pipe--;
return ret;
} }
static void mixer_ctx_remove(struct mixer_context *mixer_ctx) static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
...@@ -1158,15 +1155,14 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) ...@@ -1158,15 +1155,14 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
continue; continue;
ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1 << ctx->pipe, &plane_configs[i]); &plane_configs[i]);
if (ret) if (ret)
return ret; return ret;
} }
exynos_plane = &ctx->planes[DEFAULT_WIN]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
&mixer_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
mixer_ctx_remove(ctx); mixer_ctx_remove(ctx);
ret = PTR_ERR(ctx->crtc); ret = PTR_ERR(ctx->crtc);
......
...@@ -140,11 +140,11 @@ ...@@ -140,11 +140,11 @@
#define MXR_INT_EN_VSYNC (1 << 11) #define MXR_INT_EN_VSYNC (1 << 11)
#define MXR_INT_EN_ALL (0x0f << 8) #define MXR_INT_EN_ALL (0x0f << 8)
/* bit for MXR_INT_STATUS */ /* bits for MXR_INT_STATUS */
#define MXR_INT_CLEAR_VSYNC (1 << 11) #define MXR_INT_CLEAR_VSYNC (1 << 11)
#define MXR_INT_STATUS_VSYNC (1 << 0) #define MXR_INT_STATUS_VSYNC (1 << 0)
/* bit for MXR_LAYER_CFG */ /* bits for MXR_LAYER_CFG */
#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8) #define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0) #define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0)
#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4) #define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
...@@ -152,5 +152,8 @@ ...@@ -152,5 +152,8 @@
#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0) #define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
#define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0) #define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0)
/* bits for MXR_CM_COEFF_Y */
#define MXR_CM_COEFF_RGB_FULL (1 << 30)
#endif /* SAMSUNG_REGS_MIXER_H */ #endif /* SAMSUNG_REGS_MIXER_H */
...@@ -118,6 +118,7 @@ ...@@ -118,6 +118,7 @@
#define WINCONx_ENWIN_F (1 << 0) #define WINCONx_ENWIN_F (1 << 0)
/* SHADOWCON */ /* SHADOWCON */
#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n))) #define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
/* VIDOSDxD */ /* VIDOSDxD */
......
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