2015-12-17 03:02:36

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 0/8] drm/rockchip: covert to support atomic API

The series of patches coverting drm rockchip to atomic API, do some
cleanup and some fixes on atomic side.

TODO: fence is not support on current version.

Tested on rk3288 popmetal board.

All guys can test it with following url:
test case: https://github.com/markyzq/libdrm.git atomictest
kernel:
https://github.com/markyzq/kernel-drm-rockchip.git drm-rockchip-next-12-17

Changes in v3:
Reported by kbuild test robot
- fix rockchip_crtc_wait_for_update undefined when build drm rockchip as modules.

Changes in v2:
- Optimization commit planes sequence.
- Get vblank count on atomic_begin to protect vblank event.
Advised by Daniel Stone
- Direct return -EINVAL when yuv address is not support, instead of adjust it.
- code formating and cleanup.
Advised by Thierry Reding & Daniel Vetter
- Hook mode_set into crtc enable instead of hack crtc enable on mode set.

v2: http://www.spinics.net/lists/arm-kernel/msg468423.html
v1: http://lists.freedesktop.org/archives/dri-devel/2015-November/095745.html

Mark Yao (8):
drm/rockchip: Use new vblank api drm_crtc_vblank_*
drm/rockchip: vop: replace dpms with enable/disable
drm/rockchip: Convert to support atomic API
drm/rockchip: Optimization vop mode set
drm/rockchip: support atomic asynchronous commit
drm/rockchip: direct config connecter gate and out_mode
drm: bridge/dw_hdmi: add atomic API support
drm/rockchip: dw_hdmi: use encoder enable function

drivers/gpu/drm/bridge/dw_hdmi.c | 23 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 21 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 20 +-
drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 123 +++++
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 782 +++++++++++----------------
6 files changed, 495 insertions(+), 488 deletions(-)

--
1.7.9.5


2015-12-17 03:03:28

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 1/8] drm/rockchip: Use new vblank api drm_crtc_vblank_*

No functional update, drm_vblank_* is the legacy version of
drm_crtc_vblank_*. and use new api make driver more clean.

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None

drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 13 +++++++------
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 7 +++----
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 +++++++++++-------------
3 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index f22e1e1..cfd9b83 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -64,11 +64,11 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
}
EXPORT_SYMBOL_GPL(rockchip_drm_dma_detach_device);

-int rockchip_register_crtc_funcs(struct drm_device *dev,
- const struct rockchip_crtc_funcs *crtc_funcs,
- int pipe)
+int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
+ const struct rockchip_crtc_funcs *crtc_funcs)
{
- struct rockchip_drm_private *priv = dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;

if (pipe > ROCKCHIP_MAX_CRTC)
return -EINVAL;
@@ -79,9 +79,10 @@ int rockchip_register_crtc_funcs(struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(rockchip_register_crtc_funcs);

-void rockchip_unregister_crtc_funcs(struct drm_device *dev, int pipe)
+void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc)
{
- struct rockchip_drm_private *priv = dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;

if (pipe > ROCKCHIP_MAX_CRTC)
return;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index dc4e5f0..069d6d4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -52,10 +52,9 @@ struct rockchip_drm_private {
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
};

-int rockchip_register_crtc_funcs(struct drm_device *dev,
- const struct rockchip_crtc_funcs *crtc_funcs,
- int pipe);
-void rockchip_unregister_crtc_funcs(struct drm_device *dev, int pipe);
+int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
+ const struct rockchip_crtc_funcs *crtc_funcs);
+void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
int rockchip_drm_encoder_get_mux_id(struct device_node *node,
struct drm_encoder *encoder);
int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc, int connector_type,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index dd8e086..f82c7ba 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -119,8 +119,6 @@ struct vop {
/* vop dclk reset */
struct reset_control *dclk_rst;

- int pipe;
-
struct vop_win win[];
};

@@ -692,7 +690,7 @@ static void vop_enable(struct drm_crtc *crtc)

enable_irq(vop->irq);

- drm_vblank_on(vop->drm_dev, vop->pipe);
+ drm_crtc_vblank_on(crtc);

return;

@@ -711,7 +709,7 @@ static void vop_disable(struct drm_crtc *crtc)
if (!vop->is_enabled)
return;

- drm_vblank_off(crtc->dev, vop->pipe);
+ drm_crtc_vblank_off(crtc);

/*
* Vop standby will take effect at end of current frame,
@@ -918,7 +916,7 @@ static int vop_update_plane_event(struct drm_plane *plane,
*/
mutex_lock(&vop->vsync_mutex);
if (fb != vop_win_last_pending_fb(vop_win)) {
- ret = drm_vblank_get(plane->dev, vop->pipe);
+ ret = drm_crtc_vblank_get(crtc);
if (ret) {
DRM_ERROR("failed to get vblank, %d\n", ret);
mutex_unlock(&vop->vsync_mutex);
@@ -929,7 +927,7 @@ static int vop_update_plane_event(struct drm_plane *plane,

ret = vop_win_queue_fb(vop_win, fb, yrgb_mst, event);
if (ret) {
- drm_vblank_put(plane->dev, vop->pipe);
+ drm_crtc_vblank_put(crtc);
mutex_unlock(&vop->vsync_mutex);
return ret;
}
@@ -1023,7 +1021,7 @@ static int vop_disable_plane(struct drm_plane *plane)

vop = to_vop(plane->crtc);

- ret = drm_vblank_get(plane->dev, vop->pipe);
+ ret = drm_crtc_vblank_get(plane->crtc);
if (ret) {
DRM_ERROR("failed to get vblank, %d\n", ret);
return ret;
@@ -1033,7 +1031,7 @@ static int vop_disable_plane(struct drm_plane *plane)

ret = vop_win_queue_fb(vop_win, NULL, 0, NULL);
if (ret) {
- drm_vblank_put(plane->dev, vop->pipe);
+ drm_crtc_vblank_put(plane->crtc);
mutex_unlock(&vop->vsync_mutex);
return ret;
}
@@ -1295,7 +1293,7 @@ static void vop_win_state_complete(struct vop_win *vop_win,
}

list_del(&state->head);
- drm_vblank_put(crtc->dev, vop->pipe);
+ drm_crtc_vblank_put(crtc);
}

static void vop_crtc_destroy(struct drm_crtc *crtc)
@@ -1410,6 +1408,7 @@ done:
static irqreturn_t vop_isr(int irq, void *data)
{
struct vop *vop = data;
+ struct drm_crtc *crtc = &vop->crtc;
uint32_t intr0_reg, active_irqs;
unsigned long flags;
int ret = IRQ_NONE;
@@ -1438,7 +1437,7 @@ static irqreturn_t vop_isr(int irq, void *data)
}

if (active_irqs & FS_INTR) {
- drm_handle_vblank(vop->drm_dev, vop->pipe);
+ drm_crtc_handle_vblank(crtc);
active_irqs &= ~FS_INTR;
ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
}
@@ -1531,8 +1530,7 @@ static int vop_create_crtc(struct vop *vop)

init_completion(&vop->dsp_hold_completion);
crtc->port = port;
- vop->pipe = drm_crtc_index(crtc);
- rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
+ rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);

return 0;

@@ -1548,7 +1546,7 @@ static void vop_destroy_crtc(struct vop *vop)
{
struct drm_crtc *crtc = &vop->crtc;

- rockchip_unregister_crtc_funcs(vop->drm_dev, vop->pipe);
+ rockchip_unregister_crtc_funcs(crtc);
of_node_put(crtc->port);
drm_crtc_cleanup(crtc);
}
--
1.7.9.5

2015-12-17 03:02:39

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 2/8] drm/rockchip: vop: replace dpms with enable/disable

For vop, power by enable/disable is more suitable then legacy dpms
function, and enable/disable more closely to the new atomic API.

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None

drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 37 +++------------------------
1 file changed, 4 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index f82c7ba..1e60ddd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -632,7 +632,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(&vop->irq_lock, flags);
}

-static void vop_enable(struct drm_crtc *crtc)
+static void vop_crtc_enable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
int ret;
@@ -702,7 +702,7 @@ err_disable_hclk:
clk_disable(vop->hclk);
}

-static void vop_disable(struct drm_crtc *crtc)
+static void vop_crtc_disable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);

@@ -1107,30 +1107,6 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
.disable_vblank = vop_crtc_disable_vblank,
};

-static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- vop_enable(crtc);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- vop_disable(crtc);
- break;
- default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
- break;
- }
-}
-
-static void vop_crtc_prepare(struct drm_crtc *crtc)
-{
- vop_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
-}
-
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -1241,17 +1217,12 @@ out:
return ret;
}

-static void vop_crtc_commit(struct drm_crtc *crtc)
-{
-}
-
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
- .dpms = vop_crtc_dpms,
- .prepare = vop_crtc_prepare,
+ .enable = vop_crtc_enable,
+ .disable = vop_crtc_disable,
.mode_fixup = vop_crtc_mode_fixup,
.mode_set = vop_crtc_mode_set,
.mode_set_base = vop_crtc_mode_set_base,
- .commit = vop_crtc_commit,
};

static int vop_crtc_page_flip(struct drm_crtc *crtc,
--
1.7.9.5

2015-12-17 03:02:45

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 3/8] drm/rockchip: Convert to support atomic API

Rockchip vop not support hw vblank counter, needed check the committed
register if it's really take effect.

Signed-off-by: Mark Yao <[email protected]>
Signed-off-by: Tomasz Figa <[email protected]>
---
Changes in v3:
Reported by kbuild test robot
- fix rockchip_crtc_wait_for_update undefined when build drm rockchip as modules.

Changes in v2:
- Optimization commit planes sequence.
- Get vblank count on atomic_begin to protect vblank event.
Adviced by Daniel Stone
- Direct return -EINVAL when yuv address is not support, instead of adjust it.
- code formating and cleanup.
Adviced by Thierry Reding & Daniel Vetter
- Hook mode_set into crtc enable instead of hack crtc enable on mode set.

drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 5 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 +-
drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 95 ++++
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 657 +++++++++++----------------
4 files changed, 363 insertions(+), 397 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index cfd9b83..ab3e0f6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -213,6 +213,8 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
*/
drm_dev->vblank_disable_allowed = true;

+ drm_mode_config_reset(drm_dev);
+
ret = rockchip_drm_fbdev_init(drm_dev);
if (ret)
goto err_vblank_cleanup;
@@ -276,7 +278,8 @@ const struct vm_operations_struct rockchip_drm_vm_ops = {
};

static struct drm_driver rockchip_drm_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM |
+ DRIVER_PRIME | DRIVER_ATOMIC,
.load = rockchip_drm_load,
.unload = rockchip_drm_unload,
.lastclose = rockchip_drm_lastclose,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 069d6d4..4468f98 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,6 +18,7 @@
#define _ROCKCHIP_DRM_DRV_H

#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem.h>

#include <linux/module.h>
@@ -38,6 +39,7 @@ struct drm_connector;
struct rockchip_crtc_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
+ void (*wait_for_update)(struct drm_crtc *crtc);
};

/*
@@ -63,5 +65,4 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev);
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
-
#endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index b8ac591..7c974a4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <drm/drm.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>

@@ -166,9 +167,103 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper);
}

+static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc)
+{
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe];
+
+ if (crtc_funcs && crtc_funcs->wait_for_update)
+ crtc_funcs->wait_for_update(crtc);
+}
+
+static void
+rockchip_atomic_wait_for_complete(struct drm_atomic_state *old_state)
+{
+ struct drm_crtc_state *old_crtc_state;
+ struct drm_crtc *crtc;
+ int i, ret;
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ /* No one cares about the old state, so abuse it for tracking
+ * and store whether we hold a vblank reference (and should do a
+ * vblank wait) in the ->enable boolean.
+ */
+ old_crtc_state->enable = false;
+
+ if (!crtc->state->active)
+ continue;
+
+ ret = drm_crtc_vblank_get(crtc);
+ if (ret != 0)
+ continue;
+
+ old_crtc_state->enable = true;
+ }
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ if (!old_crtc_state->enable)
+ continue;
+
+ rockchip_crtc_wait_for_update(crtc);
+ drm_crtc_vblank_put(crtc);
+ }
+}
+
+int rockchip_drm_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ int ret;
+
+ if (async)
+ return -EBUSY;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ drm_atomic_helper_swap_state(dev, state);
+
+ /*
+ * TODO: do fence wait here.
+ */
+
+ /*
+ * Rockchip crtc support runtime PM, can't update display planes
+ * when crtc is disabled.
+ *
+ * drm_atomic_helper_commit comments detail that:
+ * For drivers supporting runtime PM the recommended sequence is
+ *
+ * drm_atomic_helper_commit_modeset_disables(dev, state);
+ *
+ * drm_atomic_helper_commit_modeset_enables(dev, state);
+ *
+ * drm_atomic_helper_commit_planes(dev, state, true);
+ *
+ * See the kerneldoc entries for these three functions for more details.
+ */
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state, true);
+
+ rockchip_atomic_wait_for_complete(state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+
+ drm_atomic_state_free(state);
+
+ return 0;
+}
+
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_user_fb_create,
.output_poll_changed = rockchip_drm_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = rockchip_drm_atomic_commit,
};

struct drm_framebuffer *
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 1e60ddd..44f6154 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -14,6 +14,7 @@

#include <drm/drm.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
@@ -63,12 +64,15 @@

#define to_vop(x) container_of(x, struct vop, crtc)
#define to_vop_win(x) container_of(x, struct vop_win, base)
+#define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)

-struct vop_win_state {
- struct list_head head;
- struct drm_framebuffer *fb;
+struct vop_plane_state {
+ struct drm_plane_state base;
+ int format;
+ struct drm_rect src;
+ struct drm_rect dest;
dma_addr_t yrgb_mst;
- struct drm_pending_vblank_event *event;
+ bool enable;
};

struct vop_win {
@@ -76,8 +80,7 @@ struct vop_win {
const struct vop_win_data *data;
struct vop *vop;

- struct list_head pending;
- struct vop_win_state *active;
+ struct vop_plane_state state;
};

struct vop {
@@ -93,6 +96,8 @@ struct vop {
struct mutex vsync_mutex;
bool vsync_work_pending;
struct completion dsp_hold_completion;
+ struct completion wait_update_complete;
+ struct drm_pending_vblank_event *event;

const struct vop_data *data;

@@ -632,7 +637,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(&vop->irq_lock, flags);
}

-static void vop_crtc_enable(struct drm_crtc *crtc)
+static void vop_enable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
int ret;
@@ -746,224 +751,188 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
pm_runtime_put(vop->dev);
}

-/*
- * Caller must hold vsync_mutex.
- */
-static struct drm_framebuffer *vop_win_last_pending_fb(struct vop_win *vop_win)
-{
- struct vop_win_state *last;
- struct vop_win_state *active = vop_win->active;
-
- if (list_empty(&vop_win->pending))
- return active ? active->fb : NULL;
-
- last = list_last_entry(&vop_win->pending, struct vop_win_state, head);
- return last ? last->fb : NULL;
-}
-
-/*
- * Caller must hold vsync_mutex.
- */
-static int vop_win_queue_fb(struct vop_win *vop_win,
- struct drm_framebuffer *fb, dma_addr_t yrgb_mst,
- struct drm_pending_vblank_event *event)
+static void vop_plane_destroy(struct drm_plane *plane)
{
- struct vop_win_state *state;
-
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
-
- state->fb = fb;
- state->yrgb_mst = yrgb_mst;
- state->event = event;
-
- list_add_tail(&state->head, &vop_win->pending);
-
- return 0;
+ drm_plane_cleanup(plane);
}

-static int vop_update_plane_event(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x,
- int crtc_y, unsigned int crtc_w,
- unsigned int crtc_h, uint32_t src_x,
- uint32_t src_y, uint32_t src_w,
- uint32_t src_h,
- struct drm_pending_vblank_event *event)
+static int vop_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_framebuffer *fb = state->fb;
struct vop_win *vop_win = to_vop_win(plane);
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
const struct vop_win_data *win = vop_win->data;
- struct vop *vop = to_vop(crtc);
- struct drm_gem_object *obj;
- struct rockchip_gem_object *rk_obj;
- struct drm_gem_object *uv_obj;
- struct rockchip_gem_object *rk_uv_obj;
- unsigned long offset;
- unsigned int actual_w;
- unsigned int actual_h;
- unsigned int dsp_stx;
- unsigned int dsp_sty;
- unsigned int y_vir_stride;
- unsigned int uv_vir_stride = 0;
- dma_addr_t yrgb_mst;
- dma_addr_t uv_mst = 0;
- enum vop_data_format format;
- uint32_t val;
- bool is_alpha;
- bool rb_swap;
- bool is_yuv;
bool visible;
int ret;
- struct drm_rect dest = {
- .x1 = crtc_x,
- .y1 = crtc_y,
- .x2 = crtc_x + crtc_w,
- .y2 = crtc_y + crtc_h,
- };
- struct drm_rect src = {
- /* 16.16 fixed point */
- .x1 = src_x,
- .y1 = src_y,
- .x2 = src_x + src_w,
- .y2 = src_y + src_h,
- };
- const struct drm_rect clip = {
- .x2 = crtc->mode.hdisplay,
- .y2 = crtc->mode.vdisplay,
- };
- bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
+ struct drm_rect *dest = &vop_plane_state->dest;
+ struct drm_rect *src = &vop_plane_state->src;
+ struct drm_rect clip;
int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
DRM_PLANE_HELPER_NO_SCALING;
int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
DRM_PLANE_HELPER_NO_SCALING;

- ret = drm_plane_helper_check_update(plane, crtc, fb,
- &src, &dest, &clip,
+ crtc = crtc ? crtc : plane->state->crtc;
+ /*
+ * Both crtc or plane->state->crtc can be null.
+ */
+ if (!crtc || !fb)
+ goto out_disable;
+ src->x1 = state->src_x;
+ src->y1 = state->src_y;
+ src->x2 = state->src_x + state->src_w;
+ src->y2 = state->src_y + state->src_h;
+ dest->x1 = state->crtc_x;
+ dest->y1 = state->crtc_y;
+ dest->x2 = state->crtc_x + state->crtc_w;
+ dest->y2 = state->crtc_y + state->crtc_h;
+
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc->mode.hdisplay;
+ clip.y2 = crtc->mode.vdisplay;
+
+ ret = drm_plane_helper_check_update(plane, crtc, state->fb,
+ src, dest, &clip,
min_scale,
max_scale,
- can_position, false, &visible);
+ true, true, &visible);
if (ret)
return ret;

if (!visible)
- return 0;
+ goto out_disable;

- is_alpha = is_alpha_support(fb->pixel_format);
- rb_swap = has_rb_swapped(fb->pixel_format);
- is_yuv = is_yuv_support(fb->pixel_format);
+ vop_plane_state->format = vop_convert_format(fb->pixel_format);
+ if (vop_plane_state->format < 0)
+ return vop_plane_state->format;

- format = vop_convert_format(fb->pixel_format);
- if (format < 0)
- return format;
-
- obj = rockchip_fb_get_gem_obj(fb, 0);
- if (!obj) {
- DRM_ERROR("fail to get rockchip gem object from framebuffer\n");
+ /*
+ * Src.x1 can be odd when do clip, but yuv plane start point
+ * need align with 2 pixel.
+ */
+ if (is_yuv_support(fb->pixel_format) && ((src->x1 >> 16) % 2))
return -EINVAL;
- }

- rk_obj = to_rockchip_obj(obj);
+ vop_plane_state->enable = true;

- if (is_yuv) {
- /*
- * Src.x1 can be odd when do clip, but yuv plane start point
- * need align with 2 pixel.
- */
- val = (src.x1 >> 16) % 2;
- src.x1 += val << 16;
- src.x2 += val << 16;
- }
+ return 0;

- actual_w = (src.x2 - src.x1) >> 16;
- actual_h = (src.y2 - src.y1) >> 16;
+out_disable:
+ vop_plane_state->enable = false;
+ return 0;
+}

- dsp_stx = dest.x1 + crtc->mode.htotal - crtc->mode.hsync_start;
- dsp_sty = dest.y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
+static void vop_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(old_state);
+ struct vop_win *vop_win = to_vop_win(plane);
+ const struct vop_win_data *win = vop_win->data;
+ struct vop *vop = to_vop(old_state->crtc);

- offset = (src.x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
- offset += (src.y1 >> 16) * fb->pitches[0];
+ if (!old_state->crtc)
+ return;

- yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
- y_vir_stride = fb->pitches[0] >> 2;
+ spin_lock(&vop->reg_lock);

- if (is_yuv) {
- int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
- int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
- int bpp = drm_format_plane_cpp(fb->pixel_format, 1);
+ VOP_WIN_SET(vop, win, enable, 0);

- uv_obj = rockchip_fb_get_gem_obj(fb, 1);
- if (!uv_obj) {
- DRM_ERROR("fail to get uv object from framebuffer\n");
- return -EINVAL;
- }
- rk_uv_obj = to_rockchip_obj(uv_obj);
- uv_vir_stride = fb->pitches[1] >> 2;
+ spin_unlock(&vop->reg_lock);

- offset = (src.x1 >> 16) * bpp / hsub;
- offset += (src.y1 >> 16) * fb->pitches[1] / vsub;
+ vop_plane_state->enable = false;
+}

- uv_mst = rk_uv_obj->dma_addr + offset + fb->offsets[1];
- }
+static void vop_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_crtc *crtc = state->crtc;
+ struct vop_win *vop_win = to_vop_win(plane);
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
+ const struct vop_win_data *win = vop_win->data;
+ struct vop *vop = to_vop(state->crtc);
+ struct drm_framebuffer *fb = state->fb;
+ unsigned int actual_w, actual_h;
+ unsigned int dsp_stx, dsp_sty;
+ uint32_t act_info, dsp_info, dsp_st;
+ struct drm_rect *src = &vop_plane_state->src;
+ struct drm_rect *dest = &vop_plane_state->dest;
+ struct drm_gem_object *obj, *uv_obj;
+ struct rockchip_gem_object *rk_obj, *rk_uv_obj;
+ unsigned long offset;
+ dma_addr_t dma_addr;
+ uint32_t val;
+ bool rb_swap;

/*
- * If this plane update changes the plane's framebuffer, (or more
- * precisely, if this update has a different framebuffer than the last
- * update), enqueue it so we can track when it completes.
- *
- * Only when we discover that this update has completed, can we
- * unreference any previous framebuffers.
+ * can't update plane when vop is disabled.
*/
- mutex_lock(&vop->vsync_mutex);
- if (fb != vop_win_last_pending_fb(vop_win)) {
- ret = drm_crtc_vblank_get(crtc);
- if (ret) {
- DRM_ERROR("failed to get vblank, %d\n", ret);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
-
- drm_framebuffer_reference(fb);
+ if (!crtc)
+ return;

- ret = vop_win_queue_fb(vop_win, fb, yrgb_mst, event);
- if (ret) {
- drm_crtc_vblank_put(crtc);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
+ if (WARN_ON(!vop->is_enabled))
+ return;

- vop->vsync_work_pending = true;
+ if (!vop_plane_state->enable) {
+ vop_plane_atomic_disable(plane, old_state);
+ return;
}
- mutex_unlock(&vop->vsync_mutex);
+
+ obj = rockchip_fb_get_gem_obj(fb, 0);
+ rk_obj = to_rockchip_obj(obj);
+
+ actual_w = drm_rect_width(src) >> 16;
+ actual_h = drm_rect_height(src) >> 16;
+ act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
+
+ dsp_info = (drm_rect_height(dest) - 1) << 16;
+ dsp_info |= (drm_rect_width(dest) - 1) & 0xffff;
+
+ dsp_stx = dest->x1 + crtc->mode.htotal - crtc->mode.hsync_start;
+ dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
+ dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
+
+ offset = (src->x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
+ offset += (src->y1 >> 16) * fb->pitches[0];
+ vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];

spin_lock(&vop->reg_lock);

- VOP_WIN_SET(vop, win, format, format);
- VOP_WIN_SET(vop, win, yrgb_vir, y_vir_stride);
- VOP_WIN_SET(vop, win, yrgb_mst, yrgb_mst);
- if (is_yuv) {
- VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride);
- VOP_WIN_SET(vop, win, uv_mst, uv_mst);
+ VOP_WIN_SET(vop, win, format, vop_plane_state->format);
+ VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2);
+ VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
+ if (is_yuv_support(fb->pixel_format)) {
+ int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
+ int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
+ int bpp = drm_format_plane_cpp(fb->pixel_format, 1);
+
+ uv_obj = rockchip_fb_get_gem_obj(fb, 1);
+ rk_uv_obj = to_rockchip_obj(uv_obj);
+
+ offset = (src->x1 >> 16) * bpp / hsub;
+ offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
+
+ dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
+ VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2);
+ VOP_WIN_SET(vop, win, uv_mst, dma_addr);
}

if (win->phy->scl)
scl_vop_cal_scl_fac(vop, win, actual_w, actual_h,
- dest.x2 - dest.x1, dest.y2 - dest.y1,
+ drm_rect_width(dest), drm_rect_height(dest),
fb->pixel_format);

- val = (actual_h - 1) << 16;
- val |= (actual_w - 1) & 0xffff;
- VOP_WIN_SET(vop, win, act_info, val);
+ VOP_WIN_SET(vop, win, act_info, act_info);
+ VOP_WIN_SET(vop, win, dsp_info, dsp_info);
+ VOP_WIN_SET(vop, win, dsp_st, dsp_st);

- val = (dest.y2 - dest.y1 - 1) << 16;
- val |= (dest.x2 - dest.x1 - 1) & 0xffff;
- VOP_WIN_SET(vop, win, dsp_info, val);
- val = dsp_sty << 16;
- val |= dsp_stx & 0xffff;
- VOP_WIN_SET(vop, win, dsp_st, val);
+ rb_swap = has_rb_swapped(fb->pixel_format);
VOP_WIN_SET(vop, win, rb_swap, rb_swap);

- if (is_alpha) {
+ if (is_alpha_support(fb->pixel_format)) {
VOP_WIN_SET(vop, win, dst_alpha_ctl,
DST_FACTOR_M0(ALPHA_SRC_INVERSE));
val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) |
@@ -977,86 +946,70 @@ static int vop_update_plane_event(struct drm_plane *plane,
}

VOP_WIN_SET(vop, win, enable, 1);
-
- vop_cfg_done(vop);
spin_unlock(&vop->reg_lock);
-
- return 0;
}

-static int vop_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y, uint32_t src_w,
- uint32_t src_h)
-{
- return vop_update_plane_event(plane, crtc, fb, crtc_x, crtc_y, crtc_w,
- crtc_h, src_x, src_y, src_w, src_h,
- NULL);
-}
+static const struct drm_plane_helper_funcs plane_helper_funcs = {
+ .atomic_check = vop_plane_atomic_check,
+ .atomic_update = vop_plane_atomic_update,
+ .atomic_disable = vop_plane_atomic_disable,
+};

-static int vop_update_primary_plane(struct drm_crtc *crtc,
- struct drm_pending_vblank_event *event)
+void vop_atomic_plane_reset(struct drm_plane *plane)
{
- unsigned int crtc_w, crtc_h;
+ struct vop_plane_state *vop_plane_state =
+ to_vop_plane_state(plane->state);

- crtc_w = crtc->primary->fb->width - crtc->x;
- crtc_h = crtc->primary->fb->height - crtc->y;
+ if (plane->state && plane->state->fb)
+ drm_framebuffer_unreference(plane->state->fb);
+
+ kfree(vop_plane_state);
+ vop_plane_state = kzalloc(sizeof(*vop_plane_state), GFP_KERNEL);
+ if (!vop_plane_state)
+ return;

- return vop_update_plane_event(crtc->primary, crtc, crtc->primary->fb,
- 0, 0, crtc_w, crtc_h, crtc->x << 16,
- crtc->y << 16, crtc_w << 16,
- crtc_h << 16, event);
+ plane->state = &vop_plane_state->base;
+ plane->state->plane = plane;
}

-static int vop_disable_plane(struct drm_plane *plane)
+struct drm_plane_state *
+vop_atomic_plane_duplicate_state(struct drm_plane *plane)
{
- struct vop_win *vop_win = to_vop_win(plane);
- const struct vop_win_data *win = vop_win->data;
- struct vop *vop;
- int ret;
-
- if (!plane->crtc)
- return 0;
+ struct vop_plane_state *old_vop_plane_state;
+ struct vop_plane_state *vop_plane_state;

- vop = to_vop(plane->crtc);
+ if (WARN_ON(!plane->state))
+ return NULL;

- ret = drm_crtc_vblank_get(plane->crtc);
- if (ret) {
- DRM_ERROR("failed to get vblank, %d\n", ret);
- return ret;
- }
+ old_vop_plane_state = to_vop_plane_state(plane->state);
+ vop_plane_state = kmemdup(old_vop_plane_state,
+ sizeof(*vop_plane_state), GFP_KERNEL);
+ if (!vop_plane_state)
+ return NULL;

- mutex_lock(&vop->vsync_mutex);
+ __drm_atomic_helper_plane_duplicate_state(plane,
+ &vop_plane_state->base);

- ret = vop_win_queue_fb(vop_win, NULL, 0, NULL);
- if (ret) {
- drm_crtc_vblank_put(plane->crtc);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
-
- vop->vsync_work_pending = true;
- mutex_unlock(&vop->vsync_mutex);
-
- spin_lock(&vop->reg_lock);
- VOP_WIN_SET(vop, win, enable, 0);
- vop_cfg_done(vop);
- spin_unlock(&vop->reg_lock);
-
- return 0;
+ return &vop_plane_state->base;
}

-static void vop_plane_destroy(struct drm_plane *plane)
+static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
- vop_disable_plane(plane);
- drm_plane_cleanup(plane);
+ struct vop_plane_state *vop_state = to_vop_plane_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(plane, state);
+
+ kfree(vop_state);
}

static const struct drm_plane_funcs vop_plane_funcs = {
- .update_plane = vop_update_plane,
- .disable_plane = vop_disable_plane,
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
.destroy = vop_plane_destroy,
+ .reset = vop_atomic_plane_reset,
+ .atomic_duplicate_state = vop_atomic_plane_duplicate_state,
+ .atomic_destroy_state = vop_atomic_plane_destroy_state,
};

int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
@@ -1077,7 +1030,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
struct vop *vop = to_vop(crtc);
unsigned long flags;

- if (!vop->is_enabled)
+ if (WARN_ON(!vop->is_enabled))
return -EPERM;

spin_lock_irqsave(&vop->irq_lock, flags);
@@ -1094,7 +1047,7 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
struct vop *vop = to_vop(crtc);
unsigned long flags;

- if (!vop->is_enabled)
+ if (WARN_ON(!vop->is_enabled))
return;

spin_lock_irqsave(&vop->irq_lock, flags);
@@ -1102,9 +1055,18 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
spin_unlock_irqrestore(&vop->irq_lock, flags);
}

+static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
+{
+ struct vop *vop = to_vop(crtc);
+
+ reinit_completion(&vop->wait_update_complete);
+ WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100));
+}
+
static const struct rockchip_crtc_funcs private_crtc_funcs = {
.enable_vblank = vop_crtc_enable_vblank,
.disable_vblank = vop_crtc_disable_vblank,
+ .wait_for_update = vop_crtc_wait_for_update,
};

static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -1117,29 +1079,10 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}

-static int vop_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- int ret;
-
- crtc->x = x;
- crtc->y = y;
-
- ret = vop_update_primary_plane(crtc, NULL);
- if (ret < 0) {
- DRM_ERROR("fail to update plane\n");
- return ret;
- }
-
- return 0;
-}
-
-static int vop_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y, struct drm_framebuffer *fb)
+static void vop_crtc_enable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
u16 hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
u16 hdisplay = adjusted_mode->hdisplay;
u16 htotal = adjusted_mode->htotal;
@@ -1150,9 +1093,9 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
u16 vact_end = vact_st + vdisplay;
- int ret, ret_clk;
uint32_t val;

+ vop_enable(crtc);
/*
* disable dclk to stop frame scan, so that we can safe config mode and
* enable iommu.
@@ -1172,7 +1115,6 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
default:
DRM_ERROR("unsupport connector_type[%d]\n",
vop->connector_type);
- ret = -EINVAL;
goto out;
};
VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
@@ -1194,9 +1136,6 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
VOP_CTRL_SET(vop, vact_st_end, val);
VOP_CTRL_SET(vop, vpost_st_end, val);

- ret = vop_crtc_mode_set_base(crtc, x, y, fb);
- if (ret)
- goto out;

/*
* reset dclk, take all mode config affect, so the clk would run in
@@ -1208,172 +1147,97 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,

clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
out:
- ret_clk = clk_enable(vop->dclk);
- if (ret_clk < 0) {
- dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk);
- return ret_clk;
- }
-
- return ret;
+ if (clk_enable(vop->dclk) < 0)
+ dev_err(vop->dev, "failed to enable dclk\n");
}

-static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
- .enable = vop_crtc_enable,
- .disable = vop_crtc_disable,
- .mode_fixup = vop_crtc_mode_fixup,
- .mode_set = vop_crtc_mode_set,
- .mode_set_base = vop_crtc_mode_set_base,
-};
-
-static int vop_crtc_page_flip(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event,
- uint32_t page_flip_flags)
+static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
struct vop *vop = to_vop(crtc);
- struct drm_framebuffer *old_fb = crtc->primary->fb;
- int ret;

- /* when the page flip is requested, crtc should be on */
- if (!vop->is_enabled) {
- DRM_DEBUG("page flip request rejected because crtc is off.\n");
- return 0;
- }
+ if (WARN_ON(!vop->is_enabled))
+ return;

- crtc->primary->fb = fb;
+ spin_lock(&vop->reg_lock);

- ret = vop_update_primary_plane(crtc, event);
- if (ret)
- crtc->primary->fb = old_fb;
+ vop_cfg_done(vop);

- return ret;
+ spin_unlock(&vop->reg_lock);
}

-static void vop_win_state_complete(struct vop_win *vop_win,
- struct vop_win_state *state)
+static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
- struct vop *vop = vop_win->vop;
- struct drm_crtc *crtc = &vop->crtc;
- struct drm_device *drm = crtc->dev;
- unsigned long flags;
+ struct vop *vop = to_vop(crtc);

- if (state->event) {
- spin_lock_irqsave(&drm->event_lock, flags);
- drm_crtc_send_vblank_event(crtc, state->event);
- spin_unlock_irqrestore(&drm->event_lock, flags);
- }
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);

- list_del(&state->head);
- drm_crtc_vblank_put(crtc);
+ vop->event = crtc->state->event;
+ crtc->state->event = NULL;
+ }
}

+static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
+ .enable = vop_crtc_enable,
+ .disable = vop_crtc_disable,
+ .mode_fixup = vop_crtc_mode_fixup,
+ .atomic_flush = vop_crtc_atomic_flush,
+ .atomic_begin = vop_crtc_atomic_begin,
+};
+
static void vop_crtc_destroy(struct drm_crtc *crtc)
{
drm_crtc_cleanup(crtc);
}

static const struct drm_crtc_funcs vop_crtc_funcs = {
- .set_config = drm_crtc_helper_set_config,
- .page_flip = vop_crtc_page_flip,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
.destroy = vop_crtc_destroy,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};

-static bool vop_win_state_is_active(struct vop_win *vop_win,
- struct vop_win_state *state)
+static bool vop_win_pending_is_complete(struct vop_win *vop_win)
{
- bool active = false;
-
- if (state->fb) {
- dma_addr_t yrgb_mst;
-
- /* check yrgb_mst to tell if pending_fb is now front */
- yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
-
- active = (yrgb_mst == state->yrgb_mst);
- } else {
- bool enabled;
-
- /* if enable bit is clear, plane is now disabled */
- enabled = VOP_WIN_GET(vop_win->vop, vop_win->data, enable);
-
- active = (enabled == 0);
- }
-
- return active;
-}
+ struct drm_plane *plane = &vop_win->base;
+ struct vop_plane_state *state = to_vop_plane_state(plane->state);
+ dma_addr_t yrgb_mst;

-static void vop_win_state_destroy(struct vop_win_state *state)
-{
- struct drm_framebuffer *fb = state->fb;
+ if (!state->enable)
+ return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;

- if (fb)
- drm_framebuffer_unreference(fb);
+ yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);

- kfree(state);
+ return yrgb_mst == state->yrgb_mst;
}

-static void vop_win_update_state(struct vop_win *vop_win)
+static void vop_handle_vblank(struct vop *vop)
{
- struct vop_win_state *state, *n, *new_active = NULL;
-
- /* Check if any pending states are now active */
- list_for_each_entry(state, &vop_win->pending, head)
- if (vop_win_state_is_active(vop_win, state)) {
- new_active = state;
- break;
- }
-
- if (!new_active)
- return;
+ struct drm_device *drm = vop->drm_dev;
+ struct drm_crtc *crtc = &vop->crtc;
+ unsigned long flags;
+ int i;

- /*
- * Destroy any 'skipped' pending states - states that were queued
- * before the newly active state.
- */
- list_for_each_entry_safe(state, n, &vop_win->pending, head) {
- if (state == new_active)
- break;
- vop_win_state_complete(vop_win, state);
- vop_win_state_destroy(state);
+ for (i = 0; i < vop->data->win_size; i++) {
+ if (!vop_win_pending_is_complete(&vop->win[i]))
+ return;
}

- vop_win_state_complete(vop_win, new_active);
-
- if (vop_win->active)
- vop_win_state_destroy(vop_win->active);
- vop_win->active = new_active;
-}
-
-static bool vop_win_has_pending_state(struct vop_win *vop_win)
-{
- return !list_empty(&vop_win->pending);
-}
-
-static irqreturn_t vop_isr_thread(int irq, void *data)
-{
- struct vop *vop = data;
- const struct vop_data *vop_data = vop->data;
- unsigned int i;
-
- mutex_lock(&vop->vsync_mutex);
-
- if (!vop->vsync_work_pending)
- goto done;
+ if (vop->event) {
+ spin_lock_irqsave(&drm->event_lock, flags);

- vop->vsync_work_pending = false;
+ drm_crtc_send_vblank_event(crtc, vop->event);
+ drm_crtc_vblank_put(crtc);
+ vop->event = NULL;

- for (i = 0; i < vop_data->win_size; i++) {
- struct vop_win *vop_win = &vop->win[i];
-
- vop_win_update_state(vop_win);
- if (vop_win_has_pending_state(vop_win))
- vop->vsync_work_pending = true;
+ spin_unlock_irqrestore(&drm->event_lock, flags);
}
-
-done:
- mutex_unlock(&vop->vsync_mutex);
-
- return IRQ_HANDLED;
+ if (!completion_done(&vop->wait_update_complete))
+ complete(&vop->wait_update_complete);
}

static irqreturn_t vop_isr(int irq, void *data)
@@ -1409,8 +1273,9 @@ static irqreturn_t vop_isr(int irq, void *data)

if (active_irqs & FS_INTR) {
drm_crtc_handle_vblank(crtc);
+ vop_handle_vblank(vop);
active_irqs &= ~FS_INTR;
- ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+ ret = IRQ_HANDLED;
}

/* Unhandled irqs are spurious. */
@@ -1455,6 +1320,7 @@ static int vop_create_crtc(struct vop *vop)
}

plane = &vop_win->base;
+ drm_plane_helper_add(plane, &plane_helper_funcs);
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
primary = plane;
else if (plane->type == DRM_PLANE_TYPE_CURSOR)
@@ -1490,6 +1356,7 @@ static int vop_create_crtc(struct vop *vop)
DRM_ERROR("failed to initialize overlay plane\n");
goto err_cleanup_crtc;
}
+ drm_plane_helper_add(&vop_win->base, &plane_helper_funcs);
}

port = of_get_child_by_name(dev->of_node, "port");
@@ -1500,6 +1367,7 @@ static int vop_create_crtc(struct vop *vop)
}

init_completion(&vop->dsp_hold_completion);
+ init_completion(&vop->wait_update_complete);
crtc->port = port;
rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);

@@ -1633,7 +1501,6 @@ static void vop_win_init(struct vop *vop)

vop_win->data = win_data;
vop_win->vop = vop;
- INIT_LIST_HEAD(&vop_win->pending);
}
}

@@ -1694,8 +1561,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)

mutex_init(&vop->vsync_mutex);

- ret = devm_request_threaded_irq(dev, vop->irq, vop_isr, vop_isr_thread,
- IRQF_SHARED, dev_name(dev), vop);
+ ret = devm_request_irq(dev, vop->irq, vop_isr,
+ IRQF_SHARED, dev_name(dev), vop);
if (ret)
return ret;

--
1.7.9.5

2015-12-17 03:02:43

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 4/8] drm/rockchip: Optimization vop mode set

Rk3288 vop timing registers is immediately register, when configure
timing on display active time, will cause tearing. use dclk reset is
not a good idea to avoid this tearing. we can avoid tearing by using
standby register.

Vop standby register will take effect at end of current frame, and
go back to work immediately when exit standby.

So we can use standby register to protect this context.

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 51 ++++++++++++++++++---------
1 file changed, 35 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 44f6154..9ace3ae 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1097,10 +1097,40 @@ static void vop_crtc_enable(struct drm_crtc *crtc)

vop_enable(crtc);
/*
- * disable dclk to stop frame scan, so that we can safe config mode and
- * enable iommu.
+ * If dclk rate is zero, mean that scanout is stop,
+ * we don't need wait any more.
*/
- clk_disable(vop->dclk);
+ if (clk_get_rate(vop->dclk)) {
+ /*
+ * Rk3288 vop timing register is immediately, when configure
+ * display timing on display time, may cause tearing.
+ *
+ * Vop standby will take effect at end of current frame,
+ * if dsp hold valid irq happen, it means standby complete.
+ *
+ * mode set:
+ * standby and wait complete --> |----
+ * | display time
+ * |----
+ * |---> dsp hold irq
+ * configure display timing --> |
+ * standby exit |
+ * | new frame start.
+ */
+
+ reinit_completion(&vop->dsp_hold_completion);
+ vop_dsp_hold_valid_irq_enable(vop);
+
+ spin_lock(&vop->reg_lock);
+
+ VOP_CTRL_SET(vop, standby, 1);
+
+ spin_unlock(&vop->reg_lock);
+
+ wait_for_completion(&vop->dsp_hold_completion);
+
+ vop_dsp_hold_valid_irq_disable(vop);
+ }

switch (vop->connector_type) {
case DRM_MODE_CONNECTOR_LVDS:
@@ -1115,7 +1145,6 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
default:
DRM_ERROR("unsupport connector_type[%d]\n",
vop->connector_type);
- goto out;
};
VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);

@@ -1136,19 +1165,9 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
VOP_CTRL_SET(vop, vact_st_end, val);
VOP_CTRL_SET(vop, vpost_st_end, val);

-
- /*
- * reset dclk, take all mode config affect, so the clk would run in
- * correct frame.
- */
- reset_control_assert(vop->dclk_rst);
- usleep_range(10, 20);
- reset_control_deassert(vop->dclk_rst);
-
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
-out:
- if (clk_enable(vop->dclk) < 0)
- dev_err(vop->dev, "failed to enable dclk\n");
+
+ VOP_CTRL_SET(vop, standby, 0);
}

static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
--
1.7.9.5

2015-12-17 03:07:34

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 5/8] drm/rockchip: support atomic asynchronous commit

If drm core requests a async commit, rockchip_drm_atomic_commit
will schedule a work task to update later.

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2:
- serialize outstanding asynchronous commits
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 3 ++
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 10 +++++
drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 54 ++++++++++++++++++++-------
3 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index ab3e0f6..5edd5ccb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -140,6 +140,9 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
if (!private)
return -ENOMEM;

+ mutex_init(&private->commit.lock);
+ INIT_WORK(&private->commit.work, rockchip_drm_atomic_work);
+
drm_dev->dev_private = private;

drm_mode_config_init(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 4468f98..bb8b076 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -42,6 +42,13 @@ struct rockchip_crtc_funcs {
void (*wait_for_update)(struct drm_crtc *crtc);
};

+struct rockchip_atomic_commit {
+ struct work_struct work;
+ struct drm_atomic_state *state;
+ struct drm_device *dev;
+ struct mutex lock;
+};
+
/*
* Rockchip drm private structure.
*
@@ -52,8 +59,11 @@ struct rockchip_drm_private {
struct drm_fb_helper fbdev_helper;
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
+
+ struct rockchip_atomic_commit commit;
};

+void rockchip_drm_atomic_work(struct work_struct *work);
int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
const struct rockchip_crtc_funcs *crtc_funcs);
void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 7c974a4..0bc1d5e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -210,20 +210,11 @@ rockchip_atomic_wait_for_complete(struct drm_atomic_state *old_state)
}
}

-int rockchip_drm_atomic_commit(struct drm_device *dev,
- struct drm_atomic_state *state,
- bool async)
+static void
+rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
{
- int ret;
-
- if (async)
- return -EBUSY;
-
- ret = drm_atomic_helper_prepare_planes(dev, state);
- if (ret)
- return ret;
-
- drm_atomic_helper_swap_state(dev, state);
+ struct drm_atomic_state *state = commit->state;
+ struct drm_device *dev = commit->dev;

/*
* TODO: do fence wait here.
@@ -255,6 +246,43 @@ int rockchip_drm_atomic_commit(struct drm_device *dev,
drm_atomic_helper_cleanup_planes(dev, state);

drm_atomic_state_free(state);
+}
+
+void rockchip_drm_atomic_work(struct work_struct *work)
+{
+ struct rockchip_atomic_commit *commit = container_of(work,
+ struct rockchip_atomic_commit, work);
+
+ rockchip_atomic_commit_complete(commit);
+}
+
+int rockchip_drm_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ struct rockchip_drm_private *private = dev->dev_private;
+ struct rockchip_atomic_commit *commit = &private->commit;
+ int ret;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ /* serialize outstanding asynchronous commits */
+ mutex_lock(&commit->lock);
+ flush_work(&commit->work);
+
+ drm_atomic_helper_swap_state(dev, state);
+
+ commit->dev = dev;
+ commit->state = state;
+
+ if (async)
+ schedule_work(&commit->work);
+ else
+ rockchip_atomic_commit_complete(commit);
+
+ mutex_unlock(&commit->lock);

return 0;
}
--
1.7.9.5

2015-12-17 03:10:00

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 6/8] drm/rockchip: direct config connecter gate and out_mode

Both connecter gate and out_mode are not conflict with mode set
configure. Direct setting connecter gate and out_mode, that allow
connector do rockchip_drm_crtc_mode_config after mode set.

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 39 +++++++++++++--------------
1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 9ace3ae..6ded4cc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -89,9 +89,6 @@ struct vop {
struct drm_device *drm_dev;
bool is_enabled;

- int connector_type;
- int connector_out_mode;
-
/* mutex vsync_ work */
struct mutex vsync_mutex;
bool vsync_work_pending;
@@ -1018,8 +1015,24 @@ int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
{
struct vop *vop = to_vop(crtc);

- vop->connector_type = connector_type;
- vop->connector_out_mode = out_mode;
+ if (WARN_ON(!vop->is_enabled))
+ return -EINVAL;
+
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_LVDS:
+ VOP_CTRL_SET(vop, rgb_en, 1);
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ VOP_CTRL_SET(vop, edp_en, 1);
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ VOP_CTRL_SET(vop, hdmi_en, 1);
+ break;
+ default:
+ DRM_ERROR("unsupport connector_type[%d]\n", connector_type);
+ return -EINVAL;
+ };
+ VOP_CTRL_SET(vop, out_mode, out_mode);

return 0;
}
@@ -1132,22 +1145,6 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
vop_dsp_hold_valid_irq_disable(vop);
}

- switch (vop->connector_type) {
- case DRM_MODE_CONNECTOR_LVDS:
- VOP_CTRL_SET(vop, rgb_en, 1);
- break;
- case DRM_MODE_CONNECTOR_eDP:
- VOP_CTRL_SET(vop, edp_en, 1);
- break;
- case DRM_MODE_CONNECTOR_HDMIA:
- VOP_CTRL_SET(vop, hdmi_en, 1);
- break;
- default:
- DRM_ERROR("unsupport connector_type[%d]\n",
- vop->connector_type);
- };
- VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
-
val = 0x8;
val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
--
1.7.9.5

2015-12-17 03:09:53

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 7/8] drm: bridge/dw_hdmi: add atomic API support

Fill atomic needed funcs with default atomic helper library.

Rockchip use dw_hdmi, and drm/rockchip will covert to atomic api,
we need dw_hdmi support atomic funcs.

Now another drm driver use dw_hdmi is imx, not yet atomic, so
check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.

Cc: Russell King <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Andy Yan <[email protected]>
Cc: Fabio Estevam <[email protected]>
Cc: Thierry Reding <[email protected]>

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2:
Adviced by Daniel Vetter
- check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.

drivers/gpu/drm/bridge/dw_hdmi.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 56de9f1..dc0bdd4 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -22,6 +22,7 @@

#include <drm/drm_of.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
@@ -1522,6 +1523,17 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.force = dw_hdmi_connector_force,
};

+static struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
+ .force = dw_hdmi_connector_force,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
.mode_valid = dw_hdmi_connector_mode_valid,
@@ -1645,8 +1657,15 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)

drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
+
+ if (drm_core_check_feature(drm, DRIVER_ATOMIC))
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_atomic_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ else
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);

hdmi->connector.encoder = encoder;

--
1.7.9.5

2015-12-17 03:09:55

by Mark yao

[permalink] [raw]
Subject: [PATCH 8/8] drm/rockchip: dw_hdmi: use encoder enable function

encoder.enable is more compatible to atomic api than encoder.prepare/commit

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None

drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 525b5a8..8e1605c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -195,12 +195,15 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
{
}

-static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
{
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
u32 val;
int mux;

+ rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
+ ROCKCHIP_OUT_MODE_AAAA);
+
mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
if (mux)
val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
@@ -212,17 +215,10 @@ static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
(mux) ? "LIT" : "BIG");
}

-static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
-{
- rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
- ROCKCHIP_OUT_MODE_AAAA);
-}
-
static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
- .prepare = dw_hdmi_rockchip_encoder_prepare,
- .commit = dw_hdmi_rockchip_encoder_commit,
+ .enable = dw_hdmi_rockchip_encoder_enable,
.disable = dw_hdmi_rockchip_encoder_disable,
};

--
1.7.9.5

2015-12-17 03:12:50

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 7/8] drm: bridge/dw_hdmi: add atomic API support

Fill atomic needed funcs with default atomic helper library.

Rockchip use dw_hdmi, and drm/rockchip will covert to atomic api,
we need dw_hdmi support atomic funcs.

Now another drm driver use dw_hdmi is imx, not yet atomic, so
check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.

Cc: Russell King <[email protected]>
Cc: Philipp Zabel <[email protected]>
Cc: Andy Yan <[email protected]>
Cc: Fabio Estevam <[email protected]>
Cc: Thierry Reding <[email protected]>

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2:
Adviced by Daniel Vetter
- check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.

drivers/gpu/drm/bridge/dw_hdmi.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 56de9f1..dc0bdd4 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -22,6 +22,7 @@

#include <drm/drm_of.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
@@ -1522,6 +1523,17 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.force = dw_hdmi_connector_force,
};

+static struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
+ .force = dw_hdmi_connector_force,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
.mode_valid = dw_hdmi_connector_mode_valid,
@@ -1645,8 +1657,15 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)

drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
+
+ if (drm_core_check_feature(drm, DRIVER_ATOMIC))
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_atomic_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ else
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);

hdmi->connector.encoder = encoder;

--
1.7.9.5

2015-12-17 03:14:24

by Mark yao

[permalink] [raw]
Subject: [PATCH v3 8/8] drm/rockchip: dw_hdmi: use encoder enable function

encoder.enable is more compatible to atomic api than encoder.prepare/commit

Signed-off-by: Mark Yao <[email protected]>
---
Changes in v3: None
Changes in v2: None

drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 525b5a8..8e1605c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -195,12 +195,15 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
{
}

-static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
{
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
u32 val;
int mux;

+ rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
+ ROCKCHIP_OUT_MODE_AAAA);
+
mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
if (mux)
val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
@@ -212,17 +215,10 @@ static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
(mux) ? "LIT" : "BIG");
}

-static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
-{
- rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
- ROCKCHIP_OUT_MODE_AAAA);
-}
-
static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
- .prepare = dw_hdmi_rockchip_encoder_prepare,
- .commit = dw_hdmi_rockchip_encoder_commit,
+ .enable = dw_hdmi_rockchip_encoder_enable,
.disable = dw_hdmi_rockchip_encoder_disable,
};

--
1.7.9.5

2015-12-17 03:16:04

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH v3 7/8] drm: bridge/dw_hdmi: add atomic API support

Sorry, Ops, fat finger, discard this lost thread mail.

On 2015年12月17日 11:08, Mark Yao wrote:
> Fill atomic needed funcs with default atomic helper library.
>
> Rockchip use dw_hdmi, and drm/rockchip will covert to atomic api,
> we need dw_hdmi support atomic funcs.
>
> Now another drm driver use dw_hdmi is imx, not yet atomic, so
> check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.
>
> Cc: Russell King <[email protected]>
> Cc: Philipp Zabel <[email protected]>
> Cc: Andy Yan <[email protected]>
> Cc: Fabio Estevam <[email protected]>
> Cc: Thierry Reding <[email protected]>
>
> Signed-off-by: Mark Yao <[email protected]>
> ---
> Changes in v3: None
> Changes in v2:
> Adviced by Daniel Vetter
> - check DRIVER_ATOMIC at runtime to spilt atomic and not atomic.
>
> drivers/gpu/drm/bridge/dw_hdmi.c | 23 +++++++++++++++++++++--
> 1 file changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
> index 56de9f1..dc0bdd4 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
> @@ -22,6 +22,7 @@
>
> #include <drm/drm_of.h>
> #include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> #include <drm/drm_crtc_helper.h>
> #include <drm/drm_edid.h>
> #include <drm/drm_encoder_slave.h>
> @@ -1522,6 +1523,17 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
> .force = dw_hdmi_connector_force,
> };
>
> +static struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = {
> + .dpms = drm_atomic_helper_connector_dpms,
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .detect = dw_hdmi_connector_detect,
> + .destroy = dw_hdmi_connector_destroy,
> + .force = dw_hdmi_connector_force,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
> .get_modes = dw_hdmi_connector_get_modes,
> .mode_valid = dw_hdmi_connector_mode_valid,
> @@ -1645,8 +1657,15 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
>
> drm_connector_helper_add(&hdmi->connector,
> &dw_hdmi_connector_helper_funcs);
> - drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
> - DRM_MODE_CONNECTOR_HDMIA);
> +
> + if (drm_core_check_feature(drm, DRIVER_ATOMIC))
> + drm_connector_init(drm, &hdmi->connector,
> + &dw_hdmi_atomic_connector_funcs,
> + DRM_MODE_CONNECTOR_HDMIA);
> + else
> + drm_connector_init(drm, &hdmi->connector,
> + &dw_hdmi_connector_funcs,
> + DRM_MODE_CONNECTOR_HDMIA);
>
> hdmi->connector.encoder = encoder;
>


--
Mark Yao

2015-12-17 03:16:34

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH 8/8] drm/rockchip: dw_hdmi: use encoder enable function

Sorry, Ops, fat finger, discard this lost thread mail.

On 2015年12月17日 11:08, Mark Yao wrote:
> encoder.enable is more compatible to atomic api than encoder.prepare/commit
>
> Signed-off-by: Mark Yao <[email protected]>
> ---
> Changes in v3: None
> Changes in v2: None
>
> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++---------
> 1 file changed, 5 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> index 525b5a8..8e1605c 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> @@ -195,12 +195,15 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
> {
> }
>
> -static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
> +static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
> {
> struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
> u32 val;
> int mux;
>
> + rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
> + ROCKCHIP_OUT_MODE_AAAA);
> +
> mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
> if (mux)
> val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
> @@ -212,17 +215,10 @@ static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
> (mux) ? "LIT" : "BIG");
> }
>
> -static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
> -{
> - rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
> - ROCKCHIP_OUT_MODE_AAAA);
> -}
> -
> static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
> .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
> .mode_set = dw_hdmi_rockchip_encoder_mode_set,
> - .prepare = dw_hdmi_rockchip_encoder_prepare,
> - .commit = dw_hdmi_rockchip_encoder_commit,
> + .enable = dw_hdmi_rockchip_encoder_enable,
> .disable = dw_hdmi_rockchip_encoder_disable,
> };
>


--
Mark Yao

2015-12-17 10:00:32

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v3 0/8] drm/rockchip: covert to support atomic API

Hi Mark,

Am Donnerstag, 17. Dezember 2015, 11:01:07 schrieb Mark Yao:
> The series of patches coverting drm rockchip to atomic API, do some
> cleanup and some fixes on atomic side.
>
> TODO: fence is not support on current version.
>
> Tested on rk3288 popmetal board.

In general this works nicely and hdmi is still working on my firefly, so

Tested-by: Heiko Stuebner <[email protected]>


I get one warning though, which seems to be related to fbcon grabbing
the framebuffer it seems.


HDMI plugged in on boot:

[ 4.345329] ------------[ cut here ]------------
[ 4.345360] WARNING: CPU: 1 PID: 66 at drivers/gpu/drm/drm_atomic_helper.c:682 drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200()
[ 4.345373] Modules linked in:
[ 4.345386] CPU: 1 PID: 66 Comm: kworker/u8:1 Not tainted 4.4.0-rc5+ #2787
[ 4.345392] Hardware name: Rockchip (Device Tree)
[ 4.345411] Workqueue: deferwq deferred_probe_work_func
[ 4.345438] [<c0019914>] (unwind_backtrace) from [<c0014bcc>] (show_stack+0x20/0x24)
[ 4.345458] [<c0014bcc>] (show_stack) from [<c02c4344>] (dump_stack+0x84/0xb8)
[ 4.345479] [<c02c4344>] (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4)
[ 4.345496] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>] (warn_slowpath_null+0x2c/0x34)
[ 4.345514] [<c0029b08>] (warn_slowpath_null) from [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200)
[ 4.345534] [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c)
[ 4.345557] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108)
[ 4.345576] [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>] (rockchip_drm_atomic_commit+0x84/0xa0)
[ 4.345594] [<c0387984>] (rockchip_drm_atomic_commit) from [<c0384c58>] (drm_atomic_commit+0x60/0x70)
[ 4.345609] [<c0384c58>] (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258)
[ 4.345625] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80)
[ 4.345640] [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from [<c036529c>] (drm_fb_helper_set_par+0x50/0x60)
[ 4.345659] [<c036529c>] (drm_fb_helper_set_par) from [<c03052cc>] (fbcon_init+0x328/0x458)
[ 4.345676] [<c03052cc>] (fbcon_init) from [<c033a66c>] (visual_init+0xc4/0x114)
[ 4.345692] [<c033a66c>] (visual_init) from [<c033c098>] (do_bind_con_driver+0x1fc/0x330)
[ 4.345707] [<c033c098>] (do_bind_con_driver) from [<c033c540>] (do_take_over_console+0x174/0x1b4)
[ 4.345722] [<c033c540>] (do_take_over_console) from [<c0305464>] (do_fbcon_takeover+0x68/0xd0)
[ 4.345738] [<c0305464>] (do_fbcon_takeover) from [<c0305c6c>] (fbcon_event_notify+0x3fc/0x7d8)
[ 4.345756] [<c0305c6c>] (fbcon_event_notify) from [<c004d144>] (notifier_call_chain+0x58/0x80)
[ 4.345771] [<c004d144>] (notifier_call_chain) from [<c004d4d4>] (__blocking_notifier_call_chain+0x54/0x6c)
[ 4.345785] [<c004d4d4>] (__blocking_notifier_call_chain) from [<c004d514>] (blocking_notifier_call_chain+0x28/0x30)
[ 4.345804] [<c004d514>] (blocking_notifier_call_chain) from [<c0308c68>] (fb_notifier_call_chain+0x24/0x2c)
[ 4.345822] [<c0308c68>] (fb_notifier_call_chain) from [<c030aa7c>] (register_framebuffer+0x214/0x264)
[ 4.345839] [<c030aa7c>] (register_framebuffer) from [<c0365a00>] (drm_fb_helper_initial_config+0x2dc/0x34c)
[ 4.345856] [<c0365a00>] (drm_fb_helper_initial_config) from [<c038823c>] (rockchip_drm_fbdev_init+0x9c/0xe4)
[ 4.345873] [<c038823c>] (rockchip_drm_fbdev_init) from [<c03876bc>] (rockchip_drm_load+0x25c/0x2b0)
[ 4.345892] [<c03876bc>] (rockchip_drm_load) from [<c036eae4>] (drm_dev_register+0x80/0xc4)
[ 4.345910] [<c036eae4>] (drm_dev_register) from [<c03873d4>] (rockchip_drm_bind+0x58/0x84)
[ 4.345932] [<c03873d4>] (rockchip_drm_bind) from [<c03b4b54>] (try_to_bring_up_master.part.0+0xbc/0x114)
[ 4.345950] [<c03b4b54>] (try_to_bring_up_master.part.0) from [<c03b4da0>] (component_add+0xb0/0x118)
[ 4.345967] [<c03b4da0>] (component_add) from [<c038a2d8>] (vop_probe+0x40/0x4c)
[ 4.345984] [<c038a2d8>] (vop_probe) from [<c03bc350>] (platform_drv_probe+0x60/0xb0)
[ 4.345999] [<c03bc350>] (platform_drv_probe) from [<c03b9ffc>] (driver_probe_device+0x1a0/0x418)
[ 4.346014] [<c03b9ffc>] (driver_probe_device) from [<c03ba3f8>] (__device_attach_driver+0x94/0xa0)
[ 4.346028] [<c03ba3f8>] (__device_attach_driver) from [<c03b82a0>] (bus_for_each_drv+0x94/0xa4)
[ 4.346042] [<c03b82a0>] (bus_for_each_drv) from [<c03b9d3c>] (__device_attach+0xa4/0x144)
[ 4.346055] [<c03b9d3c>] (__device_attach) from [<c03ba564>] (device_initial_probe+0x1c/0x20)
[ 4.346068] [<c03ba564>] (device_initial_probe) from [<c03b91d4>] (bus_probe_device+0x38/0x94)
[ 4.346082] [<c03b91d4>] (bus_probe_device) from [<c03b9714>] (deferred_probe_work_func+0x8c/0xbc)
[ 4.346098] [<c03b9714>] (deferred_probe_work_func) from [<c0045094>] (process_one_work+0x328/0x668)
[ 4.346112] [<c0045094>] (process_one_work) from [<c0046304>] (worker_thread+0x2cc/0x41c)
[ 4.346128] [<c0046304>] (worker_thread) from [<c004bbb8>] (kthread+0xf4/0x10c)
[ 4.346146] [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24)
[ 4.346155] ---[ end trace 8cd78a9f6ee0a57e ]---


Plugging in HDMI after boot:

[ 20.559534] ------------[ cut here ]------------
[ 20.564412] WARNING: CPU: 3 PID: 74 at drivers/gpu/drm/drm_atomic_helper.c:682 drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200()
[ 20.576991] Modules linked in:
[ 20.580175] CPU: 3 PID: 74 Comm: irq/51-ff980000 Not tainted 4.4.0-rc5+ #2787
[ 20.587502] Hardware name: Rockchip (Device Tree)
[ 20.592347] [<c0019914>] (unwind_backtrace) from [<c0014bcc>] (show_stack+0x20/0x24)
[ 20.600319] [<c0014bcc>] (show_stack) from [<c02c4344>] (dump_stack+0x84/0xb8)
[ 20.607776] [<c02c4344>] (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4)
[ 20.616087] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>] (warn_slowpath_null+0x2c/0x34)
[ 20.625106] [<c0029b08>] (warn_slowpath_null) from [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200)
[ 20.636382] [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c)
[ 20.649732] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108)
[ 20.661789] [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>] (rockchip_drm_atomic_commit+0x84/0xa0)
[ 20.672442] [<c0387984>] (rockchip_drm_atomic_commit) from [<c0384c58>] (drm_atomic_commit+0x60/0x70)
[ 20.681711] [<c0384c58>] (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258)
[ 20.690418] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80)
[ 20.701033] [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from [<c036529c>] (drm_fb_helper_set_par+0x50/0x60)
[ 20.711907] [<c036529c>] (drm_fb_helper_set_par) from [<c03651b4>] (drm_fb_helper_hotplug_event+0xc8/0xe0)
[ 20.721569] [<c03651b4>] (drm_fb_helper_hotplug_event) from [<c0387bd0>] (rockchip_drm_output_poll_changed+0x24/0x28)
[ 20.732185] [<c0387bd0>] (rockchip_drm_output_poll_changed) from [<c035aaf8>] (drm_kms_helper_hotplug_event+0x34/0x38)
[ 20.742891] [<c035aaf8>] (drm_kms_helper_hotplug_event) from [<c035b434>] (drm_helper_hpd_irq_event+0x120/0x150)
[ 20.753078] [<c035b434>] (drm_helper_hpd_irq_event) from [<c038dd1c>] (dw_hdmi_irq+0x14c/0x18c)
[ 20.761772] [<c038dd1c>] (dw_hdmi_irq) from [<c008d030>] (irq_thread_fn+0x2c/0x44)
[ 20.769350] [<c008d030>] (irq_thread_fn) from [<c008d33c>] (irq_thread+0x118/0x21c)
[ 20.777019] [<c008d33c>] (irq_thread) from [<c004bbb8>] (kthread+0xf4/0x10c)
[ 20.784083] [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24)
[ 20.791300] ---[ end trace 3deaa51d288067a0 ]---

2015-12-17 10:32:45

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH v3 0/8] drm/rockchip: covert to support atomic API

On 2015年12月17日 18:00, Heiko Stübner wrote:
> Hi Mark,
>
> Am Donnerstag, 17. Dezember 2015, 11:01:07 schrieb Mark Yao:
>> The series of patches coverting drm rockchip to atomic API, do some
>> cleanup and some fixes on atomic side.
>>
>> TODO: fence is not support on current version.
>>
>> Tested on rk3288 popmetal board.
> In general this works nicely and hdmi is still working on my firefly, so
>
> Tested-by: Heiko Stuebner <[email protected]>

Thanks.

>
> I get one warning though, which seems to be related to fbcon grabbing
> the framebuffer it seems.
>
>
> HDMI plugged in on boot:
>
> [ 4.345329] ------------[ cut here ]------------
> [ 4.345360] WARNING: CPU: 1 PID: 66 at drivers/gpu/drm/drm_atomic_helper.c:682 drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200()
> [ 4.345373] Modules linked in:
> [ 4.345386] CPU: 1 PID: 66 Comm: kworker/u8:1 Not tainted 4.4.0-rc5+ #2787
> [ 4.345392] Hardware name: Rockchip (Device Tree)
> [ 4.345411] Workqueue: deferwq deferred_probe_work_func
> [ 4.345438] [<c0019914>] (unwind_backtrace) from [<c0014bcc>] (show_stack+0x20/0x24)
> [ 4.345458] [<c0014bcc>] (show_stack) from [<c02c4344>] (dump_stack+0x84/0xb8)
> [ 4.345479] [<c02c4344>] (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4)
> [ 4.345496] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>] (warn_slowpath_null+0x2c/0x34)
> [ 4.345514] [<c0029b08>] (warn_slowpath_null) from [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200)
> [ 4.345534] [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c)
> [ 4.345557] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108)
> [ 4.345576] [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>] (rockchip_drm_atomic_commit+0x84/0xa0)
> [ 4.345594] [<c0387984>] (rockchip_drm_atomic_commit) from [<c0384c58>] (drm_atomic_commit+0x60/0x70)
> [ 4.345609] [<c0384c58>] (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258)
> [ 4.345625] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80)
> [ 4.345640] [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from [<c036529c>] (drm_fb_helper_set_par+0x50/0x60)
> [ 4.345659] [<c036529c>] (drm_fb_helper_set_par) from [<c03052cc>] (fbcon_init+0x328/0x458)
> [ 4.345676] [<c03052cc>] (fbcon_init) from [<c033a66c>] (visual_init+0xc4/0x114)
> [ 4.345692] [<c033a66c>] (visual_init) from [<c033c098>] (do_bind_con_driver+0x1fc/0x330)
> [ 4.345707] [<c033c098>] (do_bind_con_driver) from [<c033c540>] (do_take_over_console+0x174/0x1b4)
> [ 4.345722] [<c033c540>] (do_take_over_console) from [<c0305464>] (do_fbcon_takeover+0x68/0xd0)
> [ 4.345738] [<c0305464>] (do_fbcon_takeover) from [<c0305c6c>] (fbcon_event_notify+0x3fc/0x7d8)
> [ 4.345756] [<c0305c6c>] (fbcon_event_notify) from [<c004d144>] (notifier_call_chain+0x58/0x80)
> [ 4.345771] [<c004d144>] (notifier_call_chain) from [<c004d4d4>] (__blocking_notifier_call_chain+0x54/0x6c)
> [ 4.345785] [<c004d4d4>] (__blocking_notifier_call_chain) from [<c004d514>] (blocking_notifier_call_chain+0x28/0x30)
> [ 4.345804] [<c004d514>] (blocking_notifier_call_chain) from [<c0308c68>] (fb_notifier_call_chain+0x24/0x2c)
> [ 4.345822] [<c0308c68>] (fb_notifier_call_chain) from [<c030aa7c>] (register_framebuffer+0x214/0x264)
> [ 4.345839] [<c030aa7c>] (register_framebuffer) from [<c0365a00>] (drm_fb_helper_initial_config+0x2dc/0x34c)
> [ 4.345856] [<c0365a00>] (drm_fb_helper_initial_config) from [<c038823c>] (rockchip_drm_fbdev_init+0x9c/0xe4)
> [ 4.345873] [<c038823c>] (rockchip_drm_fbdev_init) from [<c03876bc>] (rockchip_drm_load+0x25c/0x2b0)
> [ 4.345892] [<c03876bc>] (rockchip_drm_load) from [<c036eae4>] (drm_dev_register+0x80/0xc4)
> [ 4.345910] [<c036eae4>] (drm_dev_register) from [<c03873d4>] (rockchip_drm_bind+0x58/0x84)
> [ 4.345932] [<c03873d4>] (rockchip_drm_bind) from [<c03b4b54>] (try_to_bring_up_master.part.0+0xbc/0x114)
> [ 4.345950] [<c03b4b54>] (try_to_bring_up_master.part.0) from [<c03b4da0>] (component_add+0xb0/0x118)
> [ 4.345967] [<c03b4da0>] (component_add) from [<c038a2d8>] (vop_probe+0x40/0x4c)
> [ 4.345984] [<c038a2d8>] (vop_probe) from [<c03bc350>] (platform_drv_probe+0x60/0xb0)
> [ 4.345999] [<c03bc350>] (platform_drv_probe) from [<c03b9ffc>] (driver_probe_device+0x1a0/0x418)
> [ 4.346014] [<c03b9ffc>] (driver_probe_device) from [<c03ba3f8>] (__device_attach_driver+0x94/0xa0)
> [ 4.346028] [<c03ba3f8>] (__device_attach_driver) from [<c03b82a0>] (bus_for_each_drv+0x94/0xa4)
> [ 4.346042] [<c03b82a0>] (bus_for_each_drv) from [<c03b9d3c>] (__device_attach+0xa4/0x144)
> [ 4.346055] [<c03b9d3c>] (__device_attach) from [<c03ba564>] (device_initial_probe+0x1c/0x20)
> [ 4.346068] [<c03ba564>] (device_initial_probe) from [<c03b91d4>] (bus_probe_device+0x38/0x94)
> [ 4.346082] [<c03b91d4>] (bus_probe_device) from [<c03b9714>] (deferred_probe_work_func+0x8c/0xbc)
> [ 4.346098] [<c03b9714>] (deferred_probe_work_func) from [<c0045094>] (process_one_work+0x328/0x668)
> [ 4.346112] [<c0045094>] (process_one_work) from [<c0046304>] (worker_thread+0x2cc/0x41c)
> [ 4.346128] [<c0046304>] (worker_thread) from [<c004bbb8>] (kthread+0xf4/0x10c)
> [ 4.346146] [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24)
> [ 4.346155] ---[ end trace 8cd78a9f6ee0a57e ]---
>
>
> Plugging in HDMI after boot:
>
> [ 20.559534] ------------[ cut here ]------------
> [ 20.564412] WARNING: CPU: 3 PID: 74 at drivers/gpu/drm/drm_atomic_helper.c:682 drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200()
> [ 20.576991] Modules linked in:
> [ 20.580175] CPU: 3 PID: 74 Comm: irq/51-ff980000 Not tainted 4.4.0-rc5+ #2787
> [ 20.587502] Hardware name: Rockchip (Device Tree)
> [ 20.592347] [<c0019914>] (unwind_backtrace) from [<c0014bcc>] (show_stack+0x20/0x24)
> [ 20.600319] [<c0014bcc>] (show_stack) from [<c02c4344>] (dump_stack+0x84/0xb8)
> [ 20.607776] [<c02c4344>] (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4)
> [ 20.616087] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>] (warn_slowpath_null+0x2c/0x34)
> [ 20.625106] [<c0029b08>] (warn_slowpath_null) from [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200)
> [ 20.636382] [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c)
> [ 20.649732] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108)
> [ 20.661789] [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>] (rockchip_drm_atomic_commit+0x84/0xa0)
> [ 20.672442] [<c0387984>] (rockchip_drm_atomic_commit) from [<c0384c58>] (drm_atomic_commit+0x60/0x70)
> [ 20.681711] [<c0384c58>] (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258)
> [ 20.690418] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80)
> [ 20.701033] [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from [<c036529c>] (drm_fb_helper_set_par+0x50/0x60)
> [ 20.711907] [<c036529c>] (drm_fb_helper_set_par) from [<c03651b4>] (drm_fb_helper_hotplug_event+0xc8/0xe0)
> [ 20.721569] [<c03651b4>] (drm_fb_helper_hotplug_event) from [<c0387bd0>] (rockchip_drm_output_poll_changed+0x24/0x28)
> [ 20.732185] [<c0387bd0>] (rockchip_drm_output_poll_changed) from [<c035aaf8>] (drm_kms_helper_hotplug_event+0x34/0x38)
> [ 20.742891] [<c035aaf8>] (drm_kms_helper_hotplug_event) from [<c035b434>] (drm_helper_hpd_irq_event+0x120/0x150)
> [ 20.753078] [<c035b434>] (drm_helper_hpd_irq_event) from [<c038dd1c>] (dw_hdmi_irq+0x14c/0x18c)
> [ 20.761772] [<c038dd1c>] (dw_hdmi_irq) from [<c008d030>] (irq_thread_fn+0x2c/0x44)
> [ 20.769350] [<c008d030>] (irq_thread_fn) from [<c008d33c>] (irq_thread+0x118/0x21c)
> [ 20.777019] [<c008d33c>] (irq_thread) from [<c004bbb8>] (kthread+0xf4/0x10c)
> [ 20.784083] [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24)
> [ 20.791300] ---[ end trace 3deaa51d288067a0 ]---
>
>
>
>
Hi Heiko
This issue can be explained from following thread:
https://lkml.org/lkml/2015/11/16/498

You can fix it by following changes:

@@ -1667,8 +1667,6 @@ static int dw_hdmi_register(struct drm_device
*drm, struct dw_hdmi *hdmi)
&dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);

- hdmi->connector.encoder = encoder;


Thanks.

--
Mark Yao

2015-12-17 12:04:05

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v3 0/8] drm/rockchip: covert to support atomic API

Hi Mark,

Am Donnerstag, 17. Dezember 2015, 18:32:31 schrieb Mark yao:
> On 2015年12月17日 18:00, Heiko Stübner wrote:
> > Am Donnerstag, 17. Dezember 2015, 11:01:07 schrieb Mark Yao:
> >> The series of patches coverting drm rockchip to atomic API, do some
> >> cleanup and some fixes on atomic side.

[...]

> > Plugging in HDMI after boot:
> >
> > [ 20.559534] ------------[ cut here ]------------
> > [ 20.564412] WARNING: CPU: 3 PID: 74 at
> > drivers/gpu/drm/drm_atomic_helper.c:682
> > drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200() [ 20.576991]
> > Modules linked in:
> > [ 20.580175] CPU: 3 PID: 74 Comm: irq/51-ff980000 Not tainted 4.4.0-rc5+
> > #2787 [ 20.587502] Hardware name: Rockchip (Device Tree)
> > [ 20.592347] [<c0019914>] (unwind_backtrace) from [<c0014bcc>]
> > (show_stack+0x20/0x24) [ 20.600319] [<c0014bcc>] (show_stack) from
> > [<c02c4344>] (dump_stack+0x84/0xb8) [ 20.607776] [<c02c4344>]
> > (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4) [
> > 20.616087] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>]
> > (warn_slowpath_null+0x2c/0x34) [ 20.625106] [<c0029b08>]
> > (warn_slowpath_null) from [<c0361144>]
> > (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200) [ 20.636382]
> > [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from
> > [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c) [
> > 20.649732] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from
> > [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108) [ 20.661789]
> > [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>]
> > (rockchip_drm_atomic_commit+0x84/0xa0) [ 20.672442] [<c0387984>]
> > (rockchip_drm_atomic_commit) from [<c0384c58>]
> > (drm_atomic_commit+0x60/0x70) [ 20.681711] [<c0384c58>]
> > (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258) [
> > 20.690418] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>]
> > (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80) [ 20.701033]
> > [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from
> > [<c036529c>] (drm_fb_helper_set_par+0x50/0x60) [ 20.711907]
> > [<c036529c>] (drm_fb_helper_set_par) from [<c03651b4>]
> > (drm_fb_helper_hotplug_event+0xc8/0xe0) [ 20.721569] [<c03651b4>]
> > (drm_fb_helper_hotplug_event) from [<c0387bd0>]
> > (rockchip_drm_output_poll_changed+0x24/0x28) [ 20.732185] [<c0387bd0>]
> > (rockchip_drm_output_poll_changed) from [<c035aaf8>]
> > (drm_kms_helper_hotplug_event+0x34/0x38) [ 20.742891] [<c035aaf8>]
> > (drm_kms_helper_hotplug_event) from [<c035b434>]
> > (drm_helper_hpd_irq_event+0x120/0x150) [ 20.753078] [<c035b434>]
> > (drm_helper_hpd_irq_event) from [<c038dd1c>] (dw_hdmi_irq+0x14c/0x18c) [
> > 20.761772] [<c038dd1c>] (dw_hdmi_irq) from [<c008d030>]
> > (irq_thread_fn+0x2c/0x44) [ 20.769350] [<c008d030>] (irq_thread_fn)
> > from [<c008d33c>] (irq_thread+0x118/0x21c) [ 20.777019] [<c008d33c>]
> > (irq_thread) from [<c004bbb8>] (kthread+0xf4/0x10c) [ 20.784083]
> > [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24) [
> > 20.791300] ---[ end trace 3deaa51d288067a0 ]---
>
> Hi Heiko
> This issue can be explained from following thread:
> https://lkml.org/lkml/2015/11/16/498
>
> You can fix it by following changes:
>
> @@ -1667,8 +1667,6 @@ static int dw_hdmi_register(struct drm_device
> *drm, struct dw_hdmi *hdmi)
> &dw_hdmi_connector_funcs,
> DRM_MODE_CONNECTOR_HDMIA);
>
> - hdmi->connector.encoder = encoder;

yep that fixes the warning. From the thread you mention, it looks like that
assignment should also be removed in the non-atomic case (i.MX)?

Or if it is really necessary there could also wrap it in a conditional to only
be set for the non-atomic case.


Heiko

2015-12-17 14:27:32

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH v3 0/8] drm/rockchip: covert to support atomic API

On Thu, Dec 17, 2015 at 01:03:53PM +0100, Heiko Stübner wrote:
> Hi Mark,
>
> Am Donnerstag, 17. Dezember 2015, 18:32:31 schrieb Mark yao:
> > On 2015年12月17日 18:00, Heiko Stübner wrote:
> > > Am Donnerstag, 17. Dezember 2015, 11:01:07 schrieb Mark Yao:
> > >> The series of patches coverting drm rockchip to atomic API, do some
> > >> cleanup and some fixes on atomic side.
>
> [...]
>
> > > Plugging in HDMI after boot:
> > >
> > > [ 20.559534] ------------[ cut here ]------------
> > > [ 20.564412] WARNING: CPU: 3 PID: 74 at
> > > drivers/gpu/drm/drm_atomic_helper.c:682
> > > drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200() [ 20.576991]
> > > Modules linked in:
> > > [ 20.580175] CPU: 3 PID: 74 Comm: irq/51-ff980000 Not tainted 4.4.0-rc5+
> > > #2787 [ 20.587502] Hardware name: Rockchip (Device Tree)
> > > [ 20.592347] [<c0019914>] (unwind_backtrace) from [<c0014bcc>]
> > > (show_stack+0x20/0x24) [ 20.600319] [<c0014bcc>] (show_stack) from
> > > [<c02c4344>] (dump_stack+0x84/0xb8) [ 20.607776] [<c02c4344>]
> > > (dump_stack) from [<c0029a20>] (warn_slowpath_common+0x98/0xc4) [
> > > 20.616087] [<c0029a20>] (warn_slowpath_common) from [<c0029b08>]
> > > (warn_slowpath_null+0x2c/0x34) [ 20.625106] [<c0029b08>]
> > > (warn_slowpath_null) from [<c0361144>]
> > > (drm_atomic_helper_update_legacy_modeset_state+0x6c/0x200) [ 20.636382]
> > > [<c0361144>] (drm_atomic_helper_update_legacy_modeset_state) from
> > > [<c0361684>] (drm_atomic_helper_commit_modeset_disables+0x1e4/0x35c) [
> > > 20.649732] [<c0361684>] (drm_atomic_helper_commit_modeset_disables) from
> > > [<c038782c>] (rockchip_atomic_commit_complete+0x34/0x108) [ 20.661789]
> > > [<c038782c>] (rockchip_atomic_commit_complete) from [<c0387984>]
> > > (rockchip_drm_atomic_commit+0x84/0xa0) [ 20.672442] [<c0387984>]
> > > (rockchip_drm_atomic_commit) from [<c0384c58>]
> > > (drm_atomic_commit+0x60/0x70) [ 20.681711] [<c0384c58>]
> > > (drm_atomic_commit) from [<c0363ab0>] (restore_fbdev_mode+0x128/0x258) [
> > > 20.690418] [<c0363ab0>] (restore_fbdev_mode) from [<c0365208>]
> > > (drm_fb_helper_restore_fbdev_mode_unlocked+0x3c/0x80) [ 20.701033]
> > > [<c0365208>] (drm_fb_helper_restore_fbdev_mode_unlocked) from
> > > [<c036529c>] (drm_fb_helper_set_par+0x50/0x60) [ 20.711907]
> > > [<c036529c>] (drm_fb_helper_set_par) from [<c03651b4>]
> > > (drm_fb_helper_hotplug_event+0xc8/0xe0) [ 20.721569] [<c03651b4>]
> > > (drm_fb_helper_hotplug_event) from [<c0387bd0>]
> > > (rockchip_drm_output_poll_changed+0x24/0x28) [ 20.732185] [<c0387bd0>]
> > > (rockchip_drm_output_poll_changed) from [<c035aaf8>]
> > > (drm_kms_helper_hotplug_event+0x34/0x38) [ 20.742891] [<c035aaf8>]
> > > (drm_kms_helper_hotplug_event) from [<c035b434>]
> > > (drm_helper_hpd_irq_event+0x120/0x150) [ 20.753078] [<c035b434>]
> > > (drm_helper_hpd_irq_event) from [<c038dd1c>] (dw_hdmi_irq+0x14c/0x18c) [
> > > 20.761772] [<c038dd1c>] (dw_hdmi_irq) from [<c008d030>]
> > > (irq_thread_fn+0x2c/0x44) [ 20.769350] [<c008d030>] (irq_thread_fn)
> > > from [<c008d33c>] (irq_thread+0x118/0x21c) [ 20.777019] [<c008d33c>]
> > > (irq_thread) from [<c004bbb8>] (kthread+0xf4/0x10c) [ 20.784083]
> > > [<c004bbb8>] (kthread) from [<c0010010>] (ret_from_fork+0x14/0x24) [
> > > 20.791300] ---[ end trace 3deaa51d288067a0 ]---
> >
> > Hi Heiko
> > This issue can be explained from following thread:
> > https://lkml.org/lkml/2015/11/16/498
> >
> > You can fix it by following changes:
> >
> > @@ -1667,8 +1667,6 @@ static int dw_hdmi_register(struct drm_device
> > *drm, struct dw_hdmi *hdmi)
> > &dw_hdmi_connector_funcs,
> > DRM_MODE_CONNECTOR_HDMIA);
> >
> > - hdmi->connector.encoder = encoder;
>
> yep that fixes the warning. From the thread you mention, it looks like that
> assignment should also be removed in the non-atomic case (i.MX)?
>
> Or if it is really necessary there could also wrap it in a conditional to only
> be set for the non-atomic case.

It wont work with non-atomic, but it'll only break things from the 2nd
modeset onwards. Someone needs to fix that bug, since afaiu the code it'd
blow up for non-atomic if you remove it on even the first modeset.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch