Skip to content

Commit

Permalink
staging: drm/omap: DMM based hardware scrolling console
Browse files Browse the repository at this point in the history
Add support for YWRAP scrolling by shuffling pages around in DMM
instead of sw blits.

Note that fbcon only utilizes this mode if the y resolution is
divided evenly by the font height.  So, for example, a 1920x1080
display using a 16 pixel tall font will not utilize this, but a
1280x1024 display would.

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 Dec 13, 2011
1 parent 65b0bd0 commit a6a9182
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 46 deletions.
4 changes: 2 additions & 2 deletions drivers/staging/omapdrm/omap_dmm_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@
#define DMM_PATSTATUS_ERR_UPD_DATA (1<<14)
#define DMM_PATSTATUS_ERR_ACCESS (1<<15)

/* note: don't treat DMM_PATSTATUS_ERR_ACCESS as an error */
#define DMM_PATSTATUS_ERR (DMM_PATSTATUS_ERR_INV_DESCR | \
DMM_PATSTATUS_ERR_INV_DATA | \
DMM_PATSTATUS_ERR_UPD_AREA | \
DMM_PATSTATUS_ERR_UPD_CTRL | \
DMM_PATSTATUS_ERR_UPD_DATA | \
DMM_PATSTATUS_ERR_ACCESS)
DMM_PATSTATUS_ERR_UPD_DATA)



Expand Down
35 changes: 22 additions & 13 deletions drivers/staging/omapdrm/omap_dmm_tiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm)
* corresponding slot is cleared (ie. dummy_pa is programmed)
*/
static int dmm_txn_append(struct dmm_txn *txn, struct pat_area *area,
struct page **pages)
struct page **pages, uint32_t npages, uint32_t roll)
{
dma_addr_t pat_pa = 0;
uint32_t *data;
Expand All @@ -197,8 +197,11 @@ static int dmm_txn_append(struct dmm_txn *txn, struct pat_area *area,
data = alloc_dma(txn, 4*i, &pat->data_pa);

while (i--) {
data[i] = (pages && pages[i]) ?
page_to_phys(pages[i]) : engine->dmm->dummy_pa;
int n = i + roll;
if (n >= npages)
n -= npages;
data[i] = (pages && pages[n]) ?
page_to_phys(pages[n]) : engine->dmm->dummy_pa;
}

/* fill in lut with new addresses */
Expand Down Expand Up @@ -262,7 +265,8 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
/*
* DMM programming
*/
static int fill(struct tcm_area *area, struct page **pages, bool wait)
static int fill(struct tcm_area *area, struct page **pages,
uint32_t npages, uint32_t roll, bool wait)
{
int ret = 0;
struct tcm_area slice, area_s;
Expand All @@ -278,12 +282,11 @@ static int fill(struct tcm_area *area, struct page **pages, bool wait)
.x1 = slice.p1.x, .y1 = slice.p1.y,
};

ret = dmm_txn_append(txn, &p_area, pages);
ret = dmm_txn_append(txn, &p_area, pages, npages, roll);
if (ret)
goto fail;

if (pages)
pages += tcm_sizeof(slice);
roll += tcm_sizeof(slice);
}

ret = dmm_txn_commit(txn, wait);
Expand All @@ -298,11 +301,12 @@ static int fill(struct tcm_area *area, struct page **pages, bool wait)

/* note: slots for which pages[i] == NULL are filled w/ dummy page
*/
int tiler_pin(struct tiler_block *block, struct page **pages, bool wait)
int tiler_pin(struct tiler_block *block, struct page **pages,
uint32_t npages, uint32_t roll, bool wait)
{
int ret;

ret = fill(&block->area, pages, wait);
ret = fill(&block->area, pages, npages, roll, wait);

if (ret)
tiler_unpin(block);
Expand All @@ -312,7 +316,7 @@ int tiler_pin(struct tiler_block *block, struct page **pages, bool wait)

int tiler_unpin(struct tiler_block *block)
{
return fill(&block->area, NULL, false);
return fill(&block->area, NULL, 0, 0, false);
}

/*
Expand Down Expand Up @@ -558,8 +562,13 @@ int omap_dmm_init(struct drm_device *dev)
goto fail;
}

/* enable some interrupts! */
writel(0xfefefefe, omap_dmm->base + DMM_PAT_IRQENABLE_SET);
/* Enable all interrupts for each refill engine except
* ERR_LUT_MISS<n> (which is just advisory, and we don't care
* about because we want to be able to refill live scanout
* buffers for accelerated pan/scroll) and FILL_DSC<n> which
* we just generally don't care about.
*/
writel(0x7e7e7e7e, omap_dmm->base + DMM_PAT_IRQENABLE_SET);

lut_table_size = omap_dmm->lut_width * omap_dmm->lut_height *
omap_dmm->num_lut;
Expand Down Expand Up @@ -658,7 +667,7 @@ int omap_dmm_init(struct drm_device *dev)
/* initialize all LUTs to dummy page entries */
for (i = 0; i < omap_dmm->num_lut; i++) {
area.tcm = omap_dmm->tcm[i];
if (fill(&area, NULL, true))
if (fill(&area, NULL, 0, 0, true))
dev_err(omap_dmm->dev, "refill failed");
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/staging/omapdrm/omap_dmm_tiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ int omap_dmm_init(struct drm_device *dev);
int omap_dmm_remove(void);

/* pin/unpin */
int tiler_pin(struct tiler_block *block, struct page **pages, bool wait);
int tiler_pin(struct tiler_block *block, struct page **pages,
uint32_t npages, uint32_t roll, bool wait);
int tiler_unpin(struct tiler_block *block);

/* reserve/release */
Expand Down
3 changes: 3 additions & 0 deletions drivers/staging/omapdrm/omap_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ struct omap_drm_private {
struct drm_connector *connectors[8];

struct drm_fb_helper *fbdev;

bool has_dmm;
};

struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev);
Expand Down Expand Up @@ -107,6 +109,7 @@ int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
void (*fxn)(void *arg), void *arg);
int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll);
int omap_gem_get_paddr(struct drm_gem_object *obj,
dma_addr_t *paddr, bool remap);
int omap_gem_put_paddr(struct drm_gem_object *obj);
Expand Down
22 changes: 3 additions & 19 deletions drivers/staging/omapdrm/omap_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,25 +218,9 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,

size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height);

if (bo) {
DBG("using existing %d byte buffer (needed %d)", bo->size, size);
if (size > bo->size) {
dev_err(dev->dev, "provided buffer object is too small!\n");
goto fail;
}
} else {
/* for convenience of all the various callers who don't want
* to be bothered to allocate their own buffer..
*/
union omap_gem_size gsize = {
.bytes = size,
};
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
if (!bo) {
dev_err(dev->dev, "failed to allocate buffer object\n");
goto fail;
}
if (size > bo->size) {
dev_err(dev->dev, "provided buffer object is too small!\n");
goto fail;
}

omap_fb->bo = bo;
Expand Down
73 changes: 68 additions & 5 deletions drivers/staging/omapdrm/omap_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
struct omap_fbdev {
struct drm_fb_helper base;
struct drm_framebuffer *fb;
struct drm_gem_object *bo;
};

static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
static struct drm_fb_helper *get_fb(struct fb_info *fbi);

static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
size_t count, loff_t *ppos)
Expand Down Expand Up @@ -68,6 +70,31 @@ static void omap_fbdev_imageblit(struct fb_info *fbi,
image->width, image->height);
}

static int omap_fbdev_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
struct drm_fb_helper *helper = get_fb(fbi);
struct omap_fbdev *fbdev = to_omap_fbdev(helper);
struct omap_drm_private *priv;
int npages;

if (!helper)
goto fallback;

priv = helper->dev->dev_private;
if (!priv->has_dmm)
goto fallback;

/* DMM roll shifts in 4K pages: */
npages = fbi->fix.line_length >> PAGE_SHIFT;
omap_gem_roll(fbdev->bo, var->yoffset * npages);

return 0;

fallback:
return drm_fb_helper_pan_display(var, fbi);
}

static struct fb_ops omap_fb_ops = {
.owner = THIS_MODULE,

Expand All @@ -82,7 +109,7 @@ static struct fb_ops omap_fb_ops = {

.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_pan_display = omap_fbdev_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,

Expand All @@ -95,7 +122,9 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
{
struct omap_fbdev *fbdev = to_omap_fbdev(helper);
struct drm_device *dev = helper->dev;
struct omap_drm_private *priv = dev->dev_private;
struct drm_framebuffer *fb = NULL;
union omap_gem_size gsize;
struct fb_info *fbi = NULL;
struct drm_mode_fb_cmd mode_cmd = {0};
dma_addr_t paddr;
Expand All @@ -109,16 +138,37 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
sizes->surface_bpp = 32;
sizes->surface_depth = 32;

DBG("create fbdev: %dx%d@%d", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp);
DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp,
sizes->fb_width, sizes->fb_height);

mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;

mode_cmd.bpp = sizes->surface_bpp;
mode_cmd.depth = sizes->surface_depth;

fb = omap_framebuffer_init(dev, &mode_cmd, NULL);
mode_cmd.pitch = align_pitch(
mode_cmd.width * ((mode_cmd.bpp + 7) / 8),
mode_cmd.width, mode_cmd.bpp);

if (priv->has_dmm) {
/* need to align pitch to page size if using DMM scrolling */
mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE);
}

/* allocate backing bo */
gsize = (union omap_gem_size){
.bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height),
};
DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
if (!fbdev->bo) {
dev_err(dev->dev, "failed to allocate buffer object\n");
goto fail;
}

fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo);
if (!fb) {
dev_err(dev->dev, "failed to allocate fb\n");
ret = -ENOMEM;
Expand Down Expand Up @@ -153,7 +203,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
}

drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);

size = omap_framebuffer_get_buffer(fb, 0, 0,
&vaddr, &paddr, &screen_width);
Expand All @@ -165,6 +215,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
fbi->fix.smem_start = paddr;
fbi->fix.smem_len = size;

/* if we have DMM, then we can use it for scrolling by just
* shuffling pages around in DMM rather than doing sw blit.
*/
if (priv->has_dmm) {
DRM_INFO("Enabling DMM ywrap scrolling\n");
fbi->flags |= FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST;
fbi->fix.ywrapstep = 1;
}

DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);

Expand Down Expand Up @@ -300,5 +359,9 @@ void omap_fbdev_free(struct drm_device *dev)

kfree(fbdev);

/* this will free the backing object */
if (fbdev->fb)
fbdev->fb->funcs->destroy(fbdev->fb);

priv->fbdev = NULL;
}
Loading

0 comments on commit a6a9182

Please sign in to comment.