Skip to content

Commit

Permalink
drm/sti: atomic crtc/plane update
Browse files Browse the repository at this point in the history
Better fit STI hardware structure.
Planes are no more responsible of updating mixer information such
as z-order and status. It is now up to the CRTC atomic flush to
do it. Plane actions (enable or disable) are performed atomically.
Disabling of a plane is synchronize with the vsync event.

Signed-off-by: Vincent Abriou <vincent.abriou@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
  • Loading branch information
Vincent Abriou authored and Benjamin Gaignard committed Aug 3, 2015
1 parent 9e1f05b commit 29d1dc6
Show file tree
Hide file tree
Showing 13 changed files with 809 additions and 877 deletions.
32 changes: 12 additions & 20 deletions drivers/gpu/drm/sti/sti_compositor.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev,
{
struct sti_compositor *compo = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0;
unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
struct sti_private *dev_priv = drm_dev->dev_private;
struct drm_plane *cursor = NULL;
struct drm_plane *primary = NULL;
struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
unsigned int array_size = compo->data.nb_subdev;

struct sti_plane *plane;

dev_priv->compo = compo;

/* Register mixer subdev and video subdev first */
Expand Down Expand Up @@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev,
/* Nothing to do, already done at the first round */
break;
case STI_CURSOR_SUBDEV:
plane = sti_cursor_create(compo->dev, desc[i].id,
compo->regs + desc[i].offset);
if (!plane) {
cursor = sti_cursor_create(drm_dev, compo->dev,
desc[i].id,
compo->regs + desc[i].offset,
1);
if (!cursor) {
DRM_ERROR("Can't create CURSOR plane\n");
break;
}
cursor = sti_plane_init(drm_dev, plane, 1,
DRM_PLANE_TYPE_CURSOR);
plane_id++;
break;
case STI_GPD_SUBDEV:
plane = sti_gdp_create(compo->dev, desc[i].id,
compo->regs + desc[i].offset);
if (!plane) {
primary = sti_gdp_create(drm_dev, compo->dev,
desc[i].id,
compo->regs + desc[i].offset,
(1 << mixer_id) - 1,
plane_type);
if (!primary) {
DRM_ERROR("Can't create GDP plane\n");
break;
}
primary = sti_plane_init(drm_dev, plane,
(1 << mixer_id) - 1,
plane_type);
plane_id++;
break;
default:
DRM_ERROR("Unknown subdev compoment type\n");
Expand All @@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev,
/* Allow usage of vblank without having to call drm_irq_install */
drm_dev->irq_enabled = 1;

DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
crtc_id, plane_id);
DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");

return 0;
}

Expand Down
133 changes: 95 additions & 38 deletions drivers/gpu/drm/sti/sti_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@
#include "sti_compositor.h"
#include "sti_crtc.h"
#include "sti_drv.h"
#include "sti_vid.h"
#include "sti_vtg.h"

static void sti_crtc_dpms(struct drm_crtc *crtc, int mode)
{
DRM_DEBUG_KMS("\n");
}

static void sti_crtc_prepare(struct drm_crtc *crtc)
static void sti_crtc_enable(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);

mixer->enabled = true;
DRM_DEBUG_DRIVER("\n");

mixer->status = STI_MIXER_READY;

/* Prepare and enable the compo IP clock */
if (mixer->id == STI_MIXER_MAIN) {
Expand All @@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc)
DRM_INFO("Failed to prepare/enable compo_aux clk\n");
}

sti_mixer_clear_all_planes(mixer);
drm_crtc_vblank_on(crtc);
}

static void sti_crtc_commit(struct drm_crtc *crtc)
static void sti_crtc_disabling(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);
struct sti_plane *plane;

if ((!mixer || !compo)) {
DRM_ERROR("Can't find mixer or compositor)\n");
return;
}

/* get GDP which is reserved to the CRTC FB */
plane = to_sti_plane(crtc->primary);
if (!plane)
DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n");

/* Enable plane on mixer */
if (sti_mixer_set_plane_status(mixer, plane, true))
DRM_ERROR("Cannot enable plane at mixer\n");
DRM_DEBUG_DRIVER("\n");

drm_crtc_vblank_on(crtc);
mixer->status = STI_MIXER_DISABLING;
}

static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
Expand Down Expand Up @@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);

if (!mixer->enabled)
return;

DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));

/* Disable Background */
Expand All @@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
clk_disable_unprepare(compo->clk_compo_aux);
}

mixer->enabled = false;
mixer->status = STI_MIXER_DISABLED;
}

static void
sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
sti_crtc_prepare(crtc);
sti_crtc_enable(crtc);
sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
}

Expand All @@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc)

static void sti_crtc_atomic_flush(struct drm_crtc *crtc)
{
struct drm_device *drm_dev = crtc->dev;
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
struct drm_plane *p;

DRM_DEBUG_DRIVER("\n");

/* perform plane actions */
list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
struct sti_plane *plane = to_sti_plane(p);

switch (plane->status) {
case STI_PLANE_UPDATED:
/* update planes tag as updated */
DRM_DEBUG_DRIVER("update plane %s\n",
sti_plane_to_str(plane));

if (sti_mixer_set_plane_depth(mixer, plane)) {
DRM_ERROR("Cannot set plane %s depth\n",
sti_plane_to_str(plane));
break;
}

if (sti_mixer_set_plane_status(mixer, plane, true)) {
DRM_ERROR("Cannot enable plane %s at mixer\n",
sti_plane_to_str(plane));
break;
}

/* if plane is HQVDP_0 then commit the vid[0] */
if (plane->desc == STI_HQVDP_0)
sti_vid_commit(compo->vid[0], p->state);

plane->status = STI_PLANE_READY;

break;
case STI_PLANE_DISABLING:
/* disabling sequence for planes tag as disabling */
DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
sti_plane_to_str(plane));

if (sti_mixer_set_plane_status(mixer, plane, false)) {
DRM_ERROR("Cannot disable plane %s at mixer\n",
sti_plane_to_str(plane));
continue;
}

if (plane->desc == STI_CURSOR)
/* tag plane status for disabled */
plane->status = STI_PLANE_DISABLED;
else
/* tag plane status for flushing */
plane->status = STI_PLANE_FLUSHING;

/* if plane is HQVDP_0 then disable the vid[0] */
if (plane->desc == STI_HQVDP_0)
sti_vid_disable(compo->vid[0]);

break;
default:
/* Other status case are not handled */
break;
}
}
}

static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.dpms = sti_crtc_dpms,
.prepare = sti_crtc_prepare,
.commit = sti_crtc_commit,
.enable = sti_crtc_enable,
.disable = sti_crtc_disabling,
.mode_fixup = sti_crtc_mode_fixup,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = sti_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
.disable = sti_crtc_disable,
.atomic_begin = sti_crtc_atomic_begin,
.atomic_flush = sti_crtc_atomic_flush,
};
Expand Down Expand Up @@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
}
spin_unlock_irqrestore(&drm_dev->event_lock, flags);

if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
struct drm_plane *p;

/* Disable mixer only if all overlay planes (GDP and VDP)
* are disabled */
list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
struct sti_plane *plane = to_sti_plane(p);

if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
if (plane->status != STI_PLANE_DISABLED)
return 0;
}
sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
}

return 0;
}

Expand All @@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
}
EXPORT_SYMBOL(sti_crtc_enable_vblank);

void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
{
struct sti_private *priv = dev->dev_private;
struct sti_private *priv = drm_dev->dev_private;
struct sti_compositor *compo = priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;

Expand All @@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)

/* free the resources of the pending requests */
if (compo->mixer[crtc]->pending_event) {
drm_vblank_put(dev, crtc);
drm_vblank_put(drm_dev, crtc);
compo->mixer[crtc]->pending_event = NULL;
}
}
Expand Down
Loading

0 comments on commit 29d1dc6

Please sign in to comment.