This patch set seems to be required to form a practical solution for the OMAP5 based Pyra.
What we need is to rotate the LCD on the MIPI port for X11/DRM/FB by 90 degrees because it is a portrait display installed in landscape rotation.
This should either be done by xrandr/xorg.conf and/or some module parameter during boot.
Independently, we also should be able to support xrandr on the HDMI port.
We only need this on OMAP5 Pyra, not on OMAP3 devices like OpenPandora or GTA04.
Since we have a multi-arch kernel the solution should not explicitly depend on the SoC we use or force to config for a specific SOC.
At the moment this is partially a hack to make it working but some patches even miss signed-offs. So let's start to discuss them and improve until we can submit this work for review by a broader public (LKML).
Andreas Kemnade (1): omapdrm: try to allocate non-tiled buffer object if tiled fails
H. Nikolaus Schaller (1): XXX: fbmem: force use of device memtype
Matthijs van Duin (8): ARM: introduce pgprot_device() drm: omapdrm: improve choice of memory type for tiled memory XXX omapdrm: factor out _omap_gem_(un)pin XXX omapdrm: force tiled buffers to be pinned and page-aligned XXX omapdrm: fast userspace mapping of tiled buffers XXX ARM: fbdev: force use of device memtype XXX omapdrm: allocate fbdev in TILER XXX add fbdev_rotation param to module drm_kms_helper
arch/arm/include/asm/pgtable.h | 3 + drivers/gpu/drm/drm_fb_helper.c | 35 +++-- drivers/gpu/drm/omapdrm/omap_fbdev.c | 45 ++++++- drivers/gpu/drm/omapdrm/omap_gem.c | 246 ++++++++++++++++++++++------------- drivers/video/fbdev/core/fbmem.c | 4 + include/uapi/drm/omap_drm.h | 12 +- 6 files changed, 239 insertions(+), 106 deletions(-)
From: Matthijs van Duin matthijsvanduin@gmail.com
strongly-ordered memory is usually expensive overkill.
Signed-off-by: Matthijs van Duin matthijsvanduin@gmail.com --- arch/arm/include/asm/pgtable.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 150ece66ddf3..25be1269a15a 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -122,6 +122,9 @@ extern pgprot_t pgprot_s2_device; #define pgprot_writecombine(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+#define pgprot_device(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_SHARED) + #define pgprot_stronglyordered(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
From: Matthijs van Duin matthijsvanduin@gmail.com
On omap5/dra7 tiled memory is currently strongly-ordered, which is just painfully and needlessly slow. Using device memory suffices and is much faster. Even normal uncacheable memory is safe if the application avoids reading from the framebuffer, so I've added a flag to enable userspace to indicate it really wants the memory type requested.
The option to use strongly-ordered memory has been retained as an extra memory type in case anyone needs it for some reason.
Signed-off-by: Matthijs van Duin matthijsvanduin@gmail.com --- drivers/gpu/drm/omapdrm/omap_gem.c | 30 +++++++++++++++++++----------- include/uapi/drm/omap_drm.h | 12 ++++++++---- 2 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 5c5c86ddd6f4..374f259f367d 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -582,11 +582,19 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj, vma->vm_flags &= ~VM_PFNMAP; vma->vm_flags |= VM_MIXEDMAP;
- if (omap_obj->flags & OMAP_BO_WC) { - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - } else if (omap_obj->flags & OMAP_BO_UNCACHED) { - vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); - } else { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + + switch (omap_obj->flags & OMAP_BO_CACHE_MASK) { + case OMAP_BO_WC: + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + break; + case OMAP_BO_UNCACHED: + vma->vm_page_prot = pgprot_device(vma->vm_page_prot); + break; + case OMAP_BO_SYNC: + vma->vm_page_prot = pgprot_stronglyordered(vma->vm_page_prot); + break; + default: /* * We do have some private objects, at least for scanout buffers * on hardware without DMM/TILER. But these are allocated write- @@ -603,8 +611,6 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj, fput(vma->vm_file); vma->vm_pgoff = 0; vma->vm_file = get_file(obj->filp); - - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); }
return 0; @@ -1142,11 +1148,13 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, flags |= OMAP_BO_MEM_SHMEM;
/* - * Currently don't allow cached buffers. There is some caching - * stuff that needs to be handled better. + * Unless caller knows what he's doing replace cacheable and + * normal uncacheable memory types by default type for cpu. */ - flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED); - flags |= tiler_get_cpu_cache_flags(); + if (!(flags & (OMAP_BO_UNCACHED | OMAP_BO_FORCE))) { + flags &= ~OMAP_BO_CACHE_MASK; + flags |= tiler_get_cpu_cache_flags(); + } } else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { /* * OMAP_BO_SCANOUT hints that the buffer doesn't need to be diff --git a/include/uapi/drm/omap_drm.h b/include/uapi/drm/omap_drm.h index 1fccffef9e27..7fa3bcb6ddbc 100644 --- a/include/uapi/drm/omap_drm.h +++ b/include/uapi/drm/omap_drm.h @@ -42,10 +42,14 @@ struct drm_omap_param { #define OMAP_BO_CACHE_MASK 0x00000006 /* cache type mask, see cache modes */ #define OMAP_BO_TILED_MASK 0x00000f00 /* tiled mapping mask, see tiled modes */
-/* cache modes */ -#define OMAP_BO_CACHED 0x00000000 /* default */ -#define OMAP_BO_WC 0x00000002 /* write-combine */ -#define OMAP_BO_UNCACHED 0x00000004 /* strongly-ordered (uncached) */ +/* memory types / cache modes */ +#define OMAP_BO_CACHED 0x00000000 /* normal cacheable */ +#define OMAP_BO_WC 0x00000002 /* normal non-cacheable */ +#define OMAP_BO_UNCACHED 0x00000004 /* device */ +#define OMAP_BO_SYNC 0x00000006 /* strongly-ordered */ + +/* allow use of normal memory types even when this is hazardous */ +#define OMAP_BO_FORCE 0x00000010
/* tiled modes */ #define OMAP_BO_TILED_8 0x00000100
From: Matthijs van Duin matthijsvanduin@gmail.com
--- drivers/gpu/drm/omapdrm/omap_gem.c | 164 ++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 75 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 374f259f367d..fa118d3089a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -791,6 +791,66 @@ void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, } }
+static int _omap_gem_pin(struct drm_gem_object *obj) +{ + struct omap_drm_private *priv = obj->dev->dev_private; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + struct page **pages; + uint32_t npages = obj->size >> PAGE_SHIFT; + enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + struct tiler_block *block; + int ret; + + if (is_contiguous(omap_obj)) + return 0; + if (!priv->has_dmm) + return -EINVAL; + + if (omap_obj->dma_addr_cnt) { + omap_obj->dma_addr_cnt++; + return 0; + } + + BUG_ON(omap_obj->block); + + ret = get_pages(obj, &pages); + if (ret) + return ret; + + if (omap_obj->flags & OMAP_BO_TILED) { + block = tiler_reserve_2d(fmt, + omap_obj->width, + omap_obj->height, 0); + } else { + block = tiler_reserve_1d(obj->size); + } + + if (IS_ERR(block)) { + ret = PTR_ERR(block); + dev_err(obj->dev->dev, + "could not remap: %d (%d)\n", ret, fmt); + return ret; + } + + /* TODO: enable async refill.. */ + ret = tiler_pin(block, pages, npages, + omap_obj->roll, true); + if (ret) { + tiler_release(block); + dev_err(obj->dev->dev, + "could not pin: %d\n", ret); + return ret; + } + + omap_obj->dma_addr_cnt = 1; + omap_obj->dma_addr = tiler_ssptr(block); + omap_obj->block = block; + + DBG("got dma address: %pad", &omap_obj->dma_addr); + + return 0; +} + /** * omap_gem_pin() - Pin a GEM object in memory * @obj: the GEM object @@ -807,70 +867,44 @@ void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, */ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) { - struct omap_drm_private *priv = obj->dev->dev_private; - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret = 0; + int ret;
mutex_lock(&obj->dev->struct_mutex);
- if (!is_contiguous(omap_obj) && priv->has_dmm) { - if (omap_obj->dma_addr_cnt == 0) { - struct page **pages; - uint32_t npages = obj->size >> PAGE_SHIFT; - enum tiler_fmt fmt = gem2fmt(omap_obj->flags); - struct tiler_block *block; - - BUG_ON(omap_obj->block); - - ret = get_pages(obj, &pages); - if (ret) - goto fail; + ret = _omap_gem_pin(obj);
- if (omap_obj->flags & OMAP_BO_TILED) { - block = tiler_reserve_2d(fmt, - omap_obj->width, - omap_obj->height, 0); - } else { - block = tiler_reserve_1d(obj->size); - } + if (ret == 0) + *dma_addr = to_omap_bo(obj)->dma_addr;
- if (IS_ERR(block)) { - ret = PTR_ERR(block); - dev_err(obj->dev->dev, - "could not remap: %d (%d)\n", ret, fmt); - goto fail; - } - - /* TODO: enable async refill.. */ - ret = tiler_pin(block, pages, npages, - omap_obj->roll, true); - if (ret) { - tiler_release(block); - dev_err(obj->dev->dev, - "could not pin: %d\n", ret); - goto fail; - } + mutex_unlock(&obj->dev->struct_mutex);
- omap_obj->dma_addr = tiler_ssptr(block); - omap_obj->block = block; + return ret; +}
- DBG("got dma address: %pad", &omap_obj->dma_addr); - } +static void _omap_gem_unpin(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret;
- omap_obj->dma_addr_cnt++; + if (is_contiguous(omap_obj)) + return; + if (omap_obj->dma_addr_cnt--) + return; + if (WARN_ON(!omap_obj->block)) + return;
- *dma_addr = omap_obj->dma_addr; - } else if (is_contiguous(omap_obj)) { - *dma_addr = omap_obj->dma_addr; - } else { - ret = -EINVAL; - goto fail; + ret = tiler_unpin(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not unpin pages: %d\n", ret); } - -fail: - mutex_unlock(&obj->dev->struct_mutex); - - return ret; + ret = tiler_release(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not release unmap: %d\n", ret); + } + omap_obj->dma_addr = 0; + omap_obj->block = NULL; }
/** @@ -883,28 +917,8 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) */ void omap_gem_unpin(struct drm_gem_object *obj) { - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret; - mutex_lock(&obj->dev->struct_mutex); - if (omap_obj->dma_addr_cnt > 0) { - omap_obj->dma_addr_cnt--; - if (omap_obj->dma_addr_cnt == 0) { - ret = tiler_unpin(omap_obj->block); - if (ret) { - dev_err(obj->dev->dev, - "could not unpin pages: %d\n", ret); - } - ret = tiler_release(omap_obj->block); - if (ret) { - dev_err(obj->dev->dev, - "could not release unmap: %d\n", ret); - } - omap_obj->dma_addr = 0; - omap_obj->block = NULL; - } - } - + _omap_gem_unpin(obj); mutex_unlock(&obj->dev->struct_mutex); }
From: Matthijs van Duin matthijsvanduin@gmail.com
--- drivers/gpu/drm/omapdrm/omap_gem.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index fa118d3089a3..6cf190156dcf 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -820,7 +820,7 @@ static int _omap_gem_pin(struct drm_gem_object *obj) if (omap_obj->flags & OMAP_BO_TILED) { block = tiler_reserve_2d(fmt, omap_obj->width, - omap_obj->height, 0); + omap_obj->height, PAGE_SIZE); } else { block = tiler_reserve_1d(obj->size); } @@ -1106,6 +1106,9 @@ void omap_gem_free_object(struct drm_gem_object *obj)
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+ if (omap_obj->flags & OMAP_BO_TILED) + _omap_gem_unpin(obj); + spin_lock(&priv->list_lock); list_del(&omap_obj->mm_list); spin_unlock(&priv->list_lock); @@ -1229,6 +1232,12 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, goto err_release; }
+ if (flags & OMAP_BO_TILED) { + ret = _omap_gem_pin(obj); + if (ret) + goto err_release; + } + spin_lock(&priv->list_lock); list_add(&omap_obj->mm_list, &priv->obj_list); spin_unlock(&priv->list_lock);
From: Matthijs van Duin matthijsvanduin@gmail.com
--- drivers/gpu/drm/omapdrm/omap_gem.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 6cf190156dcf..670845b19e49 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -396,6 +396,7 @@ static int fault_1d(struct drm_gem_object *obj, return vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); }
+#if 0 /* Special handling for the case of faulting in 2d tiled buffers */ static int fault_2d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) @@ -497,6 +498,7 @@ static int fault_2d(struct drm_gem_object *obj,
return 0; } +#endif
/** * omap_gem_fault - pagefault handler for GEM objects @@ -536,7 +538,7 @@ int omap_gem_fault(struct vm_fault *vmf) */
if (omap_obj->flags & OMAP_BO_TILED) - ret = fault_2d(obj, vma, vmf); + ret = -EFAULT; //fault_2d(obj, vma, vmf); else ret = fault_1d(obj, vma, vmf);
@@ -579,8 +581,10 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj, { struct omap_gem_object *omap_obj = to_omap_bo(obj);
- vma->vm_flags &= ~VM_PFNMAP; - vma->vm_flags |= VM_MIXEDMAP; + if (!(omap_obj->flags & OMAP_BO_TILED)) { + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_flags |= VM_MIXEDMAP; + }
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
@@ -613,6 +617,25 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj, vma->vm_file = get_file(obj->filp); }
+ if (omap_obj->flags & OMAP_BO_TILED) { + const enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + const uint vstride = tiler_vsize(fmt, omap_obj->width, 1); + const uint pstride = tiler_stride(fmt, 0) >> PAGE_SHIFT; + unsigned long vaddr = vma->vm_start; + unsigned long pfn = omap_obj->dma_addr >> PAGE_SHIFT; + uint i; + int ret = 0; + for (i = 0; i < omap_obj->height; i++) { + ret = remap_pfn_range(vma, vaddr, pfn, vstride, + vma->vm_page_prot); + if (ret) + break; + vaddr += vstride; + pfn += pstride; + } + return ret; + } + return 0; }
From: Matthijs van Duin matthijsvanduin@gmail.com
This *really* doesn't belong here
I should just override fb_mmap for omapdrm fbdev --- arch/arm/include/asm/fb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/fb.h b/arch/arm/include/asm/fb.h index d92e99cd8c8a..b4974b825dc1 100644 --- a/arch/arm/include/asm/fb.h +++ b/arch/arm/include/asm/fb.h @@ -8,7 +8,7 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off) { - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + vma->vm_page_prot = pgprot_device(vma->vm_page_prot); }
static inline int fb_is_primary_device(struct fb_info *info)
From: Matthijs van Duin matthijsvanduin@gmail.com
For now I'm just forcing its actual width to the container width (8192 pixels). It's a giant waste of RAM, but it makes the buffer physically contiguous which ensures easy compatibility with existing fbdev code and hassle-free mapping into kernel memory. --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 21 ++++++++++++++++++--- drivers/gpu/drm/omapdrm/omap_gem.c | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 9273118040b7..b181c7e89560 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -118,10 +118,10 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); - mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height;
+#if 0 mode_cmd.pitches[0] = DIV_ROUND_UP(mode_cmd.width * sizes->surface_bpp, 8);
@@ -137,6 +137,21 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, }; 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); +#else + // XXX needs implementation fix, so disable for now. + fbdev->ywrap_enabled = false; + + gsize = (union omap_gem_size){ + .tiled = { + .width = 8192, // XXX HACK + .height = mode_cmd.height, + } + }; + fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_TILED_32 | OMAP_BO_WC); + + mode_cmd.pitches[0] = PAGE_ALIGN( + DIV_ROUND_UP(gsize.tiled.width * sizes->surface_bpp, 8)); +#endif if (!fbdev->bo) { dev_err(dev->dev, "failed to allocate buffer object\n"); ret = -ENOMEM; @@ -194,9 +209,9 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, dev->mode_config.fb_base = dma_addr;
fbi->screen_base = omap_gem_vaddr(fbdev->bo); - fbi->screen_size = fbdev->bo->size; + fbi->screen_size = fb->pitches[0] * sizes->surface_height; fbi->fix.smem_start = dma_addr; - fbi->fix.smem_len = fbdev->bo->size; + fbi->fix.smem_len = fbi->screen_size;
/* if we have DMM, then we can use it for scrolling by just * shuffling pages around in DMM rather than doing sw blit. diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 670845b19e49..4ef2db367a04 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1020,16 +1020,24 @@ int omap_gem_put_pages(struct drm_gem_object *obj) void *omap_gem_vaddr(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); + void *va = omap_obj->vaddr; WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); - if (!omap_obj->vaddr) { + if (va) + return va; + if (omap_obj->flags & OMAP_BO_TILED) { + // FIXME to avoid contiguous mapping? + va = ioremap(omap_obj->dma_addr, obj->size); + } else { struct page **pages; int ret = get_pages(obj, &pages); if (ret) return ERR_PTR(ret); - omap_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, + va = vmap(pages, obj->size >> PAGE_SHIFT, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } - return omap_obj->vaddr; + if (!IS_ERR(va)) + omap_obj->vaddr = va; + return va; } #endif
@@ -1151,6 +1159,8 @@ void omap_gem_free_object(struct drm_gem_object *obj) if (omap_obj->flags & OMAP_BO_MEM_DMA_API) { dma_free_wc(dev->dev, obj->size, omap_obj->vaddr, omap_obj->dma_addr); + } else if (omap_obj->flags & OMAP_BO_TILED) { + iounmap(omap_obj->vaddr); } else if (omap_obj->vaddr) { vunmap(omap_obj->vaddr); } else if (obj->import_attach) {
From: Matthijs van Duin matthijsvanduin@gmail.com
runtime changes are at your own risk --- drivers/gpu/drm/drm_fb_helper.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e56166334455..51fed577f821 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -54,6 +54,9 @@ MODULE_PARM_DESC(drm_fbdev_overalloc, "Overallocation of the fbdev buffer (%) [default=" __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
+static uint drm_fbdev_rotation = DRM_MODE_ROTATE_0; +module_param_named(fbdev_rotation, drm_fbdev_rotation, uint, 0644); + static LIST_HEAD(kernel_fb_helper_list); static DEFINE_MUTEX(kernel_fb_helper_lock);
@@ -376,7 +379,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ goto out_state; }
- plane_state->rotation = DRM_MODE_ROTATE_0; + plane_state->rotation = drm_fbdev_rotation;
plane->old_fb = plane->fb; plane_mask |= 1 << drm_plane_index(plane); @@ -445,7 +448,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper) if (plane->rotation_property) drm_mode_plane_set_obj_prop(plane, plane->rotation_property, - DRM_MODE_ROTATE_0); + drm_fbdev_rotation); }
for (i = 0; i < fb_helper->crtc_count; i++) { @@ -1766,7 +1769,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_display_mode *desired_mode; struct drm_mode_set *mode_set; - int x, y, j; + int width, height, x, y, j; /* in case of tile group, are we the last tile vert or horiz? * If no tile group you are always the last one both vertically * and horizontally @@ -1779,6 +1782,14 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (!desired_mode) continue;
+ if (drm_rotation_90_or_270(drm_fbdev_rotation)) { + height = desired_mode->hdisplay; + width = desired_mode->vdisplay; + } else { + width = desired_mode->hdisplay; + height = desired_mode->vdisplay; + } + crtc_count++;
x = fb_helper->crtc_info[i].x; @@ -1787,8 +1798,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (gamma_size == 0) gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
- sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width); - sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height); + sizes.surface_width = max_t(u32, width + x, sizes.surface_width); + sizes.surface_height = max_t(u32, height + y, sizes.surface_height);
for (j = 0; j < mode_set->num_connectors; j++) { struct drm_connector *connector = mode_set->connectors[j]; @@ -1802,9 +1813,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, }
if (lasth) - sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width); + sizes.fb_width = min_t(u32, width + x, sizes.fb_width); if (lastv) - sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height); + sizes.fb_height = min_t(u32, height + y, sizes.fb_height); }
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { @@ -2597,6 +2608,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config); int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { int err = 0; + unsigned width, height;
if (!drm_fbdev_emulation) return 0; @@ -2616,7 +2628,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
DRM_DEBUG_KMS("\n");
- drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height); + if (drm_rotation_90_or_270(drm_fbdev_rotation)) { + width = fb_helper->fb->height; + height = fb_helper->fb->width; + } else { + width = fb_helper->fb->width; + height = fb_helper->fb->height; + } + drm_setup_crtcs(fb_helper, width, height); drm_setup_crtcs_fb(fb_helper); mutex_unlock(&fb_helper->lock);
From: Andreas Kemnade andreas@kemnade.info
If omap_gem_new is called with OMAP_BO_TILED_32 and there is no DMM it immediatetly returns NULL. That causes a framebuffer device not to be created if there is no DMM available. So do a second try to allocate a buffer object using the old parameters so a framebuffer will still be created on OMAP3 devices.
Signed-off-by: Andreas Kemnade andreas@kemnade.info --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index b181c7e89560..65a936253521 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -152,6 +152,30 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, mode_cmd.pitches[0] = PAGE_ALIGN( DIV_ROUND_UP(gsize.tiled.width * sizes->surface_bpp, 8)); #endif + + if (!fbdev->bo) { + mode_cmd.pitches[0] = + DIV_ROUND_UP(mode_cmd.width * sizes->surface_bpp, 8); + + fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled; + if (fbdev->ywrap_enabled) { + /* need to align pitch to page size + * if using DMM scrolling + */ + mode_cmd.pitches[0] = PAGE_ALIGN(mode_cmd.pitches[0]); + } + + /* allocate backing bo */ + gsize = (union omap_gem_size){ + .bytes = PAGE_ALIGN(mode_cmd.pitches[0] * + 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"); ret = -ENOMEM;
This reverts commit "XXX ARM: fbdev: force use of device memtype This *really* doesn't belong here I should just override fb_mmap for omapdrm fbdev"
and moves the override option to fb_mmap.
Missing: choose pgprot_device() for OMAP5 with TILER only and pgprot_writecombine() otherwise. --- arch/arm/include/asm/fb.h | 2 +- drivers/video/fbdev/core/fbmem.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/fb.h b/arch/arm/include/asm/fb.h index b4974b825dc1..d92e99cd8c8a 100644 --- a/arch/arm/include/asm/fb.h +++ b/arch/arm/include/asm/fb.h @@ -8,7 +8,7 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off) { - vma->vm_page_prot = pgprot_device(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); }
static inline int fb_is_primary_device(struct fb_info *info) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index f741ba8df01b..d40b1b549d87 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1434,7 +1434,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) * SME protection is removed */ vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); +#if 0 // OMAP5 TILER may need it (or not?) but it breaks on OMAP3 + vma->vm_page_prot = pgprot_device(vma->vm_page_prot); +#else // all others incl. OMAP3 w/o TILER fb_pgprotect(file, vma, start); +#endif
return vm_iomap_memory(vma, start, len); }
Hi,
On Mon, 5 Feb 2018 17:20:55 +0100 "H. Nikolaus Schaller" hns@goldelico.com wrote:
This patch set seems to be required to form a practical solution for the OMAP5 based Pyra.
What we need is to rotate the LCD on the MIPI port for X11/DRM/FB by 90 degrees because it is a portrait display installed in landscape rotation.
This should either be done by xrandr/xorg.conf and/or some module parameter during boot.
Independently, we also should be able to support xrandr on the HDMI port.
We only need this on OMAP5 Pyra, not on OMAP3 devices like OpenPandora or GTA04.
Since we have a multi-arch kernel the solution should not explicitly depend on the SoC we use or force to config for a specific SOC.
At the moment this is partially a hack to make it working but some patches even miss signed-offs. So let's start to discuss them and improve until we can submit this work for review by a broader public (LKML).
Andreas Kemnade (1): omapdrm: try to allocate non-tiled buffer object if tiled fails
For reviewing (and bisect-ability) it would be easier to have this squashed with omapdrm: allocate fbdev in TILER.
Another question: Sebastian Reichel showed a rotated console on omap4 in his fosdem presentation, so can we do it the same way? As it rotated hdmi and lcd the same time it does not look like something done in a lcd driver chip...
Regards, Andreas
Hi,
Am 06.02.2018 um 07:03 schrieb Andreas Kemnade andreas@kemnade.info:
Hi,
On Mon, 5 Feb 2018 17:20:55 +0100 "H. Nikolaus Schaller" hns@goldelico.com wrote:
This patch set seems to be required to form a practical solution for the OMAP5 based Pyra.
What we need is to rotate the LCD on the MIPI port for X11/DRM/FB by 90 degrees because it is a portrait display installed in landscape rotation.
This should either be done by xrandr/xorg.conf and/or some module parameter during boot.
Independently, we also should be able to support xrandr on the HDMI port.
We only need this on OMAP5 Pyra, not on OMAP3 devices like OpenPandora or GTA04.
Since we have a multi-arch kernel the solution should not explicitly depend on the SoC we use or force to config for a specific SOC.
At the moment this is partially a hack to make it working but some patches even miss signed-offs. So let's start to discuss them and improve until we can submit this work for review by a broader public (LKML).
Andreas Kemnade (1): omapdrm: try to allocate non-tiled buffer object if tiled fails
For reviewing (and bisect-ability) it would be easier to have this squashed with omapdrm: allocate fbdev in TILER.
In the long run, yes.
At the moment I did not want to squash patches from different authors, especially as "omapdrm: allocate fbdev in TILER" does not yet have a signed-off.
Another question: Sebastian Reichel showed a rotated console on omap4 in his fosdem presentation, so can we do it the same way?
Interesting.
Well, we can do it the same way if we know the way he is doing it. Did he share any details? Or a pointer to the code doing this?
I think this TILER patch set can do the same (on OMAP5) if rotation is initialized earlier. During LetuxOS boot some blinking cursor appears unrotated.
Then LetuxOS user-space runs our tiler-ctl script and rotates by 270 degrees. After that the blinking cursor is correctly rotated until it is replaced by X11.
So I think by enabling console and doing the setup earlier it could do that.
As it rotated hdmi and lcd the same time it does not look like something done in a lcd driver chip...
Maybe he is swapping x and y coordinates when changing pixels in the shared fb. But that does not solve all rotation problems, especially for software optimized for a specific framebuffer layout.
BR, Nikolaus
Hi,
On Tue, Feb 06, 2018 at 09:40:02AM +0100, H. Nikolaus Schaller wrote:
Another question: Sebastian Reichel showed a rotated console on omap4 in his fosdem presentation, so can we do it the same way?
Interesting.
Well, we can do it the same way if we know the way he is doing it. Did he share any details? Or a pointer to the code doing this?
I just specified "fbcon=rotate:1" on the command line. This will result in the kernel console being rendered rotated on all displays. This directly renders the console rotated, so it's completly unrelated to omapdrm. X is not affected and will start without rotation being applied. For Droid 4 / OMAP4 xrandr based rotation does work without any patches, though (except for [0]).
I plan to add support for the new "panel orientation" property [1] to omapdrm once support for manually updated displays landed. This should help to get rotation applied correctly out of the box without any hacks required in the omapdrm code.
[0] https://lists.x.org/archives/xorg-devel/2018-February/055793.html [1] https://www.spinics.net/lists/dri-devel/msg158239.html
-- Sebastian