Skip to content

Commit

Permalink
staging: drm/omap: add drm_plane support
Browse files Browse the repository at this point in the history
Because framebuffer layer and overlay scanout video pipes are basically
thing in OMAP display subsystem (the only difference being that the first
video pipe does not support scaling or YUV formats), much of the CRTC
code is pulled into the plane implementation, and a private plane object
is used by the CRTC object.  This avoids code duplication between the
plane and CRTC.

Signed-off-by: Rob Clark <rob@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Rob Clark authored and Greg Kroah-Hartman committed Feb 8, 2012
1 parent ae43d7c commit bb5c2d9
Show file tree
Hide file tree
Showing 6 changed files with 403 additions and 168 deletions.
1 change: 1 addition & 0 deletions drivers/staging/omapdrm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ccflags-y := -Iinclude/drm -Werror
omapdrm-y := omap_drv.o \
omap_debugfs.o \
omap_crtc.o \
omap_plane.o \
omap_encoder.o \
omap_connector.o \
omap_fb.o \
Expand Down
189 changes: 44 additions & 145 deletions drivers/staging/omapdrm/omap_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,196 +27,95 @@

struct omap_crtc {
struct drm_crtc base;
struct omap_overlay *ovl;
struct omap_overlay_info info;
struct drm_plane *plane;
const char *name;
int id;

/* if there is a pending flip, this will be non-null: */
/* if there is a pending flip, these will be non-null: */
struct drm_pending_vblank_event *event;
struct drm_framebuffer *old_fb;
};

/* push changes down to dss2 */
static int commit(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_overlay *ovl = omap_crtc->ovl;
struct omap_overlay_info *info = &omap_crtc->info;
int ret;

DBG("%s", omap_crtc->ovl->name);
DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
info->out_height, info->screen_width);
DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);

/* NOTE: do we want to do this at all here, or just wait
* for dpms(ON) since other CRTC's may not have their mode
* set yet, so fb dimensions may still change..
*/
ret = ovl->set_overlay_info(ovl, info);
if (ret) {
dev_err(dev->dev, "could not set overlay info\n");
return ret;
}

/* our encoder doesn't necessarily get a commit() after this, in
* particular in the dpms() and mode_set_base() cases, so force the
* manager to update:
*
* could this be in the encoder somehow?
*/
if (ovl->manager) {
ret = ovl->manager->apply(ovl->manager);
if (ret) {
dev_err(dev->dev, "could not apply settings\n");
return ret;
}
}

if (info->enabled) {
omap_framebuffer_flush(crtc->fb, crtc->x, crtc->y,
crtc->fb->width, crtc->fb->height);
}

return 0;
}

/* update parameters that are dependent on the framebuffer dimensions and
* position within the fb that this crtc scans out from. This is called
* when framebuffer dimensions or x,y base may have changed, either due
* to our mode, or a change in another crtc that is scanning out of the
* same fb.
*/
static void update_scanout(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
dma_addr_t paddr;
unsigned int screen_width;

omap_framebuffer_get_buffer(crtc->fb, crtc->x, crtc->y,
NULL, &paddr, &screen_width);

DBG("%s: %d,%d: %08x (%d)", omap_crtc->ovl->name,
crtc->x, crtc->y, (u32)paddr, screen_width);

omap_crtc->info.paddr = paddr;
omap_crtc->info.screen_width = screen_width;
}

static void omap_crtc_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->ovl->name);
/* not supported.. at least not yet */
}

static void omap_crtc_destroy(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->ovl->name);
omap_crtc->plane->funcs->destroy(omap_crtc->plane);
drm_crtc_cleanup(crtc);
kfree(omap_crtc);
}

static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
int i;

DBG("%s: %d", omap_crtc->ovl->name, mode);
WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));

if (mode == DRM_MODE_DPMS_ON) {
update_scanout(crtc);
omap_crtc->info.enabled = true;
} else {
omap_crtc->info.enabled = false;
for (i = 0; i < priv->num_planes; i++) {
struct drm_plane *plane = priv->planes[i];
if (plane->crtc == crtc)
WARN_ON(omap_plane_dpms(plane, mode));
}

WARN_ON(commit(crtc));
}

static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->ovl->name);
return true;
}

static int omap_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 *old_fb)
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_plane *plane = omap_crtc->plane;

DBG("%s: %d,%d: %dx%d", omap_crtc->ovl->name, x, y,
mode->hdisplay, mode->vdisplay);

/* just use adjusted mode */
mode = adjusted_mode;

omap_crtc->info.width = mode->hdisplay;
omap_crtc->info.height = mode->vdisplay;
omap_crtc->info.out_width = mode->hdisplay;
omap_crtc->info.out_height = mode->vdisplay;
omap_crtc->info.color_mode = OMAP_DSS_COLOR_RGB24U;
omap_crtc->info.rotation_type = OMAP_DSS_ROT_DMA;
omap_crtc->info.rotation = OMAP_DSS_ROT_0;
omap_crtc->info.global_alpha = 0xff;
omap_crtc->info.mirror = 0;
omap_crtc->info.mirror = 0;
omap_crtc->info.pos_x = 0;
omap_crtc->info.pos_y = 0;
#if 0 /* re-enable when these are available in DSS2 driver */
omap_crtc->info.zorder = 3; /* GUI in the front, video behind */
omap_crtc->info.min_x_decim = 1;
omap_crtc->info.max_x_decim = 1;
omap_crtc->info.min_y_decim = 1;
omap_crtc->info.max_y_decim = 1;
#endif

update_scanout(crtc);

return 0;
return plane->funcs->update_plane(plane, crtc, crtc->fb,
0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16,
mode->hdisplay << 16, mode->vdisplay << 16);
}

static void omap_crtc_prepare(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_overlay *ovl = omap_crtc->ovl;

DBG("%s", omap_crtc->ovl->name);

ovl->get_overlay_info(ovl, &omap_crtc->info);

DBG("%s", omap_crtc->name);
omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}

static void omap_crtc_commit(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->ovl->name);
DBG("%s", omap_crtc->name);
omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}

static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
struct drm_framebuffer *old_fb)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_plane *plane = omap_crtc->plane;
struct drm_display_mode *mode = &crtc->mode;

DBG("%s %d,%d: fb=%p", omap_crtc->ovl->name, x, y, old_fb);

update_scanout(crtc);

return commit(crtc);
return plane->funcs->update_plane(plane, crtc, crtc->fb,
0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16,
mode->hdisplay << 16, mode->vdisplay << 16);
}

static void omap_crtc_load_lut(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->ovl->name);
}

static void page_flip_cb(void *arg)
Expand All @@ -225,15 +124,16 @@ static void page_flip_cb(void *arg)
struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_pending_vblank_event *event = omap_crtc->event;
struct drm_framebuffer *old_fb = omap_crtc->old_fb;
struct timeval now;
unsigned long flags;

WARN_ON(!event);

omap_crtc->event = NULL;
omap_crtc->old_fb = NULL;

update_scanout(crtc);
WARN_ON(commit(crtc));
omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);

/* wakeup userspace */
/* TODO: this should happen *after* flip in vsync IRQ handler */
Expand Down Expand Up @@ -264,8 +164,9 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
return -EINVAL;
}

crtc->fb = fb;
omap_crtc->old_fb = crtc->fb;
omap_crtc->event = event;
crtc->fb = fb;

omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ,
page_flip_cb, crtc);
Expand All @@ -290,12 +191,6 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
.load_lut = omap_crtc_load_lut,
};

struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return omap_crtc->ovl;
}

/* initialize crtc */
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct omap_overlay *ovl, int id)
Expand All @@ -310,9 +205,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
goto fail;
}

omap_crtc->ovl = ovl;
omap_crtc->id = id;
crtc = &omap_crtc->base;

omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true);
omap_crtc->plane->crtc = crtc;
omap_crtc->name = ovl->name;
omap_crtc->id = id;

drm_crtc_init(dev, crtc, &omap_crtc_funcs);
drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);

Expand Down
53 changes: 33 additions & 20 deletions drivers/staging/omapdrm/omap_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
struct omap_overlay_manager *mgr = NULL;
struct drm_crtc *crtc;

if (ovl->manager) {
DBG("disconnecting %s from %s", ovl->name,
ovl->manager->name);
ovl->unset_manager(ovl);
}

/* find next best connector, ones with detected connection first
*/
while (*j < priv->num_connectors && !mgr) {
Expand Down Expand Up @@ -245,11 +239,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
(*j)++;
}

if (mgr) {
DBG("connecting %s to %s", ovl->name, mgr->name);
ovl->set_manager(ovl, mgr);
}

crtc = omap_crtc_init(dev, ovl, priv->num_crtcs);

if (!crtc) {
Expand All @@ -265,6 +254,26 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
return 0;
}

static int create_plane(struct drm_device *dev, struct omap_overlay *ovl,
unsigned int possible_crtcs)
{
struct omap_drm_private *priv = dev->dev_private;
struct drm_plane *plane =
omap_plane_init(dev, ovl, possible_crtcs, false);

if (!plane) {
dev_err(dev->dev, "could not create plane: %s\n",
ovl->name);
return -ENOMEM;
}

BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));

priv->planes[priv->num_planes++] = plane;

return 0;
}

static int match_dev_name(struct omap_dss_device *dssdev, void *data)
{
return !strcmp(dssdev->name, data);
Expand Down Expand Up @@ -332,6 +341,12 @@ static int omap_modeset_init(struct drm_device *dev)
omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
create_crtc(dev, ovl, &j, connected_connectors);
}

for (i = 0; i < kms_pdata->pln_cnt; i++) {
struct omap_overlay *ovl =
omap_dss_get_overlay(kms_pdata->pln_ids[i]);
create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
}
} else {
/* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try
* to make educated guesses about everything else
Expand All @@ -353,6 +368,12 @@ static int omap_modeset_init(struct drm_device *dev)
create_crtc(dev, omap_dss_get_overlay(i),
&j, connected_connectors);
}

/* use any remaining overlays as drm planes */
for (; i < omap_dss_get_num_overlays(); i++) {
struct omap_overlay *ovl = omap_dss_get_overlay(i);
create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
}
}

/* for now keep the mapping of CRTCs and encoders static.. */
Expand All @@ -361,15 +382,7 @@ static int omap_modeset_init(struct drm_device *dev)
struct omap_overlay_manager *mgr =
omap_encoder_get_manager(encoder);

encoder->possible_crtcs = 0;

for (j = 0; j < priv->num_crtcs; j++) {
struct omap_overlay *ovl =
omap_crtc_get_overlay(priv->crtcs[j]);
if (ovl->manager == mgr) {
encoder->possible_crtcs |= (1 << j);
}
}
encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;

DBG("%s: possible_crtcs=%08x", mgr->name,
encoder->possible_crtcs);
Expand Down
Loading

0 comments on commit bb5c2d9

Please sign in to comment.