From 71f83bad9ea32c5fba8d675021a8ce56e9ccd507 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 21 Feb 2014 15:40:38 -0600 Subject: [PATCH 01/15] UMP: add interface to create cachable allocation from physical blocks To be used by exynos-drm for Mali integration. --- drivers/gpu/arm/ump/common/ump_kernel_ref_drv.c | 11 ++++++++--- .../arm/ump/include/ump_kernel_interface_ref_drv.h | 1 + drivers/gpu/arm/ump/linux/ump_kernel_linux.c | 1 + include/ump/ump_kernel_interface_ref_drv.h | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/arm/ump/common/ump_kernel_ref_drv.c b/drivers/gpu/arm/ump/common/ump_kernel_ref_drv.c index a2a7b8c329c476..72dd233681c54a 100644 --- a/drivers/gpu/arm/ump/common/ump_kernel_ref_drv.c +++ b/drivers/gpu/arm/ump/common/ump_kernel_ref_drv.c @@ -23,7 +23,7 @@ #define UMP_ADDR_ALIGN_OFFSET(x) ((x)&(UMP_MINIMUM_SIZE-1)) static void phys_blocks_release(void * ctx, struct ump_dd_mem * descriptor); -UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks) +UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks2(ump_dd_physical_block * blocks, unsigned long num_blocks, int is_cached) { ump_dd_mem * mem; unsigned long size_total = 0; @@ -93,8 +93,7 @@ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd mem->backend_info = NULL; mem->ctx = NULL; mem->release_func = phys_blocks_release; - /* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */ - mem->is_cached = 0; + mem->is_cached = is_cached; mem->hw_device = _UMP_UK_USED_BY_CPU; mem->lock_usage = UMP_NOT_LOCKED; @@ -104,6 +103,12 @@ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd return (ump_dd_handle)mem; } +UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks) +{ + /* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */ + return ump_dd_handle_create_from_phys_blocks2(blocks, num_blocks, 0); +} + static void phys_blocks_release(void * ctx, struct ump_dd_mem * descriptor) { _mali_osk_free(descriptor->block_array); diff --git a/drivers/gpu/arm/ump/include/ump_kernel_interface_ref_drv.h b/drivers/gpu/arm/ump/include/ump_kernel_interface_ref_drv.h index c9937461a0ff5e..637be0cf106380 100644 --- a/drivers/gpu/arm/ump/include/ump_kernel_interface_ref_drv.h +++ b/drivers/gpu/arm/ump/include/ump_kernel_interface_ref_drv.h @@ -23,6 +23,7 @@ extern "C" { /** Turn specified physical memory into UMP memory. */ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks); +UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks2(ump_dd_physical_block * blocks, unsigned long num_blocks, int is_cached); #ifdef __cplusplus } diff --git a/drivers/gpu/arm/ump/linux/ump_kernel_linux.c b/drivers/gpu/arm/ump/linux/ump_kernel_linux.c index a2a4716f37d916..bc4f730d7c34b5 100644 --- a/drivers/gpu/arm/ump/linux/ump_kernel_linux.c +++ b/drivers/gpu/arm/ump/linux/ump_kernel_linux.c @@ -453,6 +453,7 @@ EXPORT_SYMBOL(ump_dd_reference_release); /* Export our own extended kernel space allocator */ EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks); +EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks2); /* Setup init and exit functions for this module */ module_init(ump_initialize_module); diff --git a/include/ump/ump_kernel_interface_ref_drv.h b/include/ump/ump_kernel_interface_ref_drv.h index eb57fd88f3f229..2ff17e8badc12f 100644 --- a/include/ump/ump_kernel_interface_ref_drv.h +++ b/include/ump/ump_kernel_interface_ref_drv.h @@ -23,6 +23,7 @@ extern "C" { /** Turn specified physical memory into UMP memory. */ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks); +UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks2(ump_dd_physical_block * blocks, unsigned long num_blocks, int is_cached); #ifdef __cplusplus } From d2ca42418241b4c2729295c8ceb7d1013e656658 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 24 Dec 2013 11:09:37 -0600 Subject: [PATCH 02/15] UMP/exynos-drm integration Add a new exynos ioctl: DRM_IOCTL_EXYNOS_GEM_CREATE2 This behaves exactly like the original CREATE but it also creates a UMP handle for the allocation, and returns the relevant UMP secure ID to userspace. --- drivers/gpu/drm/exynos/exynos_drm_buf.c | 18 ++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_buf.h | 1 + drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_gem.c | 31 +++++++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_gem.h | 4 ++++ include/uapi/drm/exynos_drm.h | 11 +++++++++ 6 files changed, 67 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 3fc524f5925044..751732d33299c8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -11,6 +11,7 @@ #include #include +#include #include "exynos_drm_drv.h" #include "exynos_drm_gem.h" @@ -194,6 +195,23 @@ int exynos_drm_alloc_buf(struct drm_device *dev, void exynos_drm_free_buf(struct drm_device *dev, unsigned int flags, struct exynos_drm_gem_buf *buffer) { + if (buffer->ump_handle) + ump_dd_reference_release(buffer->ump_handle); lowlevel_buffer_deallocate(dev, flags, buffer); } + +ump_dd_handle exynos_drm_get_ump_handle(struct exynos_drm_gem_buf *buffer) +{ + ump_dd_physical_block ump_mem; + int is_cached; + + if (buffer->ump_handle) + return buffer->ump_handle; + + ump_mem.addr = buffer->dma_addr; + ump_mem.size = buffer->size; + is_cached = dma_get_attr(DMA_ATTR_NON_CONSISTENT, &buffer->dma_attrs); + buffer->ump_handle = ump_dd_handle_create_from_phys_blocks2(&ump_mem, 1, is_cached); + return buffer->ump_handle; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h index a6412f19673cb3..642216723df572 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.h +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h @@ -30,4 +30,5 @@ void exynos_drm_free_buf(struct drm_device *dev, unsigned int flags, struct exynos_drm_gem_buf *buffer); +ump_dd_handle exynos_drm_get_ump_handle(struct exynos_drm_gem_buf *buffer); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 3da5c2d214d887..4d1c902e10d318 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -221,6 +221,8 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = { static struct drm_ioctl_desc exynos_ioctls[] = { DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, DRM_UNLOCKED | DRM_AUTH), + DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE2, exynos_drm_gem_create2_ioctl, + DRM_UNLOCKED | DRM_AUTH), DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET, exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED | DRM_AUTH), diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index c58249e04d9a13..f65a5d9f1aec48 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -13,6 +13,7 @@ #include #include +#include #include "exynos_drm_drv.h" #include "exynos_drm_gem.h" @@ -263,6 +264,36 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, return 0; } +int exynos_drm_gem_create2_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_exynos_gem_create2 *args = data; + struct exynos_drm_gem_obj *exynos_gem_obj; + ump_dd_handle ump_handle; + int ret; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); + if (IS_ERR(exynos_gem_obj)) + return PTR_ERR(exynos_gem_obj); + + ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, + &args->handle); + if (ret) { + exynos_drm_gem_destroy(exynos_gem_obj); + return ret; + } + + ump_handle = exynos_drm_get_ump_handle(exynos_gem_obj->buffer); + if (ump_handle != UMP_DD_HANDLE_INVALID) + args->name = ump_dd_secure_id_get(ump_handle); + else + args->name = 0; + + return 0; +} + dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, unsigned int gem_handle, struct drm_file *filp) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 35ebac47dc2bac..21648a7816bd1e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -11,6 +11,7 @@ #ifndef _EXYNOS_DRM_GEM_H_ #define _EXYNOS_DRM_GEM_H_ +#include #define to_exynos_gem_obj(x) container_of(x,\ struct exynos_drm_gem_obj, base) @@ -40,6 +41,7 @@ struct exynos_drm_gem_buf { unsigned int write; struct page **pages; struct sg_table *sgt; + ump_dd_handle ump_handle; unsigned long size; bool pfnmap; }; @@ -92,6 +94,8 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, */ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int exynos_drm_gem_create2_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* * get dma address from gem handle and this function could be used for diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h index d5844122ff329d..8356c5e283bfda 100644 --- a/include/uapi/drm/exynos_drm.h +++ b/include/uapi/drm/exynos_drm.h @@ -32,6 +32,13 @@ struct drm_exynos_gem_create { unsigned int handle; }; +struct drm_exynos_gem_create2 { + uint64_t size; + unsigned int flags; + unsigned int handle; + uint32_t name; +}; + /** * A structure for getting buffer offset. * @@ -321,6 +328,7 @@ struct drm_exynos_ipp_cmd_ctrl { /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ #define DRM_EXYNOS_GEM_GET 0x04 #define DRM_EXYNOS_VIDI_CONNECTION 0x07 +#define DRM_EXYNOS_GEM_CREATE2 0x0a /* G2D */ #define DRM_EXYNOS_G2D_GET_VER 0x20 @@ -336,6 +344,9 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) +#define DRM_IOCTL_EXYNOS_GEM_CREATE2 DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_CREATE2, struct drm_exynos_gem_create2) + #define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off) From 90566156e37bacf0dac1ede9f8a80d58ffd1e246 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 8 Oct 2012 14:50:44 -0500 Subject: [PATCH 03/15] drm/exynos: page flip fixes The event wouldn't be on any list at this point, so nothing to delete it from. Signed-off-by: Rob Clark Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1847f1d9b3fb46..09434e17db3037 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -226,7 +226,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); - list_del(&event->base.link); goto out; } From 453b4145355a2ab999e62178982c361b14522a44 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 22 May 2013 11:48:40 +0900 Subject: [PATCH 04/15] drm/exynos: use drm_send_vblank_event() helper Rebased. Signed-off-by: Rob Clark Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 09434e17db3037..c200e4d71e3d96 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -409,7 +409,6 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) { struct exynos_drm_private *dev_priv = dev->dev_private; struct drm_pending_vblank_event *e, *t; - struct timeval now; struct drm_crtc *drm_crtc = dev_priv->crtc[crtc]; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); unsigned long flags; @@ -424,13 +423,8 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) if (crtc != e->pipe) continue; - do_gettimeofday(&now); - e->event.sequence = 0; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); + list_del(&e->base.link); + drm_send_vblank_event(dev, -1, e); drm_vblank_put(dev, crtc); atomic_set(&exynos_crtc->pending_flip, 0); wake_up(&exynos_crtc->pending_flip_queue); From d96c8274d5ace19125791898693114d048dda154 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 26 Feb 2014 14:22:53 -0600 Subject: [PATCH 05/15] drm/exynos: accept flip requests when the crtc is off Previously, we were rejecting flip requests when off. But Mali does not like being told 'no' for an answer, and ignores it. So let's honour these requests as if the display were powered up. --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index c200e4d71e3d96..26117c7a9463c4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -208,10 +208,17 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, DRM_DEBUG_KMS("%s\n", __FILE__); - /* when the page flip is requested, crtc's dpms should be on */ + /* if the CRTC is off, just save the new framebuffer address for use if + * we get turned on again later, and report to userspace that the flip + * completed. */ if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { - DRM_ERROR("failed page flip request.\n"); - return -EINVAL; + crtc->fb = fb; + if (event) { + spin_lock_irq(&dev->event_lock); + drm_send_vblank_event(dev, -1, event); + spin_unlock_irq(&dev->event_lock); + } + return 0; } mutex_lock(&dev->struct_mutex); From 266d26a871ead13e1af0b26a01fdc620af7aca0e Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 27 Feb 2014 13:00:04 -0600 Subject: [PATCH 06/15] drm/exynos: disable 800x600 for odroid Can't figure out how to make this resolution be displayed acceptably. --- drivers/gpu/drm/exynos/exynos_hdmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 2e7ac427c52408..529e566834556f 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1050,6 +1050,11 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing) (check_timing->vmode & FB_VMODE_INTERLACED) ? true : false); + /* 800x600 is displayed badly like 1024x768, but I can't find a timing + * hack to make it look OK. */ + if (check_timing->xres == 800 && check_timing->yres == 600) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) if (hdmiphy_v14_configs[i].pixel_clock == check_timing->pixclock) From 10d08bec3e150cd424f797d2bc8b110a810b29b7 Mon Sep 17 00:00:00 2001 From: poul Date: Fri, 13 Dec 2013 11:02:06 +0100 Subject: [PATCH 07/15] mm: Don't put CMA Pages on per-cpu lists Author: Laura Abbottt - lauraa@codeaurora.org When freeing zero order pages, CMA pages are treated the same as regular movable pages. This means CMA pages are likely to be allocated for something other than contiguous memory. This patch frees CMA pages directly. http://lists.linaro.org/pipermail/linaro-mm-sig/2012-June/002093.html Change-Id: I07b285121a7d4110a4e7fda1509e037e19607ea9 --- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9c7ab13252b694..1daef00a9ae2f9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1325,7 +1325,7 @@ void free_hot_cold_page(struct page *page, int cold) * excessively into the page allocator */ if (migratetype >= MIGRATE_PCPTYPES) { - if (unlikely(migratetype == MIGRATE_ISOLATE)) { + if (unlikely(migratetype == MIGRATE_ISOLATE) || is_migrate_cma(migratetype)) { free_one_page(zone, page, 0, migratetype); goto out; } From dc5ea62a95c893abfc0b7d4b9cd59687556327dc Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 18 Mar 2014 16:48:13 -0400 Subject: [PATCH 08/15] s5p-fimc: Fix RGB32 to BGR32 as this is what the HW produces Testing showed that HW produces BGR32 rather then RGB32 as exposed in the driver. The documentation seems to state the pixels are stored in little endian order. --- drivers/media/platform/s5p-fimc/fimc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 2812c7ad38c29a..8d6ba2ffc1432d 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -56,8 +56,8 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "ARGB8888, 32 bpp", - .fourcc = V4L2_PIX_FMT_RGB32, + .name = "BGRA8888, 32 bpp", + .fourcc = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = FIMC_FMT_RGB888, .memplanes = 1, From fb1a9c153b7709b0731978e10e0817c4236f4c95 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 21 Mar 2014 17:15:17 -0400 Subject: [PATCH 09/15] s5p-fimc: Align imagesize to row size for tiled formats For tiled format, we need to allocated a multiple of the row size. A good example is for 1280x720, wich get adjusted to 1280x736. In tiles this mean Y plane is 20x23 and UV plane 20x12. Because of the rounding, the previous code would only have enough space to fit half of the last row. --- drivers/media/platform/s5p-fimc/fimc-core.c | 22 ++++++++++++--------- drivers/media/platform/s5p-fimc/fimc-m2m.c | 4 ++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 8d6ba2ffc1432d..6e3a61f7d84645 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -712,13 +712,8 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) bpl = (bpl * frame->fmt->depth[0]) / 8; pixm->plane_fmt[i].bytesperline = bpl; - if (frame->fmt->flags & FMT_FLAGS_COMPRESSED) { - pixm->plane_fmt[i].sizeimage = frame->payload[i]; - continue; - } - pixm->plane_fmt[i].sizeimage = (frame->o_width * - frame->o_height * frame->fmt->depth[i]) / 8; - } + pixm->plane_fmt[i].sizeimage = frame->payload[i]; + } return 0; } @@ -761,6 +756,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, for (i = 0; i < pix->num_planes; ++i) { struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; u32 bpl = plane_fmt->bytesperline; + u32 sizeimage; if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) bpl = pix->width; /* Planar */ @@ -773,8 +769,16 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, bytesperline = bpl; plane_fmt->bytesperline = bytesperline; - plane_fmt->sizeimage = max((pix->width * pix->height * - fmt->depth[i]) / 8, plane_fmt->sizeimage); + sizeimage = pix->width * pix->height * fmt->depth[i] / 8; + + /* Ensure full row for tiled formats */ + if (tiled_fmt(fmt)) { + /* 64 * 32 * plane_fmt->bytesperline / 64 */ + u32 row_size = plane_fmt->bytesperline * 32; + sizeimage = ALIGN(sizeimage, row_size); + } + + plane_fmt->sizeimage = max(sizeimage, plane_fmt->sizeimage); } } diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index cef068874f5960..b9b7b1faecca1a 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -389,8 +389,8 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, fimc_alpha_ctrl_update(ctx); for (i = 0; i < frame->fmt->colplanes; i++) { - frame->payload[i] = - (pix->width * pix->height * frame->fmt->depth[i]) / 8; + struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; + frame->payload[i] = plane_fmt->sizeimage; } fimc_fill_frame(frame, f); From a810b34f19bacc0b70f1f8cec8ccad646621eb58 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 21 Mar 2014 19:49:31 -0400 Subject: [PATCH 10/15] s5p-fimc: Backport bytesperline calculation fix The supported planar YUV format (YUV420P and YUV422P) has 3 planes, where the bytesperline for each should be width, widht/2, width/2. It is expected that width has been aligned to a multiple of 4 to stay word aligned. --- drivers/media/platform/s5p-fimc/fimc-core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 6e3a61f7d84645..f8da78ca665060 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -764,9 +764,16 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, if (fmt->colplanes == 1 && /* Packed */ (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) bpl = (pix->width * fmt->depth[0]) / 8; - - if (i == 0) /* Same bytesperline for each plane. */ + /* + * Currently bytesperline for each plane is same, except + * V4L2_PIX_FMT_YUV420M format. This calculation may need + * to be changed when other multi-planar formats are added + * to the fimc_formats[] array. + */ + if (i == 0) bytesperline = bpl; + else if (i == 1 && fmt->memplanes == 3) + bytesperline /= 2; plane_fmt->bytesperline = bytesperline; sizeimage = pix->width * pix->height * fmt->depth[i] / 8; From 4873f5c42462941e131e91c042ae560022864eaa Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 25 Mar 2014 11:08:19 -0400 Subject: [PATCH 11/15] s5p-fimc: Iterate for each memory plane Depth and payload is defined per memory plane. It's better to iterate using number of memory planes. this was not causing much issue since the rest of the arrays involved where intialized to zero. --- drivers/media/platform/s5p-fimc/fimc-core.c | 2 +- drivers/media/platform/s5p-fimc/fimc-m2m.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index f8da78ca665060..67e1217fa61b51 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -446,7 +446,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) struct fimc_variant *variant = ctx->fimc_dev->variant; u32 i, depth = 0; - for (i = 0; i < f->fmt->colplanes; i++) + for (i = 0; i < f->fmt->memplanes; i++) depth += f->fmt->depth[i]; f->dma_offset.y_h = f->offs_h; diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index b9b7b1faecca1a..7ab0a4c291171c 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -388,7 +388,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, /* Update RGB Alpha control state and value range */ fimc_alpha_ctrl_update(ctx); - for (i = 0; i < frame->fmt->colplanes; i++) { + for (i = 0; i < frame->fmt->memplanes; i++) { struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; frame->payload[i] = plane_fmt->sizeimage; } @@ -536,7 +536,7 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) else halign = ffs(fimc->variant->min_vsize_align) - 1; - for (i = 0; i < f->fmt->colplanes; i++) + for (i = 0; i < f->fmt->memplanes; i++) depth += f->fmt->depth[i]; v4l_bound_align_image(&cr->c.width, min_size, f->o_width, From 444ffcb3e95fc13a135ad915835908344daca264 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 25 Mar 2014 11:10:27 -0400 Subject: [PATCH 12/15] s5p-fimc: Fix YUV422P depth All YUV 422 has 16bit per pixels. --- drivers/media/platform/s5p-fimc/fimc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 67e1217fa61b51..e19153f16722ed 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -118,7 +118,7 @@ static struct fimc_fmt fimc_formats[] = { }, { .name = "YUV 4:2:2 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = { 12 }, + .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, .memplanes = 1, .colplanes = 3, From 80093c331b656daf787068716ca1e32a7ec79b88 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 25 Mar 2014 11:12:47 -0400 Subject: [PATCH 13/15] s5p-fimc: Reuse calculated sizes This formula did not take into account the required tiled alignement for NV12MT format. As this was already computed an store in payload array initially, simply reuse that value. --- drivers/media/platform/s5p-fimc/fimc-m2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 7ab0a4c291171c..a39eda38420063 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -193,7 +193,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, *num_planes = f->fmt->memplanes; for (i = 0; i < f->fmt->memplanes; i++) { - sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8; + sizes[i] = f->payload[i]; allocators[i] = ctx->fimc_dev->alloc_ctx; } return 0; From 41c370f8c9da069eb3cab4dc8dd4201f1c3ce52a Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 26 Mar 2014 18:39:52 -0400 Subject: [PATCH 14/15] s5p-fimc: Use roundup() instead of ALIGN() The size of a row is not always a power of two, so ALIGN cannot be used. --- drivers/media/platform/s5p-fimc/fimc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index e19153f16722ed..69e902a4c9f5fe 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -782,7 +782,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, if (tiled_fmt(fmt)) { /* 64 * 32 * plane_fmt->bytesperline / 64 */ u32 row_size = plane_fmt->bytesperline * 32; - sizeimage = ALIGN(sizeimage, row_size); + sizeimage = roundup(sizeimage, row_size); } plane_fmt->sizeimage = max(sizeimage, plane_fmt->sizeimage); From c5f4e52d24420cabd224d4c1dccf2d3f01648d8a Mon Sep 17 00:00:00 2001 From: John Sheu Date: Wed, 6 Feb 2013 20:03:01 -0300 Subject: [PATCH 15/15] [media] v4l2-mem2mem: drop rdy_queue on STREAMOFF When a v4l2-mem2mem context gets a STREAMOFF call on either its CAPTURE or OUTPUT queues, we should: * Drop the corresponding rdy_queue, since a subsequent STREAMON expects an empty queue. * Deschedule the context, as it now has at least one empty queue and cannot run. Signed-off-by: John Sheu Acked-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 31 +++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 438ea45d107497..ef24295230c845 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -405,10 +405,35 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - struct vb2_queue *vq; + struct v4l2_m2m_dev *m2m_dev; + struct v4l2_m2m_queue_ctx *q_ctx; + unsigned long flags_job, flags; + int ret; - vq = v4l2_m2m_get_vq(m2m_ctx, type); - return vb2_streamoff(vq, type); + q_ctx = get_queue_ctx(m2m_ctx, type); + ret = vb2_streamoff(&q_ctx->q, type); + if (ret) + return ret; + + m2m_dev = m2m_ctx->m2m_dev; + spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job); + /* We should not be scheduled anymore, since we're dropping a queue. */ + INIT_LIST_HEAD(&m2m_ctx->queue); + m2m_ctx->job_flags = 0; + + spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); + /* Drop queue, since streamoff returns device to the same state as after + * calling reqbufs. */ + INIT_LIST_HEAD(&q_ctx->rdy_queue); + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); + + if (m2m_dev->curr_ctx == m2m_ctx) { + m2m_dev->curr_ctx = NULL; + wake_up(&m2m_ctx->finished); + } + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); + + return 0; } EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);