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/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_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1847f1d9b3fb46..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); @@ -226,7 +233,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; } @@ -410,7 +416,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; @@ -425,13 +430,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); 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/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) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 2812c7ad38c29a..69e902a4c9f5fe 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, @@ -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, @@ -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; @@ -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 */ @@ -768,13 +764,28 @@ 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; - 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 = roundup(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..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; @@ -388,9 +388,9 @@ 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++) { - frame->payload[i] = - (pix->width * pix->height * frame->fmt->depth[i]) / 8; + 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; } fimc_fill_frame(frame, f); @@ -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, 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); 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) 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 } 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; }