From 90844f00049e9f42573fd31d7c32e8fd31d3fd07 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Mon, 15 Aug 2016 01:02:38 +0100 Subject: [PATCH 01/46] drm: make drm_get_format_name thread-safe Signed-off-by: Eric Engestrom [danvet: Clarify that the returned pointer must be freed with kfree().] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 6 ++- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 6 ++- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 6 ++- drivers/gpu/drm/drm_atomic.c | 5 ++- drivers/gpu/drm/drm_crtc.c | 21 ++++++---- drivers/gpu/drm/drm_fourcc.c | 17 ++++---- .../gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 6 ++- drivers/gpu/drm/i915/i915_debugfs.c | 11 +++++- drivers/gpu/drm/i915/intel_atomic_plane.c | 6 ++- drivers/gpu/drm/i915/intel_display.c | 39 ++++++++++++------- drivers/gpu/drm/radeon/atombios_crtc.c | 12 ++++-- include/drm/drm_fourcc.h | 2 +- 12 files changed, 89 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index c1b04e9aab57..0bf895920fbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2071,6 +2071,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; + const char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2182,8 +2183,9 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + format_name = drm_get_format_name(target_fb->pixel_format); + DRM_ERROR("Unsupported screen format %s\n", format_name); + kfree(format_name); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index d4bf133908b1..1558a974ad00 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2046,6 +2046,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; + const char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2157,8 +2158,9 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + format_name = drm_get_format_name(target_fb->pixel_format); + DRM_ERROR("Unsupported screen format %s\n", format_name); + kfree(format_name); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 4fdfab1e9200..71a037546dae 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1952,6 +1952,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; + const char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2056,8 +2057,9 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + format_name = drm_get_format_name(target_fb->pixel_format); + DRM_ERROR("Unsupported screen format %s\n", format_name); + kfree(format_name); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index fa3930757972..087391f08a69 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -837,8 +837,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format); if (ret) { - DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", - drm_get_format_name(state->fb->pixel_format)); + const char *format_name = drm_get_format_name(state->fb->pixel_format); + DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", format_name); + kfree(format_name); return ret; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e92bb9d3f90f..f4e3ebebe79a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2592,8 +2592,9 @@ static int __setplane_internal(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, fb->pixel_format); if (ret) { - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(fb->pixel_format)); + const char *format_name = drm_get_format_name(fb->pixel_format); + DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); + kfree(format_name); goto out; } @@ -2902,8 +2903,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = drm_plane_check_pixel_format(crtc->primary, fb->pixel_format); if (ret) { - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(fb->pixel_format)); + const char *format_name = drm_get_format_name(fb->pixel_format); + DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); + kfree(format_name); goto out; } } @@ -3279,6 +3281,7 @@ int drm_mode_addfb(struct drm_device *dev, static int format_check(const struct drm_mode_fb_cmd2 *r) { uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; + const char *format_name; switch (format) { case DRM_FORMAT_C8: @@ -3343,8 +3346,9 @@ static int format_check(const struct drm_mode_fb_cmd2 *r) case DRM_FORMAT_YVU444: return 0; default: - DRM_DEBUG_KMS("invalid pixel format %s\n", - drm_get_format_name(r->pixel_format)); + format_name = drm_get_format_name(r->pixel_format); + DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); + kfree(format_name); return -EINVAL; } } @@ -3355,8 +3359,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) ret = format_check(r); if (ret) { - DRM_DEBUG_KMS("bad framebuffer format %s\n", - drm_get_format_name(r->pixel_format)); + const char *format_name = drm_get_format_name(r->pixel_format); + DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); + kfree(format_name); return ret; } diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 0645c85d5f95..d8f65c4fadf7 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -39,16 +39,14 @@ static char printable_char(int c) * drm_get_format_name - return a string for drm fourcc format * @format: format to compute name of * - * Note that the buffer used by this function is globally shared and owned by - * the function itself. - * - * FIXME: This isn't really multithreading safe. + * Note that the buffer returned by this function is owned by the caller + * and will need to be freed using kfree(). */ const char *drm_get_format_name(uint32_t format) { - static char buf[32]; + char *buf = kmalloc(32, GFP_KERNEL); - snprintf(buf, sizeof(buf), + snprintf(buf, 32, "%c%c%c%c %s-endian (0x%08x)", printable_char(format & 0xff), printable_char((format >> 8) & 0xff), @@ -73,6 +71,8 @@ EXPORT_SYMBOL(drm_get_format_name); void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { + const char *format_name; + switch (format) { case DRM_FORMAT_C8: case DRM_FORMAT_RGB332: @@ -127,8 +127,9 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, *bpp = 32; break; default: - DRM_DEBUG_KMS("unsupported pixel format %s\n", - drm_get_format_name(format)); + format_name = drm_get_format_name(format); + DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name); + kfree(format_name); *depth = 0; *bpp = 0; break; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index c3707d47cd89..ac7fa02b341f 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -608,15 +608,17 @@ static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); + const char *format_name; u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; u32 stride = fb->pitches[0]; u32 addr = (u32)obj->paddr + y * stride; DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n", ch + 1, y, in_h, stride, (u32)obj->paddr); + format_name = drm_get_format_name(fb->pixel_format); DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n", - addr, fb->width, fb->height, fmt, - drm_get_format_name(fb->pixel_format)); + addr, fb->width, fb->height, fmt, format_name); + kfree(format_name); /* get reg offset */ reg_ctrl = RD_CH_CTRL(ch); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f62285c1ed7f..120869e7622d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3113,6 +3113,7 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { struct drm_plane_state *state; struct drm_plane *plane = &intel_plane->base; + const char *format_name; if (!plane->state) { seq_puts(m, "plane->state is NULL!\n"); @@ -3121,6 +3122,12 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) state = plane->state; + if (state->fb) { + format_name = drm_get_format_name(state->fb->pixel_format); + } else { + format_name = kstrdup("N/A", GFP_KERNEL); + } + seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n", plane->base.id, plane_type(intel_plane->base.type), @@ -3134,8 +3141,10 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) ((state->src_w & 0xffff) * 15625) >> 10, (state->src_h >> 16), ((state->src_h & 0xffff) * 15625) >> 10, - state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A", + format_name, plane_rotation(state->rotation)); + + kfree(format_name); } } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index e06d1f5334cf..98288d87c2ce 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -143,6 +143,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, crtc_state->base.enable ? crtc_state->pipe_src_h : 0; if (state->fb && intel_rotation_90_or_270(state->rotation)) { + const char *format_name; if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); @@ -157,8 +158,9 @@ static int intel_plane_atomic_check(struct drm_plane *plane, switch (state->fb->pixel_format) { case DRM_FORMAT_C8: case DRM_FORMAT_RGB565: - DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", - drm_get_format_name(state->fb->pixel_format)); + format_name = drm_get_format_name(state->fb->pixel_format); + DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", format_name); + kfree(format_name); return -EINVAL; default: diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c6f27ab99e8f..acc1ba36c5fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12258,6 +12258,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("planes on this crtc\n"); list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + const char *format_name; intel_plane = to_intel_plane(plane); if (intel_plane->pipe != crtc->pipe) continue; @@ -12270,11 +12271,12 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, continue; } + format_name = drm_get_format_name(fb->pixel_format); + DRM_DEBUG_KMS("[PLANE:%d:%s] enabled", plane->base.id, plane->name); DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = %s", - fb->base.id, fb->width, fb->height, - drm_get_format_name(fb->pixel_format)); + fb->base.id, fb->width, fb->height, format_name); DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n", state->scaler_id, state->base.src.x1 >> 16, @@ -12284,6 +12286,8 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, state->base.dst.x1, state->base.dst.y1, drm_rect_width(&state->base.dst), drm_rect_height(&state->base.dst)); + + kfree(format_name); } } @@ -14911,6 +14915,7 @@ static int intel_framebuffer_init(struct drm_device *dev, unsigned int aligned_height; int ret; u32 pitch_limit, stride_alignment; + const char *format_name; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -14985,16 +14990,18 @@ static int intel_framebuffer_init(struct drm_device *dev, break; case DRM_FORMAT_XRGB1555: if (INTEL_INFO(dev)->gen > 3) { - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } break; case DRM_FORMAT_ABGR8888: if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && INTEL_INFO(dev)->gen < 9) { - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } break; @@ -15002,15 +15009,17 @@ static int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_XBGR2101010: if (INTEL_INFO(dev)->gen < 4) { - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } break; case DRM_FORMAT_ABGR2101010: if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } break; @@ -15019,14 +15028,16 @@ static int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_YVYU: case DRM_FORMAT_VYUY: if (INTEL_INFO(dev)->gen < 5) { - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } break; default: - DRM_DEBUG("unsupported pixel format: %s\n", - drm_get_format_name(mode_cmd->pixel_format)); + format_name = drm_get_format_name(mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", format_name); + kfree(format_name); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a97abc8af657..981ca3f5842e 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1154,6 +1154,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; + const char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1257,8 +1258,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + format_name = drm_get_format_name(target_fb->pixel_format); + DRM_ERROR("Unsupported screen format %s\n", format_name); + kfree(format_name); return -EINVAL; } @@ -1469,6 +1471,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; + const char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1558,8 +1561,9 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + format_name = drm_get_format_name(target_fb->pixel_format); + DRM_ERROR("Unsupported screen format %s\n", format_name); + kfree(format_name); return -EINVAL; } diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 7f90a396cf2b..030d22d3ed96 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -32,6 +32,6 @@ int drm_format_horz_chroma_subsampling(uint32_t format); int drm_format_vert_chroma_subsampling(uint32_t format); int drm_format_plane_width(int width, uint32_t format, int plane); int drm_format_plane_height(int height, uint32_t format, int plane); -const char *drm_get_format_name(uint32_t format); +const char *drm_get_format_name(uint32_t format) __malloc; #endif /* __DRM_FOURCC_H__ */ From ae4e46b14bd7a12fb7908425846be7ceb0853bbc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Aug 2016 16:42:18 +0100 Subject: [PATCH 02/46] dma-buf: Wait on the reservation object when sync'ing before CPU access Rendering operations to the dma-buf are tracked implicitly via the reservation_object (dmabuf->resv). This is used to allow poll() to wait upon outstanding rendering (or just query the current status of rendering). The dma-buf sync ioctl allows userspace to prepare the dma-buf for CPU access, which should include waiting upon rendering. (Some drivers may need to do more work to ensure that the dma-buf mmap is coherent as well as complete.) v2: Always wait upon the reservation object implicitly. We choose to do it after the native handler in case it can do so more efficiently. Testcase: igt/prime_vgem Testcase: igt/gem_concurrent_blit # *vgem* Signed-off-by: Chris Wilson Cc: Sumit Semwal Cc: Daniel Vetter Cc: Eric Anholt Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/1471275738-31994-1-git-send-email-chris@chris-wilson.co.uk --- drivers/dma-buf/dma-buf.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index ddaee60ae52a..cf04d249a6a4 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -586,6 +586,22 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, } EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); +static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + bool write = (direction == DMA_BIDIRECTIONAL || + direction == DMA_TO_DEVICE); + struct reservation_object *resv = dmabuf->resv; + long ret; + + /* Wait on any implicit rendering fences */ + ret = reservation_object_wait_timeout_rcu(resv, write, true, + MAX_SCHEDULE_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} /** * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the @@ -608,6 +624,13 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, if (dmabuf->ops->begin_cpu_access) ret = dmabuf->ops->begin_cpu_access(dmabuf, direction); + /* Ensure that all fences are waited upon - but we first allow + * the native handler the chance to do so more efficiently if it + * chooses. A double invocation here will be reasonably cheap no-op. + */ + if (ret == 0) + ret = __dma_buf_begin_cpu_access(dmabuf, direction); + return ret; } EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access); From b0f566838cfe086a96bffd9c67dd8844a41870ea Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 15 Aug 2016 15:03:51 +0000 Subject: [PATCH 03/46] drm/mgag200: fix error return code in mgag200fb_create() Fix to return error code -ENOMEM from the vmalloc() error handling case instead of 0, as done elsewhere in this function. Fixes: aec9e12953e7 ("drm/mgag200: Fix error handling paths in fbdev driver") Signed-off-by: Wei Yongjun Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471273431-6753-1-git-send-email-weiyj.lk@gmail.com --- drivers/gpu/drm/mgag200/mgag200_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 81325f64134f..88dd2214114d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -183,8 +183,10 @@ static int mgag200fb_create(struct drm_fb_helper *helper, } sysram = vmalloc(size); - if (!sysram) + if (!sysram) { + ret = -ENOMEM; goto err_sysram; + } info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { From d3828147079551189e1350c6676cd961de904cf2 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Mon, 15 Aug 2016 16:29:55 +0100 Subject: [PATCH 04/46] drm: remove `const` attribute to hint at caller that they now own the memory Signed-off-by: Eric Engestrom Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 +- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_crtc.c | 8 ++++---- drivers/gpu/drm/drm_fourcc.c | 4 ++-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 2 +- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/intel_atomic_plane.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/radeon/atombios_crtc.c | 4 ++-- include/drm/drm_fourcc.h | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 0bf895920fbc..741da36cd8b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2071,7 +2071,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - const char *format_name; + char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 1558a974ad00..2282eb60aba6 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2046,7 +2046,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - const char *format_name; + char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 71a037546dae..8b7ad345771f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1952,7 +1952,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; - const char *format_name; + char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 087391f08a69..5cb2e22d5d55 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -837,7 +837,7 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format); if (ret) { - const char *format_name = drm_get_format_name(state->fb->pixel_format); + char *format_name = drm_get_format_name(state->fb->pixel_format); DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", format_name); kfree(format_name); return ret; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f4e3ebebe79a..93ea5ddd1e49 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2592,7 +2592,7 @@ static int __setplane_internal(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, fb->pixel_format); if (ret) { - const char *format_name = drm_get_format_name(fb->pixel_format); + char *format_name = drm_get_format_name(fb->pixel_format); DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); kfree(format_name); goto out; @@ -2903,7 +2903,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = drm_plane_check_pixel_format(crtc->primary, fb->pixel_format); if (ret) { - const char *format_name = drm_get_format_name(fb->pixel_format); + char *format_name = drm_get_format_name(fb->pixel_format); DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); kfree(format_name); goto out; @@ -3281,7 +3281,7 @@ int drm_mode_addfb(struct drm_device *dev, static int format_check(const struct drm_mode_fb_cmd2 *r) { uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; - const char *format_name; + char *format_name; switch (format) { case DRM_FORMAT_C8: @@ -3359,7 +3359,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) ret = format_check(r); if (ret) { - const char *format_name = drm_get_format_name(r->pixel_format); + char *format_name = drm_get_format_name(r->pixel_format); DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); kfree(format_name); return ret; diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index d8f65c4fadf7..c81546c15c93 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -42,7 +42,7 @@ static char printable_char(int c) * Note that the buffer returned by this function is owned by the caller * and will need to be freed using kfree(). */ -const char *drm_get_format_name(uint32_t format) +char *drm_get_format_name(uint32_t format) { char *buf = kmalloc(32, GFP_KERNEL); @@ -71,7 +71,7 @@ EXPORT_SYMBOL(drm_get_format_name); void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { - const char *format_name; + char *format_name; switch (format) { case DRM_FORMAT_C8: diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index ac7fa02b341f..eaa3df75fc5c 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -608,7 +608,7 @@ static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); - const char *format_name; + char *format_name; u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; u32 stride = fb->pitches[0]; u32 addr = (u32)obj->paddr + y * stride; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 120869e7622d..64e41cf74d11 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3113,7 +3113,7 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { struct drm_plane_state *state; struct drm_plane *plane = &intel_plane->base; - const char *format_name; + char *format_name; if (!plane->state) { seq_puts(m, "plane->state is NULL!\n"); diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 98288d87c2ce..b82de3072d4f 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -143,7 +143,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, crtc_state->base.enable ? crtc_state->pipe_src_h : 0; if (state->fb && intel_rotation_90_or_270(state->rotation)) { - const char *format_name; + char *format_name; if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index acc1ba36c5fa..3902e57d9df5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12258,7 +12258,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("planes on this crtc\n"); list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - const char *format_name; + char *format_name; intel_plane = to_intel_plane(plane); if (intel_plane->pipe != crtc->pipe) continue; @@ -14915,7 +14915,7 @@ static int intel_framebuffer_init(struct drm_device *dev, unsigned int aligned_height; int ret; u32 pitch_limit, stride_alignment; - const char *format_name; + char *format_name; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 981ca3f5842e..a89c4803aced 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1154,7 +1154,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - const char *format_name; + char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1471,7 +1471,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; - const char *format_name; + char *format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 030d22d3ed96..b106337de1bf 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -32,6 +32,6 @@ int drm_format_horz_chroma_subsampling(uint32_t format); int drm_format_vert_chroma_subsampling(uint32_t format); int drm_format_plane_width(int width, uint32_t format, int plane); int drm_format_plane_height(int height, uint32_t format, int plane); -const char *drm_get_format_name(uint32_t format) __malloc; +char *drm_get_format_name(uint32_t format) __malloc; #endif /* __DRM_FOURCC_H__ */ From e1f96ef46caf8ed0bf06a694bef98bc31444415f Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 16 Aug 2016 15:06:08 +0800 Subject: [PATCH 05/46] drm: drop DRIVER_HAVE_IRQ flag for some drivers Since commit 4984979b9b90 ("drm/irq: simplify irq checks in drm_wait_vblank"), the drm driver feature flag DRIVER_HAVE_IRQ is only required for drivers that have an IRQ handler managed by the DRM core. Some drivers, armada, etnaviv, kirin and sti, set this flag without .irq_handler setup in drm_driver. These drivers manage IRQ handler by themselves and the flag DRIVER_HAVE_IRQ makes no sense there. Drop the flag for these drivers to avoid confusion. Signed-off-by: Shawn Guo Cc: Vincent Abriou Cc: Xinliang Liu Acked-by: Russell King (for armada and etnaviv) Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471331168-5601-1-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/armada/armada_drv.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 3 +-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 2 +- drivers/gpu/drm/sti/sti_drv.c | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index f5ebdd681445..1e0e68f608e4 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -211,7 +211,7 @@ static struct drm_driver armada_drm_driver = { .desc = "Armada SoC DRM", .date = "20120730", .driver_features = DRIVER_GEM | DRIVER_MODESET | - DRIVER_HAVE_IRQ | DRIVER_PRIME, + DRIVER_PRIME, .ioctls = armada_ioctls, .fops = &armada_drm_fops, }; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index ffd1b32caa8d..fd0ed61565f3 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -488,8 +488,7 @@ static const struct file_operations fops = { }; static struct drm_driver etnaviv_drm_driver = { - .driver_features = DRIVER_HAVE_IRQ | - DRIVER_GEM | + .driver_features = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, .open = etnaviv_open, diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 1edd9bc80294..1fc2f502d20d 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -169,7 +169,7 @@ static int kirin_gem_cma_dumb_create(struct drm_file *file, static struct drm_driver kirin_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC | DRIVER_HAVE_IRQ, + DRIVER_ATOMIC, .fops = &kirin_drm_fops, .gem_free_object_unlocked = drm_gem_cma_free_object, diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 96bd3d08b2d4..f8311b2bc84e 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -282,7 +282,7 @@ static const struct file_operations sti_driver_fops = { }; static struct drm_driver sti_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, From 62cacc79398383d3ff47011557c77e71369126ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:37 +0200 Subject: [PATCH 06/46] drm/doc: Fix more kerneldoc/sphinx warnings These are the leftovers I could only track down using keep_warnings = True. For some of them we might want to update our style guide on how to reference structures and constants, not sure ... Cc: Markus Heiser Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-1-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 4 +-- drivers/gpu/drm/drm_fb_helper.c | 2 +- drivers/gpu/drm/drm_irq.c | 8 ++--- drivers/gpu/drm/drm_simple_kms_helper.c | 2 +- drivers/gpu/drm/i915/i915_vgpu.c | 42 ++++++++++++------------- drivers/gpu/drm/i915/intel_audio.c | 6 ++-- drivers/gpu/drm/i915/intel_guc_fwif.h | 5 +-- include/drm/drm_crtc.h | 8 ++--- include/drm/drm_gem.h | 4 +-- 9 files changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 93ea5ddd1e49..fd9dcecb3eb5 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1266,7 +1266,7 @@ static unsigned int drm_num_planes(struct drm_device *dev) * @plane: plane object to init * @possible_crtcs: bitmask of possible CRTCs * @funcs: callbacks for the new plane - * @formats: array of supported formats (%DRM_FORMAT_*) + * @formats: array of supported formats (DRM_FORMAT\_\*) * @format_count: number of elements in @formats * @type: type of plane (overlay, primary, cursor) * @name: printf style format string for the plane name, or NULL for default name @@ -1381,7 +1381,7 @@ static void drm_plane_unregister_all(struct drm_device *dev) * @plane: plane object to init * @possible_crtcs: bitmask of possible CRTCs * @funcs: callbacks for the new plane - * @formats: array of supported formats (%DRM_FORMAT_*) + * @formats: array of supported formats (DRM_FORMAT\_\*) * @format_count: number of elements in @formats * @is_primary: plane type (primary vs overlay) * diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index aed79d31930c..c0d1066ea419 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2193,7 +2193,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config); * @fb_helper: the drm_fb_helper * * Scan the connectors attached to the fb_helper and try to put together a - * setup after *notification of a change in output configuration. + * setup after notification of a change in output configuration. * * Called at runtime, takes the mode config locks to be able to check/change the * modeset configuration. Must be run from process context (which usually means diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index c0c3f2006203..404a1ce7730c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -713,10 +713,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); * Negative value on error, failure or if not supported in current * video mode: * - * -EINVAL - Invalid CRTC. - * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. - * -ENOTSUPP - Function not supported in current display mode. - * -EIO - Failed, e.g., due to failed scanout position query. + * -EINVAL Invalid CRTC. + * -EAGAIN Temporary unavailable, e.g., called before initial modeset. + * -ENOTSUPP Function not supported in current display mode. + * -EIO Failed, e.g., due to failed scanout position query. * * Returns or'ed positive status flags on success: * diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 0a02efe978ee..bada17166512 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -137,7 +137,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { * @dev: DRM device * @pipe: simple display pipe object to initialize * @funcs: callbacks for the display pipe (optional) - * @formats: array of supported formats (%DRM_FORMAT_*) + * @formats: array of supported formats (DRM_FORMAT\_\*) * @format_count: number of elements in @formats * @connector: connector to attach and register * diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index 142bac976919..ca2e91259948 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -156,27 +156,27 @@ static int vgt_balloon_space(struct drm_mm *mm, * host point of view, the graphic address space is partitioned by multiple * vGPUs in different VMs. :: * - * vGPU1 view Host view - * 0 ------> +-----------+ +-----------+ - * ^ |###########| | vGPU3 | - * | |###########| +-----------+ - * | |###########| | vGPU2 | - * | +-----------+ +-----------+ - * mappable GM | available | ==> | vGPU1 | - * | +-----------+ +-----------+ - * | |###########| | | - * v |###########| | Host | - * +=======+===========+ +===========+ - * ^ |###########| | vGPU3 | - * | |###########| +-----------+ - * | |###########| | vGPU2 | - * | +-----------+ +-----------+ - * unmappable GM | available | ==> | vGPU1 | - * | +-----------+ +-----------+ - * | |###########| | | - * | |###########| | Host | - * v |###########| | | - * total GM size ------> +-----------+ +-----------+ + * vGPU1 view Host view + * 0 ------> +-----------+ +-----------+ + * ^ |###########| | vGPU3 | + * | |###########| +-----------+ + * | |###########| | vGPU2 | + * | +-----------+ +-----------+ + * mappable GM | available | ==> | vGPU1 | + * | +-----------+ +-----------+ + * | |###########| | | + * v |###########| | Host | + * +=======+===========+ +===========+ + * ^ |###########| | vGPU3 | + * | |###########| +-----------+ + * | |###########| | vGPU2 | + * | +-----------+ +-----------+ + * unmappable GM | available | ==> | vGPU1 | + * | +-----------+ +-----------+ + * | |###########| | | + * | |###########| | Host | + * v |###########| | | + * total GM size ------> +-----------+ +-----------+ * * Returns: * zero on success, non-zero if configuration invalid or ballooning failed diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index d32f586f9c05..85389cdd0bec 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -51,10 +51,10 @@ * related registers. (The notable exception is the power management, not * covered here.) * - * The struct i915_audio_component is used to interact between the graphics - * and audio drivers. The struct i915_audio_component_ops *ops in it is + * The struct &i915_audio_component is used to interact between the graphics + * and audio drivers. The struct &i915_audio_component_ops @ops in it is * defined in graphics driver and called in audio driver. The - * struct i915_audio_component_audio_ops *audio_ops is called from i915 driver. + * struct &i915_audio_component_audio_ops @audio_ops is called from i915 driver. */ static const struct { diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 944786d7075b..e40db2d2ae99 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -155,6 +155,7 @@ * * +-------------------------------+ * | guc_css_header | + * | | * | contains major/minor version | * +-------------------------------+ * | uCode | @@ -176,10 +177,10 @@ * * 1. Header, uCode and RSA are must-have components. * 2. All firmware components, if they present, are in the sequence illustrated - * in the layout table above. + * in the layout table above. * 3. Length info of each component can be found in header, in dwords. * 4. Modulus and exponent key are not required by driver. They may not appear - * in fw. So driver will load a truncated firmware in this case. + * in fw. So driver will load a truncated firmware in this case. */ struct guc_css_header { diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b618b506b04d..194eebb2f9d7 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1197,7 +1197,7 @@ struct drm_encoder_funcs { * @head: list management * @base: base KMS object * @name: human readable name, can be overwritten by the driver - * @encoder_type: one of the %DRM_MODE_ENCODER_ types in drm_mode.h + * @encoder_type: one of the DRM_MODE_ENCODER_ types in drm_mode.h * @possible_crtcs: bitmask of potential CRTC bindings * @possible_clones: bitmask of potential sibling encoders for cloning * @crtc: currently bound CRTC @@ -1250,7 +1250,7 @@ struct drm_encoder { * @head: list management * @base: base KMS object * @name: human readable name, can be overwritten by the driver - * @connector_type: one of the %DRM_MODE_CONNECTOR_ types from drm_mode.h + * @connector_type: one of the DRM_MODE_CONNECTOR_ types from drm_mode.h * @connector_type_id: index into connector type enum * @interlace_allowed: can this connector handle interlaced modes? * @doublescan_allowed: can this connector handle doublescan? @@ -1263,11 +1263,11 @@ struct drm_encoder { * @funcs: connector control functions * @edid_blob_ptr: DRM property containing EDID if present * @properties: property tracking for this connector - * @polled: a %DRM_CONNECTOR_POLL_ value for core driven polling + * @polled: a DRM_CONNECTOR_POLL_ value for core driven polling * @dpms: current dpms state * @helper_private: mid-layer private data * @cmdline_mode: mode line parsed from the kernel cmdline for this connector - * @force: a %DRM_FORCE_ state for forced mode sets + * @force: a DRM_FORCE_ state for forced mode sets * @override_edid: has the EDID been overwritten through debugfs for testing? * @encoder_ids: valid encoders for this connector * @encoder: encoder driving this connector, if any diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index fca1cd1b9c26..9f63736e6163 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -210,8 +210,8 @@ drm_gem_object_reference(struct drm_gem_object *obj) * drm_gem_object_unreference_unlocked(). * * Drivers should never call this directly in their code. Instead they should - * wrap it up into a driver_gem_object_unreference(struct driver_gem_object - * *obj) wrapper function, and use that. Shared code should never call this, to + * wrap it up into a ``driver_gem_object_unreference(struct driver_gem_object + * *obj)`` wrapper function, and use that. Shared code should never call this, to * avoid breaking drivers by accident which still depend upon dev->struct_mutex * locking. */ From bcb32b691c639f38575d7b7f1be53de0a468d6e8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:38 +0200 Subject: [PATCH 07/46] drm/doc: Light drm-kms-helper.rst cleanup - Move the common vtable stuff to the top - Move "Tile Group" to a more appropriate heading level - Throw away the old intro for the crtc helpers (it's entirely stale, e.g. helpers have become modular years ago), and replace it with a general intro about the motivation behind helpers. - Reorder helpers to group them together a bit better, and explain that grouping in the intro. - Make sure the introductory DOC section is always first. v2: - Remove bogus files accidentally added (Sean). - Spelling fixes (Sean). Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-2-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 212 +++++++++++++------------- Documentation/gpu/drm-uapi.rst | 3 + 2 files changed, 109 insertions(+), 106 deletions(-) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 0b302fedf1af..34f755bc9133 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -2,38 +2,45 @@ Mode Setting Helper Functions ============================= -The plane, CRTC, encoder and connector functions provided by the drivers -implement the DRM API. They're called by the DRM core and ioctl handlers -to handle device state changes and configuration request. As -implementing those functions often requires logic not specific to -drivers, mid-layer helper functions are available to avoid duplicating -boilerplate code. +The DRM subsystem aims for a strong separation between core code and helper +libraries. Core code takes care of general setup and teardown and decoding +userspace requests to kernel internal objects. Everything else is handled by a +large set of helper libraries, which can be combined freely to pick and choose +for each driver what fits, and avoid shared code where special behaviour is +needed. -The DRM core contains one mid-layer implementation. The mid-layer -provides implementations of several plane, CRTC, encoder and connector -functions (called from the top of the mid-layer) that pre-process -requests and call lower-level functions provided by the driver (at the -bottom of the mid-layer). For instance, the -:c:func:`drm_crtc_helper_set_config()` function can be used to -fill the :c:type:`struct drm_crtc_funcs ` -set_config field. When called, it will split the set_config operation -in smaller, simpler operations and call the driver to handle them. +This distinction between core code and helpers is especially strong in the +modesetting code, where there's a shared userspace ABI for all drivers. This is +in contrast to the render side, where pretty much everything (with very few +exceptions) can be considered optional helper code. -To use the mid-layer, drivers call -:c:func:`drm_crtc_helper_add()`, -:c:func:`drm_encoder_helper_add()` and -:c:func:`drm_connector_helper_add()` functions to install their -mid-layer bottom operations handlers, and fill the :c:type:`struct -drm_crtc_funcs `, :c:type:`struct -drm_encoder_funcs ` and :c:type:`struct -drm_connector_funcs ` structures with -pointers to the mid-layer top API functions. Installing the mid-layer -bottom operation handlers is best done right after registering the -corresponding KMS object. +There are a few areas these helpers can grouped into: -The mid-layer is not split between CRTC, encoder and connector -operations. To use it, a driver must provide bottom functions for all of -the three KMS entities. +* Helpers to implement modesetting. The important ones here are the atomic + helpers. Old drivers still often use the legacy CRTC helpers. They both share + the same set of common helper vtables. For really simple drivers (anything + that would have been a great fit in the deprecated fbdev subsystem) there's + also the simple display pipe helpers. + +* There's a big pile of helpers for handling outputs. First the generic bridge + helpers for handling encoder and transcoder IP blocks. Second the panel helpers + for handling panel-related information and logic. Plus then a big set of + helpers for the various sink standards (DisplayPort, HDMI, MIPI DSI). Finally + there's also generic helpers for handling output probing, and for dealing with + EDIDs. + +* The last group of helpers concerns itself with the frontend side of a display + pipeline: Planes, handling rectangles for visibility checking and scissoring, + flip queues and assorted bits. + +Modeset Helper Reference for Common Vtables +=========================================== + +.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h + :internal: + +.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h + :doc: overview Atomic Modeset Helper Functions Reference ========================================= @@ -62,33 +69,27 @@ Atomic State Reset and Initialization .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c :export: -Modeset Helper Reference for Common Vtables -=========================================== - -.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h - :internal: - -.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h - :doc: overview - Legacy CRTC/Modeset Helper Functions Reference ============================================== -.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c - :export: - .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c :doc: overview -Output Probing Helper Functions Reference -========================================= - -.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c - :doc: output probing helper overview - -.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c :export: +Simple KMS Helper Reference +=========================== + +.. kernel-doc:: include/drm/drm_simple_kms_helper.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c + :export: + +.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c + :doc: overview + fbdev Helper Functions Reference ================================ @@ -110,6 +111,36 @@ Framebuffer CMA Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c :export: +Bridges +======= + +Overview +-------- + +.. kernel-doc:: drivers/gpu/drm/drm_bridge.c + :doc: overview + +Default bridge callback sequence +-------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_bridge.c + :doc: bridge callbacks + +.. kernel-doc:: drivers/gpu/drm/drm_bridge.c + :export: + +Panel Helper Reference +====================== + +.. kernel-doc:: include/drm/drm_panel.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_panel.c + :export: + +.. kernel-doc:: drivers/gpu/drm/drm_panel.c + :doc: drm panel + Display Port Helper Functions Reference ======================================= @@ -158,6 +189,15 @@ MIPI DSI Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_mipi_dsi.c :export: +Output Probing Helper Functions Reference +========================================= + +.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c + :doc: output probing helper overview + +.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c + :export: + EDID Helper Functions Reference =============================== @@ -176,18 +216,6 @@ Rectangle Utilities Reference .. kernel-doc:: drivers/gpu/drm/drm_rect.c :export: -Flip-work Helper Reference -========================== - -.. kernel-doc:: include/drm/drm_flip_work.h - :doc: flip utils - -.. kernel-doc:: include/drm/drm_flip_work.h - :internal: - -.. kernel-doc:: drivers/gpu/drm/drm_flip_work.c - :export: - HDMI Infoframes Helper Reference ================================ @@ -202,59 +230,31 @@ libraries and hence is also included here. .. kernel-doc:: drivers/video/hdmi.c :export: +Flip-work Helper Reference +========================== + +.. kernel-doc:: include/drm/drm_flip_work.h + :doc: flip utils + +.. kernel-doc:: include/drm/drm_flip_work.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_flip_work.c + :export: + Plane Helper Reference ====================== -.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c - :export: - .. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c :doc: overview +.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c + :export: + Tile group ----------- +========== + +# FIXME: This should probably be moved into a property documentation section .. kernel-doc:: drivers/gpu/drm/drm_crtc.c :doc: Tile group - -Bridges -======= - -Overview --------- - -.. kernel-doc:: drivers/gpu/drm/drm_bridge.c - :doc: overview - -Default bridge callback sequence --------------------------------- - -.. kernel-doc:: drivers/gpu/drm/drm_bridge.c - :doc: bridge callbacks - -.. kernel-doc:: drivers/gpu/drm/drm_bridge.c - :export: - -Panel Helper Reference -====================== - -.. kernel-doc:: include/drm/drm_panel.h - :internal: - -.. kernel-doc:: drivers/gpu/drm/drm_panel.c - :export: - -.. kernel-doc:: drivers/gpu/drm/drm_panel.c - :doc: drm panel - -Simple KMS Helper Reference -=========================== - -.. kernel-doc:: include/drm/drm_simple_kms_helper.h - :internal: - -.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c - :export: - -.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c - :doc: overview diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 536bf3eaadd4..94876938aef3 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -33,6 +33,9 @@ Primary Nodes, DRM Master and Authentication .. kernel-doc:: include/drm/drm_auth.h :internal: +Open-Source Userspace Requirements +================================== + Render nodes ============ From 1de72faf10c367d80039761dca5f761b42abca01 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:39 +0200 Subject: [PATCH 08/46] drm/kms-helpers: Extract drm_modeset_helper.[hc] While reviewing docs I spotted that we have a few functions that really just don't fit into their containing helper library section. Extract them and shovel them all into a new library for random one-off aux stuff. v2: Remove wrongly added files for real. Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-3-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 9 ++ drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_crtc_helper.c | 56 ---------- drivers/gpu/drm/drm_modeset_helper.c | 153 ++++++++++++++++++++++++++ drivers/gpu/drm/drm_plane_helper.c | 66 ----------- include/drm/drm_atomic_helper.h | 2 + include/drm/drm_crtc_helper.h | 6 +- include/drm/drm_modeset_helper.h | 36 ++++++ include/drm/drm_plane_helper.h | 4 +- 9 files changed, 203 insertions(+), 131 deletions(-) create mode 100644 drivers/gpu/drm/drm_modeset_helper.c create mode 100644 include/drm/drm_modeset_helper.h diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 34f755bc9133..59fa3c11efab 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -258,3 +258,12 @@ Tile group .. kernel-doc:: drivers/gpu/drm/drm_crtc.c :doc: Tile group + +Auxiliary Modeset Helpers +========================= + +.. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c + :doc: aux kms helpers + +.. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c + :export: diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0238bf8bc8c3..a5824d926dc9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -24,7 +24,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ - drm_simple_kms_helper.o drm_blend.o + drm_simple_kms_helper.o drm_blend.o drm_modeset_helper.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 604d3ef72ffa..5d2cb138eba6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -74,35 +74,6 @@ * &drm_connector_helper_funcs. */ -/** - * drm_helper_move_panel_connectors_to_head() - move panels to the front in the - * connector list - * @dev: drm device to operate on - * - * Some userspace presumes that the first connected connector is the main - * display, where it's supposed to display e.g. the login screen. For - * laptops, this should be the main panel. Use this function to sort all - * (eDP/LVDS) panels to the front of the connector list, instead of - * painstakingly trying to initialize them in the right order. - */ -void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) -{ - struct drm_connector *connector, *tmp; - struct list_head panel_list; - - INIT_LIST_HEAD(&panel_list); - - list_for_each_entry_safe(connector, tmp, - &dev->mode_config.connector_list, head) { - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || - connector->connector_type == DRM_MODE_CONNECTOR_eDP) - list_move_tail(&connector->head, &panel_list); - } - - list_splice(&panel_list, &dev->mode_config.connector_list); -} -EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); - /** * drm_helper_encoder_in_use - check if a given encoder is in use * @encoder: encoder to check @@ -912,33 +883,6 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode) } EXPORT_SYMBOL(drm_helper_connector_dpms); -/** - * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata - * @fb: drm_framebuffer object to fill out - * @mode_cmd: metadata from the userspace fb creation request - * - * This helper can be used in a drivers fb_create callback to pre-fill the fb's - * metadata fields. - */ -void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - int i; - - fb->width = mode_cmd->width; - fb->height = mode_cmd->height; - for (i = 0; i < 4; i++) { - fb->pitches[i] = mode_cmd->pitches[i]; - fb->offsets[i] = mode_cmd->offsets[i]; - fb->modifier[i] = mode_cmd->modifier[i]; - } - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, - &fb->bits_per_pixel); - fb->pixel_format = mode_cmd->pixel_format; - fb->flags = mode_cmd->flags; -} -EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); - /** * drm_helper_resume_force_mode - force-restore mode setting configuration * @dev: drm_device which should be restored diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c new file mode 100644 index 000000000000..1d45738f8f98 --- /dev/null +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include + +/** + * DOC: aux kms helpers + * + * This helper library contains various one-off functions which don't really fit + * anywhere else in the DRM modeset helper library. + */ + +/** + * drm_helper_move_panel_connectors_to_head() - move panels to the front in the + * connector list + * @dev: drm device to operate on + * + * Some userspace presumes that the first connected connector is the main + * display, where it's supposed to display e.g. the login screen. For + * laptops, this should be the main panel. Use this function to sort all + * (eDP/LVDS) panels to the front of the connector list, instead of + * painstakingly trying to initialize them in the right order. + */ +void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) +{ + struct drm_connector *connector, *tmp; + struct list_head panel_list; + + INIT_LIST_HEAD(&panel_list); + + list_for_each_entry_safe(connector, tmp, + &dev->mode_config.connector_list, head) { + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + list_move_tail(&connector->head, &panel_list); + } + + list_splice(&panel_list, &dev->mode_config.connector_list); +} +EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); + +/** + * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata + * @fb: drm_framebuffer object to fill out + * @mode_cmd: metadata from the userspace fb creation request + * + * This helper can be used in a drivers fb_create callback to pre-fill the fb's + * metadata fields. + */ +void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + int i; + + fb->width = mode_cmd->width; + fb->height = mode_cmd->height; + for (i = 0; i < 4; i++) { + fb->pitches[i] = mode_cmd->pitches[i]; + fb->offsets[i] = mode_cmd->offsets[i]; + fb->modifier[i] = mode_cmd->modifier[i]; + } + drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, + &fb->bits_per_pixel); + fb->pixel_format = mode_cmd->pixel_format; + fb->flags = mode_cmd->flags; +} +EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); + +/* + * This is the minimal list of formats that seem to be safe for modeset use + * with all current DRM drivers. Most hardware can actually support more + * formats than this and drivers may specify a more accurate list when + * creating the primary plane. However drivers that still call + * drm_plane_init() will use this minimal format list as the default. + */ +static const uint32_t safe_modeset_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + +static struct drm_plane *create_primary_plane(struct drm_device *dev) +{ + struct drm_plane *primary; + int ret; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (primary == NULL) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + /* + * Remove the format_default field from drm_plane when dropping + * this helper. + */ + primary->format_default = true; + + /* possible_crtc's will be filled in later by crtc_init */ + ret = drm_universal_plane_init(dev, primary, 0, + &drm_primary_helper_funcs, + safe_modeset_formats, + ARRAY_SIZE(safe_modeset_formats), + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + kfree(primary); + primary = NULL; + } + + return primary; +} + +/** + * drm_crtc_init - Legacy CRTC initialization function + * @dev: DRM device + * @crtc: CRTC object to init + * @funcs: callbacks for the new CRTC + * + * Initialize a CRTC object with a default helper-provided primary plane and no + * cursor plane. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + const struct drm_crtc_funcs *funcs) +{ + struct drm_plane *primary; + + primary = create_primary_plane(dev); + return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, + NULL); +} +EXPORT_SYMBOL(drm_crtc_init); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index b522aabd1ab0..50b9c1bfc6f6 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -63,18 +63,6 @@ * the details. */ -/* - * This is the minimal list of formats that seem to be safe for modeset use - * with all current DRM drivers. Most hardware can actually support more - * formats than this and drivers may specify a more accurate list when - * creating the primary plane. However drivers that still call - * drm_plane_init() will use this minimal format list as the default. - */ -static const uint32_t safe_modeset_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, -}; - /* * Returns the connectors currently associated with a CRTC. This function * should be called twice: once with a NULL connector list to retrieve @@ -438,60 +426,6 @@ const struct drm_plane_funcs drm_primary_helper_funcs = { }; EXPORT_SYMBOL(drm_primary_helper_funcs); -static struct drm_plane *create_primary_plane(struct drm_device *dev) -{ - struct drm_plane *primary; - int ret; - - primary = kzalloc(sizeof(*primary), GFP_KERNEL); - if (primary == NULL) { - DRM_DEBUG_KMS("Failed to allocate primary plane\n"); - return NULL; - } - - /* - * Remove the format_default field from drm_plane when dropping - * this helper. - */ - primary->format_default = true; - - /* possible_crtc's will be filled in later by crtc_init */ - ret = drm_universal_plane_init(dev, primary, 0, - &drm_primary_helper_funcs, - safe_modeset_formats, - ARRAY_SIZE(safe_modeset_formats), - DRM_PLANE_TYPE_PRIMARY, NULL); - if (ret) { - kfree(primary); - primary = NULL; - } - - return primary; -} - -/** - * drm_crtc_init - Legacy CRTC initialization function - * @dev: DRM device - * @crtc: CRTC object to init - * @funcs: callbacks for the new CRTC - * - * Initialize a CRTC object with a default helper-provided primary plane and no - * cursor plane. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, - const struct drm_crtc_funcs *funcs) -{ - struct drm_plane *primary; - - primary = create_primary_plane(dev); - return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, - NULL); -} -EXPORT_SYMBOL(drm_crtc_init); - int drm_plane_helper_commit(struct drm_plane *plane, struct drm_plane_state *plane_state, struct drm_framebuffer *old_fb) diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index d86ae5dcd7b4..5a02e499f32b 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -29,6 +29,8 @@ #define DRM_ATOMIC_HELPER_H_ #include +#include +#include struct drm_atomic_state; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 4b37afa2b73b..982c299e435a 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -41,6 +41,7 @@ #include #include +#include extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); @@ -53,11 +54,6 @@ extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); -extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); - -extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - const struct drm_mode_fb_cmd2 *mode_cmd); - extern void drm_helper_resume_force_mode(struct drm_device *dev); int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/include/drm/drm_modeset_helper.h b/include/drm/drm_modeset_helper.h new file mode 100644 index 000000000000..b8051d5abe10 --- /dev/null +++ b/include/drm/drm_modeset_helper.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_KMS_HELPER_H__ +#define __DRM_KMS_HELPER_H__ + +#include + +void drm_helper_move_panel_connectors_to_head(struct drm_device *); + +void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + const struct drm_mode_fb_cmd2 *mode_cmd); + +int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + const struct drm_crtc_funcs *funcs); + +#endif diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index fbc8ecb3e5e8..c18959685c06 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -27,6 +27,7 @@ #include #include #include +#include /* * Drivers that don't allow primary plane scaling may pass this macro in place @@ -37,9 +38,6 @@ */ #define DRM_PLANE_HELPER_NO_SCALING (1<<16) -int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, - const struct drm_crtc_funcs *funcs); - int drm_plane_helper_check_state(struct drm_plane_state *state, const struct drm_rect *clip, int min_scale, int max_scale, From 8febdf0d596729d1115beb3dc0a394263a94ffb2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:40 +0200 Subject: [PATCH 09/46] drm/doc: Reorg drm-mm.rst - Readjust headings - we lost one level through the extraction into a separate .rst file. - Merge helper reference sections with the helper documentation - that split was just an artifact of the docbook toolchain sucking at too deep nesting levels. No such problems with sphinx. - Move the cma helpers in with the gem documentation, since they're helpers to implement gem using CMA/dma memory as a backend. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-4-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-mm.rst | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 59f9822fecd0..bca808535dfd 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -26,12 +26,12 @@ TTM, but has no video RAM management capabilities and is thus limited to UMA devices. The Translation Table Manager (TTM) ------------------------------------ +=================================== TTM design background and information belongs here. TTM initialization -~~~~~~~~~~~~~~~~~~ +------------------ **Warning** @@ -77,7 +77,7 @@ object, ttm_global_item_ref() is used to create an initial reference count for the TTM, which will call your initialization function. The Graphics Execution Manager (GEM) ------------------------------------- +==================================== The GEM design approach has resulted in a memory manager that doesn't provide full coverage of all (or even all common) use cases in its @@ -114,7 +114,7 @@ read & write, mapping, and domain ownership transfers are left to driver-specific ioctls. GEM Initialization -~~~~~~~~~~~~~~~~~~ +------------------ Drivers that use GEM must set the DRIVER_GEM bit in the struct :c:type:`struct drm_driver ` driver_features @@ -132,7 +132,7 @@ typically not managed by GEM, and must be initialized separately into its own DRM MM object. GEM Objects Creation -~~~~~~~~~~~~~~~~~~~~ +-------------------- GEM splits creation of GEM objects and allocation of the memory that backs them in two distinct operations. @@ -173,7 +173,7 @@ a call to :c:func:`drm_gem_private_object_init()` instead of must be managed by drivers. GEM Objects Lifetime -~~~~~~~~~~~~~~~~~~~~ +-------------------- All GEM objects are reference-counted by the GEM core. References can be acquired and release by :c:func:`calling @@ -196,7 +196,7 @@ resources created by the GEM core, which need to be released with :c:func:`drm_gem_object_release()`. GEM Objects Naming -~~~~~~~~~~~~~~~~~~ +------------------ Communication between userspace and the kernel refers to GEM objects using local handles, global names or, more recently, file descriptors. @@ -245,7 +245,7 @@ Furthermore PRIME also allows cross-device buffer sharing since it is based on dma-bufs. GEM Objects Mapping -~~~~~~~~~~~~~~~~~~~ +------------------- Because mapping operations are fairly heavyweight GEM favours read/write-like access to buffers, implemented through driver-specific @@ -304,7 +304,7 @@ Drivers that want to map the GEM object upfront instead of handling page faults can implement their own mmap file operation handler. Memory Coherency -~~~~~~~~~~~~~~~~ +---------------- When mapped to the device or used in a command buffer, backing pages for an object are flushed to memory and marked write combined so as to be @@ -320,7 +320,7 @@ blocks the client and waits for rendering to complete before performing any necessary flushing operations). Command Execution -~~~~~~~~~~~~~~~~~ +----------------- Perhaps the most important GEM function for GPU devices is providing a command execution interface to clients. Client programs construct @@ -348,8 +348,20 @@ GEM Function Reference .. kernel-doc:: include/drm/drm_gem.h :internal: +GEM CMA Helper Functions Reference +---------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c + :doc: cma helpers + +.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c + :export: + +.. kernel-doc:: include/drm/drm_gem_cma_helper.h + :internal: + VMA Offset Manager ------------------- +================== .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c :doc: vma offset manager @@ -361,14 +373,14 @@ VMA Offset Manager :internal: PRIME Buffer Sharing --------------------- +==================== PRIME is the cross device buffer sharing framework in drm, originally created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME buffers are dma-buf based file descriptors. Overview and Driver Interface -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------- Similar to GEM global names, PRIME file descriptors are also used to share buffer objects across processes. They offer additional security: @@ -406,7 +418,7 @@ struct drm_gem_object \*obj, int flags); struct drm_gem_object \* support PRIME. PRIME Helper Functions -~~~~~~~~~~~~~~~~~~~~~~ +---------------------- .. kernel-doc:: drivers/gpu/drm/drm_prime.c :doc: PRIME Helpers @@ -418,16 +430,16 @@ PRIME Function References :export: DRM MM Range Allocator ----------------------- +====================== Overview -~~~~~~~~ +-------- .. kernel-doc:: drivers/gpu/drm/drm_mm.c :doc: Overview LRU Scan/Eviction Support -~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------- .. kernel-doc:: drivers/gpu/drm/drm_mm.c :doc: lru scan roaster @@ -440,15 +452,3 @@ DRM MM Range Allocator Function References .. kernel-doc:: include/drm/drm_mm.h :internal: - -CMA Helper Functions Reference ------------------------------- - -.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c - :doc: cma helpers - -.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c - :export: - -.. kernel-doc:: include/drm/drm_gem_cma_helper.h - :internal: From 311b62d94c0b172298c8a9c1f995f1ce8bbba539 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:41 +0200 Subject: [PATCH 10/46] drm/doc: Reorg for drm-kms.rst - Again adjust headings a bit, and don't mix up the initialization sections with other stuff. - Remove the doc for output polling, that vfunc is now properly documented in the vfunc reference sections. - Move the grab-bag with all the core stuff (i.e. drm_crtc.[hc]) to the front for a more prominent place. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-5-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 50 +++++++++++++---------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 8dfa4b214b96..c92afa82b130 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -2,9 +2,6 @@ Kernel Mode Setting (KMS) ========================= -Mode Setting -============ - Drivers must initialize the mode setting core by calling :c:func:`drm_mode_config_init()` on the DRM device. The function initializes the :c:type:`struct drm_device ` @@ -18,17 +15,20 @@ be setup by initializing the following fields. - struct drm_mode_config_funcs \*funcs; Mode setting functions. -Display Modes Function Reference --------------------------------- +KMS Data Structures +=================== -.. kernel-doc:: include/drm/drm_modes.h +.. kernel-doc:: include/drm/drm_crtc.h :internal: -.. kernel-doc:: drivers/gpu/drm/drm_modes.c +KMS API Functions +================= + +.. kernel-doc:: drivers/gpu/drm/drm_crtc.c :export: Atomic Mode Setting Function Reference --------------------------------------- +====================================== .. kernel-doc:: drivers/gpu/drm/drm_atomic.c :export: @@ -37,7 +37,7 @@ Atomic Mode Setting Function Reference :internal: Frame Buffer Abstraction ------------------------- +======================== Frame buffers are abstract memory objects that provide a source of pixels to scanout to a CRTC. Applications explicitly request the @@ -65,13 +65,13 @@ drivers can manually clean up a framebuffer at module unload time with :c:func:`drm_framebuffer_unregister_private()`. DRM Format Handling -------------------- +=================== .. kernel-doc:: drivers/gpu/drm/drm_fourcc.c :export: Dumb Buffer Objects -------------------- +=================== The KMS API doesn't standardize backing storage object creation and leaves it to driver-specific ioctls. Furthermore actually creating a @@ -114,14 +114,14 @@ Note that dumb objects may not be used for gpu acceleration, as has been attempted on some ARM embedded platforms. Such drivers really must have a hardware-specific ioctl to allocate suitable buffer objects. -Output Polling --------------- +Display Modes Function Reference +================================ -void (\*output_poll_changed)(struct drm_device \*dev); -This operation notifies the driver that the status of one or more -connectors has changed. Drivers that use the fb helper can just call the -:c:func:`drm_fb_helper_hotplug_event()` function to handle this -operation. +.. kernel-doc:: include/drm/drm_modes.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_modes.c + :export: KMS Initialization and Cleanup ============================== @@ -463,20 +463,8 @@ created for fetching EDID data and performing monitor detection. Once the process is complete, the new connector is registered with sysfs to make its properties available to applications. -KMS API Functions ------------------ - -.. kernel-doc:: drivers/gpu/drm/drm_crtc.c - :export: - -KMS Data Structures -------------------- - -.. kernel-doc:: include/drm/drm_crtc.h - :internal: - KMS Locking ------------ +=========== .. kernel-doc:: drivers/gpu/drm/drm_modeset_lock.c :doc: kms locking From f1d1326c99a9dbbfd8bc389f7a8f90a8ef6d8aa9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:42 +0200 Subject: [PATCH 11/46] drm/etnaviv: Don't set drm_device->platformdev It's deprecated and only should be used by drivers which still use drm_platform_init, not by anyone else. And indeed it's entirely unused and can be nuked. Cc: Lucas Stach Cc: Russell King Cc: Christian Gmeiner Acked-by: Lucas Stach Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-6-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index fd0ed61565f3..e3164d90399d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -532,8 +532,6 @@ static int etnaviv_bind(struct device *dev) if (!drm) return -ENOMEM; - drm->platformdev = to_platform_device(dev); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(dev, "failed to allocate private data\n"); From d25bcfb8c2e18b9b36f037f38be4d4792ebf8d57 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:43 +0200 Subject: [PATCH 12/46] drm/hisilicon: Don't set drm_device->platformdev It's deprecated and only should be used by drivers which still use drm_platform_init, not by anyone else. And indeed it's entirely unused and can be nuked. This required a bit more fudging, but I guess kirin_dc_ops really wants to operate on the platform_device, not something else. Also bonus points for implementing abstraction, and then storing the vfunc in a global variable. Cc: Xinliang Liu Cc: Xinwei Kong Cc: Archit Taneja Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-7-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 10 +++++----- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 6 ++---- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index eaa3df75fc5c..91188f33b1d9 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -989,9 +989,9 @@ static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) return 0; } -static int ade_drm_init(struct drm_device *dev) +static int ade_drm_init(struct platform_device *pdev) { - struct platform_device *pdev = dev->platformdev; + struct drm_device *drm_dev = platform_get_drvdata(dev); struct ade_data *ade; struct ade_hw_ctx *ctx; struct ade_crtc *acrtc; @@ -1050,9 +1050,9 @@ static int ade_drm_init(struct drm_device *dev) return 0; } -static void ade_drm_cleanup(struct drm_device *dev) +static void ade_drm_cleanup(struct platform_device *pdev) { - struct platform_device *pdev = dev->platformdev; + struct drm_device *drm_dev = platform_get_drvdata(dev); struct ade_data *ade = platform_get_drvdata(pdev); struct drm_crtc *crtc = &ade->acrtc.base; @@ -1062,4 +1062,4 @@ static void ade_drm_cleanup(struct drm_device *dev) const struct kirin_dc_ops ade_dc_ops = { .init = ade_drm_init, .cleanup = ade_drm_cleanup -}; +; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 1fc2f502d20d..6b0f9f6c16e1 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -41,7 +41,7 @@ static int kirin_drm_kms_cleanup(struct drm_device *dev) #endif drm_kms_helper_poll_fini(dev); drm_vblank_cleanup(dev); - dc_ops->cleanup(dev); + dc_ops->cleanup(to_platform_device(dev->dev)); drm_mode_config_cleanup(dev); devm_kfree(dev->dev, priv); dev->dev_private = NULL; @@ -103,7 +103,7 @@ static int kirin_drm_kms_init(struct drm_device *dev) kirin_drm_mode_config_init(dev); /* display controller init */ - ret = dc_ops->init(dev); + ret = dc_ops->init(to_platform_device(dev)); if (ret) goto err_mode_config_cleanup; @@ -210,8 +210,6 @@ static int kirin_drm_bind(struct device *dev) if (!drm_dev) return -ENOMEM; - drm_dev->platformdev = to_platform_device(dev); - ret = kirin_drm_kms_init(drm_dev); if (ret) goto err_drm_dev_unref; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index 1a07caf8e7f4..a0bb217c4c64 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -15,8 +15,8 @@ /* display controller init/cleanup ops */ struct kirin_dc_ops { - int (*init)(struct drm_device *dev); - void (*cleanup)(struct drm_device *dev); + int (*init)(struct platform_device *pdev); + void (*cleanup)(struct platform_device *pdev); }; struct kirin_drm_private { From ecfd8efcf7f9ba9eadb23a98d9eb9d5586b868e7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:44 +0200 Subject: [PATCH 13/46] drm/doc: Remove outdated FIXME for the page_flip callback Since the drm_event cleanup work (as prep for fence support) drivers don't need to bother themselves any more with this, the drm event core takes care of that. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-8-git-send-email-daniel.vetter@ffwll.ch --- include/drm/drm_crtc.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 194eebb2f9d7..410175be4c6a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -547,16 +547,6 @@ struct drm_crtc_funcs { * counter and timestamp tracking though, e.g. if they have accurate * timestamp registers in hardware. * - * FIXME: - * - * Up to that point drivers need to manage events themselves and can use - * even->base.list freely for that. Specifically they need to ensure - * that they don't send out page flip (or vblank) events for which the - * corresponding drm file has been closed already. The drm core - * unfortunately does not (yet) take care of that. Therefore drivers - * currently must clean up and release pending events in their - * ->preclose driver function. - * * This callback is optional. * * NOTE: From 6ab10b76ff6252bd9be0849c40f5865e39a29961 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:45 +0200 Subject: [PATCH 14/46] drm/kms: Nuke dirty_info property It was added way back together with the dirty_fb ioctl, but neither generic xfree86-modesetting nor the vmware driver use it. Everyone is supposed to just unconditionally call the dirtyfb when they do frontbuffer rendering. And since unused uabi is bad uabi (there's reasons we require open source userspace for everything) let's nuke this. For reference see commit 884840aa3ce3214259e69557be5b4ce0d781ffa4 Author: Jakob Bornecrantz Date: Thu Dec 3 23:25:47 2009 +0000 drm: Add dirty ioctl and property Cc: Jakob Bornecrantz Cc: Dave Airlie Cc: Sinclair Yeh Cc: Thomas Hellstrom Acked-by: Thomas Hellstrom Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-9-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 31 ---------------------------- drivers/gpu/drm/udl/udl_connector.c | 3 --- drivers/gpu/drm/udl/udl_modeset.c | 2 -- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 9 -------- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 11 ---------- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 7 ------- include/drm/drm_crtc.h | 7 ------- 7 files changed, 70 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fd9dcecb3eb5..eb7aba874652 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -136,12 +136,6 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, drm_tv_subconnector_enum_list) -static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { - { DRM_MODE_DIRTY_OFF, "Off" }, - { DRM_MODE_DIRTY_ON, "On" }, - { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, -}; - struct drm_conn_prop_enum_list { int type; const char *name; @@ -1887,31 +1881,6 @@ int drm_mode_create_aspect_ratio_property(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); -/** - * drm_mode_create_dirty_property - create dirty property - * @dev: DRM device - * - * Called by a driver the first time it's needed, must be attached to desired - * connectors. - */ -int drm_mode_create_dirty_info_property(struct drm_device *dev) -{ - struct drm_property *dirty_info; - - if (dev->mode_config.dirty_info_property) - return 0; - - dirty_info = - drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, - "dirty", - drm_dirty_info_enum_list, - ARRAY_SIZE(drm_dirty_info_enum_list)); - dev->mode_config.dirty_info_property = dirty_info; - - return 0; -} -EXPORT_SYMBOL(drm_mode_create_dirty_info_property); - /** * drm_mode_create_suggested_offset_properties - create suggests offset properties * @dev: DRM device diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 4709b54c204c..d2f57c52f7db 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -150,8 +150,5 @@ int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) drm_connector_register(connector); drm_mode_connector_attach_encoder(connector, encoder); - drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); return 0; } diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index f92ea9579674..73695127c573 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -441,8 +441,6 @@ int udl_modeset_init(struct drm_device *dev) dev->mode_config.funcs = &udl_mode_funcs; - drm_mode_create_dirty_info_property(dev); - udl_crtc_init(dev); encoder = udl_encoder_init(dev); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 63ccd9871ec9..23ec673d5e16 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -376,9 +376,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_mode_crtc_set_gamma_size(crtc, 256); - drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); drm_object_attach_property(&connector->base, dev_priv->hotplug_mode_update_property, 1); drm_object_attach_property(&connector->base, @@ -421,10 +418,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) if (ret != 0) goto err_free; - ret = drm_mode_create_dirty_info_property(dev); - if (ret != 0) - goto err_vblank_cleanup; - vmw_kms_create_implicit_placement_property(dev_priv, true); if (dev_priv->capabilities & SVGA_CAP_MULTIMON) @@ -439,8 +432,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) return 0; -err_vblank_cleanup: - drm_vblank_cleanup(dev); err_free: kfree(dev_priv->ldu_priv); dev_priv->ldu_priv = NULL; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index b74eae2b8594..f42359084adc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -537,9 +537,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) drm_mode_crtc_set_gamma_size(crtc, 256); - drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); drm_object_attach_property(&connector->base, dev_priv->hotplug_mode_update_property, 1); drm_object_attach_property(&connector->base, @@ -574,10 +571,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) if (unlikely(ret != 0)) return ret; - ret = drm_mode_create_dirty_info_property(dev); - if (unlikely(ret != 0)) - goto err_vblank_cleanup; - vmw_kms_create_implicit_placement_property(dev_priv, false); for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) @@ -588,10 +581,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) DRM_INFO("Screen Objects Display Unit initialized\n"); return 0; - -err_vblank_cleanup: - drm_vblank_cleanup(dev); - return ret; } int vmw_kms_sou_close_display(struct vmw_private *dev_priv) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 41932a7c4f79..94ad8d2acf9a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1130,9 +1130,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) drm_mode_crtc_set_gamma_size(crtc, 256); - drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); drm_object_attach_property(&connector->base, dev_priv->hotplug_mode_update_property, 1); drm_object_attach_property(&connector->base, @@ -1202,10 +1199,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) if (unlikely(ret != 0)) return ret; - ret = drm_mode_create_dirty_info_property(dev); - if (unlikely(ret != 0)) - goto err_vblank_cleanup; - dev_priv->active_display_unit = vmw_du_screen_target; vmw_kms_create_implicit_placement_property(dev_priv, false); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 410175be4c6a..5a7809f029ba 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2639,12 +2639,6 @@ struct drm_mode_config { * HDMI infoframe aspect ratio setting. */ struct drm_property *aspect_ratio_property; - /** - * @dirty_info_property: Optional connector property to give userspace a - * hint that the DIRTY_FB ioctl should be used. - */ - struct drm_property *dirty_info_property; - /** * @degamma_lut_property: Optional CRTC property to set the LUT used to * convert the framebuffer's colors to linear gamma. @@ -2943,7 +2937,6 @@ extern int drm_mode_create_tv_properties(struct drm_device *dev, const char * const modes[]); extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); -extern int drm_mode_create_dirty_info_property(struct drm_device *dev); extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, From 5d070be68380baf61279d650b52563243cfaaa00 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:46 +0200 Subject: [PATCH 15/46] drm/doc: Include drm_atomic.h Accidentally the wrong file. Oops. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-10-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index c92afa82b130..3ae4c12aca08 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -33,7 +33,7 @@ Atomic Mode Setting Function Reference .. kernel-doc:: drivers/gpu/drm/drm_atomic.c :export: -.. kernel-doc:: drivers/gpu/drm/drm_atomic.c +.. kernel-doc:: include/drm/drm_atomic.h :internal: Frame Buffer Abstraction From 7520a277d97be6e8a8ec038bb5ed01f40d4f9aeb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 15 Aug 2016 16:07:02 +0200 Subject: [PATCH 16/46] drm: Extract drm_framebuffer.[hc] Also start with drm_modeset.h with the core bits, since we need to untangle this mess somehow. That allows us to move the drm_modes.h include to the right spot, except for the temporary connector status enum. That will get fixed as soon as drm_connector.h exists. v2: Rebase. v3: Move drm_crtc_force_disable_all back again, that wasn't meant to be moved (Sean). v4: Rebase. Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter --- Documentation/gpu/drm-kms.rst | 9 + drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_crtc.c | 801 +--------------------------- drivers/gpu/drm/drm_crtc_internal.h | 40 +- drivers/gpu/drm/drm_framebuffer.c | 796 +++++++++++++++++++++++++++ include/drm/drm_crtc.h | 162 +----- include/drm/drm_framebuffer.h | 170 ++++++ include/drm/drm_modes.h | 2 + include/drm/drm_modeset.h | 50 ++ 9 files changed, 1075 insertions(+), 958 deletions(-) create mode 100644 drivers/gpu/drm/drm_framebuffer.c create mode 100644 include/drm/drm_framebuffer.h create mode 100644 include/drm/drm_modeset.h diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 3ae4c12aca08..8264a88a8695 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -64,6 +64,15 @@ fbdev framebuffer when the struct :c:type:`struct drm_framebuffer drivers can manually clean up a framebuffer at module unload time with :c:func:`drm_framebuffer_unregister_private()`. +Frame Buffer Functions Reference +-------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c + :export: + +.. kernel-doc:: include/drm/drm_framebuffer.h + :internal: + DRM Format Handling =================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a5824d926dc9..c71ec42ce511 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -12,7 +12,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ - drm_modeset_lock.o drm_atomic.o drm_bridge.o + drm_modeset_lock.o drm_atomic.o drm_bridge.o \ + drm_framebuffer.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index eb7aba874652..d596a491b517 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -40,15 +40,11 @@ #include #include #include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" -static struct drm_framebuffer * -internal_framebuffer_create(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *r, - struct drm_file *file_priv); - /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ const char *fnname(int val) \ @@ -238,11 +234,11 @@ EXPORT_SYMBOL(drm_get_subpixel_order_name); * Internal function to assign a slot in the object idr and optionally * register the object into the idr. */ -static int drm_mode_object_get_reg(struct drm_device *dev, - struct drm_mode_object *obj, - uint32_t obj_type, - bool register_obj, - void (*obj_free_cb)(struct kref *kref)) +int drm_mode_object_get_reg(struct drm_device *dev, + struct drm_mode_object *obj, + uint32_t obj_type, + bool register_obj, + void (*obj_free_cb)(struct kref *kref)) { int ret; @@ -285,8 +281,8 @@ int drm_mode_object_get(struct drm_device *dev, return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); } -static void drm_mode_object_register(struct drm_device *dev, - struct drm_mode_object *obj) +void drm_mode_object_register(struct drm_device *dev, + struct drm_mode_object *obj) { mutex_lock(&dev->mode_config.idr_mutex); idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); @@ -315,8 +311,8 @@ void drm_mode_object_unregister(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); } -static struct drm_mode_object *_object_find(struct drm_device *dev, - uint32_t id, uint32_t type) +struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type) { struct drm_mode_object *obj = NULL; @@ -351,7 +347,7 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, { struct drm_mode_object *obj = NULL; - obj = _object_find(dev, id, type); + obj = __drm_mode_object_find(dev, id, type); return obj; } EXPORT_SYMBOL(drm_mode_object_find); @@ -435,199 +431,6 @@ int drm_crtc_force_disable_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_crtc_force_disable_all); -static void drm_framebuffer_free(struct kref *kref) -{ - struct drm_framebuffer *fb = - container_of(kref, struct drm_framebuffer, base.refcount); - struct drm_device *dev = fb->dev; - - /* - * The lookup idr holds a weak reference, which has not necessarily been - * removed at this point. Check for that. - */ - drm_mode_object_unregister(dev, &fb->base); - - fb->funcs->destroy(fb); -} - -/** - * drm_framebuffer_init - initialize a framebuffer - * @dev: DRM device - * @fb: framebuffer to be initialized - * @funcs: ... with these functions - * - * Allocates an ID for the framebuffer's parent mode object, sets its mode - * functions & device file and adds it to the master fd list. - * - * IMPORTANT: - * This functions publishes the fb and makes it available for concurrent access - * by other users. Which means by this point the fb _must_ be fully set up - - * since all the fb attributes are invariant over its lifetime, no further - * locking but only correct reference counting is required. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, - const struct drm_framebuffer_funcs *funcs) -{ - int ret; - - INIT_LIST_HEAD(&fb->filp_head); - fb->dev = dev; - fb->funcs = funcs; - - ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, - false, drm_framebuffer_free); - if (ret) - goto out; - - mutex_lock(&dev->mode_config.fb_lock); - dev->mode_config.num_fb++; - list_add(&fb->head, &dev->mode_config.fb_list); - mutex_unlock(&dev->mode_config.fb_lock); - - drm_mode_object_register(dev, &fb->base); -out: - return ret; -} -EXPORT_SYMBOL(drm_framebuffer_init); - -/** - * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference - * @dev: drm device - * @id: id of the fb object - * - * If successful, this grabs an additional reference to the framebuffer - - * callers need to make sure to eventually unreference the returned framebuffer - * again, using @drm_framebuffer_unreference. - */ -struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, - uint32_t id) -{ - struct drm_mode_object *obj; - struct drm_framebuffer *fb = NULL; - - obj = _object_find(dev, id, DRM_MODE_OBJECT_FB); - if (obj) - fb = obj_to_fb(obj); - return fb; -} -EXPORT_SYMBOL(drm_framebuffer_lookup); - -/** - * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr - * @fb: fb to unregister - * - * Drivers need to call this when cleaning up driver-private framebuffers, e.g. - * those used for fbdev. Note that the caller must hold a reference of it's own, - * i.e. the object may not be destroyed through this call (since it'll lead to a - * locking inversion). - */ -void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) -{ - struct drm_device *dev; - - if (!fb) - return; - - dev = fb->dev; - - /* Mark fb as reaped and drop idr ref. */ - drm_mode_object_unregister(dev, &fb->base); -} -EXPORT_SYMBOL(drm_framebuffer_unregister_private); - -/** - * drm_framebuffer_cleanup - remove a framebuffer object - * @fb: framebuffer to remove - * - * Cleanup framebuffer. This function is intended to be used from the drivers - * ->destroy callback. It can also be used to clean up driver private - * framebuffers embedded into a larger structure. - * - * Note that this function does not remove the fb from active usuage - if it is - * still used anywhere, hilarity can ensue since userspace could call getfb on - * the id and get back -EINVAL. Obviously no concern at driver unload time. - * - * Also, the framebuffer will not be removed from the lookup idr - for - * user-created framebuffers this will happen in in the rmfb ioctl. For - * driver-private objects (e.g. for fbdev) drivers need to explicitly call - * drm_framebuffer_unregister_private. - */ -void drm_framebuffer_cleanup(struct drm_framebuffer *fb) -{ - struct drm_device *dev = fb->dev; - - mutex_lock(&dev->mode_config.fb_lock); - list_del(&fb->head); - dev->mode_config.num_fb--; - mutex_unlock(&dev->mode_config.fb_lock); -} -EXPORT_SYMBOL(drm_framebuffer_cleanup); - -/** - * drm_framebuffer_remove - remove and unreference a framebuffer object - * @fb: framebuffer to remove - * - * Scans all the CRTCs and planes in @dev's mode_config. If they're - * using @fb, removes it, setting it to NULL. Then drops the reference to the - * passed-in framebuffer. Might take the modeset locks. - * - * Note that this function optimizes the cleanup away if the caller holds the - * last reference to the framebuffer. It is also guaranteed to not take the - * modeset locks in this case. - */ -void drm_framebuffer_remove(struct drm_framebuffer *fb) -{ - struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_plane *plane; - - if (!fb) - return; - - dev = fb->dev; - - WARN_ON(!list_empty(&fb->filp_head)); - - /* - * drm ABI mandates that we remove any deleted framebuffers from active - * useage. But since most sane clients only remove framebuffers they no - * longer need, try to optimize this away. - * - * Since we're holding a reference ourselves, observing a refcount of 1 - * means that we're the last holder and can skip it. Also, the refcount - * can never increase from 1 again, so we don't need any barriers or - * locks. - * - * Note that userspace could try to race with use and instate a new - * usage _after_ we've cleared all current ones. End result will be an - * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot - * in this manner. - */ - if (drm_framebuffer_read_refcount(fb) > 1) { - drm_modeset_lock_all(dev); - /* remove from any CRTC */ - drm_for_each_crtc(crtc, dev) { - if (crtc->primary->fb == fb) { - /* should turn off the crtc */ - if (drm_crtc_force_disable(crtc)) - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); - } - } - - drm_for_each_plane(plane, dev) { - if (plane->fb == fb) - drm_plane_force_disable(plane); - } - drm_modeset_unlock_all(dev); - } - - drm_framebuffer_unreference(fb); -} -EXPORT_SYMBOL(drm_framebuffer_remove); - DEFINE_WW_CLASS(crtc_ww_class); static unsigned int drm_num_crtcs(struct drm_device *dev) @@ -3011,7 +2814,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, */ if (req->flags & DRM_MODE_CURSOR_BO) { if (req->handle) { - fb = internal_framebuffer_create(dev, &fbreq, file_priv); + fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); return PTR_ERR(fb); @@ -3209,581 +3012,6 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) } EXPORT_SYMBOL(drm_mode_legacy_fb_format); -/** - * drm_mode_addfb - add an FB to the graphics configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Add a new FB to the specified CRTC, given a user request. This is the - * original addfb ioctl which only supported RGB formats. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_addfb(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_fb_cmd *or = data; - struct drm_mode_fb_cmd2 r = {}; - int ret; - - /* convert to new format and call new ioctl */ - r.fb_id = or->fb_id; - r.width = or->width; - r.height = or->height; - r.pitches[0] = or->pitch; - r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); - r.handles[0] = or->handle; - - ret = drm_mode_addfb2(dev, &r, file_priv); - if (ret) - return ret; - - or->fb_id = r.fb_id; - - return 0; -} - -static int format_check(const struct drm_mode_fb_cmd2 *r) -{ - uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; - char *format_name; - - switch (format) { - case DRM_FORMAT_C8: - case DRM_FORMAT_RGB332: - case DRM_FORMAT_BGR233: - case DRM_FORMAT_XRGB4444: - case DRM_FORMAT_XBGR4444: - case DRM_FORMAT_RGBX4444: - case DRM_FORMAT_BGRX4444: - case DRM_FORMAT_ARGB4444: - case DRM_FORMAT_ABGR4444: - case DRM_FORMAT_RGBA4444: - case DRM_FORMAT_BGRA4444: - case DRM_FORMAT_XRGB1555: - case DRM_FORMAT_XBGR1555: - case DRM_FORMAT_RGBX5551: - case DRM_FORMAT_BGRX5551: - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_ABGR1555: - case DRM_FORMAT_RGBA5551: - case DRM_FORMAT_BGRA5551: - case DRM_FORMAT_RGB565: - case DRM_FORMAT_BGR565: - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBX8888: - case DRM_FORMAT_BGRX8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_RGBA1010102: - case DRM_FORMAT_BGRA1010102: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_AYUV: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 0; - default: - format_name = drm_get_format_name(r->pixel_format); - DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); - kfree(format_name); - return -EINVAL; - } -} - -static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) -{ - int ret, hsub, vsub, num_planes, i; - - ret = format_check(r); - if (ret) { - char *format_name = drm_get_format_name(r->pixel_format); - DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); - kfree(format_name); - return ret; - } - - hsub = drm_format_horz_chroma_subsampling(r->pixel_format); - vsub = drm_format_vert_chroma_subsampling(r->pixel_format); - num_planes = drm_format_num_planes(r->pixel_format); - - if (r->width == 0 || r->width % hsub) { - DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); - return -EINVAL; - } - - if (r->height == 0 || r->height % vsub) { - DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); - return -EINVAL; - } - - for (i = 0; i < num_planes; i++) { - unsigned int width = r->width / (i != 0 ? hsub : 1); - unsigned int height = r->height / (i != 0 ? vsub : 1); - unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); - - if (!r->handles[i]) { - DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); - return -EINVAL; - } - - if ((uint64_t) width * cpp > UINT_MAX) - return -ERANGE; - - if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) - return -ERANGE; - - if (r->pitches[i] < width * cpp) { - DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); - return -EINVAL; - } - - if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { - DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", - r->modifier[i], i); - return -EINVAL; - } - - /* modifier specific checks: */ - switch (r->modifier[i]) { - case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: - /* NOTE: the pitch restriction may be lifted later if it turns - * out that no hw has this restriction: - */ - if (r->pixel_format != DRM_FORMAT_NV12 || - width % 128 || height % 32 || - r->pitches[i] % 128) { - DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); - return -EINVAL; - } - break; - - default: - break; - } - } - - for (i = num_planes; i < 4; i++) { - if (r->modifier[i]) { - DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); - return -EINVAL; - } - - /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ - if (!(r->flags & DRM_MODE_FB_MODIFIERS)) - continue; - - if (r->handles[i]) { - DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); - return -EINVAL; - } - - if (r->pitches[i]) { - DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); - return -EINVAL; - } - - if (r->offsets[i]) { - DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); - return -EINVAL; - } - } - - return 0; -} - -static struct drm_framebuffer * -internal_framebuffer_create(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *r, - struct drm_file *file_priv) -{ - struct drm_mode_config *config = &dev->mode_config; - struct drm_framebuffer *fb; - int ret; - - if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { - DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); - return ERR_PTR(-EINVAL); - } - - if ((config->min_width > r->width) || (r->width > config->max_width)) { - DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", - r->width, config->min_width, config->max_width); - return ERR_PTR(-EINVAL); - } - if ((config->min_height > r->height) || (r->height > config->max_height)) { - DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", - r->height, config->min_height, config->max_height); - return ERR_PTR(-EINVAL); - } - - if (r->flags & DRM_MODE_FB_MODIFIERS && - !dev->mode_config.allow_fb_modifiers) { - DRM_DEBUG_KMS("driver does not support fb modifiers\n"); - return ERR_PTR(-EINVAL); - } - - ret = framebuffer_check(r); - if (ret) - return ERR_PTR(ret); - - fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); - if (IS_ERR(fb)) { - DRM_DEBUG_KMS("could not create framebuffer\n"); - return fb; - } - - return fb; -} - -/** - * drm_mode_addfb2 - add an FB to the graphics configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Add a new FB to the specified CRTC, given a user request with format. This is - * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers - * and uses fourcc codes as pixel format specifiers. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_addfb2(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_fb_cmd2 *r = data; - struct drm_framebuffer *fb; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - fb = internal_framebuffer_create(dev, r, file_priv); - if (IS_ERR(fb)) - return PTR_ERR(fb); - - DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); - r->fb_id = fb->base.id; - - /* Transfer ownership to the filp for reaping on close */ - mutex_lock(&file_priv->fbs_lock); - list_add(&fb->filp_head, &file_priv->fbs); - mutex_unlock(&file_priv->fbs_lock); - - return 0; -} - -struct drm_mode_rmfb_work { - struct work_struct work; - struct list_head fbs; -}; - -static void drm_mode_rmfb_work_fn(struct work_struct *w) -{ - struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); - - while (!list_empty(&arg->fbs)) { - struct drm_framebuffer *fb = - list_first_entry(&arg->fbs, typeof(*fb), filp_head); - - list_del_init(&fb->filp_head); - drm_framebuffer_remove(fb); - } -} - -/** - * drm_mode_rmfb - remove an FB from the configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Remove the FB specified by the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_rmfb(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_framebuffer *fb = NULL; - struct drm_framebuffer *fbl = NULL; - uint32_t *id = data; - int found = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - fb = drm_framebuffer_lookup(dev, *id); - if (!fb) - return -ENOENT; - - mutex_lock(&file_priv->fbs_lock); - list_for_each_entry(fbl, &file_priv->fbs, filp_head) - if (fb == fbl) - found = 1; - if (!found) { - mutex_unlock(&file_priv->fbs_lock); - goto fail_unref; - } - - list_del_init(&fb->filp_head); - mutex_unlock(&file_priv->fbs_lock); - - /* drop the reference we picked up in framebuffer lookup */ - drm_framebuffer_unreference(fb); - - /* - * we now own the reference that was stored in the fbs list - * - * drm_framebuffer_remove may fail with -EINTR on pending signals, - * so run this in a separate stack as there's no way to correctly - * handle this after the fb is already removed from the lookup table. - */ - if (drm_framebuffer_read_refcount(fb) > 1) { - struct drm_mode_rmfb_work arg; - - INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); - INIT_LIST_HEAD(&arg.fbs); - list_add_tail(&fb->filp_head, &arg.fbs); - - schedule_work(&arg.work); - flush_work(&arg.work); - destroy_work_on_stack(&arg.work); - } else - drm_framebuffer_unreference(fb); - - return 0; - -fail_unref: - drm_framebuffer_unreference(fb); - return -ENOENT; -} - -/** - * drm_mode_getfb - get FB info - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Lookup the FB given its ID and return info about it. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getfb(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_fb_cmd *r = data; - struct drm_framebuffer *fb; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - fb = drm_framebuffer_lookup(dev, r->fb_id); - if (!fb) - return -ENOENT; - - r->height = fb->height; - r->width = fb->width; - r->depth = fb->depth; - r->bpp = fb->bits_per_pixel; - r->pitch = fb->pitches[0]; - if (fb->funcs->create_handle) { - if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || - drm_is_control_client(file_priv)) { - ret = fb->funcs->create_handle(fb, file_priv, - &r->handle); - } else { - /* GET_FB() is an unprivileged ioctl so we must not - * return a buffer-handle to non-master processes! For - * backwards-compatibility reasons, we cannot make - * GET_FB() privileged, so just return an invalid handle - * for non-masters. */ - r->handle = 0; - ret = 0; - } - } else { - ret = -ENODEV; - } - - drm_framebuffer_unreference(fb); - - return ret; -} - -/** - * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Lookup the FB and flush out the damaged area supplied by userspace as a clip - * rectangle list. Generic userspace which does frontbuffer rendering must call - * this ioctl to flush out the changes on manual-update display outputs, e.g. - * usb display-link, mipi manual update panels or edp panel self refresh modes. - * - * Modesetting drivers which always update the frontbuffer do not need to - * implement the corresponding ->dirty framebuffer callback. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_dirtyfb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_clip_rect __user *clips_ptr; - struct drm_clip_rect *clips = NULL; - struct drm_mode_fb_dirty_cmd *r = data; - struct drm_framebuffer *fb; - unsigned flags; - int num_clips; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - fb = drm_framebuffer_lookup(dev, r->fb_id); - if (!fb) - return -ENOENT; - - num_clips = r->num_clips; - clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; - - if (!num_clips != !clips_ptr) { - ret = -EINVAL; - goto out_err1; - } - - flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; - - /* If userspace annotates copy, clips must come in pairs */ - if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { - ret = -EINVAL; - goto out_err1; - } - - if (num_clips && clips_ptr) { - if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { - ret = -EINVAL; - goto out_err1; - } - clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); - if (!clips) { - ret = -ENOMEM; - goto out_err1; - } - - ret = copy_from_user(clips, clips_ptr, - num_clips * sizeof(*clips)); - if (ret) { - ret = -EFAULT; - goto out_err2; - } - } - - if (fb->funcs->dirty) { - ret = fb->funcs->dirty(fb, file_priv, flags, r->color, - clips, num_clips); - } else { - ret = -ENOSYS; - } - -out_err2: - kfree(clips); -out_err1: - drm_framebuffer_unreference(fb); - - return ret; -} - -/** - * drm_fb_release - remove and free the FBs on this file - * @priv: drm file for the ioctl - * - * Destroy all the FBs associated with @filp. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -void drm_fb_release(struct drm_file *priv) -{ - struct drm_framebuffer *fb, *tfb; - struct drm_mode_rmfb_work arg; - - INIT_LIST_HEAD(&arg.fbs); - - /* - * When the file gets released that means no one else can access the fb - * list any more, so no need to grab fpriv->fbs_lock. And we need to - * avoid upsetting lockdep since the universal cursor code adds a - * framebuffer while holding mutex locks. - * - * Note that a real deadlock between fpriv->fbs_lock and the modeset - * locks is impossible here since no one else but this function can get - * at it any more. - */ - list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { - if (drm_framebuffer_read_refcount(fb) > 1) { - list_move_tail(&fb->filp_head, &arg.fbs); - } else { - list_del_init(&fb->filp_head); - - /* This drops the fpriv->fbs reference. */ - drm_framebuffer_unreference(fb); - } - } - - if (!list_empty(&arg.fbs)) { - INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); - - schedule_work(&arg.work); - flush_work(&arg.work); - destroy_work_on_stack(&arg.work); - } -} - static bool drm_property_type_valid(struct drm_property *property) { if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) @@ -4496,7 +3724,7 @@ struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, struct drm_mode_object *obj; struct drm_property_blob *blob = NULL; - obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB); + obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); if (obj) blob = obj_to_blob(obj); return blob; @@ -4892,7 +4120,8 @@ bool drm_property_change_valid_get(struct drm_property *property, if (value == 0) return true; - *ref = _object_find(property->dev, value, property->values[0]); + *ref = __drm_mode_object_find(property->dev, value, + property->values[0]); return *ref != NULL; } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 0c34e6d906d1..67a7b4540630 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -35,8 +35,17 @@ /* drm_crtc.c */ void drm_connector_ida_init(void); void drm_connector_ida_destroy(void); +int drm_mode_object_get_reg(struct drm_device *dev, + struct drm_mode_object *obj, + uint32_t obj_type, + bool register_obj, + void (*obj_free_cb)(struct kref *kref)); +void drm_mode_object_register(struct drm_device *dev, + struct drm_mode_object *obj); int drm_mode_object_get(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type); +struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type); void drm_mode_object_unregister(struct drm_device *dev, struct drm_mode_object *object); bool drm_property_change_valid_get(struct drm_property *property, @@ -64,18 +73,6 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* framebuffer IOCTLs */ -extern int drm_mode_addfb(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_addfb2(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_rmfb(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_getfb(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_dirtyfb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); - /* IOCTLs */ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -120,6 +117,25 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* drm_framebuffer.c */ +struct drm_framebuffer * +drm_internal_framebuffer_create(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *r, + struct drm_file *file_priv); +void drm_framebuffer_free(struct kref *kref); + +/* IOCTL */ +int drm_mode_addfb(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_addfb2(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_rmfb(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_getfb(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_dirtyfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); + /* drm_atomic.c */ int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c new file mode 100644 index 000000000000..74572c8a50b8 --- /dev/null +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "drm_crtc_internal.h" + +/** + * drm_mode_addfb - add an FB to the graphics configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Add a new FB to the specified CRTC, given a user request. This is the + * original addfb ioctl which only supported RGB formats. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_addfb(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd *or = data; + struct drm_mode_fb_cmd2 r = {}; + int ret; + + /* convert to new format and call new ioctl */ + r.fb_id = or->fb_id; + r.width = or->width; + r.height = or->height; + r.pitches[0] = or->pitch; + r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); + r.handles[0] = or->handle; + + ret = drm_mode_addfb2(dev, &r, file_priv); + if (ret) + return ret; + + or->fb_id = r.fb_id; + + return 0; +} + +static int format_check(const struct drm_mode_fb_cmd2 *r) +{ + uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; + char *format_name; + + switch (format) { + case DRM_FORMAT_C8: + case DRM_FORMAT_RGB332: + case DRM_FORMAT_BGR233: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_AYUV: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 0; + default: + format_name = drm_get_format_name(r->pixel_format); + DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); + kfree(format_name); + return -EINVAL; + } +} + +static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) +{ + int ret, hsub, vsub, num_planes, i; + + ret = format_check(r); + if (ret) { + char *format_name = drm_get_format_name(r->pixel_format); + DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); + kfree(format_name); + return ret; + } + + hsub = drm_format_horz_chroma_subsampling(r->pixel_format); + vsub = drm_format_vert_chroma_subsampling(r->pixel_format); + num_planes = drm_format_num_planes(r->pixel_format); + + if (r->width == 0 || r->width % hsub) { + DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); + return -EINVAL; + } + + if (r->height == 0 || r->height % vsub) { + DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); + return -EINVAL; + } + + for (i = 0; i < num_planes; i++) { + unsigned int width = r->width / (i != 0 ? hsub : 1); + unsigned int height = r->height / (i != 0 ? vsub : 1); + unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); + + if (!r->handles[i]) { + DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); + return -EINVAL; + } + + if ((uint64_t) width * cpp > UINT_MAX) + return -ERANGE; + + if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) + return -ERANGE; + + if (r->pitches[i] < width * cpp) { + DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); + return -EINVAL; + } + + if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { + DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", + r->modifier[i], i); + return -EINVAL; + } + + /* modifier specific checks: */ + switch (r->modifier[i]) { + case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: + /* NOTE: the pitch restriction may be lifted later if it turns + * out that no hw has this restriction: + */ + if (r->pixel_format != DRM_FORMAT_NV12 || + width % 128 || height % 32 || + r->pitches[i] % 128) { + DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); + return -EINVAL; + } + break; + + default: + break; + } + } + + for (i = num_planes; i < 4; i++) { + if (r->modifier[i]) { + DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); + return -EINVAL; + } + + /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ + if (!(r->flags & DRM_MODE_FB_MODIFIERS)) + continue; + + if (r->handles[i]) { + DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); + return -EINVAL; + } + + if (r->pitches[i]) { + DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); + return -EINVAL; + } + + if (r->offsets[i]) { + DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); + return -EINVAL; + } + } + + return 0; +} + +struct drm_framebuffer * +drm_internal_framebuffer_create(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *r, + struct drm_file *file_priv) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_framebuffer *fb; + int ret; + + if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { + DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); + return ERR_PTR(-EINVAL); + } + + if ((config->min_width > r->width) || (r->width > config->max_width)) { + DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", + r->width, config->min_width, config->max_width); + return ERR_PTR(-EINVAL); + } + if ((config->min_height > r->height) || (r->height > config->max_height)) { + DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", + r->height, config->min_height, config->max_height); + return ERR_PTR(-EINVAL); + } + + if (r->flags & DRM_MODE_FB_MODIFIERS && + !dev->mode_config.allow_fb_modifiers) { + DRM_DEBUG_KMS("driver does not support fb modifiers\n"); + return ERR_PTR(-EINVAL); + } + + ret = framebuffer_check(r); + if (ret) + return ERR_PTR(ret); + + fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); + if (IS_ERR(fb)) { + DRM_DEBUG_KMS("could not create framebuffer\n"); + return fb; + } + + return fb; +} + +/** + * drm_mode_addfb2 - add an FB to the graphics configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Add a new FB to the specified CRTC, given a user request with format. This is + * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers + * and uses fourcc codes as pixel format specifiers. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_addfb2(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd2 *r = data; + struct drm_framebuffer *fb; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_internal_framebuffer_create(dev, r, file_priv); + if (IS_ERR(fb)) + return PTR_ERR(fb); + + DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + r->fb_id = fb->base.id; + + /* Transfer ownership to the filp for reaping on close */ + mutex_lock(&file_priv->fbs_lock); + list_add(&fb->filp_head, &file_priv->fbs); + mutex_unlock(&file_priv->fbs_lock); + + return 0; +} + +struct drm_mode_rmfb_work { + struct work_struct work; + struct list_head fbs; +}; + +static void drm_mode_rmfb_work_fn(struct work_struct *w) +{ + struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); + + while (!list_empty(&arg->fbs)) { + struct drm_framebuffer *fb = + list_first_entry(&arg->fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_remove(fb); + } +} + +/** + * drm_mode_rmfb - remove an FB from the configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Remove the FB specified by the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_rmfb(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_framebuffer *fb = NULL; + struct drm_framebuffer *fbl = NULL; + uint32_t *id = data; + int found = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, *id); + if (!fb) + return -ENOENT; + + mutex_lock(&file_priv->fbs_lock); + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = 1; + if (!found) { + mutex_unlock(&file_priv->fbs_lock); + goto fail_unref; + } + + list_del_init(&fb->filp_head); + mutex_unlock(&file_priv->fbs_lock); + + /* drop the reference we picked up in framebuffer lookup */ + drm_framebuffer_unreference(fb); + + /* + * we now own the reference that was stored in the fbs list + * + * drm_framebuffer_remove may fail with -EINTR on pending signals, + * so run this in a separate stack as there's no way to correctly + * handle this after the fb is already removed from the lookup table. + */ + if (drm_framebuffer_read_refcount(fb) > 1) { + struct drm_mode_rmfb_work arg; + + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + INIT_LIST_HEAD(&arg.fbs); + list_add_tail(&fb->filp_head, &arg.fbs); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); + } else + drm_framebuffer_unreference(fb); + + return 0; + +fail_unref: + drm_framebuffer_unreference(fb); + return -ENOENT; +} + +/** + * drm_mode_getfb - get FB info + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Lookup the FB given its ID and return info about it. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getfb(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd *r = data; + struct drm_framebuffer *fb; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, r->fb_id); + if (!fb) + return -ENOENT; + + r->height = fb->height; + r->width = fb->width; + r->depth = fb->depth; + r->bpp = fb->bits_per_pixel; + r->pitch = fb->pitches[0]; + if (fb->funcs->create_handle) { + if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || + drm_is_control_client(file_priv)) { + ret = fb->funcs->create_handle(fb, file_priv, + &r->handle); + } else { + /* GET_FB() is an unprivileged ioctl so we must not + * return a buffer-handle to non-master processes! For + * backwards-compatibility reasons, we cannot make + * GET_FB() privileged, so just return an invalid handle + * for non-masters. */ + r->handle = 0; + ret = 0; + } + } else { + ret = -ENODEV; + } + + drm_framebuffer_unreference(fb); + + return ret; +} + +/** + * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Lookup the FB and flush out the damaged area supplied by userspace as a clip + * rectangle list. Generic userspace which does frontbuffer rendering must call + * this ioctl to flush out the changes on manual-update display outputs, e.g. + * usb display-link, mipi manual update panels or edp panel self refresh modes. + * + * Modesetting drivers which always update the frontbuffer do not need to + * implement the corresponding ->dirty framebuffer callback. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_dirtyfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_clip_rect __user *clips_ptr; + struct drm_clip_rect *clips = NULL; + struct drm_mode_fb_dirty_cmd *r = data; + struct drm_framebuffer *fb; + unsigned flags; + int num_clips; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, r->fb_id); + if (!fb) + return -ENOENT; + + num_clips = r->num_clips; + clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; + + if (!num_clips != !clips_ptr) { + ret = -EINVAL; + goto out_err1; + } + + flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; + + /* If userspace annotates copy, clips must come in pairs */ + if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { + ret = -EINVAL; + goto out_err1; + } + + if (num_clips && clips_ptr) { + if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { + ret = -EINVAL; + goto out_err1; + } + clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); + if (!clips) { + ret = -ENOMEM; + goto out_err1; + } + + ret = copy_from_user(clips, clips_ptr, + num_clips * sizeof(*clips)); + if (ret) { + ret = -EFAULT; + goto out_err2; + } + } + + if (fb->funcs->dirty) { + ret = fb->funcs->dirty(fb, file_priv, flags, r->color, + clips, num_clips); + } else { + ret = -ENOSYS; + } + +out_err2: + kfree(clips); +out_err1: + drm_framebuffer_unreference(fb); + + return ret; +} + +/** + * drm_fb_release - remove and free the FBs on this file + * @priv: drm file for the ioctl + * + * Destroy all the FBs associated with @filp. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +void drm_fb_release(struct drm_file *priv) +{ + struct drm_framebuffer *fb, *tfb; + struct drm_mode_rmfb_work arg; + + INIT_LIST_HEAD(&arg.fbs); + + /* + * When the file gets released that means no one else can access the fb + * list any more, so no need to grab fpriv->fbs_lock. And we need to + * avoid upsetting lockdep since the universal cursor code adds a + * framebuffer while holding mutex locks. + * + * Note that a real deadlock between fpriv->fbs_lock and the modeset + * locks is impossible here since no one else but this function can get + * at it any more. + */ + list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { + if (drm_framebuffer_read_refcount(fb) > 1) { + list_move_tail(&fb->filp_head, &arg.fbs); + } else { + list_del_init(&fb->filp_head); + + /* This drops the fpriv->fbs reference. */ + drm_framebuffer_unreference(fb); + } + } + + if (!list_empty(&arg.fbs)) { + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); + } +} + +void drm_framebuffer_free(struct kref *kref) +{ + struct drm_framebuffer *fb = + container_of(kref, struct drm_framebuffer, base.refcount); + struct drm_device *dev = fb->dev; + + /* + * The lookup idr holds a weak reference, which has not necessarily been + * removed at this point. Check for that. + */ + drm_mode_object_unregister(dev, &fb->base); + + fb->funcs->destroy(fb); +} + +/** + * drm_framebuffer_init - initialize a framebuffer + * @dev: DRM device + * @fb: framebuffer to be initialized + * @funcs: ... with these functions + * + * Allocates an ID for the framebuffer's parent mode object, sets its mode + * functions & device file and adds it to the master fd list. + * + * IMPORTANT: + * This functions publishes the fb and makes it available for concurrent access + * by other users. Which means by this point the fb _must_ be fully set up - + * since all the fb attributes are invariant over its lifetime, no further + * locking but only correct reference counting is required. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs) +{ + int ret; + + INIT_LIST_HEAD(&fb->filp_head); + fb->dev = dev; + fb->funcs = funcs; + + ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, + false, drm_framebuffer_free); + if (ret) + goto out; + + mutex_lock(&dev->mode_config.fb_lock); + dev->mode_config.num_fb++; + list_add(&fb->head, &dev->mode_config.fb_list); + mutex_unlock(&dev->mode_config.fb_lock); + + drm_mode_object_register(dev, &fb->base); +out: + return ret; +} +EXPORT_SYMBOL(drm_framebuffer_init); + +/** + * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference + * @dev: drm device + * @id: id of the fb object + * + * If successful, this grabs an additional reference to the framebuffer - + * callers need to make sure to eventually unreference the returned framebuffer + * again, using @drm_framebuffer_unreference. + */ +struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *obj; + struct drm_framebuffer *fb = NULL; + + obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_FB); + if (obj) + fb = obj_to_fb(obj); + return fb; +} +EXPORT_SYMBOL(drm_framebuffer_lookup); + +/** + * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr + * @fb: fb to unregister + * + * Drivers need to call this when cleaning up driver-private framebuffers, e.g. + * those used for fbdev. Note that the caller must hold a reference of it's own, + * i.e. the object may not be destroyed through this call (since it'll lead to a + * locking inversion). + */ +void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) +{ + struct drm_device *dev; + + if (!fb) + return; + + dev = fb->dev; + + /* Mark fb as reaped and drop idr ref. */ + drm_mode_object_unregister(dev, &fb->base); +} +EXPORT_SYMBOL(drm_framebuffer_unregister_private); + +/** + * drm_framebuffer_cleanup - remove a framebuffer object + * @fb: framebuffer to remove + * + * Cleanup framebuffer. This function is intended to be used from the drivers + * ->destroy callback. It can also be used to clean up driver private + * framebuffers embedded into a larger structure. + * + * Note that this function does not remove the fb from active usuage - if it is + * still used anywhere, hilarity can ensue since userspace could call getfb on + * the id and get back -EINVAL. Obviously no concern at driver unload time. + * + * Also, the framebuffer will not be removed from the lookup idr - for + * user-created framebuffers this will happen in in the rmfb ioctl. For + * driver-private objects (e.g. for fbdev) drivers need to explicitly call + * drm_framebuffer_unregister_private. + */ +void drm_framebuffer_cleanup(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + + mutex_lock(&dev->mode_config.fb_lock); + list_del(&fb->head); + dev->mode_config.num_fb--; + mutex_unlock(&dev->mode_config.fb_lock); +} +EXPORT_SYMBOL(drm_framebuffer_cleanup); + +/** + * drm_framebuffer_remove - remove and unreference a framebuffer object + * @fb: framebuffer to remove + * + * Scans all the CRTCs and planes in @dev's mode_config. If they're + * using @fb, removes it, setting it to NULL. Then drops the reference to the + * passed-in framebuffer. Might take the modeset locks. + * + * Note that this function optimizes the cleanup away if the caller holds the + * last reference to the framebuffer. It is also guaranteed to not take the + * modeset locks in this case. + */ +void drm_framebuffer_remove(struct drm_framebuffer *fb) +{ + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_plane *plane; + + if (!fb) + return; + + dev = fb->dev; + + WARN_ON(!list_empty(&fb->filp_head)); + + /* + * drm ABI mandates that we remove any deleted framebuffers from active + * useage. But since most sane clients only remove framebuffers they no + * longer need, try to optimize this away. + * + * Since we're holding a reference ourselves, observing a refcount of 1 + * means that we're the last holder and can skip it. Also, the refcount + * can never increase from 1 again, so we don't need any barriers or + * locks. + * + * Note that userspace could try to race with use and instate a new + * usage _after_ we've cleared all current ones. End result will be an + * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot + * in this manner. + */ + if (drm_framebuffer_read_refcount(fb) > 1) { + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + if (drm_crtc_force_disable(crtc)) + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + } + } + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } + drm_modeset_unlock_all(dev); + } + + drm_framebuffer_unreference(fb); +} +EXPORT_SYMBOL(drm_framebuffer_remove); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5a7809f029ba..0119161cad57 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -36,10 +36,12 @@ #include #include #include +#include +#include +#include struct drm_device; struct drm_mode_set; -struct drm_framebuffer; struct drm_object_properties; struct drm_file; struct drm_clip_rect; @@ -47,14 +49,6 @@ struct device_node; struct fence; struct edid; -struct drm_mode_object { - uint32_t id; - uint32_t type; - struct drm_object_properties *properties; - struct kref refcount; - void (*free_cb)(struct kref *kref); -}; - #define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { int count, atomic_count; @@ -94,15 +88,6 @@ static inline uint64_t I642U64(int64_t val) #define DRM_REFLECT_Y BIT(5) #define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) -enum drm_connector_force { - DRM_FORCE_UNSPECIFIED, - DRM_FORCE_OFF, - DRM_FORCE_ON, /* force on analog part normally */ - DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ -}; - -#include - enum drm_connector_status { connector_status_connected = 1, connector_status_disconnected = 2, @@ -166,101 +151,6 @@ struct drm_tile_group { u8 group_data[8]; }; -/** - * struct drm_framebuffer_funcs - framebuffer hooks - */ -struct drm_framebuffer_funcs { - /** - * @destroy: - * - * Clean up framebuffer resources, specifically also unreference the - * backing storage. The core guarantees to call this function for every - * framebuffer successfully created by ->fb_create() in - * &drm_mode_config_funcs. Drivers must also call - * drm_framebuffer_cleanup() to release DRM core resources for this - * framebuffer. - */ - void (*destroy)(struct drm_framebuffer *framebuffer); - - /** - * @create_handle: - * - * Create a buffer handle in the driver-specific buffer manager (either - * GEM or TTM) valid for the passed-in struct &drm_file. This is used by - * the core to implement the GETFB IOCTL, which returns (for - * sufficiently priviledged user) also a native buffer handle. This can - * be used for seamless transitions between modesetting clients by - * copying the current screen contents to a private buffer and blending - * between that and the new contents. - * - * GEM based drivers should call drm_gem_handle_create() to create the - * handle. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*create_handle)(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle); - /** - * @dirty: - * - * Optional callback for the dirty fb IOCTL. - * - * Userspace can notify the driver via this callback that an area of the - * framebuffer has changed and should be flushed to the display - * hardware. This can also be used internally, e.g. by the fbdev - * emulation, though that's not the case currently. - * - * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd - * for more information as all the semantics and arguments have a one to - * one mapping on this function. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*dirty)(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, unsigned flags, - unsigned color, struct drm_clip_rect *clips, - unsigned num_clips); -}; - -struct drm_framebuffer { - struct drm_device *dev; - /* - * Note that the fb is refcounted for the benefit of driver internals, - * for example some hw, disabling a CRTC/plane is asynchronous, and - * scanout does not actually complete until the next vblank. So some - * cleanup (like releasing the reference(s) on the backing GEM bo(s)) - * should be deferred. In cases like this, the driver would like to - * hold a ref to the fb even though it has already been removed from - * userspace perspective. - * The refcount is stored inside the mode object. - */ - /* - * Place on the dev->mode_config.fb_list, access protected by - * dev->mode_config.fb_lock. - */ - struct list_head head; - struct drm_mode_object base; - const struct drm_framebuffer_funcs *funcs; - unsigned int pitches[4]; - unsigned int offsets[4]; - uint64_t modifier[4]; - unsigned int width; - unsigned int height; - /* depth can be 15 or 16 */ - unsigned int depth; - int bits_per_pixel; - int flags; - uint32_t pixel_format; /* fourcc format */ - int hot_x; - int hot_y; - struct list_head filp_head; -}; - struct drm_property_blob { struct drm_mode_object base; struct drm_device *dev; @@ -2888,14 +2778,6 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj, extern int drm_object_property_get_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *value); -extern int drm_framebuffer_init(struct drm_device *dev, - struct drm_framebuffer *fb, - const struct drm_framebuffer_funcs *funcs); -extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, - uint32_t id); -extern void drm_framebuffer_remove(struct drm_framebuffer *fb); -extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); -extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); extern void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, @@ -2976,11 +2858,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, unsigned int zpos); /* Helpers */ -struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, - uint32_t id, uint32_t type); -void drm_mode_object_reference(struct drm_mode_object *obj); -void drm_mode_object_unreference(struct drm_mode_object *obj); - static inline struct drm_plane *drm_plane_find(struct drm_device *dev, uint32_t id) { @@ -3048,39 +2925,6 @@ static inline uint32_t drm_color_lut_extract(uint32_t user_input, return clamp_val(val, 0, max); } -/** - * drm_framebuffer_reference - incr the fb refcnt - * @fb: framebuffer - * - * This functions increments the fb's refcount. - */ -static inline void drm_framebuffer_reference(struct drm_framebuffer *fb) -{ - drm_mode_object_reference(&fb->base); -} - -/** - * drm_framebuffer_unreference - unref a framebuffer - * @fb: framebuffer to unref - * - * This functions decrements the fb's refcount and frees it if it drops to zero. - */ -static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb) -{ - drm_mode_object_unreference(&fb->base); -} - -/** - * drm_framebuffer_read_refcount - read the framebuffer reference count. - * @fb: framebuffer - * - * This functions returns the framebuffer's reference count. - */ -static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) -{ - return atomic_read(&fb->base.refcount.refcount); -} - /** * drm_connector_reference - incr the connector refcnt * @connector: connector diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h new file mode 100644 index 000000000000..46abdace8fa5 --- /dev/null +++ b/include/drm/drm_framebuffer.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_FRAMEBUFFER_H__ +#define __DRM_FRAMEBUFFER_H__ + +#include +#include +#include + +struct drm_framebuffer; +struct drm_file; +struct drm_device; + +/** + * struct drm_framebuffer_funcs - framebuffer hooks + */ +struct drm_framebuffer_funcs { + /** + * @destroy: + * + * Clean up framebuffer resources, specifically also unreference the + * backing storage. The core guarantees to call this function for every + * framebuffer successfully created by ->fb_create() in + * &drm_mode_config_funcs. Drivers must also call + * drm_framebuffer_cleanup() to release DRM core resources for this + * framebuffer. + */ + void (*destroy)(struct drm_framebuffer *framebuffer); + + /** + * @create_handle: + * + * Create a buffer handle in the driver-specific buffer manager (either + * GEM or TTM) valid for the passed-in struct &drm_file. This is used by + * the core to implement the GETFB IOCTL, which returns (for + * sufficiently priviledged user) also a native buffer handle. This can + * be used for seamless transitions between modesetting clients by + * copying the current screen contents to a private buffer and blending + * between that and the new contents. + * + * GEM based drivers should call drm_gem_handle_create() to create the + * handle. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*create_handle)(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle); + /** + * @dirty: + * + * Optional callback for the dirty fb IOCTL. + * + * Userspace can notify the driver via this callback that an area of the + * framebuffer has changed and should be flushed to the display + * hardware. This can also be used internally, e.g. by the fbdev + * emulation, though that's not the case currently. + * + * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd + * for more information as all the semantics and arguments have a one to + * one mapping on this function. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*dirty)(struct drm_framebuffer *framebuffer, + struct drm_file *file_priv, unsigned flags, + unsigned color, struct drm_clip_rect *clips, + unsigned num_clips); +}; + +struct drm_framebuffer { + struct drm_device *dev; + /* + * Note that the fb is refcounted for the benefit of driver internals, + * for example some hw, disabling a CRTC/plane is asynchronous, and + * scanout does not actually complete until the next vblank. So some + * cleanup (like releasing the reference(s) on the backing GEM bo(s)) + * should be deferred. In cases like this, the driver would like to + * hold a ref to the fb even though it has already been removed from + * userspace perspective. + * The refcount is stored inside the mode object. + */ + /* + * Place on the dev->mode_config.fb_list, access protected by + * dev->mode_config.fb_lock. + */ + struct list_head head; + struct drm_mode_object base; + const struct drm_framebuffer_funcs *funcs; + unsigned int pitches[4]; + unsigned int offsets[4]; + uint64_t modifier[4]; + unsigned int width; + unsigned int height; + /* depth can be 15 or 16 */ + unsigned int depth; + int bits_per_pixel; + int flags; + uint32_t pixel_format; /* fourcc format */ + int hot_x; + int hot_y; + struct list_head filp_head; +}; + +int drm_framebuffer_init(struct drm_device *dev, + struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs); +struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id); +void drm_framebuffer_remove(struct drm_framebuffer *fb); +void drm_framebuffer_cleanup(struct drm_framebuffer *fb); +void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); + +/** + * drm_framebuffer_reference - incr the fb refcnt + * @fb: framebuffer + * + * This functions increments the fb's refcount. + */ +static inline void drm_framebuffer_reference(struct drm_framebuffer *fb) +{ + drm_mode_object_reference(&fb->base); +} + +/** + * drm_framebuffer_unreference - unref a framebuffer + * @fb: framebuffer to unref + * + * This functions decrements the fb's refcount and frees it if it drops to zero. + */ +static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + drm_mode_object_unreference(&fb->base); +} + +/** + * drm_framebuffer_read_refcount - read the framebuffer reference count. + * @fb: framebuffer + * + * This functions returns the framebuffer's reference count. + */ +static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) +{ + return atomic_read(&fb->base.refcount.refcount); +} +#endif diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 48e1a56ea283..fed9fe81590c 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -27,6 +27,8 @@ #ifndef __DRM_MODES_H__ #define __DRM_MODES_H__ +#include + /* * Note on terminology: here, for brevity and convenience, we refer to connector * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, diff --git a/include/drm/drm_modeset.h b/include/drm/drm_modeset.h new file mode 100644 index 000000000000..0c2b0f3c5f34 --- /dev/null +++ b/include/drm/drm_modeset.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_MODESET_H__ +#define __DRM_MODESET_H__ + +#include +struct drm_object_properties; + +struct drm_mode_object { + uint32_t id; + uint32_t type; + struct drm_object_properties *properties; + struct kref refcount; + void (*free_cb)(struct kref *kref); +}; + +struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type); +void drm_mode_object_reference(struct drm_mode_object *obj); +void drm_mode_object_unreference(struct drm_mode_object *obj); + +/* FIXME: This is temporary until we have a drm_connector.h */ +enum drm_connector_force { + DRM_FORCE_UNSPECIFIED, + DRM_FORCE_OFF, + DRM_FORCE_ON, /* force on analog part normally */ + DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ +}; + +#endif From 750fb8c439bcaa2752d717503119f66032a22b76 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:48 +0200 Subject: [PATCH 17/46] drm/doc: Update drm_framebuffer docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move the intro section into a DOC comment, and update it slightly. - kernel-doc for struct drm_framebuffer! v2: - Copypaste fail (Sean). - Explain the linear @offsets clearer (Ville). Cc: Sean Paul Cc: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-12-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 26 +------- drivers/gpu/drm/drm_framebuffer.c | 35 ++++++++++ include/drm/drm_framebuffer.h | 106 ++++++++++++++++++++++++++---- 3 files changed, 130 insertions(+), 37 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 8264a88a8695..d244e03658cc 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -39,30 +39,8 @@ Atomic Mode Setting Function Reference Frame Buffer Abstraction ======================== -Frame buffers are abstract memory objects that provide a source of -pixels to scanout to a CRTC. Applications explicitly request the -creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls -and receive an opaque handle that can be passed to the KMS CRTC control, -plane configuration and page flip functions. - -Frame buffers rely on the underneath memory manager for low-level memory -operations. When creating a frame buffer applications pass a memory -handle (or a list of memory handles for multi-planar formats) through -the ``drm_mode_fb_cmd2`` argument. For drivers using GEM as their -userspace buffer management interface this would be a GEM handle. -Drivers are however free to use their own backing storage object -handles, e.g. vmwgfx directly exposes special TTM handles to userspace -and so expects TTM handles in the create ioctl and not GEM handles. - -The lifetime of a drm framebuffer is controlled with a reference count, -drivers can grab additional references with -:c:func:`drm_framebuffer_reference()`and drop them again with -:c:func:`drm_framebuffer_unreference()`. For driver-private -framebuffers for which the last reference is never dropped (e.g. for the -fbdev framebuffer when the struct :c:type:`struct drm_framebuffer -` is embedded into the fbdev helper struct) -drivers can manually clean up a framebuffer at module unload time with -:c:func:`drm_framebuffer_unregister_private()`. +.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c + :doc: overview Frame Buffer Functions Reference -------------------------------- diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 74572c8a50b8..30dc01e6eb5d 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -27,6 +27,41 @@ #include "drm_crtc_internal.h" +/** + * DOC: overview + * + * Frame buffers are abstract memory objects that provide a source of pixels to + * scanout to a CRTC. Applications explicitly request the creation of frame + * buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and receive an opaque + * handle that can be passed to the KMS CRTC control, plane configuration and + * page flip functions. + * + * Frame buffers rely on the underlying memory manager for allocating backing + * storage. When creating a frame buffer applications pass a memory handle + * (or a list of memory handles for multi-planar formats) through the + * struct &drm_mode_fb_cmd2 argument. For drivers using GEM as their userspace + * buffer management interface this would be a GEM handle. Drivers are however + * free to use their own backing storage object handles, e.g. vmwgfx directly + * exposes special TTM handles to userspace and so expects TTM handles in the + * create ioctl and not GEM handles. + * + * Framebuffers are tracked with struct &drm_framebuffer. They are published + * using drm_framebuffer_init() - after calling that function userspace can use + * and access the framebuffer object. The helper function + * drm_helper_mode_fill_fb_struct() can be used to pre-fill the required + * metadata fields. + * + * The lifetime of a drm framebuffer is controlled with a reference count, + * drivers can grab additional references with drm_framebuffer_reference() and + * drop them again with drm_framebuffer_unreference(). For driver-private + * framebuffers for which the last reference is never dropped (e.g. for the + * fbdev framebuffer when the struct struct &drm_framebuffer is embedded into + * the fbdev helper struct) drivers can manually clean up a framebuffer at + * module unload time with drm_framebuffer_unregister_private(). But doing this + * is not recommended, and it's better to have a normal free-standing struct + * &drm_framebuffer. + */ + /** * drm_mode_addfb - add an FB to the graphics configuration * @dev: drm device for the ioctl diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 46abdace8fa5..50deb40d3bfd 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -92,37 +92,117 @@ struct drm_framebuffer_funcs { unsigned num_clips); }; +/** + * struct drm_framebuffer - frame buffer object + * + * Note that the fb is refcounted for the benefit of driver internals, + * for example some hw, disabling a CRTC/plane is asynchronous, and + * scanout does not actually complete until the next vblank. So some + * cleanup (like releasing the reference(s) on the backing GEM bo(s)) + * should be deferred. In cases like this, the driver would like to + * hold a ref to the fb even though it has already been removed from + * userspace perspective. See drm_framebuffer_reference() and + * drm_framebuffer_unreference(). + * + * The refcount is stored inside the mode object @base. + */ struct drm_framebuffer { - struct drm_device *dev; - /* - * Note that the fb is refcounted for the benefit of driver internals, - * for example some hw, disabling a CRTC/plane is asynchronous, and - * scanout does not actually complete until the next vblank. So some - * cleanup (like releasing the reference(s) on the backing GEM bo(s)) - * should be deferred. In cases like this, the driver would like to - * hold a ref to the fb even though it has already been removed from - * userspace perspective. - * The refcount is stored inside the mode object. + /** + * @dev: DRM device this framebuffer belongs to */ - /* - * Place on the dev->mode_config.fb_list, access protected by + struct drm_device *dev; + /** + * @head: Place on the dev->mode_config.fb_list, access protected by * dev->mode_config.fb_lock. */ struct list_head head; + + /** + * @base: base modeset object structure, contains the reference count. + */ struct drm_mode_object base; + /** + * @funcs: framebuffer vfunc table + */ const struct drm_framebuffer_funcs *funcs; + /** + * @pitches: Line stride per buffer. For userspace created object this + * is copied from drm_mode_fb_cmd2. + */ unsigned int pitches[4]; + /** + * @offsets: Offset from buffer start to the actual pixel data in bytes, + * per buffer. For userspace created object this is copied from + * drm_mode_fb_cmd2. + * + * Note that this is a linear offset and does not take into account + * tiling or buffer laytou per @modifier. It meant to be used when the + * actual pixel data for this framebuffer plane starts at an offset, + * e.g. when multiple planes are allocated within the same backing + * storage buffer object. For tiled layouts this generally means it + * @offsets must at least be tile-size aligned, but hardware often has + * stricter requirements. + * + * This should not be used to specifiy x/y pixel offsets into the buffer + * data (even for linear buffers). Specifying an x/y pixel offset is + * instead done through the source rectangle in struct &drm_plane_state. + */ unsigned int offsets[4]; + /** + * @modifier: Data layout modifier, per buffer. This is used to describe + * tiling, or also special layouts (like compression) of auxiliary + * buffers. For userspace created object this is copied from + * drm_mode_fb_cmd2. + */ uint64_t modifier[4]; + /** + * @width: Logical width of the visible area of the framebuffer, in + * pixels. + */ unsigned int width; + /** + * @height: Logical height of the visible area of the framebuffer, in + * pixels. + */ unsigned int height; - /* depth can be 15 or 16 */ + /** + * @depth: Depth in bits per pixel for RGB formats. 0 for everything + * else. Legacy information derived from @pixel_format, it's suggested to use + * the DRM FOURCC codes and helper functions directly instead. + */ unsigned int depth; + /** + * @bits_per_pixel: Storage used bits per pixel for RGB formats. 0 for + * everything else. Legacy information derived from @pixel_format, it's + * suggested to use the DRM FOURCC codes and helper functions directly + * instead. + */ int bits_per_pixel; + /** + * @flags: Framebuffer flags like DRM_MODE_FB_INTERLACED or + * DRM_MODE_FB_MODIFIERS. + */ int flags; + /** + * @pixel_format: DRM FOURCC code describing the pixel format. + */ uint32_t pixel_format; /* fourcc format */ + /** + * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor + * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR + * universal plane. + */ int hot_x; + /** + * @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor + * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR + * universal plane. + */ int hot_y; + /** + * @filp_head: Placed on struct &drm_file fbs list_head, protected by + * fbs_lock in the same structure. + */ struct list_head filp_head; }; From cb34d7f2dcf0d3a326ba76fe3a8e72011215dffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 16 Aug 2016 15:34:37 +0200 Subject: [PATCH 18/46] drm: update kerneldoc for changes introduced by commits "16fadc2568e9" and "9671e228fb78" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Describe the new parameter 'bus_flags' to of_get_drm_display_mode() in the kerneldoc comments and add kerneldoc comments to the new function drm_bus_flags_from_videomode(). Signed-off-by: Lothar Waßmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471354477-25877-1-git-send-email-LW@KARO-electronics.de --- drivers/gpu/drm/drm_modes.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 15704873fd61..53f07ac7c174 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -657,6 +657,15 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, } EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); +/** + * drm_bus_flags_from_videomode - extract information about pixelclk and + * DE polarity from videomode and store it in a separate variable + * @vm: videomode structure to use + * @bus_flags: information about pixelclk and DE polarity will be stored here + * + * Sets DRM_BUS_FLAG_DE_(LOW|HIGH) and DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE + * in @bus_flags according to DISPLAY_FLAGS found in @vm + */ void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags) { *bus_flags = 0; @@ -677,6 +686,7 @@ EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode); * of_get_drm_display_mode - get a drm_display_mode from devicetree * @np: device_node with the timing specification * @dmode: will be set to the return value + * @bus_flags: information about pixelclk and DE polarity * @index: index into the list of display timings in devicetree * * This function is expensive and should only be used, if only one mode is to be From adebd6fe9f0b75e5466cd6e559cd4339b037440f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:49 +0200 Subject: [PATCH 19/46] drm: Export drm_property_replace_global_blob It's really part of the core blob interface, and the drm_connector.c extraction needs it too. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-13-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 13 +++++++------ include/drm/drm_crtc.h | 6 ++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d596a491b517..d0d6cd51843d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3761,12 +3761,12 @@ EXPORT_SYMBOL(drm_property_lookup_blob); * a completely atomic update. The access to path_blob_ptr is protected by the * caller holding a lock on the connector. */ -static int drm_property_replace_global_blob(struct drm_device *dev, - struct drm_property_blob **replace, - size_t length, - const void *data, - struct drm_mode_object *obj_holds_id, - struct drm_property *prop_holds_id) +int drm_property_replace_global_blob(struct drm_device *dev, + struct drm_property_blob **replace, + size_t length, + const void *data, + struct drm_mode_object *obj_holds_id, + struct drm_property *prop_holds_id) { struct drm_property_blob *new_blob = NULL; struct drm_property_blob *old_blob = NULL; @@ -3805,6 +3805,7 @@ static int drm_property_replace_global_blob(struct drm_device *dev, drm_property_unreference_blob(new_blob); return ret; } +EXPORT_SYMBOL(drm_property_replace_global_blob); /** * drm_mode_getblob_ioctl - get the contents of a blob property value diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0119161cad57..f4d041800551 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2808,6 +2808,12 @@ struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, const void *data); struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, uint32_t id); +int drm_property_replace_global_blob(struct drm_device *dev, + struct drm_property_blob **replace, + size_t length, + const void *data, + struct drm_mode_object *obj_holds_id, + struct drm_property *prop_holds_id); struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob); void drm_property_unreference_blob(struct drm_property_blob *blob); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); From 522171951761153172c75b94ae1f4bc9ab631745 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:50 +0200 Subject: [PATCH 20/46] drm: Extract drm_connector.[hc] Pulls in quite a lot of connector related structures (cmdline mode, force/status enums, display info), but I think that all makes perfect sense. Also had to move a few more core kms object stuff into drm_modeset.h. And as a first cleanup remove the kerneldoc for the 2 connector IOCTL - DRM core docs are aimed at drivers, no point documenting internal in excruciating detail. v2: And also pull in all the connector property code. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-14-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 9 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_connector.c | 1058 +++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 1110 +-------------------------- drivers/gpu/drm/drm_crtc_internal.h | 26 +- include/drm/drm_connector.h | 644 ++++++++++++++++ include/drm/drm_crtc.h | 601 +-------------- include/drm/drm_modes.h | 16 +- include/drm/drm_modeset.h | 36 +- 9 files changed, 1773 insertions(+), 1729 deletions(-) create mode 100644 drivers/gpu/drm/drm_connector.c create mode 100644 include/drm/drm_connector.h diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index d244e03658cc..449acc2517c7 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -110,6 +110,15 @@ Display Modes Function Reference .. kernel-doc:: drivers/gpu/drm/drm_modes.c :export: +Connector Display Sink Abstraction +================================== + +.. kernel-doc:: include/drm/drm_connector.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_connector.c + :export: + KMS Initialization and Cleanup ============================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index c71ec42ce511..2eff1a33ab63 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -13,7 +13,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ - drm_framebuffer.o + drm_framebuffer.o drm_connector.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c new file mode 100644 index 000000000000..99ece6758061 --- /dev/null +++ b/drivers/gpu/drm/drm_connector.c @@ -0,0 +1,1058 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "drm_crtc_internal.h" +#include "drm_internal.h" + +struct drm_conn_prop_enum_list { + int type; + const char *name; + struct ida ida; +}; + +/* + * Connector and encoder types. + */ +static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { + { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "eDP" }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, + { DRM_MODE_CONNECTOR_DSI, "DSI" }, + { DRM_MODE_CONNECTOR_DPI, "DPI" }, +}; + +void drm_connector_ida_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) + ida_init(&drm_connector_enum_list[i].ida); +} + +void drm_connector_ida_destroy(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) + ida_destroy(&drm_connector_enum_list[i].ida); +} + +/** + * drm_connector_get_cmdline_mode - reads the user's cmdline mode + * @connector: connector to quwery + * + * The kernel supports per-connector configration of its consoles through + * use of the video= parameter. This function parses that option and + * extracts the user's specified mode (or enable/disable status) for a + * particular connector. This is typically only used during the early fbdev + * setup. + */ +static void drm_connector_get_cmdline_mode(struct drm_connector *connector) +{ + struct drm_cmdline_mode *mode = &connector->cmdline_mode; + char *option = NULL; + + if (fb_get_options(connector->name, &option)) + return; + + if (!drm_mode_parse_command_line_for_connector(option, + connector, + mode)) + return; + + if (mode->force) { + const char *s; + + switch (mode->force) { + case DRM_FORCE_OFF: + s = "OFF"; + break; + case DRM_FORCE_ON_DIGITAL: + s = "ON - dig"; + break; + default: + case DRM_FORCE_ON: + s = "ON"; + break; + } + + DRM_INFO("forcing %s connector %s\n", connector->name, s); + connector->force = mode->force; + } + + DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", + connector->name, + mode->xres, mode->yres, + mode->refresh_specified ? mode->refresh : 60, + mode->rb ? " reduced blanking" : "", + mode->margins ? " with margins" : "", + mode->interlace ? " interlaced" : ""); +} + +static void drm_connector_free(struct kref *kref) +{ + struct drm_connector *connector = + container_of(kref, struct drm_connector, base.refcount); + struct drm_device *dev = connector->dev; + + drm_mode_object_unregister(dev, &connector->base); + connector->funcs->destroy(connector); +} + +/** + * drm_connector_init - Init a preallocated connector + * @dev: DRM device + * @connector: the connector to init + * @funcs: callbacks for this connector + * @connector_type: user visible type of the connector + * + * Initialises a preallocated connector. Connectors should be + * subclassed as part of driver connector objects. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type) +{ + struct drm_mode_config *config = &dev->mode_config; + int ret; + struct ida *connector_ida = + &drm_connector_enum_list[connector_type].ida; + + drm_modeset_lock_all(dev); + + ret = drm_mode_object_get_reg(dev, &connector->base, + DRM_MODE_OBJECT_CONNECTOR, + false, drm_connector_free); + if (ret) + goto out_unlock; + + connector->base.properties = &connector->properties; + connector->dev = dev; + connector->funcs = funcs; + + ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); + if (ret < 0) + goto out_put; + connector->index = ret; + ret = 0; + + connector->connector_type = connector_type; + connector->connector_type_id = + ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); + if (connector->connector_type_id < 0) { + ret = connector->connector_type_id; + goto out_put_id; + } + connector->name = + kasprintf(GFP_KERNEL, "%s-%d", + drm_connector_enum_list[connector_type].name, + connector->connector_type_id); + if (!connector->name) { + ret = -ENOMEM; + goto out_put_type_id; + } + + INIT_LIST_HEAD(&connector->probed_modes); + INIT_LIST_HEAD(&connector->modes); + connector->edid_blob_ptr = NULL; + connector->status = connector_status_unknown; + + drm_connector_get_cmdline_mode(connector); + + /* We should add connectors at the end to avoid upsetting the connector + * index too much. */ + list_add_tail(&connector->head, &config->connector_list); + config->num_connector++; + + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) + drm_object_attach_property(&connector->base, + config->edid_property, + 0); + + drm_object_attach_property(&connector->base, + config->dpms_property, 0); + + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); + } + + connector->debugfs_entry = NULL; +out_put_type_id: + if (ret) + ida_remove(connector_ida, connector->connector_type_id); +out_put_id: + if (ret) + ida_remove(&config->connector_ida, connector->index); +out_put: + if (ret) + drm_mode_object_unregister(dev, &connector->base); + +out_unlock: + drm_modeset_unlock_all(dev); + + return ret; +} +EXPORT_SYMBOL(drm_connector_init); + +/** + * drm_mode_connector_attach_encoder - attach a connector to an encoder + * @connector: connector to attach + * @encoder: encoder to attach @connector to + * + * This function links up a connector to an encoder. Note that the routing + * restrictions between encoders and crtcs are exposed to userspace through the + * possible_clones and possible_crtcs bitmasks. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_connector_attach_encoder(struct drm_connector *connector, + struct drm_encoder *encoder) +{ + int i; + + /* + * In the past, drivers have attempted to model the static association + * of connector to encoder in simple connector/encoder devices using a + * direct assignment of connector->encoder = encoder. This connection + * is a logical one and the responsibility of the core, so drivers are + * expected not to mess with this. + * + * Note that the error return should've been enough here, but a large + * majority of drivers ignores the return value, so add in a big WARN + * to get people's attention. + */ + if (WARN_ON(connector->encoder)) + return -EINVAL; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) { + connector->encoder_ids[i] = encoder->base.id; + return 0; + } + } + return -ENOMEM; +} +EXPORT_SYMBOL(drm_mode_connector_attach_encoder); + +static void drm_mode_remove(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + list_del(&mode->head); + drm_mode_destroy(connector->dev, mode); +} + +/** + * drm_connector_cleanup - cleans up an initialised connector + * @connector: connector to cleanup + * + * Cleans up the connector but doesn't free the object. + */ +void drm_connector_cleanup(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode, *t; + + /* The connector should have been removed from userspace long before + * it is finally destroyed. + */ + if (WARN_ON(connector->registered)) + drm_connector_unregister(connector); + + if (connector->tile_group) { + drm_mode_put_tile_group(dev, connector->tile_group); + connector->tile_group = NULL; + } + + list_for_each_entry_safe(mode, t, &connector->probed_modes, head) + drm_mode_remove(connector, mode); + + list_for_each_entry_safe(mode, t, &connector->modes, head) + drm_mode_remove(connector, mode); + + ida_remove(&drm_connector_enum_list[connector->connector_type].ida, + connector->connector_type_id); + + ida_remove(&dev->mode_config.connector_ida, + connector->index); + + kfree(connector->display_info.bus_formats); + drm_mode_object_unregister(dev, &connector->base); + kfree(connector->name); + connector->name = NULL; + list_del(&connector->head); + dev->mode_config.num_connector--; + + WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); + if (connector->state && connector->funcs->atomic_destroy_state) + connector->funcs->atomic_destroy_state(connector, + connector->state); + + memset(connector, 0, sizeof(*connector)); +} +EXPORT_SYMBOL(drm_connector_cleanup); + +/** + * drm_connector_register - register a connector + * @connector: the connector to register + * + * Register userspace interfaces for a connector + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_connector_register(struct drm_connector *connector) +{ + int ret; + + if (connector->registered) + return 0; + + ret = drm_sysfs_connector_add(connector); + if (ret) + return ret; + + ret = drm_debugfs_connector_add(connector); + if (ret) { + goto err_sysfs; + } + + if (connector->funcs->late_register) { + ret = connector->funcs->late_register(connector); + if (ret) + goto err_debugfs; + } + + drm_mode_object_register(connector->dev, &connector->base); + + connector->registered = true; + return 0; + +err_debugfs: + drm_debugfs_connector_remove(connector); +err_sysfs: + drm_sysfs_connector_remove(connector); + return ret; +} +EXPORT_SYMBOL(drm_connector_register); + +/** + * drm_connector_unregister - unregister a connector + * @connector: the connector to unregister + * + * Unregister userspace interfaces for a connector + */ +void drm_connector_unregister(struct drm_connector *connector) +{ + if (!connector->registered) + return; + + if (connector->funcs->early_unregister) + connector->funcs->early_unregister(connector); + + drm_sysfs_connector_remove(connector); + drm_debugfs_connector_remove(connector); + + connector->registered = false; +} +EXPORT_SYMBOL(drm_connector_unregister); + +void drm_connector_unregister_all(struct drm_device *dev) +{ + struct drm_connector *connector; + + /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_connector_unregister(connector); +} + +int drm_connector_register_all(struct drm_device *dev) +{ + struct drm_connector *connector; + int ret; + + /* FIXME: taking the mode config mutex ends up in a clash with + * fbcon/backlight registration */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + ret = drm_connector_register(connector); + if (ret) + goto err; + } + + return 0; + +err: + mutex_unlock(&dev->mode_config.mutex); + drm_connector_unregister_all(dev); + return ret; +} + +/** + * drm_get_connector_status_name - return a string for connector status + * @status: connector status to compute name of + * + * In contrast to the other drm_get_*_name functions this one here returns a + * const pointer and hence is threadsafe. + */ +const char *drm_get_connector_status_name(enum drm_connector_status status) +{ + if (status == connector_status_connected) + return "connected"; + else if (status == connector_status_disconnected) + return "disconnected"; + else + return "unknown"; +} +EXPORT_SYMBOL(drm_get_connector_status_name); + +static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { + { SubPixelUnknown, "Unknown" }, + { SubPixelHorizontalRGB, "Horizontal RGB" }, + { SubPixelHorizontalBGR, "Horizontal BGR" }, + { SubPixelVerticalRGB, "Vertical RGB" }, + { SubPixelVerticalBGR, "Vertical BGR" }, + { SubPixelNone, "None" }, +}; + +/** + * drm_get_subpixel_order_name - return a string for a given subpixel enum + * @order: enum of subpixel_order + * + * Note you could abuse this and return something out of bounds, but that + * would be a caller error. No unscrubbed user data should make it here. + */ +const char *drm_get_subpixel_order_name(enum subpixel_order order) +{ + return drm_subpixel_enum_list[order].name; +} +EXPORT_SYMBOL(drm_get_subpixel_order_name); + +static const struct drm_prop_enum_list drm_dpms_enum_list[] = { + { DRM_MODE_DPMS_ON, "On" }, + { DRM_MODE_DPMS_STANDBY, "Standby" }, + { DRM_MODE_DPMS_SUSPEND, "Suspend" }, + { DRM_MODE_DPMS_OFF, "Off" } +}; +DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) + +/* Optional connector properties. */ +static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { + { DRM_MODE_SCALE_NONE, "None" }, + { DRM_MODE_SCALE_FULLSCREEN, "Full" }, + { DRM_MODE_SCALE_CENTER, "Center" }, + { DRM_MODE_SCALE_ASPECT, "Full aspect" }, +}; + +static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { + { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, + { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, + { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, +}; + +static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { + { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ +}; +DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) + +static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ +}; +DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, + drm_dvi_i_subconnector_enum_list) + +static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { + { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ +}; +DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) + +static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ +}; +DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, + drm_tv_subconnector_enum_list) + +int drm_connector_create_standard_properties(struct drm_device *dev) +{ + struct drm_property *prop; + + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "EDID", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.edid_property = prop; + + prop = drm_property_create_enum(dev, 0, + "DPMS", drm_dpms_enum_list, + ARRAY_SIZE(drm_dpms_enum_list)); + if (!prop) + return -ENOMEM; + dev->mode_config.dpms_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "PATH", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.path_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "TILE", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.tile_property = prop; + + return 0; +} + +/** + * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties + * @dev: DRM device + * + * Called by a driver the first time a DVI-I connector is made. + */ +int drm_mode_create_dvi_i_properties(struct drm_device *dev) +{ + struct drm_property *dvi_i_selector; + struct drm_property *dvi_i_subconnector; + + if (dev->mode_config.dvi_i_select_subconnector_property) + return 0; + + dvi_i_selector = + drm_property_create_enum(dev, 0, + "select subconnector", + drm_dvi_i_select_enum_list, + ARRAY_SIZE(drm_dvi_i_select_enum_list)); + dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; + + dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, + "subconnector", + drm_dvi_i_subconnector_enum_list, + ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); + dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); + +/** + * drm_create_tv_properties - create TV specific connector properties + * @dev: DRM device + * @num_modes: number of different TV formats (modes) supported + * @modes: array of pointers to strings containing name of each format + * + * Called by a driver's TV initialization routine, this function creates + * the TV specific connector properties for a given device. Caller is + * responsible for allocating a list of format names and passing them to + * this routine. + */ +int drm_mode_create_tv_properties(struct drm_device *dev, + unsigned int num_modes, + const char * const modes[]) +{ + struct drm_property *tv_selector; + struct drm_property *tv_subconnector; + unsigned int i; + + if (dev->mode_config.tv_select_subconnector_property) + return 0; + + /* + * Basic connector properties + */ + tv_selector = drm_property_create_enum(dev, 0, + "select subconnector", + drm_tv_select_enum_list, + ARRAY_SIZE(drm_tv_select_enum_list)); + if (!tv_selector) + goto nomem; + + dev->mode_config.tv_select_subconnector_property = tv_selector; + + tv_subconnector = + drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, + "subconnector", + drm_tv_subconnector_enum_list, + ARRAY_SIZE(drm_tv_subconnector_enum_list)); + if (!tv_subconnector) + goto nomem; + dev->mode_config.tv_subconnector_property = tv_subconnector; + + /* + * Other, TV specific properties: margins & TV modes. + */ + dev->mode_config.tv_left_margin_property = + drm_property_create_range(dev, 0, "left margin", 0, 100); + if (!dev->mode_config.tv_left_margin_property) + goto nomem; + + dev->mode_config.tv_right_margin_property = + drm_property_create_range(dev, 0, "right margin", 0, 100); + if (!dev->mode_config.tv_right_margin_property) + goto nomem; + + dev->mode_config.tv_top_margin_property = + drm_property_create_range(dev, 0, "top margin", 0, 100); + if (!dev->mode_config.tv_top_margin_property) + goto nomem; + + dev->mode_config.tv_bottom_margin_property = + drm_property_create_range(dev, 0, "bottom margin", 0, 100); + if (!dev->mode_config.tv_bottom_margin_property) + goto nomem; + + dev->mode_config.tv_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "mode", num_modes); + if (!dev->mode_config.tv_mode_property) + goto nomem; + + for (i = 0; i < num_modes; i++) + drm_property_add_enum(dev->mode_config.tv_mode_property, i, + i, modes[i]); + + dev->mode_config.tv_brightness_property = + drm_property_create_range(dev, 0, "brightness", 0, 100); + if (!dev->mode_config.tv_brightness_property) + goto nomem; + + dev->mode_config.tv_contrast_property = + drm_property_create_range(dev, 0, "contrast", 0, 100); + if (!dev->mode_config.tv_contrast_property) + goto nomem; + + dev->mode_config.tv_flicker_reduction_property = + drm_property_create_range(dev, 0, "flicker reduction", 0, 100); + if (!dev->mode_config.tv_flicker_reduction_property) + goto nomem; + + dev->mode_config.tv_overscan_property = + drm_property_create_range(dev, 0, "overscan", 0, 100); + if (!dev->mode_config.tv_overscan_property) + goto nomem; + + dev->mode_config.tv_saturation_property = + drm_property_create_range(dev, 0, "saturation", 0, 100); + if (!dev->mode_config.tv_saturation_property) + goto nomem; + + dev->mode_config.tv_hue_property = + drm_property_create_range(dev, 0, "hue", 0, 100); + if (!dev->mode_config.tv_hue_property) + goto nomem; + + return 0; +nomem: + return -ENOMEM; +} +EXPORT_SYMBOL(drm_mode_create_tv_properties); + +/** + * drm_mode_create_scaling_mode_property - create scaling mode property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired + * connectors. + */ +int drm_mode_create_scaling_mode_property(struct drm_device *dev) +{ + struct drm_property *scaling_mode; + + if (dev->mode_config.scaling_mode_property) + return 0; + + scaling_mode = + drm_property_create_enum(dev, 0, "scaling mode", + drm_scaling_mode_enum_list, + ARRAY_SIZE(drm_scaling_mode_enum_list)); + + dev->mode_config.scaling_mode_property = scaling_mode; + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); + +/** + * drm_mode_create_aspect_ratio_property - create aspect ratio property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired + * connectors. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_create_aspect_ratio_property(struct drm_device *dev) +{ + if (dev->mode_config.aspect_ratio_property) + return 0; + + dev->mode_config.aspect_ratio_property = + drm_property_create_enum(dev, 0, "aspect ratio", + drm_aspect_ratio_enum_list, + ARRAY_SIZE(drm_aspect_ratio_enum_list)); + + if (dev->mode_config.aspect_ratio_property == NULL) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); + +/** + * drm_mode_create_suggested_offset_properties - create suggests offset properties + * @dev: DRM device + * + * Create the the suggested x/y offset property for connectors. + */ +int drm_mode_create_suggested_offset_properties(struct drm_device *dev) +{ + if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) + return 0; + + dev->mode_config.suggested_x_property = + drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); + + dev->mode_config.suggested_y_property = + drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); + + if (dev->mode_config.suggested_x_property == NULL || + dev->mode_config.suggested_y_property == NULL) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); + +/** + * drm_mode_connector_set_path_property - set tile property on connector + * @connector: connector to set property on. + * @path: path to use for property; must not be NULL. + * + * This creates a property to expose to userspace to specify a + * connector path. This is mainly used for DisplayPort MST where + * connectors have a topology and we want to allow userspace to give + * them more meaningful names. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_connector_set_path_property(struct drm_connector *connector, + const char *path) +{ + struct drm_device *dev = connector->dev; + int ret; + + ret = drm_property_replace_global_blob(dev, + &connector->path_blob_ptr, + strlen(path) + 1, + path, + &connector->base, + dev->mode_config.path_property); + return ret; +} +EXPORT_SYMBOL(drm_mode_connector_set_path_property); + +/** + * drm_mode_connector_set_tile_property - set tile property on connector + * @connector: connector to set property on. + * + * This looks up the tile information for a connector, and creates a + * property for userspace to parse if it exists. The property is of + * the form of 8 integers using ':' as a separator. + * + * Returns: + * Zero on success, errno on failure. + */ +int drm_mode_connector_set_tile_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + char tile[256]; + int ret; + + if (!connector->has_tile) { + ret = drm_property_replace_global_blob(dev, + &connector->tile_blob_ptr, + 0, + NULL, + &connector->base, + dev->mode_config.tile_property); + return ret; + } + + snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", + connector->tile_group->id, connector->tile_is_single_monitor, + connector->num_h_tile, connector->num_v_tile, + connector->tile_h_loc, connector->tile_v_loc, + connector->tile_h_size, connector->tile_v_size); + + ret = drm_property_replace_global_blob(dev, + &connector->tile_blob_ptr, + strlen(tile) + 1, + tile, + &connector->base, + dev->mode_config.tile_property); + return ret; +} +EXPORT_SYMBOL(drm_mode_connector_set_tile_property); + +/** + * drm_mode_connector_update_edid_property - update the edid property of a connector + * @connector: drm connector + * @edid: new value of the edid property + * + * This function creates a new blob modeset object and assigns its id to the + * connector's edid property. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_connector_update_edid_property(struct drm_connector *connector, + const struct edid *edid) +{ + struct drm_device *dev = connector->dev; + size_t size = 0; + int ret; + + /* ignore requests to set edid when overridden */ + if (connector->override_edid) + return 0; + + if (edid) + size = EDID_LENGTH * (1 + edid->extensions); + + ret = drm_property_replace_global_blob(dev, + &connector->edid_blob_ptr, + size, + edid, + &connector->base, + dev->mode_config.edid_property); + return ret; +} +EXPORT_SYMBOL(drm_mode_connector_update_edid_property); + +int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_connector *connector = obj_to_connector(obj); + + /* Do DPMS ourselves */ + if (property == connector->dev->mode_config.dpms_property) { + ret = (*connector->funcs->dpms)(connector, (int)value); + } else if (connector->funcs->set_property) + ret = connector->funcs->set_property(connector, property, value); + + /* store the property value if successful */ + if (!ret) + drm_object_property_set_value(&connector->base, property, value); + return ret; +} + +int drm_mode_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_connector_set_property *conn_set_prop = data; + struct drm_mode_obj_set_property obj_set_prop = { + .value = conn_set_prop->value, + .prop_id = conn_set_prop->prop_id, + .obj_id = conn_set_prop->connector_id, + .obj_type = DRM_MODE_OBJECT_CONNECTOR + }; + + /* It does all the locking and checking we need */ + return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); +} + +static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) +{ + /* For atomic drivers only state objects are synchronously updated and + * protected by modeset locks, so check those first. */ + if (connector->state) + return connector->state->best_encoder; + return connector->encoder; +} + +static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, + const struct drm_file *file_priv) +{ + /* + * If user-space hasn't configured the driver to expose the stereo 3D + * modes, don't expose them. + */ + if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) + return false; + + return true; +} + +int drm_mode_getconnector(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_connector *out_resp = data; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_display_mode *mode; + int mode_count = 0; + int encoders_count = 0; + int ret = 0; + int copied = 0; + int i; + struct drm_mode_modeinfo u_mode; + struct drm_mode_modeinfo __user *mode_ptr; + uint32_t __user *encoder_ptr; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + + mutex_lock(&dev->mode_config.mutex); + + connector = drm_connector_lookup(dev, out_resp->connector_id); + if (!connector) { + ret = -ENOENT; + goto out_unlock; + } + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) + if (connector->encoder_ids[i] != 0) + encoders_count++; + + if (out_resp->count_modes == 0) { + connector->funcs->fill_modes(connector, + dev->mode_config.max_width, + dev->mode_config.max_height); + } + + /* delayed so we get modes regardless of pre-fill_modes state */ + list_for_each_entry(mode, &connector->modes, head) + if (drm_mode_expose_to_userspace(mode, file_priv)) + mode_count++; + + out_resp->connector_id = connector->base.id; + out_resp->connector_type = connector->connector_type; + out_resp->connector_type_id = connector->connector_type_id; + out_resp->mm_width = connector->display_info.width_mm; + out_resp->mm_height = connector->display_info.height_mm; + out_resp->subpixel = connector->display_info.subpixel_order; + out_resp->connection = connector->status; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + encoder = drm_connector_get_encoder(connector); + if (encoder) + out_resp->encoder_id = encoder->base.id; + else + out_resp->encoder_id = 0; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if ((out_resp->count_modes >= mode_count) && mode_count) { + copied = 0; + mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; + list_for_each_entry(mode, &connector->modes, head) { + if (!drm_mode_expose_to_userspace(mode, file_priv)) + continue; + + drm_mode_convert_to_umode(&u_mode, mode); + if (copy_to_user(mode_ptr + copied, + &u_mode, sizeof(u_mode))) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + out_resp->count_modes = mode_count; + + ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, + (uint32_t __user *)(unsigned long)(out_resp->props_ptr), + (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), + &out_resp->count_props); + if (ret) + goto out; + + if ((out_resp->count_encoders >= encoders_count) && encoders_count) { + copied = 0; + encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] != 0) { + if (put_user(connector->encoder_ids[i], + encoder_ptr + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + } + out_resp->count_encoders = encoders_count; + +out: + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + drm_connector_unreference(connector); +out_unlock: + mutex_unlock(&dev->mode_config.mutex); + + return ret; +} + diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d0d6cd51843d..13f7b13a6f49 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -45,123 +45,15 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -/* Avoid boilerplate. I'm tired of typing. */ -#define DRM_ENUM_NAME_FN(fnname, list) \ - const char *fnname(int val) \ - { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(list); i++) { \ - if (list[i].type == val) \ - return list[i].name; \ - } \ - return "(unknown)"; \ - } - /* * Global properties */ -static const struct drm_prop_enum_list drm_dpms_enum_list[] = { - { DRM_MODE_DPMS_ON, "On" }, - { DRM_MODE_DPMS_STANDBY, "Standby" }, - { DRM_MODE_DPMS_SUSPEND, "Suspend" }, - { DRM_MODE_DPMS_OFF, "Off" } -}; - -DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) - static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, { DRM_PLANE_TYPE_PRIMARY, "Primary" }, { DRM_PLANE_TYPE_CURSOR, "Cursor" }, }; -/* - * Optional properties - */ -static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { - { DRM_MODE_SCALE_NONE, "None" }, - { DRM_MODE_SCALE_FULLSCREEN, "Full" }, - { DRM_MODE_SCALE_CENTER, "Center" }, - { DRM_MODE_SCALE_ASPECT, "Full aspect" }, -}; - -static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { - { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, - { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, - { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, -}; - -/* - * Non-global properties, but "required" for certain connectors. - */ -static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ - { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ - { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ -}; - -DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) - -static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ - { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ - { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ -}; - -DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, - drm_dvi_i_subconnector_enum_list) - -static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ - { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ -}; - -DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) - -static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ - { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ - { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ -}; - -DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, - drm_tv_subconnector_enum_list) - -struct drm_conn_prop_enum_list { - int type; - const char *name; - struct ida ida; -}; - -/* - * Connector and encoder types. - */ -static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { - { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, - { DRM_MODE_CONNECTOR_TV, "TV" }, - { DRM_MODE_CONNECTOR_eDP, "eDP" }, - { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, - { DRM_MODE_CONNECTOR_DSI, "DSI" }, - { DRM_MODE_CONNECTOR_DPI, "DPI" }, -}; - static const struct drm_prop_enum_list drm_encoder_enum_list[] = { { DRM_MODE_ENCODER_NONE, "None" }, { DRM_MODE_ENCODER_DAC, "DAC" }, @@ -174,62 +66,9 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] = { { DRM_MODE_ENCODER_DPI, "DPI" }, }; -static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { - { SubPixelUnknown, "Unknown" }, - { SubPixelHorizontalRGB, "Horizontal RGB" }, - { SubPixelHorizontalBGR, "Horizontal BGR" }, - { SubPixelVerticalRGB, "Vertical RGB" }, - { SubPixelVerticalBGR, "Vertical BGR" }, - { SubPixelNone, "None" }, -}; - -void drm_connector_ida_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) - ida_init(&drm_connector_enum_list[i].ida); -} - -void drm_connector_ida_destroy(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) - ida_destroy(&drm_connector_enum_list[i].ida); -} - -/** - * drm_get_connector_status_name - return a string for connector status - * @status: connector status to compute name of - * - * In contrast to the other drm_get_*_name functions this one here returns a - * const pointer and hence is threadsafe. +/* + * Optional properties */ -const char *drm_get_connector_status_name(enum drm_connector_status status) -{ - if (status == connector_status_connected) - return "connected"; - else if (status == connector_status_disconnected) - return "disconnected"; - else - return "unknown"; -} -EXPORT_SYMBOL(drm_get_connector_status_name); - -/** - * drm_get_subpixel_order_name - return a string for a given subpixel enum - * @order: enum of subpixel_order - * - * Note you could abuse this and return something out of bounds, but that - * would be a caller error. No unscrubbed user data should make it here. - */ -const char *drm_get_subpixel_order_name(enum subpixel_order order) -{ - return drm_subpixel_enum_list[order].name; -} -EXPORT_SYMBOL(drm_get_subpixel_order_name); - /* * Internal function to assign a slot in the object idr and optionally * register the object into the idr. @@ -580,20 +419,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -/* - * drm_mode_remove - remove and free a mode - * @connector: connector list to modify - * @mode: mode to remove - * - * Remove @mode from @connector's mode list, then free it. - */ -static void drm_mode_remove(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - list_del(&mode->head); - drm_mode_destroy(connector->dev, mode); -} - /** * drm_display_info_set_bus_formats - set the supported bus formats * @info: display info to store bus formats in @@ -628,312 +453,6 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, } EXPORT_SYMBOL(drm_display_info_set_bus_formats); -/** - * drm_connector_get_cmdline_mode - reads the user's cmdline mode - * @connector: connector to quwery - * - * The kernel supports per-connector configration of its consoles through - * use of the video= parameter. This function parses that option and - * extracts the user's specified mode (or enable/disable status) for a - * particular connector. This is typically only used during the early fbdev - * setup. - */ -static void drm_connector_get_cmdline_mode(struct drm_connector *connector) -{ - struct drm_cmdline_mode *mode = &connector->cmdline_mode; - char *option = NULL; - - if (fb_get_options(connector->name, &option)) - return; - - if (!drm_mode_parse_command_line_for_connector(option, - connector, - mode)) - return; - - if (mode->force) { - const char *s; - - switch (mode->force) { - case DRM_FORCE_OFF: - s = "OFF"; - break; - case DRM_FORCE_ON_DIGITAL: - s = "ON - dig"; - break; - default: - case DRM_FORCE_ON: - s = "ON"; - break; - } - - DRM_INFO("forcing %s connector %s\n", connector->name, s); - connector->force = mode->force; - } - - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", - connector->name, - mode->xres, mode->yres, - mode->refresh_specified ? mode->refresh : 60, - mode->rb ? " reduced blanking" : "", - mode->margins ? " with margins" : "", - mode->interlace ? " interlaced" : ""); -} - -static void drm_connector_free(struct kref *kref) -{ - struct drm_connector *connector = - container_of(kref, struct drm_connector, base.refcount); - struct drm_device *dev = connector->dev; - - drm_mode_object_unregister(dev, &connector->base); - connector->funcs->destroy(connector); -} - -/** - * drm_connector_init - Init a preallocated connector - * @dev: DRM device - * @connector: the connector to init - * @funcs: callbacks for this connector - * @connector_type: user visible type of the connector - * - * Initialises a preallocated connector. Connectors should be - * subclassed as part of driver connector objects. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_connector_init(struct drm_device *dev, - struct drm_connector *connector, - const struct drm_connector_funcs *funcs, - int connector_type) -{ - struct drm_mode_config *config = &dev->mode_config; - int ret; - struct ida *connector_ida = - &drm_connector_enum_list[connector_type].ida; - - drm_modeset_lock_all(dev); - - ret = drm_mode_object_get_reg(dev, &connector->base, - DRM_MODE_OBJECT_CONNECTOR, - false, drm_connector_free); - if (ret) - goto out_unlock; - - connector->base.properties = &connector->properties; - connector->dev = dev; - connector->funcs = funcs; - - ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); - if (ret < 0) - goto out_put; - connector->index = ret; - ret = 0; - - connector->connector_type = connector_type; - connector->connector_type_id = - ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); - if (connector->connector_type_id < 0) { - ret = connector->connector_type_id; - goto out_put_id; - } - connector->name = - kasprintf(GFP_KERNEL, "%s-%d", - drm_connector_enum_list[connector_type].name, - connector->connector_type_id); - if (!connector->name) { - ret = -ENOMEM; - goto out_put_type_id; - } - - INIT_LIST_HEAD(&connector->probed_modes); - INIT_LIST_HEAD(&connector->modes); - connector->edid_blob_ptr = NULL; - connector->status = connector_status_unknown; - - drm_connector_get_cmdline_mode(connector); - - /* We should add connectors at the end to avoid upsetting the connector - * index too much. */ - list_add_tail(&connector->head, &config->connector_list); - config->num_connector++; - - if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) - drm_object_attach_property(&connector->base, - config->edid_property, - 0); - - drm_object_attach_property(&connector->base, - config->dpms_property, 0); - - if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { - drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); - } - - connector->debugfs_entry = NULL; -out_put_type_id: - if (ret) - ida_remove(connector_ida, connector->connector_type_id); -out_put_id: - if (ret) - ida_remove(&config->connector_ida, connector->index); -out_put: - if (ret) - drm_mode_object_unregister(dev, &connector->base); - -out_unlock: - drm_modeset_unlock_all(dev); - - return ret; -} -EXPORT_SYMBOL(drm_connector_init); - -/** - * drm_connector_cleanup - cleans up an initialised connector - * @connector: connector to cleanup - * - * Cleans up the connector but doesn't free the object. - */ -void drm_connector_cleanup(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode, *t; - - /* The connector should have been removed from userspace long before - * it is finally destroyed. - */ - if (WARN_ON(connector->registered)) - drm_connector_unregister(connector); - - if (connector->tile_group) { - drm_mode_put_tile_group(dev, connector->tile_group); - connector->tile_group = NULL; - } - - list_for_each_entry_safe(mode, t, &connector->probed_modes, head) - drm_mode_remove(connector, mode); - - list_for_each_entry_safe(mode, t, &connector->modes, head) - drm_mode_remove(connector, mode); - - ida_remove(&drm_connector_enum_list[connector->connector_type].ida, - connector->connector_type_id); - - ida_remove(&dev->mode_config.connector_ida, - connector->index); - - kfree(connector->display_info.bus_formats); - drm_mode_object_unregister(dev, &connector->base); - kfree(connector->name); - connector->name = NULL; - list_del(&connector->head); - dev->mode_config.num_connector--; - - WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); - if (connector->state && connector->funcs->atomic_destroy_state) - connector->funcs->atomic_destroy_state(connector, - connector->state); - - memset(connector, 0, sizeof(*connector)); -} -EXPORT_SYMBOL(drm_connector_cleanup); - -/** - * drm_connector_register - register a connector - * @connector: the connector to register - * - * Register userspace interfaces for a connector - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_connector_register(struct drm_connector *connector) -{ - int ret; - - if (connector->registered) - return 0; - - ret = drm_sysfs_connector_add(connector); - if (ret) - return ret; - - ret = drm_debugfs_connector_add(connector); - if (ret) { - goto err_sysfs; - } - - if (connector->funcs->late_register) { - ret = connector->funcs->late_register(connector); - if (ret) - goto err_debugfs; - } - - drm_mode_object_register(connector->dev, &connector->base); - - connector->registered = true; - return 0; - -err_debugfs: - drm_debugfs_connector_remove(connector); -err_sysfs: - drm_sysfs_connector_remove(connector); - return ret; -} -EXPORT_SYMBOL(drm_connector_register); - -/** - * drm_connector_unregister - unregister a connector - * @connector: the connector to unregister - * - * Unregister userspace interfaces for a connector - */ -void drm_connector_unregister(struct drm_connector *connector) -{ - if (!connector->registered) - return; - - if (connector->funcs->early_unregister) - connector->funcs->early_unregister(connector); - - drm_sysfs_connector_remove(connector); - drm_debugfs_connector_remove(connector); - - connector->registered = false; -} -EXPORT_SYMBOL(drm_connector_unregister); - -static void drm_connector_unregister_all(struct drm_device *dev) -{ - struct drm_connector *connector; - - /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - drm_connector_unregister(connector); -} - -static int drm_connector_register_all(struct drm_device *dev) -{ - struct drm_connector *connector; - int ret; - - /* FIXME: taking the mode config mutex ends up in a clash with - * fbcon/backlight registration */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - ret = drm_connector_register(connector); - if (ret) - goto err; - } - - return 0; - -err: - mutex_unlock(&dev->mode_config.mutex); - drm_connector_unregister_all(dev); - return ret; -} - static int drm_encoder_register_all(struct drm_device *dev) { struct drm_encoder *encoder; @@ -1337,39 +856,11 @@ void drm_modeset_unregister_all(struct drm_device *dev) static int drm_mode_create_standard_properties(struct drm_device *dev) { struct drm_property *prop; + int ret; - /* - * Standard properties (apply to all connectors) - */ - prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | - DRM_MODE_PROP_IMMUTABLE, - "EDID", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.edid_property = prop; - - prop = drm_property_create_enum(dev, 0, - "DPMS", drm_dpms_enum_list, - ARRAY_SIZE(drm_dpms_enum_list)); - if (!prop) - return -ENOMEM; - dev->mode_config.dpms_property = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_BLOB | - DRM_MODE_PROP_IMMUTABLE, - "PATH", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.path_property = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_BLOB | - DRM_MODE_PROP_IMMUTABLE, - "TILE", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.tile_property = prop; + ret = drm_connector_create_standard_properties(dev); + if (ret) + return ret; prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, "type", drm_plane_type_enum_list, @@ -1489,225 +980,6 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return 0; } -/** - * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties - * @dev: DRM device - * - * Called by a driver the first time a DVI-I connector is made. - */ -int drm_mode_create_dvi_i_properties(struct drm_device *dev) -{ - struct drm_property *dvi_i_selector; - struct drm_property *dvi_i_subconnector; - - if (dev->mode_config.dvi_i_select_subconnector_property) - return 0; - - dvi_i_selector = - drm_property_create_enum(dev, 0, - "select subconnector", - drm_dvi_i_select_enum_list, - ARRAY_SIZE(drm_dvi_i_select_enum_list)); - dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; - - dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, - "subconnector", - drm_dvi_i_subconnector_enum_list, - ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); - dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; - - return 0; -} -EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); - -/** - * drm_create_tv_properties - create TV specific connector properties - * @dev: DRM device - * @num_modes: number of different TV formats (modes) supported - * @modes: array of pointers to strings containing name of each format - * - * Called by a driver's TV initialization routine, this function creates - * the TV specific connector properties for a given device. Caller is - * responsible for allocating a list of format names and passing them to - * this routine. - */ -int drm_mode_create_tv_properties(struct drm_device *dev, - unsigned int num_modes, - const char * const modes[]) -{ - struct drm_property *tv_selector; - struct drm_property *tv_subconnector; - unsigned int i; - - if (dev->mode_config.tv_select_subconnector_property) - return 0; - - /* - * Basic connector properties - */ - tv_selector = drm_property_create_enum(dev, 0, - "select subconnector", - drm_tv_select_enum_list, - ARRAY_SIZE(drm_tv_select_enum_list)); - if (!tv_selector) - goto nomem; - - dev->mode_config.tv_select_subconnector_property = tv_selector; - - tv_subconnector = - drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, - "subconnector", - drm_tv_subconnector_enum_list, - ARRAY_SIZE(drm_tv_subconnector_enum_list)); - if (!tv_subconnector) - goto nomem; - dev->mode_config.tv_subconnector_property = tv_subconnector; - - /* - * Other, TV specific properties: margins & TV modes. - */ - dev->mode_config.tv_left_margin_property = - drm_property_create_range(dev, 0, "left margin", 0, 100); - if (!dev->mode_config.tv_left_margin_property) - goto nomem; - - dev->mode_config.tv_right_margin_property = - drm_property_create_range(dev, 0, "right margin", 0, 100); - if (!dev->mode_config.tv_right_margin_property) - goto nomem; - - dev->mode_config.tv_top_margin_property = - drm_property_create_range(dev, 0, "top margin", 0, 100); - if (!dev->mode_config.tv_top_margin_property) - goto nomem; - - dev->mode_config.tv_bottom_margin_property = - drm_property_create_range(dev, 0, "bottom margin", 0, 100); - if (!dev->mode_config.tv_bottom_margin_property) - goto nomem; - - dev->mode_config.tv_mode_property = - drm_property_create(dev, DRM_MODE_PROP_ENUM, - "mode", num_modes); - if (!dev->mode_config.tv_mode_property) - goto nomem; - - for (i = 0; i < num_modes; i++) - drm_property_add_enum(dev->mode_config.tv_mode_property, i, - i, modes[i]); - - dev->mode_config.tv_brightness_property = - drm_property_create_range(dev, 0, "brightness", 0, 100); - if (!dev->mode_config.tv_brightness_property) - goto nomem; - - dev->mode_config.tv_contrast_property = - drm_property_create_range(dev, 0, "contrast", 0, 100); - if (!dev->mode_config.tv_contrast_property) - goto nomem; - - dev->mode_config.tv_flicker_reduction_property = - drm_property_create_range(dev, 0, "flicker reduction", 0, 100); - if (!dev->mode_config.tv_flicker_reduction_property) - goto nomem; - - dev->mode_config.tv_overscan_property = - drm_property_create_range(dev, 0, "overscan", 0, 100); - if (!dev->mode_config.tv_overscan_property) - goto nomem; - - dev->mode_config.tv_saturation_property = - drm_property_create_range(dev, 0, "saturation", 0, 100); - if (!dev->mode_config.tv_saturation_property) - goto nomem; - - dev->mode_config.tv_hue_property = - drm_property_create_range(dev, 0, "hue", 0, 100); - if (!dev->mode_config.tv_hue_property) - goto nomem; - - return 0; -nomem: - return -ENOMEM; -} -EXPORT_SYMBOL(drm_mode_create_tv_properties); - -/** - * drm_mode_create_scaling_mode_property - create scaling mode property - * @dev: DRM device - * - * Called by a driver the first time it's needed, must be attached to desired - * connectors. - */ -int drm_mode_create_scaling_mode_property(struct drm_device *dev) -{ - struct drm_property *scaling_mode; - - if (dev->mode_config.scaling_mode_property) - return 0; - - scaling_mode = - drm_property_create_enum(dev, 0, "scaling mode", - drm_scaling_mode_enum_list, - ARRAY_SIZE(drm_scaling_mode_enum_list)); - - dev->mode_config.scaling_mode_property = scaling_mode; - - return 0; -} -EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); - -/** - * drm_mode_create_aspect_ratio_property - create aspect ratio property - * @dev: DRM device - * - * Called by a driver the first time it's needed, must be attached to desired - * connectors. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_create_aspect_ratio_property(struct drm_device *dev) -{ - if (dev->mode_config.aspect_ratio_property) - return 0; - - dev->mode_config.aspect_ratio_property = - drm_property_create_enum(dev, 0, "aspect ratio", - drm_aspect_ratio_enum_list, - ARRAY_SIZE(drm_aspect_ratio_enum_list)); - - if (dev->mode_config.aspect_ratio_property == NULL) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); - -/** - * drm_mode_create_suggested_offset_properties - create suggests offset properties - * @dev: DRM device - * - * Create the the suggested x/y offset property for connectors. - */ -int drm_mode_create_suggested_offset_properties(struct drm_device *dev) -{ - if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) - return 0; - - dev->mode_config.suggested_x_property = - drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); - - dev->mode_config.suggested_y_property = - drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); - - if (dev->mode_config.suggested_x_property == NULL || - dev->mode_config.suggested_y_property == NULL) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); - /** * drm_mode_getresources - get graphics configuration * @dev: drm device for the ioctl @@ -1895,32 +1167,11 @@ int drm_mode_getcrtc(struct drm_device *dev, return 0; } -static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, - const struct drm_file *file_priv) -{ - /* - * If user-space hasn't configured the driver to expose the stereo 3D - * modes, don't expose them. - */ - if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) - return false; - - return true; -} - -static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) -{ - /* For atomic drivers only state objects are synchronously updated and - * protected by modeset locks, so check those first. */ - if (connector->state) - return connector->state->best_encoder; - return connector->encoder; -} - /* helper for getconnector and getproperties ioctls */ -static int get_properties(struct drm_mode_object *obj, bool atomic, - uint32_t __user *prop_ptr, uint64_t __user *prop_values, - uint32_t *arg_count_props) +int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, + uint32_t __user *prop_ptr, + uint64_t __user *prop_values, + uint32_t *arg_count_props) { int props_count; int i, ret, copied; @@ -1955,133 +1206,6 @@ static int get_properties(struct drm_mode_object *obj, bool atomic, return 0; } -/** - * drm_mode_getconnector - get connector configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Construct a connector configuration structure to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getconnector(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_get_connector *out_resp = data; - struct drm_connector *connector; - struct drm_encoder *encoder; - struct drm_display_mode *mode; - int mode_count = 0; - int encoders_count = 0; - int ret = 0; - int copied = 0; - int i; - struct drm_mode_modeinfo u_mode; - struct drm_mode_modeinfo __user *mode_ptr; - uint32_t __user *encoder_ptr; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - - mutex_lock(&dev->mode_config.mutex); - - connector = drm_connector_lookup(dev, out_resp->connector_id); - if (!connector) { - ret = -ENOENT; - goto out_unlock; - } - - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) - if (connector->encoder_ids[i] != 0) - encoders_count++; - - if (out_resp->count_modes == 0) { - connector->funcs->fill_modes(connector, - dev->mode_config.max_width, - dev->mode_config.max_height); - } - - /* delayed so we get modes regardless of pre-fill_modes state */ - list_for_each_entry(mode, &connector->modes, head) - if (drm_mode_expose_to_userspace(mode, file_priv)) - mode_count++; - - out_resp->connector_id = connector->base.id; - out_resp->connector_type = connector->connector_type; - out_resp->connector_type_id = connector->connector_type_id; - out_resp->mm_width = connector->display_info.width_mm; - out_resp->mm_height = connector->display_info.height_mm; - out_resp->subpixel = connector->display_info.subpixel_order; - out_resp->connection = connector->status; - - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - encoder = drm_connector_get_encoder(connector); - if (encoder) - out_resp->encoder_id = encoder->base.id; - else - out_resp->encoder_id = 0; - - /* - * This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. - */ - if ((out_resp->count_modes >= mode_count) && mode_count) { - copied = 0; - mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; - list_for_each_entry(mode, &connector->modes, head) { - if (!drm_mode_expose_to_userspace(mode, file_priv)) - continue; - - drm_mode_convert_to_umode(&u_mode, mode); - if (copy_to_user(mode_ptr + copied, - &u_mode, sizeof(u_mode))) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - out_resp->count_modes = mode_count; - - ret = get_properties(&connector->base, file_priv->atomic, - (uint32_t __user *)(unsigned long)(out_resp->props_ptr), - (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), - &out_resp->count_props); - if (ret) - goto out; - - if ((out_resp->count_encoders >= encoders_count) && encoders_count) { - copied = 0; - encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] != 0) { - if (put_user(connector->encoder_ids[i], - encoder_ptr + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - } - out_resp->count_encoders = encoders_count; - -out: - drm_modeset_unlock(&dev->mode_config.connection_mutex); - - drm_connector_unreference(connector); -out_unlock: - mutex_unlock(&dev->mode_config.mutex); - - return ret; -} - static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) { struct drm_connector *connector; @@ -3961,113 +3085,6 @@ int drm_mode_destroyblob_ioctl(struct drm_device *dev, return ret; } -/** - * drm_mode_connector_set_path_property - set tile property on connector - * @connector: connector to set property on. - * @path: path to use for property; must not be NULL. - * - * This creates a property to expose to userspace to specify a - * connector path. This is mainly used for DisplayPort MST where - * connectors have a topology and we want to allow userspace to give - * them more meaningful names. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path) -{ - struct drm_device *dev = connector->dev; - int ret; - - ret = drm_property_replace_global_blob(dev, - &connector->path_blob_ptr, - strlen(path) + 1, - path, - &connector->base, - dev->mode_config.path_property); - return ret; -} -EXPORT_SYMBOL(drm_mode_connector_set_path_property); - -/** - * drm_mode_connector_set_tile_property - set tile property on connector - * @connector: connector to set property on. - * - * This looks up the tile information for a connector, and creates a - * property for userspace to parse if it exists. The property is of - * the form of 8 integers using ':' as a separator. - * - * Returns: - * Zero on success, errno on failure. - */ -int drm_mode_connector_set_tile_property(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - char tile[256]; - int ret; - - if (!connector->has_tile) { - ret = drm_property_replace_global_blob(dev, - &connector->tile_blob_ptr, - 0, - NULL, - &connector->base, - dev->mode_config.tile_property); - return ret; - } - - snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", - connector->tile_group->id, connector->tile_is_single_monitor, - connector->num_h_tile, connector->num_v_tile, - connector->tile_h_loc, connector->tile_v_loc, - connector->tile_h_size, connector->tile_v_size); - - ret = drm_property_replace_global_blob(dev, - &connector->tile_blob_ptr, - strlen(tile) + 1, - tile, - &connector->base, - dev->mode_config.tile_property); - return ret; -} -EXPORT_SYMBOL(drm_mode_connector_set_tile_property); - -/** - * drm_mode_connector_update_edid_property - update the edid property of a connector - * @connector: drm connector - * @edid: new value of the edid property - * - * This function creates a new blob modeset object and assigns its id to the - * connector's edid property. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid) -{ - struct drm_device *dev = connector->dev; - size_t size = 0; - int ret; - - /* ignore requests to set edid when overridden */ - if (connector->override_edid) - return 0; - - if (edid) - size = EDID_LENGTH * (1 + edid->extensions); - - ret = drm_property_replace_global_blob(dev, - &connector->edid_blob_ptr, - size, - edid, - &connector->base, - dev->mode_config.edid_property); - return ret; -} -EXPORT_SYMBOL(drm_mode_connector_update_edid_property); - /* Some properties could refer to dynamic refcnt'd objects, or things that * need special locking to handle lifetime issues (ie. to ensure the prop * value doesn't become invalid part way through the property update due to @@ -4144,54 +3161,6 @@ void drm_property_change_valid_put(struct drm_property *property, drm_property_unreference_blob(obj_to_blob(ref)); } -/** - * drm_mode_connector_property_set_ioctl - set the current value of a connector property - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This function sets the current value for a connectors's property. It also - * calls into a driver's ->set_property callback to update the hardware state - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_connector_set_property *conn_set_prop = data; - struct drm_mode_obj_set_property obj_set_prop = { - .value = conn_set_prop->value, - .prop_id = conn_set_prop->prop_id, - .obj_id = conn_set_prop->connector_id, - .obj_type = DRM_MODE_OBJECT_CONNECTOR - }; - - /* It does all the locking and checking we need */ - return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); -} - -static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) -{ - int ret = -EINVAL; - struct drm_connector *connector = obj_to_connector(obj); - - /* Do DPMS ourselves */ - if (property == connector->dev->mode_config.dpms_property) { - ret = (*connector->funcs->dpms)(connector, (int)value); - } else if (connector->funcs->set_property) - ret = connector->funcs->set_property(connector, property, value); - - /* store the property value if successful */ - if (!ret) - drm_object_property_set_value(&connector->base, property, value); - return ret; -} - static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) @@ -4273,7 +3242,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, goto out_unref; } - ret = get_properties(obj, file_priv->atomic, + ret = drm_mode_object_get_properties(obj, file_priv->atomic, (uint32_t __user *)(unsigned long)(arg->props_ptr), (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), &arg->count_props); @@ -4285,22 +3254,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, return ret; } -/** - * drm_mode_obj_set_property_ioctl - set the current value of an object's property - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This function sets the current value for an object's property. It also calls - * into a driver's ->set_property callback to update the hardware state. - * Compared to the connector specific ioctl this one is extended to also work on - * crtc and plane objects. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -4365,47 +3318,6 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, return ret; } -/** - * drm_mode_connector_attach_encoder - attach a connector to an encoder - * @connector: connector to attach - * @encoder: encoder to attach @connector to - * - * This function links up a connector to an encoder. Note that the routing - * restrictions between encoders and crtcs are exposed to userspace through the - * possible_clones and possible_crtcs bitmasks. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder) -{ - int i; - - /* - * In the past, drivers have attempted to model the static association - * of connector to encoder in simple connector/encoder devices using a - * direct assignment of connector->encoder = encoder. This connection - * is a logical one and the responsibility of the core, so drivers are - * expected not to mess with this. - * - * Note that the error return should've been enough here, but a large - * majority of drivers ignores the return value, so add in a big WARN - * to get people's attention. - */ - if (WARN_ON(connector->encoder)) - return -EINVAL; - - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) { - connector->encoder_ids[i] = encoder->base.id; - return 0; - } - } - return -ENOMEM; -} -EXPORT_SYMBOL(drm_mode_connector_attach_encoder); - /** * drm_mode_crtc_set_gamma_size - set the gamma table size * @crtc: CRTC to set the gamma table size for diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 67a7b4540630..99a8863536ac 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -33,8 +33,6 @@ /* drm_crtc.c */ -void drm_connector_ida_init(void); -void drm_connector_ida_destroy(void); int drm_mode_object_get_reg(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type, @@ -48,6 +46,10 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type); void drm_mode_object_unregister(struct drm_device *dev, struct drm_mode_object *object); +int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, + uint32_t __user *prop_ptr, + uint64_t __user *prop_values, + uint32_t *arg_count_props); bool drm_property_change_valid_get(struct drm_property *property, uint64_t value, struct drm_mode_object **ref); @@ -85,8 +87,6 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getconnector(struct drm_device *dev, - void *data, struct drm_file *file_priv); int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_getplane(struct drm_device *dev, @@ -105,8 +105,6 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_destroyblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_gamma_get_ioctl(struct drm_device *dev, @@ -117,6 +115,22 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* drm_connector.c */ +void drm_connector_ida_init(void); +void drm_connector_ida_destroy(void); +void drm_connector_unregister_all(struct drm_device *dev); +int drm_connector_register_all(struct drm_device *dev); +int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value); +int drm_connector_create_standard_properties(struct drm_device *dev); + +/* IOCTL */ +int drm_mode_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_getconnector(struct drm_device *dev, + void *data, struct drm_file *file_priv); + /* drm_framebuffer.c */ struct drm_framebuffer * drm_internal_framebuffer_create(struct drm_device *dev, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h new file mode 100644 index 000000000000..ec2bea0b1b38 --- /dev/null +++ b/include/drm/drm_connector.h @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_CONNECTOR_H__ +#define __DRM_CONNECTOR_H__ + +#include +#include +#include + +struct drm_connector_helper_funcs; +struct drm_device; +struct drm_crtc; +struct drm_encoder; +struct drm_property; +struct drm_property_blob; +struct edid; + +enum drm_connector_force { + DRM_FORCE_UNSPECIFIED, + DRM_FORCE_OFF, + DRM_FORCE_ON, /* force on analog part normally */ + DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ +}; + +enum drm_connector_status { + connector_status_connected = 1, + connector_status_disconnected = 2, + connector_status_unknown = 3, +}; + +enum subpixel_order { + SubPixelUnknown = 0, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone, +}; + +/* + * Describes a given display (e.g. CRT or flat panel) and its limitations. + */ +struct drm_display_info { + char name[DRM_DISPLAY_INFO_LEN]; + + /* Physical size */ + unsigned int width_mm; + unsigned int height_mm; + + /* Clock limits FIXME: storage format */ + unsigned int min_vfreq, max_vfreq; + unsigned int min_hfreq, max_hfreq; + unsigned int pixel_clock; + unsigned int bpc; + + enum subpixel_order subpixel_order; + +#define DRM_COLOR_FORMAT_RGB444 (1<<0) +#define DRM_COLOR_FORMAT_YCRCB444 (1<<1) +#define DRM_COLOR_FORMAT_YCRCB422 (1<<2) + + u32 color_formats; + + const u32 *bus_formats; + unsigned int num_bus_formats; + +#define DRM_BUS_FLAG_DE_LOW (1<<0) +#define DRM_BUS_FLAG_DE_HIGH (1<<1) +/* drive data on pos. edge */ +#define DRM_BUS_FLAG_PIXDATA_POSEDGE (1<<2) +/* drive data on neg. edge */ +#define DRM_BUS_FLAG_PIXDATA_NEGEDGE (1<<3) + + u32 bus_flags; + + /* Mask of supported hdmi deep color modes */ + u8 edid_hdmi_dc_modes; + + u8 cea_rev; +}; + +/** + * struct drm_connector_state - mutable connector state + * @connector: backpointer to the connector + * @crtc: CRTC to connect connector to, NULL if disabled + * @best_encoder: can be used by helpers and drivers to select the encoder + * @state: backpointer to global drm_atomic_state + */ +struct drm_connector_state { + struct drm_connector *connector; + + struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ + + struct drm_encoder *best_encoder; + + struct drm_atomic_state *state; +}; + +/** + * struct drm_connector_funcs - control connectors on a given device + * + * Each CRTC may have one or more connectors attached to it. The functions + * below allow the core DRM code to control connectors, enumerate available modes, + * etc. + */ +struct drm_connector_funcs { + /** + * @dpms: + * + * Legacy entry point to set the per-connector DPMS state. Legacy DPMS + * is exposed as a standard property on the connector, but diverted to + * this callback in the drm core. Note that atomic drivers don't + * implement the 4 level DPMS support on the connector any more, but + * instead only have an on/off "ACTIVE" property on the CRTC object. + * + * Drivers implementing atomic modeset should use + * drm_atomic_helper_connector_dpms() to implement this hook. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*dpms)(struct drm_connector *connector, int mode); + + /** + * @reset: + * + * Reset connector hardware and software state to off. This function isn't + * called by the core directly, only through drm_mode_config_reset(). + * It's not a helper hook only for historical reasons. + * + * Atomic drivers can use drm_atomic_helper_connector_reset() to reset + * atomic state using this hook. + */ + void (*reset)(struct drm_connector *connector); + + /** + * @detect: + * + * Check to see if anything is attached to the connector. The parameter + * force is set to false whilst polling, true when checking the + * connector due to a user request. force can be used by the driver to + * avoid expensive, destructive operations during automated probing. + * + * FIXME: + * + * Note that this hook is only called by the probe helper. It's not in + * the helper library vtable purely for historical reasons. The only DRM + * core entry point to probe connector state is @fill_modes. + * + * RETURNS: + * + * drm_connector_status indicating the connector's status. + */ + enum drm_connector_status (*detect)(struct drm_connector *connector, + bool force); + + /** + * @force: + * + * This function is called to update internal encoder state when the + * connector is forced to a certain state by userspace, either through + * the sysfs interfaces or on the kernel cmdline. In that case the + * @detect callback isn't called. + * + * FIXME: + * + * Note that this hook is only called by the probe helper. It's not in + * the helper library vtable purely for historical reasons. The only DRM + * core entry point to probe connector state is @fill_modes. + */ + void (*force)(struct drm_connector *connector); + + /** + * @fill_modes: + * + * Entry point for output detection and basic mode validation. The + * driver should reprobe the output if needed (e.g. when hotplug + * handling is unreliable), add all detected modes to connector->modes + * and filter out any the device can't support in any configuration. It + * also needs to filter out any modes wider or higher than the + * parameters max_width and max_height indicate. + * + * The drivers must also prune any modes no longer valid from + * connector->modes. Furthermore it must update connector->status and + * connector->edid. If no EDID has been received for this output + * connector->edid must be NULL. + * + * Drivers using the probe helpers should use + * drm_helper_probe_single_connector_modes() or + * drm_helper_probe_single_connector_modes_nomerge() to implement this + * function. + * + * RETURNS: + * + * The number of modes detected and filled into connector->modes. + */ + int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); + + /** + * @set_property: + * + * This is the legacy entry point to update a property attached to the + * connector. + * + * Drivers implementing atomic modeset should use + * drm_atomic_helper_connector_set_property() to implement this hook. + * + * This callback is optional if the driver does not support any legacy + * driver-private properties. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*set_property)(struct drm_connector *connector, struct drm_property *property, + uint64_t val); + + /** + * @late_register: + * + * This optional hook can be used to register additional userspace + * interfaces attached to the connector, light backlight control, i2c, + * DP aux or similar interfaces. It is called late in the driver load + * sequence from drm_connector_register() when registering all the + * core drm connector interfaces. Everything added from this callback + * should be unregistered in the early_unregister callback. + * + * Returns: + * + * 0 on success, or a negative error code on failure. + */ + int (*late_register)(struct drm_connector *connector); + + /** + * @early_unregister: + * + * This optional hook should be used to unregister the additional + * userspace interfaces attached to the connector from + * late_unregister(). It is called from drm_connector_unregister(), + * early in the driver unload sequence to disable userspace access + * before data structures are torndown. + */ + void (*early_unregister)(struct drm_connector *connector); + + /** + * @destroy: + * + * Clean up connector resources. This is called at driver unload time + * through drm_mode_config_cleanup(). It can also be called at runtime + * when a connector is being hot-unplugged for drivers that support + * connector hotplugging (e.g. DisplayPort MST). + */ + void (*destroy)(struct drm_connector *connector); + + /** + * @atomic_duplicate_state: + * + * Duplicate the current atomic state for this connector and return it. + * The core and helpers gurantee that any atomic state duplicated with + * this hook and still owned by the caller (i.e. not transferred to the + * driver by calling ->atomic_commit() from struct + * &drm_mode_config_funcs) will be cleaned up by calling the + * @atomic_destroy_state hook in this structure. + * + * Atomic drivers which don't subclass struct &drm_connector_state should use + * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the + * state structure to extend it with driver-private state should use + * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is + * duplicated in a consistent fashion across drivers. + * + * It is an error to call this hook before connector->state has been + * initialized correctly. + * + * NOTE: + * + * If the duplicate state references refcounted resources this hook must + * acquire a reference for each of them. The driver must release these + * references again in @atomic_destroy_state. + * + * RETURNS: + * + * Duplicated atomic state or NULL when the allocation failed. + */ + struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector); + + /** + * @atomic_destroy_state: + * + * Destroy a state duplicated with @atomic_duplicate_state and release + * or unreference all resources it references + */ + void (*atomic_destroy_state)(struct drm_connector *connector, + struct drm_connector_state *state); + + /** + * @atomic_set_property: + * + * Decode a driver-private property value and store the decoded value + * into the passed-in state structure. Since the atomic core decodes all + * standardized properties (even for extensions beyond the core set of + * properties which might not be implemented by all drivers) this + * requires drivers to subclass the state structure. + * + * Such driver-private properties should really only be implemented for + * truly hardware/vendor specific state. Instead it is preferred to + * standardize atomic extension and decode the properties used to expose + * such an extension in the core. + * + * Do not call this function directly, use + * drm_atomic_connector_set_property() instead. + * + * This callback is optional if the driver does not support any + * driver-private atomic properties. + * + * NOTE: + * + * This function is called in the state assembly phase of atomic + * modesets, which can be aborted for any reason (including on + * userspace's request to just check whether a configuration would be + * possible). Drivers MUST NOT touch any persistent state (hardware or + * software) or data structures except the passed in @state parameter. + * + * Also since userspace controls in which order properties are set this + * function must not do any input validation (since the state update is + * incomplete and hence likely inconsistent). Instead any such input + * validation must be done in the various atomic_check callbacks. + * + * RETURNS: + * + * 0 if the property has been found, -EINVAL if the property isn't + * implemented by the driver (which shouldn't ever happen, the core only + * asks for properties attached to this connector). No other validation + * is allowed by the driver. The core already checks that the property + * value is within the range (integer, valid enum value, ...) the driver + * set when registering the property. + */ + int (*atomic_set_property)(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val); + + /** + * @atomic_get_property: + * + * Reads out the decoded driver-private property. This is used to + * implement the GETCONNECTOR IOCTL. + * + * Do not call this function directly, use + * drm_atomic_connector_get_property() instead. + * + * This callback is optional if the driver does not support any + * driver-private atomic properties. + * + * RETURNS: + * + * 0 on success, -EINVAL if the property isn't implemented by the + * driver (which shouldn't ever happen, the core only asks for + * properties attached to this connector). + */ + int (*atomic_get_property)(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val); +}; + +/* mode specified on the command line */ +struct drm_cmdline_mode { + bool specified; + bool refresh_specified; + bool bpp_specified; + int xres, yres; + int bpp; + int refresh; + bool rb; + bool interlace; + bool cvt; + bool margins; + enum drm_connector_force force; +}; + +/** + * struct drm_connector - central DRM connector control structure + * @dev: parent DRM device + * @kdev: kernel device for sysfs attributes + * @attr: sysfs attributes + * @head: list management + * @base: base KMS object + * @name: human readable name, can be overwritten by the driver + * @connector_type: one of the DRM_MODE_CONNECTOR_ types from drm_mode.h + * @connector_type_id: index into connector type enum + * @interlace_allowed: can this connector handle interlaced modes? + * @doublescan_allowed: can this connector handle doublescan? + * @stereo_allowed: can this connector handle stereo modes? + * @registered: is this connector exposed (registered) with userspace? + * @modes: modes available on this connector (from fill_modes() + user) + * @status: one of the drm_connector_status enums (connected, not, or unknown) + * @probed_modes: list of modes derived directly from the display + * @display_info: information about attached display (e.g. from EDID) + * @funcs: connector control functions + * @edid_blob_ptr: DRM property containing EDID if present + * @properties: property tracking for this connector + * @polled: a DRM_CONNECTOR_POLL_ value for core driven polling + * @dpms: current dpms state + * @helper_private: mid-layer private data + * @cmdline_mode: mode line parsed from the kernel cmdline for this connector + * @force: a DRM_FORCE_ state for forced mode sets + * @override_edid: has the EDID been overwritten through debugfs for testing? + * @encoder_ids: valid encoders for this connector + * @encoder: encoder driving this connector, if any + * @eld: EDID-like data, if present + * @dvi_dual: dual link DVI, if found + * @max_tmds_clock: max clock rate, if found + * @latency_present: AV delay info from ELD, if found + * @video_latency: video latency info from ELD, if found + * @audio_latency: audio latency info from ELD, if found + * @null_edid_counter: track sinks that give us all zeros for the EDID + * @bad_edid_counter: track sinks that give us an EDID with invalid checksum + * @edid_corrupt: indicates whether the last read EDID was corrupt + * @debugfs_entry: debugfs directory for this connector + * @state: current atomic state for this connector + * @has_tile: is this connector connected to a tiled monitor + * @tile_group: tile group for the connected monitor + * @tile_is_single_monitor: whether the tile is one monitor housing + * @num_h_tile: number of horizontal tiles in the tile group + * @num_v_tile: number of vertical tiles in the tile group + * @tile_h_loc: horizontal location of this tile + * @tile_v_loc: vertical location of this tile + * @tile_h_size: horizontal size of this tile. + * @tile_v_size: vertical size of this tile. + * + * Each connector may be connected to one or more CRTCs, or may be clonable by + * another connector if they can share a CRTC. Each connector also has a specific + * position in the broader display (referred to as a 'screen' though it could + * span multiple monitors). + */ +struct drm_connector { + struct drm_device *dev; + struct device *kdev; + struct device_attribute *attr; + struct list_head head; + + struct drm_mode_object base; + + char *name; + + /** + * @index: Compacted connector index, which matches the position inside + * the mode_config.list for drivers not supporting hot-add/removing. Can + * be used as an array index. It is invariant over the lifetime of the + * connector. + */ + unsigned index; + + int connector_type; + int connector_type_id; + bool interlace_allowed; + bool doublescan_allowed; + bool stereo_allowed; + bool registered; + struct list_head modes; /* list of modes on this connector */ + + enum drm_connector_status status; + + /* these are modes added by probing with DDC or the BIOS */ + struct list_head probed_modes; + + struct drm_display_info display_info; + const struct drm_connector_funcs *funcs; + + struct drm_property_blob *edid_blob_ptr; + struct drm_object_properties properties; + + /** + * @path_blob_ptr: + * + * DRM blob property data for the DP MST path property. + */ + struct drm_property_blob *path_blob_ptr; + + /** + * @tile_blob_ptr: + * + * DRM blob property data for the tile property (used mostly by DP MST). + * This is meant for screens which are driven through separate display + * pipelines represented by &drm_crtc, which might not be running with + * genlocked clocks. For tiled panels which are genlocked, like + * dual-link LVDS or dual-link DSI, the driver should try to not expose + * the tiling and virtualize both &drm_crtc and &drm_plane if needed. + */ + struct drm_property_blob *tile_blob_ptr; + +/* should we poll this connector for connects and disconnects */ +/* hot plug detectable */ +#define DRM_CONNECTOR_POLL_HPD (1 << 0) +/* poll for connections */ +#define DRM_CONNECTOR_POLL_CONNECT (1 << 1) +/* can cleanly poll for disconnections without flickering the screen */ +/* DACs should rarely do this without a lot of testing */ +#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) + + uint8_t polled; /* DRM_CONNECTOR_POLL_* */ + + /* requested DPMS state */ + int dpms; + + const struct drm_connector_helper_funcs *helper_private; + + /* forced on connector */ + struct drm_cmdline_mode cmdline_mode; + enum drm_connector_force force; + bool override_edid; + +#define DRM_CONNECTOR_MAX_ENCODER 3 + uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + struct drm_encoder *encoder; /* currently active encoder */ + +#define MAX_ELD_BYTES 128 + /* EDID bits */ + uint8_t eld[MAX_ELD_BYTES]; + bool dvi_dual; + int max_tmds_clock; /* in MHz */ + bool latency_present[2]; + int video_latency[2]; /* [0]: progressive, [1]: interlaced */ + int audio_latency[2]; + int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ + unsigned bad_edid_counter; + + /* Flag for raw EDID header corruption - used in Displayport + * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 + */ + bool edid_corrupt; + + struct dentry *debugfs_entry; + + struct drm_connector_state *state; + + /* DisplayID bits */ + bool has_tile; + struct drm_tile_group *tile_group; + bool tile_is_single_monitor; + + uint8_t num_h_tile, num_v_tile; + uint8_t tile_h_loc, tile_v_loc; + uint16_t tile_h_size, tile_v_size; +}; + +#define obj_to_connector(x) container_of(x, struct drm_connector, base) + +int drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type); +int drm_connector_register(struct drm_connector *connector); +void drm_connector_unregister(struct drm_connector *connector); +int drm_mode_connector_attach_encoder(struct drm_connector *connector, + struct drm_encoder *encoder); + +void drm_connector_cleanup(struct drm_connector *connector); +static inline unsigned drm_connector_index(struct drm_connector *connector) +{ + return connector->index; +} + +/** + * drm_connector_lookup - lookup connector object + * @dev: DRM device + * @id: connector object id + * + * This function looks up the connector object specified by id + * add takes a reference to it. + */ +static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR); + return mo ? obj_to_connector(mo) : NULL; +} + +/** + * drm_connector_reference - incr the connector refcnt + * @connector: connector + * + * This function increments the connector's refcount. + */ +static inline void drm_connector_reference(struct drm_connector *connector) +{ + drm_mode_object_reference(&connector->base); +} + +/** + * drm_connector_unreference - unref a connector + * @connector: connector to unref + * + * This function decrements the connector's refcount and frees it if it drops to zero. + */ +static inline void drm_connector_unreference(struct drm_connector *connector) +{ + drm_mode_object_unreference(&connector->base); +} + +const char *drm_get_connector_status_name(enum drm_connector_status status); +const char *drm_get_subpixel_order_name(enum subpixel_order order); +const char *drm_get_dpms_name(int val); +const char *drm_get_dvi_i_subconnector_name(int val); +const char *drm_get_dvi_i_select_name(int val); +const char *drm_get_tv_subconnector_name(int val); +const char *drm_get_tv_select_name(int val); + +int drm_mode_create_dvi_i_properties(struct drm_device *dev); +int drm_mode_create_tv_properties(struct drm_device *dev, + unsigned int num_modes, + const char * const modes[]); +int drm_mode_create_scaling_mode_property(struct drm_device *dev); +int drm_mode_create_aspect_ratio_property(struct drm_device *dev); +int drm_mode_create_suggested_offset_properties(struct drm_device *dev); + +int drm_mode_connector_set_path_property(struct drm_connector *connector, + const char *path); +int drm_mode_connector_set_tile_property(struct drm_connector *connector); +int drm_mode_connector_update_edid_property(struct drm_connector *connector, + const struct edid *edid); +#endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f4d041800551..e30ea0be6417 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -39,31 +39,16 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; -struct drm_object_properties; struct drm_file; struct drm_clip_rect; struct device_node; struct fence; struct edid; -#define DRM_OBJECT_MAX_PROPERTY 24 -struct drm_object_properties { - int count, atomic_count; - /* NOTE: if we ever start dynamically destroying properties (ie. - * not at drm_mode_config_cleanup() time), then we'd have to do - * a better job of detaching property from mode objects to avoid - * dangling property pointers: - */ - struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; - /* do not read/write values directly, but use drm_object_property_get_value() - * and drm_object_property_set_value(): - */ - uint64_t values[DRM_OBJECT_MAX_PROPERTY]; -}; - static inline int64_t U642I64(uint64_t val) { return (int64_t)*((int64_t *)&val); @@ -88,61 +73,6 @@ static inline uint64_t I642U64(int64_t val) #define DRM_REFLECT_Y BIT(5) #define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) -enum drm_connector_status { - connector_status_connected = 1, - connector_status_disconnected = 2, - connector_status_unknown = 3, -}; - -enum subpixel_order { - SubPixelUnknown = 0, - SubPixelHorizontalRGB, - SubPixelHorizontalBGR, - SubPixelVerticalRGB, - SubPixelVerticalBGR, - SubPixelNone, -}; - -#define DRM_COLOR_FORMAT_RGB444 (1<<0) -#define DRM_COLOR_FORMAT_YCRCB444 (1<<1) -#define DRM_COLOR_FORMAT_YCRCB422 (1<<2) - -#define DRM_BUS_FLAG_DE_LOW (1<<0) -#define DRM_BUS_FLAG_DE_HIGH (1<<1) -/* drive data on pos. edge */ -#define DRM_BUS_FLAG_PIXDATA_POSEDGE (1<<2) -/* drive data on neg. edge */ -#define DRM_BUS_FLAG_PIXDATA_NEGEDGE (1<<3) - -/* - * Describes a given display (e.g. CRT or flat panel) and its limitations. - */ -struct drm_display_info { - char name[DRM_DISPLAY_INFO_LEN]; - - /* Physical size */ - unsigned int width_mm; - unsigned int height_mm; - - /* Clock limits FIXME: storage format */ - unsigned int min_vfreq, max_vfreq; - unsigned int min_hfreq, max_hfreq; - unsigned int pixel_clock; - unsigned int bpc; - - enum subpixel_order subpixel_order; - u32 color_formats; - - const u32 *bus_formats; - unsigned int num_bus_formats; - u32 bus_flags; - - /* Mask of supported hdmi deep color modes */ - u8 edid_hdmi_dc_modes; - - u8 cea_rev; -}; - /* data corresponds to displayid vend/prod/serial */ struct drm_tile_group { struct kref refcount; @@ -179,7 +109,6 @@ struct drm_property { }; struct drm_crtc; -struct drm_connector; struct drm_encoder; struct drm_pending_vblank_event; struct drm_plane; @@ -188,7 +117,6 @@ struct drm_atomic_state; struct drm_crtc_helper_funcs; struct drm_encoder_helper_funcs; -struct drm_connector_helper_funcs; struct drm_plane_helper_funcs; /** @@ -733,291 +661,6 @@ struct drm_crtc { struct drm_modeset_acquire_ctx *acquire_ctx; }; -/** - * struct drm_connector_state - mutable connector state - * @connector: backpointer to the connector - * @crtc: CRTC to connect connector to, NULL if disabled - * @best_encoder: can be used by helpers and drivers to select the encoder - * @state: backpointer to global drm_atomic_state - */ -struct drm_connector_state { - struct drm_connector *connector; - - struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ - - struct drm_encoder *best_encoder; - - struct drm_atomic_state *state; -}; - -/** - * struct drm_connector_funcs - control connectors on a given device - * - * Each CRTC may have one or more connectors attached to it. The functions - * below allow the core DRM code to control connectors, enumerate available modes, - * etc. - */ -struct drm_connector_funcs { - /** - * @dpms: - * - * Legacy entry point to set the per-connector DPMS state. Legacy DPMS - * is exposed as a standard property on the connector, but diverted to - * this callback in the drm core. Note that atomic drivers don't - * implement the 4 level DPMS support on the connector any more, but - * instead only have an on/off "ACTIVE" property on the CRTC object. - * - * Drivers implementing atomic modeset should use - * drm_atomic_helper_connector_dpms() to implement this hook. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*dpms)(struct drm_connector *connector, int mode); - - /** - * @reset: - * - * Reset connector hardware and software state to off. This function isn't - * called by the core directly, only through drm_mode_config_reset(). - * It's not a helper hook only for historical reasons. - * - * Atomic drivers can use drm_atomic_helper_connector_reset() to reset - * atomic state using this hook. - */ - void (*reset)(struct drm_connector *connector); - - /** - * @detect: - * - * Check to see if anything is attached to the connector. The parameter - * force is set to false whilst polling, true when checking the - * connector due to a user request. force can be used by the driver to - * avoid expensive, destructive operations during automated probing. - * - * FIXME: - * - * Note that this hook is only called by the probe helper. It's not in - * the helper library vtable purely for historical reasons. The only DRM - * core entry point to probe connector state is @fill_modes. - * - * RETURNS: - * - * drm_connector_status indicating the connector's status. - */ - enum drm_connector_status (*detect)(struct drm_connector *connector, - bool force); - - /** - * @force: - * - * This function is called to update internal encoder state when the - * connector is forced to a certain state by userspace, either through - * the sysfs interfaces or on the kernel cmdline. In that case the - * @detect callback isn't called. - * - * FIXME: - * - * Note that this hook is only called by the probe helper. It's not in - * the helper library vtable purely for historical reasons. The only DRM - * core entry point to probe connector state is @fill_modes. - */ - void (*force)(struct drm_connector *connector); - - /** - * @fill_modes: - * - * Entry point for output detection and basic mode validation. The - * driver should reprobe the output if needed (e.g. when hotplug - * handling is unreliable), add all detected modes to connector->modes - * and filter out any the device can't support in any configuration. It - * also needs to filter out any modes wider or higher than the - * parameters max_width and max_height indicate. - * - * The drivers must also prune any modes no longer valid from - * connector->modes. Furthermore it must update connector->status and - * connector->edid. If no EDID has been received for this output - * connector->edid must be NULL. - * - * Drivers using the probe helpers should use - * drm_helper_probe_single_connector_modes() or - * drm_helper_probe_single_connector_modes_nomerge() to implement this - * function. - * - * RETURNS: - * - * The number of modes detected and filled into connector->modes. - */ - int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); - - /** - * @set_property: - * - * This is the legacy entry point to update a property attached to the - * connector. - * - * Drivers implementing atomic modeset should use - * drm_atomic_helper_connector_set_property() to implement this hook. - * - * This callback is optional if the driver does not support any legacy - * driver-private properties. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*set_property)(struct drm_connector *connector, struct drm_property *property, - uint64_t val); - - /** - * @late_register: - * - * This optional hook can be used to register additional userspace - * interfaces attached to the connector, light backlight control, i2c, - * DP aux or similar interfaces. It is called late in the driver load - * sequence from drm_connector_register() when registering all the - * core drm connector interfaces. Everything added from this callback - * should be unregistered in the early_unregister callback. - * - * Returns: - * - * 0 on success, or a negative error code on failure. - */ - int (*late_register)(struct drm_connector *connector); - - /** - * @early_unregister: - * - * This optional hook should be used to unregister the additional - * userspace interfaces attached to the connector from - * late_unregister(). It is called from drm_connector_unregister(), - * early in the driver unload sequence to disable userspace access - * before data structures are torndown. - */ - void (*early_unregister)(struct drm_connector *connector); - - /** - * @destroy: - * - * Clean up connector resources. This is called at driver unload time - * through drm_mode_config_cleanup(). It can also be called at runtime - * when a connector is being hot-unplugged for drivers that support - * connector hotplugging (e.g. DisplayPort MST). - */ - void (*destroy)(struct drm_connector *connector); - - /** - * @atomic_duplicate_state: - * - * Duplicate the current atomic state for this connector and return it. - * The core and helpers gurantee that any atomic state duplicated with - * this hook and still owned by the caller (i.e. not transferred to the - * driver by calling ->atomic_commit() from struct - * &drm_mode_config_funcs) will be cleaned up by calling the - * @atomic_destroy_state hook in this structure. - * - * Atomic drivers which don't subclass struct &drm_connector_state should use - * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the - * state structure to extend it with driver-private state should use - * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is - * duplicated in a consistent fashion across drivers. - * - * It is an error to call this hook before connector->state has been - * initialized correctly. - * - * NOTE: - * - * If the duplicate state references refcounted resources this hook must - * acquire a reference for each of them. The driver must release these - * references again in @atomic_destroy_state. - * - * RETURNS: - * - * Duplicated atomic state or NULL when the allocation failed. - */ - struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector); - - /** - * @atomic_destroy_state: - * - * Destroy a state duplicated with @atomic_duplicate_state and release - * or unreference all resources it references - */ - void (*atomic_destroy_state)(struct drm_connector *connector, - struct drm_connector_state *state); - - /** - * @atomic_set_property: - * - * Decode a driver-private property value and store the decoded value - * into the passed-in state structure. Since the atomic core decodes all - * standardized properties (even for extensions beyond the core set of - * properties which might not be implemented by all drivers) this - * requires drivers to subclass the state structure. - * - * Such driver-private properties should really only be implemented for - * truly hardware/vendor specific state. Instead it is preferred to - * standardize atomic extension and decode the properties used to expose - * such an extension in the core. - * - * Do not call this function directly, use - * drm_atomic_connector_set_property() instead. - * - * This callback is optional if the driver does not support any - * driver-private atomic properties. - * - * NOTE: - * - * This function is called in the state assembly phase of atomic - * modesets, which can be aborted for any reason (including on - * userspace's request to just check whether a configuration would be - * possible). Drivers MUST NOT touch any persistent state (hardware or - * software) or data structures except the passed in @state parameter. - * - * Also since userspace controls in which order properties are set this - * function must not do any input validation (since the state update is - * incomplete and hence likely inconsistent). Instead any such input - * validation must be done in the various atomic_check callbacks. - * - * RETURNS: - * - * 0 if the property has been found, -EINVAL if the property isn't - * implemented by the driver (which shouldn't ever happen, the core only - * asks for properties attached to this connector). No other validation - * is allowed by the driver. The core already checks that the property - * value is within the range (integer, valid enum value, ...) the driver - * set when registering the property. - */ - int (*atomic_set_property)(struct drm_connector *connector, - struct drm_connector_state *state, - struct drm_property *property, - uint64_t val); - - /** - * @atomic_get_property: - * - * Reads out the decoded driver-private property. This is used to - * implement the GETCONNECTOR IOCTL. - * - * Do not call this function directly, use - * drm_atomic_connector_get_property() instead. - * - * This callback is optional if the driver does not support any - * driver-private atomic properties. - * - * RETURNS: - * - * 0 on success, -EINVAL if the property isn't implemented by the - * driver (which shouldn't ever happen, the core only asks for - * properties attached to this connector). - */ - int (*atomic_get_property)(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, - uint64_t *val); -}; - /** * struct drm_encoder_funcs - encoder controls * @@ -1069,8 +712,6 @@ struct drm_encoder_funcs { void (*early_unregister)(struct drm_encoder *encoder); }; -#define DRM_CONNECTOR_MAX_ENCODER 3 - /** * struct drm_encoder - central DRM encoder structure * @dev: parent DRM device @@ -1111,171 +752,6 @@ struct drm_encoder { const struct drm_encoder_helper_funcs *helper_private; }; -/* should we poll this connector for connects and disconnects */ -/* hot plug detectable */ -#define DRM_CONNECTOR_POLL_HPD (1 << 0) -/* poll for connections */ -#define DRM_CONNECTOR_POLL_CONNECT (1 << 1) -/* can cleanly poll for disconnections without flickering the screen */ -/* DACs should rarely do this without a lot of testing */ -#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) - -#define MAX_ELD_BYTES 128 - -/** - * struct drm_connector - central DRM connector control structure - * @dev: parent DRM device - * @kdev: kernel device for sysfs attributes - * @attr: sysfs attributes - * @head: list management - * @base: base KMS object - * @name: human readable name, can be overwritten by the driver - * @connector_type: one of the DRM_MODE_CONNECTOR_ types from drm_mode.h - * @connector_type_id: index into connector type enum - * @interlace_allowed: can this connector handle interlaced modes? - * @doublescan_allowed: can this connector handle doublescan? - * @stereo_allowed: can this connector handle stereo modes? - * @registered: is this connector exposed (registered) with userspace? - * @modes: modes available on this connector (from fill_modes() + user) - * @status: one of the drm_connector_status enums (connected, not, or unknown) - * @probed_modes: list of modes derived directly from the display - * @display_info: information about attached display (e.g. from EDID) - * @funcs: connector control functions - * @edid_blob_ptr: DRM property containing EDID if present - * @properties: property tracking for this connector - * @polled: a DRM_CONNECTOR_POLL_ value for core driven polling - * @dpms: current dpms state - * @helper_private: mid-layer private data - * @cmdline_mode: mode line parsed from the kernel cmdline for this connector - * @force: a DRM_FORCE_ state for forced mode sets - * @override_edid: has the EDID been overwritten through debugfs for testing? - * @encoder_ids: valid encoders for this connector - * @encoder: encoder driving this connector, if any - * @eld: EDID-like data, if present - * @dvi_dual: dual link DVI, if found - * @max_tmds_clock: max clock rate, if found - * @latency_present: AV delay info from ELD, if found - * @video_latency: video latency info from ELD, if found - * @audio_latency: audio latency info from ELD, if found - * @null_edid_counter: track sinks that give us all zeros for the EDID - * @bad_edid_counter: track sinks that give us an EDID with invalid checksum - * @edid_corrupt: indicates whether the last read EDID was corrupt - * @debugfs_entry: debugfs directory for this connector - * @state: current atomic state for this connector - * @has_tile: is this connector connected to a tiled monitor - * @tile_group: tile group for the connected monitor - * @tile_is_single_monitor: whether the tile is one monitor housing - * @num_h_tile: number of horizontal tiles in the tile group - * @num_v_tile: number of vertical tiles in the tile group - * @tile_h_loc: horizontal location of this tile - * @tile_v_loc: vertical location of this tile - * @tile_h_size: horizontal size of this tile. - * @tile_v_size: vertical size of this tile. - * - * Each connector may be connected to one or more CRTCs, or may be clonable by - * another connector if they can share a CRTC. Each connector also has a specific - * position in the broader display (referred to as a 'screen' though it could - * span multiple monitors). - */ -struct drm_connector { - struct drm_device *dev; - struct device *kdev; - struct device_attribute *attr; - struct list_head head; - - struct drm_mode_object base; - - char *name; - - /** - * @index: Compacted connector index, which matches the position inside - * the mode_config.list for drivers not supporting hot-add/removing. Can - * be used as an array index. It is invariant over the lifetime of the - * connector. - */ - unsigned index; - - int connector_type; - int connector_type_id; - bool interlace_allowed; - bool doublescan_allowed; - bool stereo_allowed; - bool registered; - struct list_head modes; /* list of modes on this connector */ - - enum drm_connector_status status; - - /* these are modes added by probing with DDC or the BIOS */ - struct list_head probed_modes; - - struct drm_display_info display_info; - const struct drm_connector_funcs *funcs; - - struct drm_property_blob *edid_blob_ptr; - struct drm_object_properties properties; - - /** - * @path_blob_ptr: - * - * DRM blob property data for the DP MST path property. - */ - struct drm_property_blob *path_blob_ptr; - - /** - * @tile_blob_ptr: - * - * DRM blob property data for the tile property (used mostly by DP MST). - * This is meant for screens which are driven through separate display - * pipelines represented by &drm_crtc, which might not be running with - * genlocked clocks. For tiled panels which are genlocked, like - * dual-link LVDS or dual-link DSI, the driver should try to not expose - * the tiling and virtualize both &drm_crtc and &drm_plane if needed. - */ - struct drm_property_blob *tile_blob_ptr; - - uint8_t polled; /* DRM_CONNECTOR_POLL_* */ - - /* requested DPMS state */ - int dpms; - - const struct drm_connector_helper_funcs *helper_private; - - /* forced on connector */ - struct drm_cmdline_mode cmdline_mode; - enum drm_connector_force force; - bool override_edid; - uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; - struct drm_encoder *encoder; /* currently active encoder */ - - /* EDID bits */ - uint8_t eld[MAX_ELD_BYTES]; - bool dvi_dual; - int max_tmds_clock; /* in MHz */ - bool latency_present[2]; - int video_latency[2]; /* [0]: progressive, [1]: interlaced */ - int audio_latency[2]; - int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ - unsigned bad_edid_counter; - - /* Flag for raw EDID header corruption - used in Displayport - * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 - */ - bool edid_corrupt; - - struct dentry *debugfs_entry; - - struct drm_connector_state *state; - - /* DisplayID bits */ - bool has_tile; - struct drm_tile_group *tile_group; - bool tile_is_single_monitor; - - uint8_t num_h_tile, num_v_tile; - uint8_t tile_h_loc, tile_v_loc; - uint16_t tile_h_size, tile_v_size; -}; - /** * struct drm_plane_state - mutable plane state * @plane: backpointer to the plane @@ -2615,7 +2091,6 @@ struct drm_mode_config { for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) -#define obj_to_connector(x) container_of(x, struct drm_connector, base) #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) @@ -2661,19 +2136,6 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -int drm_connector_init(struct drm_device *dev, - struct drm_connector *connector, - const struct drm_connector_funcs *funcs, - int connector_type); -int drm_connector_register(struct drm_connector *connector); -void drm_connector_unregister(struct drm_connector *connector); - -extern void drm_connector_cleanup(struct drm_connector *connector); -static inline unsigned drm_connector_index(struct drm_connector *connector) -{ - return connector->index; -} - extern __printf(5, 6) int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, @@ -2742,23 +2204,10 @@ extern int drm_crtc_force_disable_all(struct drm_device *dev); extern void drm_encoder_cleanup(struct drm_encoder *encoder); -extern const char *drm_get_connector_status_name(enum drm_connector_status status); -extern const char *drm_get_subpixel_order_name(enum subpixel_order order); -extern const char *drm_get_dpms_name(int val); -extern const char *drm_get_dvi_i_subconnector_name(int val); -extern const char *drm_get_dvi_i_select_name(int val); -extern const char *drm_get_tv_subconnector_name(int val); -extern const char *drm_get_tv_select_name(int val); extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); -extern int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path); -int drm_mode_connector_set_tile_property(struct drm_connector *connector); -extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid); - extern int drm_display_info_set_bus_formats(struct drm_display_info *info, const u32 *formats, unsigned int num_formats); @@ -2819,16 +2268,6 @@ void drm_property_unreference_blob(struct drm_property_blob *blob); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); -extern int drm_mode_create_tv_properties(struct drm_device *dev, - unsigned int num_modes, - const char * const modes[]); -extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); -extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); -extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); - -extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder); extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); @@ -2888,22 +2327,6 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, return mo ? obj_to_encoder(mo) : NULL; } -/** - * drm_connector_lookup - lookup connector object - * @dev: DRM device - * @id: connector object id - * - * This function looks up the connector object specified by id - * add takes a reference to it. - */ -static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev, - uint32_t id) -{ - struct drm_mode_object *mo; - mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR); - return mo ? obj_to_connector(mo) : NULL; -} - static inline struct drm_property *drm_property_find(struct drm_device *dev, uint32_t id) { @@ -2931,28 +2354,6 @@ static inline uint32_t drm_color_lut_extract(uint32_t user_input, return clamp_val(val, 0, max); } -/** - * drm_connector_reference - incr the connector refcnt - * @connector: connector - * - * This function increments the connector's refcount. - */ -static inline void drm_connector_reference(struct drm_connector *connector) -{ - drm_mode_object_reference(&connector->base); -} - -/** - * drm_connector_unreference - unref a connector - * @connector: connector to unref - * - * This function decrements the connector's refcount and frees it if it drops to zero. - */ -static inline void drm_connector_unreference(struct drm_connector *connector) -{ - drm_mode_object_unreference(&connector->base); -} - /* Plane list iterator for legacy (overlay only) planes. */ #define drm_for_each_legacy_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index fed9fe81590c..1621e9b32330 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -28,6 +28,7 @@ #define __DRM_MODES_H__ #include +#include /* * Note on terminology: here, for brevity and convenience, we refer to connector @@ -402,21 +403,6 @@ struct drm_display_mode { enum hdmi_picture_aspect picture_aspect_ratio; }; -/* mode specified on the command line */ -struct drm_cmdline_mode { - bool specified; - bool refresh_specified; - bool bpp_specified; - int xres, yres; - int bpp; - int refresh; - bool rb; - bool interlace; - bool cvt; - bool margins; - enum drm_connector_force force; -}; - /** * drm_mode_is_stereo - check for stereo mode flags * @mode: drm_display_mode to check diff --git a/include/drm/drm_modeset.h b/include/drm/drm_modeset.h index 0c2b0f3c5f34..fe910d5efe12 100644 --- a/include/drm/drm_modeset.h +++ b/include/drm/drm_modeset.h @@ -25,6 +25,7 @@ #include struct drm_object_properties; +struct drm_property; struct drm_mode_object { uint32_t id; @@ -34,17 +35,36 @@ struct drm_mode_object { void (*free_cb)(struct kref *kref); }; +#define DRM_OBJECT_MAX_PROPERTY 24 +struct drm_object_properties { + int count, atomic_count; + /* NOTE: if we ever start dynamically destroying properties (ie. + * not at drm_mode_config_cleanup() time), then we'd have to do + * a better job of detaching property from mode objects to avoid + * dangling property pointers: + */ + struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; + /* do not read/write values directly, but use drm_object_property_get_value() + * and drm_object_property_set_value(): + */ + uint64_t values[DRM_OBJECT_MAX_PROPERTY]; +}; + +/* Avoid boilerplate. I'm tired of typing. */ +#define DRM_ENUM_NAME_FN(fnname, list) \ + const char *fnname(int val) \ + { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(list); i++) { \ + if (list[i].type == val) \ + return list[i].name; \ + } \ + return "(unknown)"; \ + } + struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type); void drm_mode_object_reference(struct drm_mode_object *obj); void drm_mode_object_unreference(struct drm_mode_object *obj); -/* FIXME: This is temporary until we have a drm_connector.h */ -enum drm_connector_force { - DRM_FORCE_UNSPECIFIED, - DRM_FORCE_OFF, - DRM_FORCE_ON, /* force on analog part normally */ - DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ -}; - #endif From 52a9fcdac303364522467310fc83a415fedbd0ae Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:51 +0200 Subject: [PATCH 21/46] drm/doc: Include new drm_blend.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's not much point in kerneldoc if it's not included: - It won't show up in the pretty html pages. - The comments itself won't get parsed, which means 0day won't pick up changes, resulting in stale docs fast. Also, uapi really should be core, not helpers, so move drm_blend.c to that. That also means that the zpos normilize function loses it's helper status (and we might as well call it always). For that, EXPORT_SYMBOL. Just spotted while integrating docs and noticing that one was missing. With sphinx there's really no excuse any more to not build the docs and make sure it's all nice! $ make DOCBOOKS="" htmldocs Cc: Marek Szyprowski Cc: Benjamin Gaignard Cc: Laurent Pinchart Cc: Ville Syrjälä Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-15-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 6 ++++++ drivers/gpu/drm/Makefile | 4 ++-- drivers/gpu/drm/drm_atomic_helper.c | 2 +- drivers/gpu/drm/drm_blend.c | 8 ++++---- drivers/gpu/drm/drm_crtc_internal.h | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 449acc2517c7..6e7ab57924f0 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -559,6 +559,12 @@ connector and plane objects by calling the pointer to the target object, a pointer to the previously created property and an initial instance value. +Blending and Z-Position properties +---------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_blend.c + :export: + Existing KMS Properties ----------------------- diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 2eff1a33ab63..193ff2d09479 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -13,7 +13,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ - drm_framebuffer.o drm_connector.o + drm_framebuffer.o drm_connector.o drm_blend.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o @@ -25,7 +25,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ - drm_simple_kms_helper.o drm_blend.o drm_modeset_helper.o + drm_simple_kms_helper.o drm_modeset_helper.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e1f5de274913..9abe0a242f96 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -594,7 +594,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev, struct drm_plane_state *plane_state; int i, ret = 0; - ret = drm_atomic_helper_normalize_zpos(dev, state); + ret = drm_atomic_normalize_zpos(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index f3c0942bd756..0813b7e021be 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -193,8 +193,7 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, } /** - * drm_atomic_helper_normalize_zpos - calculate normalized zpos values for all - * crtcs + * drm_atomic_normalize_zpos - calculate normalized zpos values for all crtcs * @dev: DRM device * @state: atomic state of DRM device * @@ -205,8 +204,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, * RETURNS * Zero for success or -errno */ -int drm_atomic_helper_normalize_zpos(struct drm_device *dev, - struct drm_atomic_state *state) +int drm_atomic_normalize_zpos(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -236,3 +235,4 @@ int drm_atomic_helper_normalize_zpos(struct drm_device *dev, } return 0; } +EXPORT_SYMBOL(drm_atomic_normalize_zpos); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 99a8863536ac..62efb9d09a85 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -160,5 +160,5 @@ int drm_modeset_register_all(struct drm_device *dev); void drm_modeset_unregister_all(struct drm_device *dev); /* drm_blend.c */ -int drm_atomic_helper_normalize_zpos(struct drm_device *dev, - struct drm_atomic_state *state); +int drm_atomic_normalize_zpos(struct drm_device *dev, + struct drm_atomic_state *state); From e15c8f4b6e5ecd370890c218688ead4e91f6b0d6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:52 +0200 Subject: [PATCH 22/46] drm: Don't export dp-aux devnode functions They're only used internally within the dp helpers. Also nuke the kerneldoc (we only document the driver interface in the drm shared functions). And move the header file from the public include/ directory to the source files into drm_crtc_helper_internal.h, similar to how we already have drm_crtc_internal.h. While at it also move drm_fb_helper_modinit since that belongs in there, too. I noticed this all since I spotted kerneldoc which wasn't pulled into the rst templates. v2: Update Copyright date. Cc: Sean Paul Cc: Rafael Antognolli Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-16-git-send-email-daniel.vetter@ffwll.ch --- .../gpu/drm/drm_crtc_helper_internal.h | 36 +++++++++---------- drivers/gpu/drm/drm_dp_aux_dev.c | 19 ++-------- drivers/gpu/drm/drm_dp_helper.c | 3 +- drivers/gpu/drm/drm_kms_helper_common.c | 3 +- include/drm/drm_fb_helper.h | 1 - 5 files changed, 23 insertions(+), 39 deletions(-) rename include/drm/drm_dp_aux_dev.h => drivers/gpu/drm/drm_crtc_helper_internal.h (63%) diff --git a/include/drm/drm_dp_aux_dev.h b/drivers/gpu/drm/drm_crtc_helper_internal.h similarity index 63% rename from include/drm/drm_dp_aux_dev.h rename to drivers/gpu/drm/drm_crtc_helper_internal.h index 1b76d990d8ab..4e6b57ae7188 100644 --- a/include/drm/drm_dp_aux_dev.h +++ b/drivers/gpu/drm/drm_crtc_helper_internal.h @@ -1,5 +1,5 @@ /* - * Copyright © 2015 Intel Corporation + * Copyright © 2016 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -8,37 +8,36 @@ * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Rafael Antognolli - * + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef DRM_DP_AUX_DEV -#define DRM_DP_AUX_DEV +/* + * This header file contains mode setting related functions and definitions + * which are only used within the drm kms helper module as internal + * implementation details and are not exported to drivers. + */ #include -#ifdef CONFIG_DRM_DP_AUX_CHARDEV +/* drm_fb_helper.c */ +int drm_fb_helper_modinit(void); +/* drm_dp_aux_dev.c */ +#ifdef CONFIG_DRM_DP_AUX_CHARDEV int drm_dp_aux_dev_init(void); void drm_dp_aux_dev_exit(void); int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); - #else - static inline int drm_dp_aux_dev_init(void) { return 0; @@ -56,7 +55,4 @@ static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) { } - -#endif - #endif diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c index 734f86a345f6..ec1ed94b2390 100644 --- a/drivers/gpu/drm/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/drm_dp_aux_dev.c @@ -36,6 +36,8 @@ #include #include +#include "drm_crtc_helper_internal.h" + struct drm_dp_aux_dev { unsigned index; struct drm_dp_aux *aux; @@ -283,12 +285,7 @@ static int auxdev_wait_atomic_t(atomic_t *p) schedule(); return 0; } -/** - * drm_dp_aux_unregister_devnode() - unregister a devnode for this aux channel - * @aux: DisplayPort AUX channel - * - * Returns 0 on success or a negative error code on failure. - */ + void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) { struct drm_dp_aux_dev *aux_dev; @@ -314,14 +311,7 @@ void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name); kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); } -EXPORT_SYMBOL(drm_dp_aux_unregister_devnode); -/** - * drm_dp_aux_register_devnode() - register a devnode for this aux channel - * @aux: DisplayPort AUX channel - * - * Returns 0 on success or a negative error code on failure. - */ int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) { struct drm_dp_aux_dev *aux_dev; @@ -347,7 +337,6 @@ int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) drm_dp_aux_unregister_devnode(aux); return res; } -EXPORT_SYMBOL(drm_dp_aux_register_devnode); int drm_dp_aux_dev_init(void) { @@ -369,11 +358,9 @@ int drm_dp_aux_dev_init(void) class_destroy(drm_dp_aux_dev_class); return res; } -EXPORT_SYMBOL(drm_dp_aux_dev_init); void drm_dp_aux_dev_exit(void) { unregister_chrdev(drm_dev_major, "aux"); class_destroy(drm_dp_aux_dev_class); } -EXPORT_SYMBOL(drm_dp_aux_dev_exit); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 5d20255f3db3..031c4d335b08 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -28,9 +28,10 @@ #include #include #include -#include #include +#include "drm_crtc_helper_internal.h" + /** * DOC: dp helpers * diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 3187c4bb01cb..45db36cd3d20 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -27,7 +27,8 @@ #include #include -#include + +#include "drm_crtc_helper_internal.h" MODULE_AUTHOR("David Airlie, Jesse Barnes"); MODULE_DESCRIPTION("DRM KMS helper"); diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 130c324f1aee..97889a90ff23 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -216,7 +216,6 @@ struct drm_fb_helper { }; #ifdef CONFIG_DRM_FBDEV_EMULATION -int drm_fb_helper_modinit(void); void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, const struct drm_fb_helper_funcs *funcs); int drm_fb_helper_init(struct drm_device *dev, From ae2a6da8762985fc238eea81b88c3b982f1c37bc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:53 +0200 Subject: [PATCH 23/46] drm: Update connector documentation - Shuffle docs from drm-kms.rst into the structure docs where it makes sense. - Put the remaining bits into a new overview section. One thing I've changed is around probing: Old docs says that you _must_ use the probe helpers, which isn't correct. Helpers are always optional. v2: Review from Sean. Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-17-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 170 ++------------------------------ drivers/gpu/drm/drm_connector.c | 33 ++++++- include/drm/drm_connector.h | 57 ++++++++++- 3 files changed, 94 insertions(+), 166 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 6e7ab57924f0..fa948b4e029b 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -110,8 +110,14 @@ Display Modes Function Reference .. kernel-doc:: drivers/gpu/drm/drm_modes.c :export: -Connector Display Sink Abstraction -================================== +Connector Abstraction +===================== + +.. kernel-doc:: drivers/gpu/drm/drm_connector.c + :doc: overview + +Connector Functions Reference +----------------------------- .. kernel-doc:: include/drm/drm_connector.h :internal: @@ -232,166 +238,6 @@ encoders unattached at initialization time. Applications (or the fbdev compatibility layer when implemented) are responsible for attaching the encoders they want to use to a CRTC. -Connectors (:c:type:`struct drm_connector `) ------------------------------------------------------------ - -A connector is the final destination for pixel data on a device, and -usually connects directly to an external display device like a monitor -or laptop panel. A connector can only be attached to one encoder at a -time. The connector is also the structure where information about the -attached display is kept, so it contains fields for display data, EDID -data, DPMS & connection status, and information about modes supported on -the attached displays. - -Connector Initialization -~~~~~~~~~~~~~~~~~~~~~~~~ - -Finally a KMS driver must create, initialize, register and attach at -least one :c:type:`struct drm_connector ` -instance. The instance is created as other KMS objects and initialized -by setting the following fields. - -interlace_allowed - Whether the connector can handle interlaced modes. - -doublescan_allowed - Whether the connector can handle doublescan. - -display_info - Display information is filled from EDID information when a display - is detected. For non hot-pluggable displays such as flat panels in - embedded systems, the driver should initialize the - display_info.width_mm and display_info.height_mm fields with the - physical size of the display. - -polled - Connector polling mode, a combination of - - DRM_CONNECTOR_POLL_HPD - The connector generates hotplug events and doesn't need to be - periodically polled. The CONNECT and DISCONNECT flags must not - be set together with the HPD flag. - - DRM_CONNECTOR_POLL_CONNECT - Periodically poll the connector for connection. - - DRM_CONNECTOR_POLL_DISCONNECT - Periodically poll the connector for disconnection. - - Set to 0 for connectors that don't support connection status - discovery. - -The connector is then registered with a call to -:c:func:`drm_connector_init()` with a pointer to the connector -functions and a connector type, and exposed through sysfs with a call to -:c:func:`drm_connector_register()`. - -Supported connector types are - -- DRM_MODE_CONNECTOR_VGA -- DRM_MODE_CONNECTOR_DVII -- DRM_MODE_CONNECTOR_DVID -- DRM_MODE_CONNECTOR_DVIA -- DRM_MODE_CONNECTOR_Composite -- DRM_MODE_CONNECTOR_SVIDEO -- DRM_MODE_CONNECTOR_LVDS -- DRM_MODE_CONNECTOR_Component -- DRM_MODE_CONNECTOR_9PinDIN -- DRM_MODE_CONNECTOR_DisplayPort -- DRM_MODE_CONNECTOR_HDMIA -- DRM_MODE_CONNECTOR_HDMIB -- DRM_MODE_CONNECTOR_TV -- DRM_MODE_CONNECTOR_eDP -- DRM_MODE_CONNECTOR_VIRTUAL - -Connectors must be attached to an encoder to be used. For devices that -map connectors to encoders 1:1, the connector should be attached at -initialization time with a call to -:c:func:`drm_mode_connector_attach_encoder()`. The driver must -also set the :c:type:`struct drm_connector ` -encoder field to point to the attached encoder. - -Finally, drivers must initialize the connectors state change detection -with a call to :c:func:`drm_kms_helper_poll_init()`. If at least -one connector is pollable but can't generate hotplug interrupts -(indicated by the DRM_CONNECTOR_POLL_CONNECT and -DRM_CONNECTOR_POLL_DISCONNECT connector flags), a delayed work will -automatically be queued to periodically poll for changes. Connectors -that can generate hotplug interrupts must be marked with the -DRM_CONNECTOR_POLL_HPD flag instead, and their interrupt handler must -call :c:func:`drm_helper_hpd_irq_event()`. The function will -queue a delayed work to check the state of all connectors, but no -periodic polling will be done. - -Connector Operations -~~~~~~~~~~~~~~~~~~~~ - - **Note** - - Unless otherwise state, all operations are mandatory. - -DPMS -'''' - -void (\*dpms)(struct drm_connector \*connector, int mode); -The DPMS operation sets the power state of a connector. The mode -argument is one of - -- DRM_MODE_DPMS_ON - -- DRM_MODE_DPMS_STANDBY - -- DRM_MODE_DPMS_SUSPEND - -- DRM_MODE_DPMS_OFF - -In all but DPMS_ON mode the encoder to which the connector is attached -should put the display in low-power mode by driving its signals -appropriately. If more than one connector is attached to the encoder -care should be taken not to change the power state of other displays as -a side effect. Low-power mode should be propagated to the encoders and -CRTCs when all related connectors are put in low-power mode. - -Modes -''''' - -int (\*fill_modes)(struct drm_connector \*connector, uint32_t -max_width, uint32_t max_height); -Fill the mode list with all supported modes for the connector. If the -``max_width`` and ``max_height`` arguments are non-zero, the -implementation must ignore all modes wider than ``max_width`` or higher -than ``max_height``. - -The connector must also fill in this operation its display_info -width_mm and height_mm fields with the connected display physical size -in millimeters. The fields should be set to 0 if the value isn't known -or is not applicable (for instance for projector devices). - -Connection Status -''''''''''''''''' - -The connection status is updated through polling or hotplug events when -supported (see ?). The status value is reported to userspace through -ioctls and must not be used inside the driver, as it only gets -initialized by a call to :c:func:`drm_mode_getconnector()` from -userspace. - -enum drm_connector_status (\*detect)(struct drm_connector -\*connector, bool force); -Check to see if anything is attached to the connector. The ``force`` -parameter is set to false whilst polling or to true when checking the -connector due to user request. ``force`` can be used by the driver to -avoid expensive, destructive operations during automated probing. - -Return connector_status_connected if something is connected to the -connector, connector_status_disconnected if nothing is connected and -connector_status_unknown if the connection state isn't known. - -Drivers should only return connector_status_connected if the -connection status has really been probed as connected. Connectors that -can't detect the connection status, or failed connection status probes, -should return connector_status_unknown. - Cleanup ------- diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 99ece6758061..6a0551744d13 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -27,6 +27,37 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" +/** + * DOC: overview + * + * In DRM connectors are the general abstraction for display sinks, and include + * als fixed panels or anything else that can display pixels in some form. As + * opposed to all other KMS objects representing hardware (like CRTC, encoder or + * plane abstractions) connectors can be hotplugged and unplugged at runtime. + * Hence they are reference-counted using drm_connector_reference() and + * drm_connector_unreference(). + * + * KMS driver must create, initialize, register and attach at a struct + * &drm_connector for each such sink. The instance is created as other KMS + * objects and initialized by setting the following fields. + * + * The connector is then registered with a call to drm_connector_init() with a + * pointer to the connector functions and a connector type, and exposed through + * sysfs with a call to drm_connector_register(). + * + * Connectors must be attached to an encoder to be used. For devices that map + * connectors to encoders 1:1, the connector should be attached at + * initialization time with a call to drm_mode_connector_attach_encoder(). The + * driver must also set the struct &drm_connector encoder field to point to the + * attached encoder. + * + * For connectors which are not fixed (like built-in panels) the driver needs to + * support hotplug notifications. The simplest way to do that is by using the + * probe helpers, see drm_kms_helper_poll_init() for connectors which don't have + * hardware support for hotplug interrupts. Connectors with hardware hotplug + * support can instead use e.g. drm_helper_hpd_irq_event(). + */ + struct drm_conn_prop_enum_list { int type; const char *name; @@ -77,7 +108,7 @@ void drm_connector_ida_destroy(void) * drm_connector_get_cmdline_mode - reads the user's cmdline mode * @connector: connector to quwery * - * The kernel supports per-connector configration of its consoles through + * The kernel supports per-connector configuration of its consoles through * use of the video= parameter. This function parses that option and * extracts the user's specified mode (or enable/disable status) for a * particular connector. This is typically only used during the early fbdev diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ec2bea0b1b38..3537b7d8259b 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -42,9 +42,36 @@ enum drm_connector_force { DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ }; +/** + * enum drm_connector_status - status for a &drm_connector + * + * This enum is used to track the connector status. There are no separate + * #defines for the uapi! + */ enum drm_connector_status { + /** + * @connector_status_connected: The connector is definitely connected to + * a sink device, and can be enabled. + */ connector_status_connected = 1, + /** + * @connector_status_disconnected: The connector isn't connected to a + * sink device which can be autodetect. For digital outputs like DP or + * HDMI (which can be realiable probed) this means there's really + * nothing there. It is driver-dependent whether a connector with this + * status can be lit up or not. + */ connector_status_disconnected = 2, + /** + * @connector_status_unknown: The connector's status could not be + * reliably detected. This happens when probing would either cause + * flicker (like load-detection when the connector is in use), or when a + * hardware resource isn't available (like when load-detection needs a + * free CRTC). It should be possible to light up the connector with one + * of the listed fallback modes. For default configuration userspace + * should only try to light up connectors with unknown status when + * there's not connector with @connector_status_connected. + */ connector_status_unknown = 3, }; @@ -416,11 +443,9 @@ struct drm_cmdline_mode { * @modes: modes available on this connector (from fill_modes() + user) * @status: one of the drm_connector_status enums (connected, not, or unknown) * @probed_modes: list of modes derived directly from the display - * @display_info: information about attached display (e.g. from EDID) * @funcs: connector control functions * @edid_blob_ptr: DRM property containing EDID if present * @properties: property tracking for this connector - * @polled: a DRM_CONNECTOR_POLL_ value for core driven polling * @dpms: current dpms state * @helper_private: mid-layer private data * @cmdline_mode: mode line parsed from the kernel cmdline for this connector @@ -485,6 +510,13 @@ struct drm_connector { /* these are modes added by probing with DDC or the BIOS */ struct list_head probed_modes; + /** + * @display_info: Display information is filled from EDID information + * when a display is detected. For non hot-pluggable displays such as + * flat panels in embedded systems, the driver should initialize the + * display_info.width_mm and display_info.height_mm fields with the + * physical size of the display. + */ struct drm_display_info display_info; const struct drm_connector_funcs *funcs; @@ -519,7 +551,26 @@ struct drm_connector { /* DACs should rarely do this without a lot of testing */ #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) - uint8_t polled; /* DRM_CONNECTOR_POLL_* */ + /** + * @polled: + * + * Connector polling mode, a combination of + * + * DRM_CONNECTOR_POLL_HPD + * The connector generates hotplug events and doesn't need to be + * periodically polled. The CONNECT and DISCONNECT flags must not + * be set together with the HPD flag. + * + * DRM_CONNECTOR_POLL_CONNECT + * Periodically poll the connector for connection. + * + * DRM_CONNECTOR_POLL_DISCONNECT + * Periodically poll the connector for disconnection. + * + * Set to 0 for connectors that don't support connection status + * discovery. + */ + uint8_t polled; /* requested DPMS state */ int dpms; From 46444537479fa836969b441198e3144026c69541 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:54 +0200 Subject: [PATCH 24/46] drm: Remove display_info->min/max_(h|v)max No one looks at it, only i915/gma500 lvds even bother to fill it out. I guess a very old plan was to use this for filtering modes, but that's already done within the edid parser. v2: Move misplaced hunk to this patch. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-18-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 8 -------- drivers/gpu/drm/gma500/mdfld_dsi_output.c | 5 ----- drivers/gpu/drm/gma500/psb_intel_lvds.c | 9 --------- drivers/gpu/drm/i915/intel_lvds.c | 11 ----------- include/drm/drm_connector.h | 3 --- 5 files changed, 36 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 38dc89083148..ea733ab5b1e0 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -415,14 +415,6 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) if (ret) return ret; - /* Didn't get an EDID, so - * Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; if (mode_dev->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c index 907cb51795c3..acb3848ef1c9 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c @@ -335,11 +335,6 @@ static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *dup_mode = NULL; struct drm_device *dev = connector->dev; - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; - if (fixed_mode) { dev_dbg(dev->dev, "fixed_mode %dx%d\n", fixed_mode->hdisplay, fixed_mode->vdisplay); diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index e55733ca46d2..fd7c91254841 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -530,15 +530,6 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) if (ret) return ret; - /* Didn't get an EDID, so - * Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; - if (mode_dev->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 49550470483e..e29f3d12fd1c 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1054,17 +1054,6 @@ void intel_lvds_init(struct drm_device *dev) } lvds_connector->base.edid = edid; - if (IS_ERR_OR_NULL(edid)) { - /* Didn't get an EDID, so - * Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; - } - list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { DRM_DEBUG_KMS("using preferred mode from EDID: "); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 3537b7d8259b..bc88a5575792 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -94,9 +94,6 @@ struct drm_display_info { unsigned int width_mm; unsigned int height_mm; - /* Clock limits FIXME: storage format */ - unsigned int min_vfreq, max_vfreq; - unsigned int min_hfreq, max_hfreq; unsigned int pixel_clock; unsigned int bpc; From b3c6c8bfe378309f8185d591579a3cb3aa2fe2e8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:55 +0200 Subject: [PATCH 25/46] drm: document drm_display_info We seem to have a bit a mess in how to describe the bus formats, with a multitude of competing ways. Might be best to consolidate it all and use MEDIA_BUS_FMT_ also for the hdmi color formats and high color modes. Also move all the display_info related functions into drm_connector.c (there's only one) to group it all together. I did decided against also moving the edid related display info functions, they seem to fit better in drm_edid.c. Instead sprinkle a few cross references around. While at that reduce the kerneldoc for static functions, there's not point in documenting internals with that much detail really. v2: Fix typo and move misplaced hunk (Sean). Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-19-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_connector.c | 34 ++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 34 ------------------ drivers/gpu/drm/drm_edid.c | 23 +++--------- include/drm/drm_connector.h | 63 ++++++++++++++++++++++++++++++--- include/drm/drm_crtc.h | 4 --- 5 files changed, 97 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 6a0551744d13..26bb78c76481 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -506,6 +506,40 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = { }; DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) +/** + * drm_display_info_set_bus_formats - set the supported bus formats + * @info: display info to store bus formats in + * @formats: array containing the supported bus formats + * @num_formats: the number of entries in the fmts array + * + * Store the supported bus formats in display info structure. + * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for + * a full list of available formats. + */ +int drm_display_info_set_bus_formats(struct drm_display_info *info, + const u32 *formats, + unsigned int num_formats) +{ + u32 *fmts = NULL; + + if (!formats && num_formats) + return -EINVAL; + + if (formats && num_formats) { + fmts = kmemdup(formats, sizeof(*formats) * num_formats, + GFP_KERNEL); + if (!fmts) + return -ENOMEM; + } + + kfree(info->bus_formats); + info->bus_formats = fmts; + info->num_bus_formats = num_formats; + + return 0; +} +EXPORT_SYMBOL(drm_display_info_set_bus_formats); + /* Optional connector properties. */ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { { DRM_MODE_SCALE_NONE, "None" }, diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 13f7b13a6f49..7f2510524f09 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -419,40 +419,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -/** - * drm_display_info_set_bus_formats - set the supported bus formats - * @info: display info to store bus formats in - * @formats: array containing the supported bus formats - * @num_formats: the number of entries in the fmts array - * - * Store the supported bus formats in display info structure. - * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for - * a full list of available formats. - */ -int drm_display_info_set_bus_formats(struct drm_display_info *info, - const u32 *formats, - unsigned int num_formats) -{ - u32 *fmts = NULL; - - if (!formats && num_formats) - return -EINVAL; - - if (formats && num_formats) { - fmts = kmemdup(formats, sizeof(*formats) * num_formats, - GFP_KERNEL); - if (!fmts) - return -ENOMEM; - } - - kfree(info->bus_formats); - info->bus_formats = fmts; - info->num_bus_formats = num_formats; - - return 0; -} -EXPORT_SYMBOL(drm_display_info_set_bus_formats); - static int drm_encoder_register_all(struct drm_device *dev) { struct drm_encoder *encoder; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 637a0aa4d3a0..62dffbccd447 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3721,14 +3721,7 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) } EXPORT_SYMBOL(drm_rgb_quant_range_selectable); -/** - * drm_assign_hdmi_deep_color_info - detect whether monitor supports - * hdmi deep color modes and update drm_display_info if so. - * @edid: monitor EDID information - * @info: Updated with maximum supported deep color bpc and color format - * if deep color supported. - * @connector: DRM connector, used only for debug output - * +/* * Parse the CEA extension according to CEA-861-B. * Return true if HDMI deep color supported, false if not or unknown. */ @@ -3822,16 +3815,6 @@ static bool drm_assign_hdmi_deep_color_info(struct edid *edid, return false; } -/** - * drm_add_display_info - pull display info out if present - * @edid: EDID data - * @info: display info (attached to connector) - * @connector: connector whose edid is used to build display info - * - * Grab any available display info and stuff it into the drm_display_info - * structure that's part of the connector. Useful for tracking bpp and - * color spaces. - */ static void drm_add_display_info(struct edid *edid, struct drm_display_info *info, struct drm_connector *connector) @@ -4052,7 +4035,9 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, * @connector: connector we're probing * @edid: EDID data * - * Add the specified modes to the connector's mode list. + * Add the specified modes to the connector's mode list. Also fills out the + * &drm_display_info structure in @connector with any information which can be + * derived from the edid. * * Return: The number of modes added or 0 if we couldn't find any. */ diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index bc88a5575792..f1576db6c044 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -84,28 +84,69 @@ enum subpixel_order { SubPixelNone, }; -/* - * Describes a given display (e.g. CRT or flat panel) and its limitations. +/** + * struct drm_display_info - runtime data about the connected sink + * + * Describes a given display (e.g. CRT or flat panel) and its limitations. For + * fixed display sinks like built-in panels there's not much difference between + * this and struct &drm_connector. But for sinks with a real cable this + * structure is meant to describe all the things at the other end of the cable. + * + * For sinks which provide an EDID this can be filled out by calling + * drm_add_edid_modes(). */ struct drm_display_info { + /** + * @name: Name of the display. + */ char name[DRM_DISPLAY_INFO_LEN]; - /* Physical size */ + /** + * @width_mm: Physical width in mm. + */ unsigned int width_mm; + /** + * @height_mm: Physical height in mm. + */ unsigned int height_mm; + /** + * @pixel_clock: Maximum pixel clock supported by the sink, in units of + * 100Hz. This mismatches the clok in &drm_display_mode (which is in + * kHZ), because that's what the EDID uses as base unit. + */ unsigned int pixel_clock; + /** + * @bpc: Maximum bits per color channel. Used by HDMI and DP outputs. + */ unsigned int bpc; + /** + * @subpixel_order: Subpixel order of LCD panels. + */ enum subpixel_order subpixel_order; #define DRM_COLOR_FORMAT_RGB444 (1<<0) #define DRM_COLOR_FORMAT_YCRCB444 (1<<1) #define DRM_COLOR_FORMAT_YCRCB422 (1<<2) + /** + * @color_formats: HDMI Color formats, selects between RGB and YCrCb + * modes. Used DRM_COLOR_FORMAT\_ defines, which are _not_ the same ones + * as used to describe the pixel format in framebuffers, and also don't + * match the formats in @bus_formats which are shared with v4l. + */ u32 color_formats; + /** + * @bus_formats: Pixel data format on the wire, somewhat redundant with + * @color_formats. Array of size @num_bus_formats encoded using + * MEDIA_BUS_FMT\_ defines shared with v4l and media drivers. + */ const u32 *bus_formats; + /** + * @num_bus_formats: Size of @bus_formats array. + */ unsigned int num_bus_formats; #define DRM_BUS_FLAG_DE_LOW (1<<0) @@ -115,14 +156,28 @@ struct drm_display_info { /* drive data on neg. edge */ #define DRM_BUS_FLAG_PIXDATA_NEGEDGE (1<<3) + /** + * @bus_flags: Additional information (like pixel signal polarity) for + * the pixel data on the bus, using DRM_BUS_FLAGS\_ defines. + */ u32 bus_flags; - /* Mask of supported hdmi deep color modes */ + /** + * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even + * more stuff redundant with @bus_formats. + */ u8 edid_hdmi_dc_modes; + /** + * @cea_rev: CEA revision of the HDMI sink. + */ u8 cea_rev; }; +int drm_display_info_set_bus_formats(struct drm_display_info *info, + const u32 *formats, + unsigned int num_formats); + /** * struct drm_connector_state - mutable connector state * @connector: backpointer to the connector diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e30ea0be6417..3fa0275e509f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2208,10 +2208,6 @@ extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); -extern int drm_display_info_set_bus_formats(struct drm_display_info *info, - const u32 *formats, - unsigned int num_formats); - static inline bool drm_property_type_is(struct drm_property *property, uint32_t type) { From b754b35b089ddfea3ff7b9b1d2e99e61d726d177 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:56 +0200 Subject: [PATCH 26/46] vgaarbiter: rst-ifiy and polish kerneldoc Move the documentation into Documentation/gpu, link it up and pull in the kernel doc. No actual text changes except that I did polish the kerneldoc a bit, especially for vga_client_register(). v2: Remove some rst from vga-switcheroo.rst that I don't understand, but which seems to be the reason why the new vgaarbiter.rst sometimes drops out of the sidebar index. v3: Drop one level of headings and clarify the vgaarb one a bit. v4: Fix some typos (Sean). Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-20-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/index.rst | 1 + Documentation/gpu/vga-switcheroo.rst | 2 - .../{vgaarbiter.txt => gpu/vgaarbiter.rst} | 143 +++++++++--------- drivers/gpu/vga/vgaarb.c | 110 +++++++++++++- include/linux/vgaarb.h | 128 ++-------------- 5 files changed, 196 insertions(+), 188 deletions(-) rename Documentation/{vgaarbiter.txt => gpu/vgaarbiter.rst} (65%) diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index fcac0fa72056..ba92f45abb76 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -12,3 +12,4 @@ Linux GPU Driver Developer's Guide drm-uapi i915 vga-switcheroo + vgaarbiter diff --git a/Documentation/gpu/vga-switcheroo.rst b/Documentation/gpu/vga-switcheroo.rst index cbbdb994f1dd..463a74fc40d1 100644 --- a/Documentation/gpu/vga-switcheroo.rst +++ b/Documentation/gpu/vga-switcheroo.rst @@ -1,5 +1,3 @@ -.. _vga_switcheroo: - ============== VGA Switcheroo ============== diff --git a/Documentation/vgaarbiter.txt b/Documentation/gpu/vgaarbiter.rst similarity index 65% rename from Documentation/vgaarbiter.txt rename to Documentation/gpu/vgaarbiter.rst index 014423e2824c..0b41b051d021 100644 --- a/Documentation/vgaarbiter.txt +++ b/Documentation/gpu/vgaarbiter.rst @@ -1,4 +1,4 @@ - +=========== VGA Arbiter =========== @@ -19,21 +19,8 @@ control bus resources. Therefore an arbitration scheme outside of the X server is needed to control the sharing of these resources. This document introduces the operation of the VGA arbiter implemented for the Linux kernel. ----------------------------------------------------------------------------- - -I. Details and Theory of Operation - I.1 vgaarb - I.2 libpciaccess - I.3 xf86VGAArbiter (X server implementation) -II. Credits -III.References - - -I. Details and Theory of Operation -================================== - -I.1 vgaarb ----------- +vgaarb kernel/userspace ABI +--------------------------- The vgaarb is a module of the Linux Kernel. When it is initially loaded, it scans all PCI devices and adds the VGA ones inside the arbitration. The @@ -44,42 +31,52 @@ explicitly tell it by calling vga_set_legacy_decoding(). The kernel exports a char device interface (/dev/vga_arbiter) to the clients, which has the following semantics: - open : open user instance of the arbiter. By default, it's attached to - the default VGA device of the system. +open + Opens a user instance of the arbiter. By default, it's attached to the + default VGA device of the system. - close : close user instance. Release locks made by the user +close + Close a user instance. Release locks made by the user - read : return a string indicating the status of the target like: +read + Return a string indicating the status of the target like: - ",decodes=,owns=,locks= (ic,mc)" + ",decodes=,owns=,locks= (ic,mc)" - An IO state string is of the form {io,mem,io+mem,none}, mc and - ic are respectively mem and io lock counts (for debugging/ - diagnostic only). "decodes" indicate what the card currently - decodes, "owns" indicates what is currently enabled on it, and - "locks" indicates what is locked by this card. If the card is - unplugged, we get "invalid" then for card_ID and an -ENODEV - error is returned for any command until a new card is targeted. + An IO state string is of the form {io,mem,io+mem,none}, mc and + ic are respectively mem and io lock counts (for debugging/ + diagnostic only). "decodes" indicate what the card currently + decodes, "owns" indicates what is currently enabled on it, and + "locks" indicates what is locked by this card. If the card is + unplugged, we get "invalid" then for card_ID and an -ENODEV + error is returned for any command until a new card is targeted. - write : write a command to the arbiter. List of commands: +write + Write a command to the arbiter. List of commands: - target : switch target to card (see below) - lock : acquires locks on target ("none" is an invalid io_state) - trylock : non-blocking acquire locks on target (returns EBUSY if - unsuccessful) - unlock : release locks on target - unlock all : release all locks on target held by this user (not - implemented yet) - decodes : set the legacy decoding attributes for the card + target + switch target to card (see below) + lock + acquires locks on target ("none" is an invalid io_state) + trylock + non-blocking acquire locks on target (returns EBUSY if + unsuccessful) + unlock + release locks on target + unlock all + release all locks on target held by this user (not implemented + yet) + decodes + set the legacy decoding attributes for the card - poll : event if something changes on any card (not just the - target) + poll + event if something changes on any card (not just the target) - card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default" - to go back to the system default card (TODO: not implemented yet). Currently, - only PCI is supported as a prefix, but the userland API may support other bus - types in the future, even if the current kernel implementation doesn't. + card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default" + to go back to the system default card (TODO: not implemented yet). Currently, + only PCI is supported as a prefix, but the userland API may support other bus + types in the future, even if the current kernel implementation doesn't. Note about locks: @@ -97,29 +94,35 @@ in the arbiter. There is also an in-kernel API of the arbiter in case DRM, vgacon, or other drivers want to use it. +In-kernel interface +------------------- -I.2 libpciaccess ----------------- +.. kernel-doc:: include/linux/vgaarb.h + :internal: + +.. kernel-doc:: drivers/gpu/vga/vgaarb.c + :export: + +libpciaccess +------------ To use the vga arbiter char device it was implemented an API inside the libpciaccess library. One field was added to struct pci_device (each device -on the system): +on the system):: /* the type of resource decoded by the device */ int vgaarb_rsrc; -Besides it, in pci_system were added: +Besides it, in pci_system were added:: int vgaarb_fd; int vga_count; struct pci_device *vga_target; struct pci_device *vga_default_dev; - The vga_count is used to track how many cards are being arbitrated, so for instance, if there is only one card, then it can completely escape arbitration. - These functions below acquire VGA resources for the given card and mark those resources as locked. If the resources requested are "normal" (and not legacy) resources, the arbiter will first check whether the card is doing legacy @@ -136,44 +139,44 @@ VGA memory and IO afaik). If the card already owns the resources, the function succeeds. vga_arb_trylock() will return (-EBUSY) instead of blocking. Nested calls are supported (a per-resource counter is maintained). +Set the target device of this client. :: -Set the target device of this client. int pci_device_vgaarb_set_target (struct pci_device *dev); - For instance, in x86 if two devices on the same bus want to lock different resources, both will succeed (lock). If devices are in different buses and -trying to lock different resources, only the first who tried succeeds. +trying to lock different resources, only the first who tried succeeds. :: + int pci_device_vgaarb_lock (void); int pci_device_vgaarb_trylock (void); -Unlock resources of device. +Unlock resources of device. :: + int pci_device_vgaarb_unlock (void); Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA Memory, both, or none. All cards default to both, the card driver (fbdev for example) should tell the arbiter if it has disabled legacy decoding, so the card can be left out of the arbitration process (and can be safe to take -interrupts at any time. +interrupts at any time. :: + int pci_device_vgaarb_decodes (int new_vgaarb_rsrc); -Connects to the arbiter device, allocates the struct +Connects to the arbiter device, allocates the struct :: + int pci_device_vgaarb_init (void); -Close the connection +Close the connection :: + void pci_device_vgaarb_fini (void); - -I.3 xf86VGAArbiter (X server implementation) --------------------------------------------- - -(TODO) +xf86VGAArbiter (X server implementation) +---------------------------------------- X server basically wraps all the functions that touch VGA registers somehow. - -II. Credits -=========== +References +---------- Benjamin Herrenschmidt (IBM?) started this work when he discussed such design with the Xorg community in 2005 [1, 2]. In the end of 2007, Paulo Zanoni and @@ -182,11 +185,7 @@ enhancing the kernel code to adapt as a kernel module and also did the implementation of the user space side [3]. Now (2009) Tiago Vignatti and Dave Airlie finally put this work in shape and queued to Jesse Barnes' PCI tree. - -III. References -============== - -[0] http://cgit.freedesktop.org/xorg/xserver/commit/?id=4b42448a2388d40f257774fbffdccaea87bd0347 -[1] http://lists.freedesktop.org/archives/xorg/2005-March/006663.html -[2] http://lists.freedesktop.org/archives/xorg/2005-March/006745.html -[3] http://lists.freedesktop.org/archives/xorg/2007-October/029507.html +0) http://cgit.freedesktop.org/xorg/xserver/commit/?id=4b42448a2388d40f257774fbffdccaea87bd0347 +1) http://lists.freedesktop.org/archives/xorg/2005-March/006663.html +2) http://lists.freedesktop.org/archives/xorg/2005-March/006745.html +3) http://lists.freedesktop.org/archives/xorg/2007-October/029507.html diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index f17cb0431833..1887f199ccb7 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -131,7 +131,24 @@ static struct vga_device *vgadev_find(struct pci_dev *pdev) return NULL; } -/* Returns the default VGA device (vgacon's babe) */ +/** + * vga_default_device - return the default VGA device, for vgacon + * + * This can be defined by the platform. The default implementation + * is rather dumb and will probably only work properly on single + * vga card setups and/or x86 platforms. + * + * If your VGA default device is not PCI, you'll have to return + * NULL here. In this case, I assume it will not conflict with + * any PCI card. If this is not true, I'll have to define two archs + * hooks for enabling/disabling the VGA default device if that is + * possible. This may be a problem with real _ISA_ VGA cards, in + * addition to a PCI one. I don't know at this point how to deal + * with that card. Can theirs IOs be disabled at all ? If not, then + * I suppose it's a matter of having the proper arch hook telling + * us about it, so we basically never allow anybody to succeed a + * vga_get()... + */ struct pci_dev *vga_default_device(void) { return vga_default; @@ -356,6 +373,40 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) wake_up_all(&vga_wait_queue); } +/** + * vga_get - acquire & locks VGA resources + * @pdev: pci device of the VGA card or NULL for the system default + * @rsrc: bit mask of resources to acquire and lock + * @interruptible: blocking should be interruptible by signals ? + * + * This function acquires VGA resources for the given card and mark those + * resources locked. If the resource requested are "normal" (and not legacy) + * resources, the arbiter will first check whether the card is doing legacy + * decoding for that type of resource. If yes, the lock is "converted" into a + * legacy resource lock. + * + * The arbiter will first look for all VGA cards that might conflict and disable + * their IOs and/or Memory access, including VGA forwarding on P2P bridges if + * necessary, so that the requested resources can be used. Then, the card is + * marked as locking these resources and the IO and/or Memory accesses are + * enabled on the card (including VGA forwarding on parent P2P bridges if any). + * + * This function will block if some conflicting card is already locking one of + * the required resources (or any resource on a different bus segment, since P2P + * bridges don't differentiate VGA memory and IO afaik). You can indicate + * whether this blocking should be interruptible by a signal (for userland + * interface) or not. + * + * Must not be called at interrupt time or in atomic context. If the card + * already owns the resources, the function succeeds. Nested calls are + * supported (a per-resource counter is maintained) + * + * On success, release the VGA resource again with vga_put(). + * + * Returns: + * + * 0 on success, negative error code on failure. + */ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) { struct vga_device *vgadev, *conflict; @@ -408,6 +459,21 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) } EXPORT_SYMBOL(vga_get); +/** + * vga_tryget - try to acquire & lock legacy VGA resources + * @pdev: pci devivce of VGA card or NULL for system default + * @rsrc: bit mask of resources to acquire and lock + * + * This function performs the same operation as vga_get(), but will return an + * error (-EBUSY) instead of blocking if the resources are already locked by + * another card. It can be called in any context + * + * On success, release the VGA resource again with vga_put(). + * + * Returns: + * + * 0 on success, negative error code on failure. + */ int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { struct vga_device *vgadev; @@ -435,6 +501,16 @@ int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) } EXPORT_SYMBOL(vga_tryget); +/** + * vga_put - release lock on legacy VGA resources + * @pdev: pci device of VGA card or NULL for system default + * @rsrc: but mask of resource to release + * + * This fuction releases resources previously locked by vga_get() or + * vga_tryget(). The resources aren't disabled right away, so that a subsequence + * vga_get() on the same card will succeed immediately. Resources have a + * counter, so locks are only released if the counter reaches 0. + */ void vga_put(struct pci_dev *pdev, unsigned int rsrc) { struct vga_device *vgadev; @@ -716,7 +792,37 @@ void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) } EXPORT_SYMBOL(vga_set_legacy_decoding); -/* call with NULL to unregister */ +/** + * vga_client_register - register or unregister a VGA arbitration client + * @pdev: pci device of the VGA client + * @cookie: client cookie to be used in callbacks + * @irq_set_state: irq state change callback + * @set_vga_decode: vga decode change callback + * + * Clients have two callback mechanisms they can use. + * + * @irq_set_state callback: If a client can't disable its GPUs VGA + * resources, then we need to be able to ask it to turn off its irqs when we + * turn off its mem and io decoding. + * + * @set_vga_decode callback: If a client can disable its GPU VGA resource, it + * will get a callback from this to set the encode/decode state. + * + * Rationale: we cannot disable VGA decode resources unconditionally some single + * GPU laptops seem to require ACPI or BIOS access to the VGA registers to + * control things like backlights etc. Hopefully newer multi-GPU laptops do + * something saner, and desktops won't have any special ACPI for this. The + * driver will get a callback when VGA arbitration is first used by userspace + * since some older X servers have issues. + * + * This function does not check whether a client for @pdev has been registered + * already. + * + * To unregister just call this function with @irq_set_state and @set_vga_decode + * both set to NULL for the same @pdev as originally used to register them. + * + * Returns: 0 on success, -1 on failure + */ int vga_client_register(struct pci_dev *pdev, void *cookie, void (*irq_set_state)(void *cookie, bool state), unsigned int (*set_vga_decode)(void *cookie, diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 8c3b412d84df..ee162e3e879b 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -73,34 +73,6 @@ static inline void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) { }; #endif -/** - * vga_get - acquire & locks VGA resources - * - * @pdev: pci device of the VGA card or NULL for the system default - * @rsrc: bit mask of resources to acquire and lock - * @interruptible: blocking should be interruptible by signals ? - * - * This function acquires VGA resources for the given - * card and mark those resources locked. If the resource requested - * are "normal" (and not legacy) resources, the arbiter will first check - * whether the card is doing legacy decoding for that type of resource. If - * yes, the lock is "converted" into a legacy resource lock. - * The arbiter will first look for all VGA cards that might conflict - * and disable their IOs and/or Memory access, including VGA forwarding - * on P2P bridges if necessary, so that the requested resources can - * be used. Then, the card is marked as locking these resources and - * the IO and/or Memory accesse are enabled on the card (including - * VGA forwarding on parent P2P bridges if any). - * This function will block if some conflicting card is already locking - * one of the required resources (or any resource on a different bus - * segment, since P2P bridges don't differenciate VGA memory and IO - * afaik). You can indicate whether this blocking should be interruptible - * by a signal (for userland interface) or not. - * Must not be called at interrupt time or in atomic context. - * If the card already owns the resources, the function succeeds. - * Nested calls are supported (a per-resource counter is maintained) - */ - #if defined(CONFIG_VGA_ARB) extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible); #else @@ -108,11 +80,14 @@ static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interrupt #endif /** - * vga_get_interruptible + * vga_get_interruptible + * @pdev: pci device of the VGA card or NULL for the system default + * @rsrc: bit mask of resources to acquire and lock * - * Shortcut to vga_get + * Shortcut to vga_get with interruptible set to true. + * + * On success, release the VGA resource again with vga_put(). */ - static inline int vga_get_interruptible(struct pci_dev *pdev, unsigned int rsrc) { @@ -120,47 +95,26 @@ static inline int vga_get_interruptible(struct pci_dev *pdev, } /** - * vga_get_uninterruptible + * vga_get_uninterruptible - shortcut to vga_get() + * @pdev: pci device of the VGA card or NULL for the system default + * @rsrc: bit mask of resources to acquire and lock * - * Shortcut to vga_get + * Shortcut to vga_get with interruptible set to false. + * + * On success, release the VGA resource again with vga_put(). */ - static inline int vga_get_uninterruptible(struct pci_dev *pdev, unsigned int rsrc) { return vga_get(pdev, rsrc, 0); } -/** - * vga_tryget - try to acquire & lock legacy VGA resources - * - * @pdev: pci devivce of VGA card or NULL for system default - * @rsrc: bit mask of resources to acquire and lock - * - * This function performs the same operation as vga_get(), but - * will return an error (-EBUSY) instead of blocking if the resources - * are already locked by another card. It can be called in any context - */ - #if defined(CONFIG_VGA_ARB) extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc); #else static inline int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { return 0; } #endif -/** - * vga_put - release lock on legacy VGA resources - * - * @pdev: pci device of VGA card or NULL for system default - * @rsrc: but mask of resource to release - * - * This function releases resources previously locked by vga_get() - * or vga_tryget(). The resources aren't disabled right away, so - * that a subsequence vga_get() on the same card will succeed - * immediately. Resources have a counter, so locks are only - * released if the counter reaches 0. - */ - #if defined(CONFIG_VGA_ARB) extern void vga_put(struct pci_dev *pdev, unsigned int rsrc); #else @@ -168,25 +122,6 @@ extern void vga_put(struct pci_dev *pdev, unsigned int rsrc); #endif -/** - * vga_default_device - * - * This can be defined by the platform. The default implementation - * is rather dumb and will probably only work properly on single - * vga card setups and/or x86 platforms. - * - * If your VGA default device is not PCI, you'll have to return - * NULL here. In this case, I assume it will not conflict with - * any PCI card. If this is not true, I'll have to define two archs - * hooks for enabling/disabling the VGA default device if that is - * possible. This may be a problem with real _ISA_ VGA cards, in - * addition to a PCI one. I don't know at this point how to deal - * with that card. Can theirs IOs be disabled at all ? If not, then - * I suppose it's a matter of having the proper arch hook telling - * us about it, so we basically never allow anybody to succeed a - * vga_get()... - */ - #ifdef CONFIG_VGA_ARB extern struct pci_dev *vga_default_device(void); extern void vga_set_default_device(struct pci_dev *pdev); @@ -195,14 +130,11 @@ static inline struct pci_dev *vga_default_device(void) { return NULL; }; static inline void vga_set_default_device(struct pci_dev *pdev) { }; #endif -/** - * vga_conflicts - * - * Architectures should define this if they have several - * independent PCI domains that can afford concurrent VGA - * decoding +/* + * Architectures should define this if they have several + * independent PCI domains that can afford concurrent VGA + * decoding */ - #ifndef __ARCH_HAS_VGA_CONFLICT static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2) { @@ -210,34 +142,6 @@ static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2) } #endif -/** - * vga_client_register - * - * @pdev: pci device of the VGA client - * @cookie: client cookie to be used in callbacks - * @irq_set_state: irq state change callback - * @set_vga_decode: vga decode change callback - * - * return value: 0 on success, -1 on failure - * Register a client with the VGA arbitration logic - * - * Clients have two callback mechanisms they can use. - * irq enable/disable callback - - * If a client can't disable its GPUs VGA resources, then we - * need to be able to ask it to turn off its irqs when we - * turn off its mem and io decoding. - * set_vga_decode - * If a client can disable its GPU VGA resource, it will - * get a callback from this to set the encode/decode state - * - * Rationale: we cannot disable VGA decode resources unconditionally - * some single GPU laptops seem to require ACPI or BIOS access to the - * VGA registers to control things like backlights etc. - * Hopefully newer multi-GPU laptops do something saner, and desktops - * won't have any special ACPI for this. - * They driver will get a callback when VGA arbitration is first used - * by userspace since we some older X servers have issues. - */ #if defined(CONFIG_VGA_ARB) int vga_client_register(struct pci_dev *pdev, void *cookie, void (*irq_set_state)(void *cookie, bool state), From 5ee4c8f064719f5c62ea53f304845f75f87f2804 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Aug 2016 22:48:57 +0200 Subject: [PATCH 27/46] drm: Fix kerneldoc in drm_plane_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville ocd'ed the parameter name, but forgot to update the docs! Fixes: df86af9133b4 ("drm/plane-helper: Add drm_plane_helper_check_state()") Cc: Sean Paul Cc: Ville Syrjälä Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471034937-651-21-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 50b9c1bfc6f6..7899fc1dcdb0 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL(drm_plane_helper_check_state); * @crtc: owning CRTC of owning plane * @fb: framebuffer to flip onto plane * @src: source coordinates in 16.16 fixed point - * @dest: integer destination coordinates + * @dst: integer destination coordinates * @clip: integer clipping coordinates * @rotation: plane rotation * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point From 68acb6afb6f56d8ab92352993425b5472cf79a78 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 16 Aug 2016 16:31:00 -0700 Subject: [PATCH 28/46] dma-buf: fix kernel-doc warning and typos Fix dma-buf kernel-doc warning and 2 minor typos in fence_array_create(). Fixes this warning: ..//drivers/dma-buf/fence-array.c:124: warning: No description found for parameter 'signal_on_any' Signed-off-by: Randy Dunlap Cc: Sumit Semwal Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/224865a5-947d-9a28-c60a-18fa86bc9329@infradead.org --- drivers/dma-buf/fence-array.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma-buf/fence-array.c b/drivers/dma-buf/fence-array.c index ee500226197b..f1989fcaf354 100644 --- a/drivers/dma-buf/fence-array.c +++ b/drivers/dma-buf/fence-array.c @@ -107,14 +107,14 @@ EXPORT_SYMBOL(fence_array_ops); * @fences: [in] array containing the fences * @context: [in] fence context to use * @seqno: [in] sequence number to use - * @signal_on_any [in] signal on any fence in the array + * @signal_on_any: [in] signal on any fence in the array * * Allocate a fence_array object and initialize the base fence with fence_init(). * In case of error it returns NULL. * - * The caller should allocte the fences array with num_fences size + * The caller should allocate the fences array with num_fences size * and fill it with the fences it wants to add to the object. Ownership of this - * array is take and fence_put() is used on each fence on release. + * array is taken and fence_put() is used on each fence on release. * * If @signal_on_any is true the fence array signals if any fence in the array * signals, otherwise it signals when all fences in the array signal. From 9cd2e854d61ccfa51686f3ed7b0c917708fc641f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 17 Aug 2016 13:59:40 +0200 Subject: [PATCH 29/46] Revert "drm/hisilicon: Don't set drm_device->platformdev" This reverts commit d25bcfb8c2e18b9b36f037f38be4d4792ebf8d57. I somehow missed that it only compiles on arm64 and broke the driver rather badly. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 10 +++++----- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 6 ++++-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 91188f33b1d9..eaa3df75fc5c 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -989,9 +989,9 @@ static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) return 0; } -static int ade_drm_init(struct platform_device *pdev) +static int ade_drm_init(struct drm_device *dev) { - struct drm_device *drm_dev = platform_get_drvdata(dev); + struct platform_device *pdev = dev->platformdev; struct ade_data *ade; struct ade_hw_ctx *ctx; struct ade_crtc *acrtc; @@ -1050,9 +1050,9 @@ static int ade_drm_init(struct platform_device *pdev) return 0; } -static void ade_drm_cleanup(struct platform_device *pdev) +static void ade_drm_cleanup(struct drm_device *dev) { - struct drm_device *drm_dev = platform_get_drvdata(dev); + struct platform_device *pdev = dev->platformdev; struct ade_data *ade = platform_get_drvdata(pdev); struct drm_crtc *crtc = &ade->acrtc.base; @@ -1062,4 +1062,4 @@ static void ade_drm_cleanup(struct platform_device *pdev) const struct kirin_dc_ops ade_dc_ops = { .init = ade_drm_init, .cleanup = ade_drm_cleanup -; +}; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 6b0f9f6c16e1..1fc2f502d20d 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -41,7 +41,7 @@ static int kirin_drm_kms_cleanup(struct drm_device *dev) #endif drm_kms_helper_poll_fini(dev); drm_vblank_cleanup(dev); - dc_ops->cleanup(to_platform_device(dev->dev)); + dc_ops->cleanup(dev); drm_mode_config_cleanup(dev); devm_kfree(dev->dev, priv); dev->dev_private = NULL; @@ -103,7 +103,7 @@ static int kirin_drm_kms_init(struct drm_device *dev) kirin_drm_mode_config_init(dev); /* display controller init */ - ret = dc_ops->init(to_platform_device(dev)); + ret = dc_ops->init(dev); if (ret) goto err_mode_config_cleanup; @@ -210,6 +210,8 @@ static int kirin_drm_bind(struct device *dev) if (!drm_dev) return -ENOMEM; + drm_dev->platformdev = to_platform_device(dev); + ret = kirin_drm_kms_init(drm_dev); if (ret) goto err_drm_dev_unref; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index a0bb217c4c64..1a07caf8e7f4 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -15,8 +15,8 @@ /* display controller init/cleanup ops */ struct kirin_dc_ops { - int (*init)(struct platform_device *pdev); - void (*cleanup)(struct platform_device *pdev); + int (*init)(struct drm_device *dev); + void (*cleanup)(struct drm_device *dev); }; struct kirin_drm_private { From 8f0e4907a8e7545850ae093a0286833f3949e4cb Mon Sep 17 00:00:00 2001 From: Clint Taylor Date: Mon, 15 Aug 2016 10:31:28 -0700 Subject: [PATCH 30/46] drm/edid: CEA mode 64 1080p100 vsync pulse width incorrect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the CEA-861 specification VIC 64 specifies a vsync pulse of 5 and a backporch of 36. Adjust vsync pulse width to match specification. Cc: Ville Syrjälä Signed-off-by: Clint Taylor Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1471282288-30909-1-git-send-email-clinton.a.taylor@intel.com --- drivers/gpu/drm/drm_edid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 62dffbccd447..50541324a4ab 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -991,7 +991,7 @@ static const struct drm_display_mode edid_cea_modes[] = { .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 64 - 1920x1080@100Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, - 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, }; From c4e68a5832021cf8c2f9a2f3419452470ca60bd8 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Mon, 15 Aug 2016 16:18:04 -0700 Subject: [PATCH 31/46] drm: Introduce DRM_DEV_* log messages This patch consolidates all the various log functions/macros into one uber function, drm_log. It also introduces some new DRM_DEV_* variants that print the device name to delineate multiple devices of the same type. Reviewed-by: Chris Wilson Reviewed-by: Eric Engestrom Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1471303084-3757-1-git-send-email-seanpaul@chromium.org --- drivers/gpu/drm/drm_drv.c | 49 ++++++++----- include/drm/drmP.h | 146 +++++++++++++++++++++++--------------- 2 files changed, 117 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 57ce9734e0c6..a7f628298365 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -63,37 +63,48 @@ static struct idr drm_minors_idr; static struct dentry *drm_debugfs_root; -void drm_err(const char *format, ...) +#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV" + +void drm_dev_printk(const struct device *dev, const char *level, + unsigned int category, const char *function_name, + const char *prefix, const char *format, ...) { struct va_format vaf; va_list args; - va_start(args, format); - - vaf.fmt = format; - vaf.va = &args; - - printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV", - __builtin_return_address(0), &vaf); - - va_end(args); -} -EXPORT_SYMBOL(drm_err); - -void drm_ut_debug_printk(const char *function_name, const char *format, ...) -{ - struct va_format vaf; - va_list args; + if (category != DRM_UT_NONE && !(drm_debug & category)) + return; va_start(args, format); vaf.fmt = format; vaf.va = &args; - printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf); + dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, + &vaf); va_end(args); } -EXPORT_SYMBOL(drm_ut_debug_printk); +EXPORT_SYMBOL(drm_dev_printk); + +void drm_printk(const char *level, unsigned int category, + const char *function_name, const char *prefix, + const char *format, ...) +{ + struct va_format vaf; + va_list args; + + if (category != DRM_UT_NONE && !(drm_debug & category)) + return; + + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); + + va_end(args); +} +EXPORT_SYMBOL(drm_printk); /* * DRM Minors diff --git a/include/drm/drmP.h b/include/drm/drmP.h index f8e87fde611b..94eb138753a9 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -127,6 +127,7 @@ struct dma_buf_attachment; * run-time by echoing the debug value in its sysfs node: * # echo 0xf > /sys/module/drm/parameters/debug */ +#define DRM_UT_NONE 0x00 #define DRM_UT_CORE 0x01 #define DRM_UT_DRIVER 0x02 #define DRM_UT_KMS 0x04 @@ -134,11 +135,15 @@ struct dma_buf_attachment; #define DRM_UT_ATOMIC 0x10 #define DRM_UT_VBL 0x20 -extern __printf(2, 3) -void drm_ut_debug_printk(const char *function_name, - const char *format, ...); -extern __printf(1, 2) -void drm_err(const char *format, ...); +extern __printf(6, 7) +void drm_dev_printk(const struct device *dev, const char *level, + unsigned int category, const char *function_name, + const char *prefix, const char *format, ...); + +extern __printf(5, 6) +void drm_printk(const char *level, unsigned int category, + const char *function_name, const char *prefix, + const char *format, ...); /***********************************************************************/ /** \name DRM template customization defaults */ @@ -169,8 +174,12 @@ void drm_err(const char *format, ...); * \param fmt printf() like format string. * \param arg arguments */ -#define DRM_ERROR(fmt, ...) \ - drm_err(fmt, ##__VA_ARGS__) +#define DRM_DEV_ERROR(dev, fmt, ...) \ + drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\ + fmt, ##__VA_ARGS__) +#define DRM_ERROR(fmt, ...) \ + drm_printk(KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*", fmt, \ + ##__VA_ARGS__) /** * Rate limited error output. Like DRM_ERROR() but won't flood the log. @@ -178,21 +187,33 @@ void drm_err(const char *format, ...); * \param fmt printf() like format string. * \param arg arguments */ -#define DRM_ERROR_RATELIMITED(fmt, ...) \ +#define DRM_DEV_ERROR_RATELIMITED(dev, fmt, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ DEFAULT_RATELIMIT_INTERVAL, \ DEFAULT_RATELIMIT_BURST); \ \ if (__ratelimit(&_rs)) \ - drm_err(fmt, ##__VA_ARGS__); \ + DRM_DEV_ERROR(dev, fmt, ##__VA_ARGS__); \ }) +#define DRM_ERROR_RATELIMITED(fmt, ...) \ + DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) -#define DRM_INFO(fmt, ...) \ - printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) +#define DRM_DEV_INFO(dev, fmt, ...) \ + drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt, \ + ##__VA_ARGS__) +#define DRM_INFO(fmt, ...) \ + drm_printk(KERN_INFO, DRM_UT_NONE, __func__, "", fmt, ##__VA_ARGS__) -#define DRM_INFO_ONCE(fmt, ...) \ - printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) +#define DRM_DEV_INFO_ONCE(dev, fmt, ...) \ +({ \ + static bool __print_once __read_mostly; \ + if (!__print_once) { \ + __print_once = true; \ + DRM_DEV_INFO(dev, fmt, ##__VA_ARGS__); \ + } \ +}) +#define DRM_INFO_ONCE(fmt, ...) DRM_DEV_INFO_ONCE(NULL, fmt, ##__VA_ARGS__) /** * Debug output. @@ -200,52 +221,51 @@ void drm_err(const char *format, ...); * \param fmt printf() like format string. * \param arg arguments */ +#define DRM_DEV_DEBUG(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \ + ##args) #define DRM_DEBUG(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_CORE)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) + drm_printk(KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, ##args) +#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \ + fmt, ##args) #define DRM_DEBUG_DRIVER(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_DRIVER)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) -#define DRM_DEBUG_KMS(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_KMS)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) -#define DRM_DEBUG_PRIME(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_PRIME)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) -#define DRM_DEBUG_ATOMIC(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_ATOMIC)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) -#define DRM_DEBUG_VBL(fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_VBL)) \ - drm_ut_debug_printk(__func__, fmt, ##args); \ - } while (0) + drm_printk(KERN_DEBUG, DRM_UT_DRIVER, __func__, "", fmt, ##args) -#define _DRM_DEFINE_DEBUG_RATELIMITED(level, fmt, args...) \ - do { \ - if (unlikely(drm_debug & DRM_UT_ ## level)) { \ - static DEFINE_RATELIMIT_STATE( \ - _rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - \ - if (__ratelimit(&_rs)) { \ - drm_ut_debug_printk(__func__, fmt, \ - ##args); \ - } \ - } \ - } while (0) +#define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \ + ##args) +#define DRM_DEBUG_KMS(fmt, args...) \ + drm_printk(KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, ##args) + +#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \ + fmt, ##args) +#define DRM_DEBUG_PRIME(fmt, args...) \ + drm_printk(KERN_DEBUG, DRM_UT_PRIME, __func__, "", fmt, ##args) + +#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \ + fmt, ##args) +#define DRM_DEBUG_ATOMIC(fmt, args...) \ + drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", fmt, ##args) + +#define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \ + ##args) +#define DRM_DEBUG_VBL(fmt, args...) \ + drm_printk(KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, ##args) + +#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \ +({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + DEFAULT_RATELIMIT_BURST); \ + if (__ratelimit(&_rs)) \ + drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ ## level, \ + __func__, "", fmt, ##args); \ +}) /** * Rate limited debug output. Like DRM_DEBUG() but won't flood the log. @@ -253,14 +273,22 @@ void drm_err(const char *format, ...); * \param fmt printf() like format string. * \param arg arguments */ +#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...) \ + DEV__DRM_DEFINE_DEBUG_RATELIMITED(dev, CORE, fmt, ##args) #define DRM_DEBUG_RATELIMITED(fmt, args...) \ - _DRM_DEFINE_DEBUG_RATELIMITED(CORE, fmt, ##args) + DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##args) +#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, args...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRIVER, fmt, ##args) #define DRM_DEBUG_DRIVER_RATELIMITED(fmt, args...) \ - _DRM_DEFINE_DEBUG_RATELIMITED(DRIVER, fmt, ##args) + DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##args) +#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, args...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, KMS, fmt, ##args) #define DRM_DEBUG_KMS_RATELIMITED(fmt, args...) \ - _DRM_DEFINE_DEBUG_RATELIMITED(KMS, fmt, ##args) + DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##args) +#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, args...) \ + _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, PRIME, fmt, ##args) #define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...) \ - _DRM_DEFINE_DEBUG_RATELIMITED(PRIME, fmt, ##args) + DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args) /*@}*/ From ee4d7899f62724d4bda28aa05bf795ef93aacd47 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 12 Aug 2016 13:00:54 -0400 Subject: [PATCH 32/46] drm/rockchip: Use DRM_DEV_ERROR in vop Since we can have multiple vops, use DRM_DEV_ERROR to make logs easier to process. Acked-by: Mark Yao Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1471021254-2563-3-git-send-email-seanpaul@chromium.org --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 ++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 31744fe99b38..ec8ad005835c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -238,7 +238,7 @@ static enum vop_data_format vop_convert_format(uint32_t format) case DRM_FORMAT_NV24: return VOP_FMT_YUV444SP; default: - DRM_ERROR("unsupport format[%08x]\n", format); + DRM_ERROR("unsupported format[%08x]\n", format); return -EINVAL; } } @@ -315,7 +315,7 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, int vskiplines = 0; if (dst_w > 3840) { - DRM_ERROR("Maximum destination width (3840) exceeded\n"); + DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); return; } @@ -353,11 +353,11 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, VOP_SCL_SET_EXT(vop, win, lb_mode, lb_mode); if (lb_mode == LB_RGB_3840X2) { if (yrgb_ver_scl_mode != SCALE_NONE) { - DRM_ERROR("ERROR : not allow yrgb ver scale\n"); + DRM_DEV_ERROR(vop->dev, "not allow yrgb ver scale\n"); return; } if (cbcr_ver_scl_mode != SCALE_NONE) { - DRM_ERROR("ERROR : not allow cbcr ver scale\n"); + DRM_DEV_ERROR(vop->dev, "not allow cbcr ver scale\n"); return; } vsu_mode = SCALE_UP_BIL; @@ -970,7 +970,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) VOP_CTRL_SET(vop, mipi_en, 1); break; default: - DRM_ERROR("unsupport connector_type[%d]\n", s->output_type); + DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", + s->output_type); } VOP_CTRL_SET(vop, out_mode, s->output_mode); @@ -1154,7 +1155,8 @@ static irqreturn_t vop_isr(int irq, void *data) /* Unhandled irqs are spurious. */ if (active_irqs) - DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); + DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n", + active_irqs); return ret; } @@ -1189,7 +1191,8 @@ static int vop_create_crtc(struct vop *vop) win_data->phy->nformats, win_data->type, NULL); if (ret) { - DRM_ERROR("failed to initialize plane\n"); + DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", + ret); goto err_cleanup_planes; } @@ -1227,7 +1230,8 @@ static int vop_create_crtc(struct vop *vop) win_data->phy->nformats, win_data->type, NULL); if (ret) { - DRM_ERROR("failed to initialize overlay plane\n"); + DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", + ret); goto err_cleanup_crtc; } drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); @@ -1235,8 +1239,8 @@ static int vop_create_crtc(struct vop *vop) port = of_get_child_by_name(dev->of_node, "port"); if (!port) { - DRM_ERROR("no port node found in %s\n", - dev->of_node->full_name); + DRM_DEV_ERROR(vop->dev, "no port node found in %s\n", + dev->of_node->full_name); ret = -ENOENT; goto err_cleanup_crtc; } From 1832040d010ecf41671104259f51f6368fcfcb5b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Aug 2016 19:00:16 +0100 Subject: [PATCH 33/46] drm: Allow drivers to modify plane_state in prepare_fb/cleanup_fb The drivers have to modify the atomic plane state during the prepare_fb callback so they track allocations, reservations and dependencies for this atomic operation involving this fb. In particular, how else do we set the plane->fence from the framebuffer! Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160818180017.20508-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 4 ++-- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 4 ++-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 4 ++-- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | 4 ++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 4 ++-- drivers/gpu/drm/omapdrm/omap_plane.c | 4 ++-- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- drivers/gpu/drm/tegra/dc.c | 4 ++-- include/drm/drm_modeset_helper_vtables.h | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 146809a97a07..72e6b7dd457b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -755,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, } static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { /* * FIXME: we should avoid this const -> non-const cast but it's @@ -780,7 +780,7 @@ static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, } static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { /* * FIXME: we should avoid this const -> non-const cast but it's diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index e50467a0deb0..2a3e92976700 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -171,13 +171,13 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, static void fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { } static int fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { return 0; } diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index eaa3df75fc5c..943f708a9dd1 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -818,14 +818,14 @@ static void ade_disable_channel(struct ade_plane *aplane) } static int ade_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { /* do nothing */ return 0; } static void ade_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { /* do nothing */ } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3902e57d9df5..54bbb9c70a75 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13976,7 +13976,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { */ int intel_prepare_plane_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { struct drm_device *dev = plane->dev; struct drm_framebuffer *fb = new_state->fb; @@ -14058,7 +14058,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, */ void intel_cleanup_plane_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { struct drm_device *dev = plane->dev; struct intel_plane_state *old_intel_state; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c29a429cbc45..b37b8ef0c745 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1225,9 +1225,9 @@ void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe); void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe); void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe); int intel_prepare_plane_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state); + struct drm_plane_state *new_state); void intel_cleanup_plane_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state); + struct drm_plane_state *old_state); int intel_plane_atomic_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 9f96dfe67769..7c9626d92019 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -99,7 +99,7 @@ static const struct drm_plane_funcs mdp4_plane_funcs = { }; static int mdp4_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); @@ -113,7 +113,7 @@ static int mdp4_plane_prepare_fb(struct drm_plane *plane, } static void mdp4_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index a02a24e75ba6..ba8f43278a44 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -250,7 +250,7 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { }; static int mdp5_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); @@ -264,7 +264,7 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane, } static void mdp5_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 4c7727e6be7c..66ac8c40db26 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -60,7 +60,7 @@ to_omap_plane_state(struct drm_plane_state *state) } static int omap_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { if (!new_state->fb) return 0; @@ -69,7 +69,7 @@ static int omap_plane_prepare_fb(struct drm_plane *plane, } static void omap_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { if (old_state->fb) omap_framebuffer_unpin(old_state->fb); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ec8ad005835c..f417b49991dd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -567,7 +567,7 @@ static void vop_plane_destroy(struct drm_plane *plane) } static int vop_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { if (plane->state->fb) drm_framebuffer_reference(plane->state->fb); @@ -576,7 +576,7 @@ static int vop_plane_prepare_fb(struct drm_plane *plane, } static void vop_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) + struct drm_plane_state *old_state) { if (old_state->fb) drm_framebuffer_unreference(old_state->fb); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 8495bd01b544..a02730f90861 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -481,13 +481,13 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = { }; static int tegra_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) + struct drm_plane_state *new_state) { return 0; } static void tegra_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_fb) + struct drm_plane_state *old_fb) { } diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 686feec6b4c8..6c8d3dad66ec 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -855,7 +855,7 @@ struct drm_plane_helper_funcs { * everything else must complete successfully. */ int (*prepare_fb)(struct drm_plane *plane, - const struct drm_plane_state *new_state); + struct drm_plane_state *new_state); /** * @cleanup_fb: * @@ -866,7 +866,7 @@ struct drm_plane_helper_funcs { * transitional plane helpers, but it is optional. */ void (*cleanup_fb)(struct drm_plane *plane, - const struct drm_plane_state *old_state); + struct drm_plane_state *old_state); /** * @atomic_check: From a6e3918bcdb1253083f962d747ec699bdb4bacd9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 18 Aug 2016 18:12:03 +0200 Subject: [PATCH 34/46] GPU-DRM-Savage: Use memdup_user() rather than duplicating Reuse existing functionality from memdup_user() instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/021efa32-c259-e799-a80e-630972291815@users.sourceforge.net --- drivers/gpu/drm/savage/savage_state.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index c01ad0aeaa58..3dc0d8ff95ec 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -1001,15 +1001,9 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ cmdbuf->cmd_addr = kcmd_addr; } if (cmdbuf->vb_size) { - kvb_addr = kmalloc(cmdbuf->vb_size, GFP_KERNEL); - if (kvb_addr == NULL) { - ret = -ENOMEM; - goto done; - } - - if (copy_from_user(kvb_addr, cmdbuf->vb_addr, - cmdbuf->vb_size)) { - ret = -EFAULT; + kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size); + if (IS_ERR(kvb_addr)) { + ret = PTR_ERR(kvb_addr); goto done; } cmdbuf->vb_addr = kvb_addr; From 7ad61e6b4a79c5057eeb2d6062b0021e33ddc9f6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 18 Aug 2016 22:35:14 +0200 Subject: [PATCH 35/46] virtio-gpu: Use memdup_user() rather than duplicating its implementation Reuse existing functionality from memdup_user() instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/401e68fc-5515-7a7a-be2e-503dee676b34@users.sourceforge.net --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index c046903cb47b..512e7cddcbae 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -152,15 +152,10 @@ static int virtio_gpu_execbuffer(struct drm_device *dev, if (ret) goto out_free; - buf = kmalloc(exbuf->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out_unresv; - } - if (copy_from_user(buf, (void __user *)(uintptr_t)exbuf->command, - exbuf->size)) { - kfree(buf); - ret = -EFAULT; + buf = memdup_user((void __user *)(uintptr_t)exbuf->command, + exbuf->size); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); goto out_unresv; } virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, From 420382adf64c93d2fc83b764013103c6035d8617 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 19 Aug 2016 11:39:29 +0300 Subject: [PATCH 36/46] drm: Don't implement empty prepare_fb()/cleanup_fb() The plane .prepare_fb() and .cleanup_fb() helpers are optional, there's no need to implement empty stubs, and no need to explicitly set the function pointers to NULL either. Signed-off-by: Laurent Pinchart [danvet: Resolved conflicts with Chris' patch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/arc/arcpgu_crtc.c | 2 -- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 15 --------------- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 15 --------------- drivers/gpu/drm/tegra/dc.c | 17 ----------------- drivers/gpu/drm/vc4/vc4_plane.c | 2 -- 5 files changed, 51 deletions(-) diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index ee0a61c2861b..7130b044b004 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -183,8 +183,6 @@ static void arc_pgu_plane_atomic_update(struct drm_plane *plane, } static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = { - .prepare_fb = NULL, - .cleanup_fb = NULL, .atomic_update = arc_pgu_plane_atomic_update, }; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index 2a3e92976700..a7e5486bd1e9 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -169,25 +169,10 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, return; } -static void -fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ -} - -static int -fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ - return 0; -} - static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = { .atomic_check = fsl_dcu_drm_plane_atomic_check, .atomic_disable = fsl_dcu_drm_plane_atomic_disable, .atomic_update = fsl_dcu_drm_plane_atomic_update, - .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb, - .prepare_fb = fsl_dcu_drm_plane_prepare_fb, }; static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 943f708a9dd1..7e7a4d43d6b6 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -817,19 +817,6 @@ static void ade_disable_channel(struct ade_plane *aplane) ade_compositor_routing_disable(base, ch); } -static int ade_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ - /* do nothing */ - return 0; -} - -static void ade_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - /* do nothing */ -} - static int ade_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -897,8 +884,6 @@ static void ade_plane_atomic_disable(struct drm_plane *plane, } static const struct drm_plane_helper_funcs ade_plane_helper_funcs = { - .prepare_fb = ade_plane_prepare_fb, - .cleanup_fb = ade_plane_cleanup_fb, .atomic_check = ade_plane_atomic_check, .atomic_update = ade_plane_atomic_update, .atomic_disable = ade_plane_atomic_disable, diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index a02730f90861..3de7ce33d3d4 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -480,17 +480,6 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = { .atomic_destroy_state = tegra_plane_atomic_destroy_state, }; -static int tegra_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ - return 0; -} - -static void tegra_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_fb) -{ -} - static int tegra_plane_state_add(struct tegra_plane *plane, struct drm_plane_state *state) { @@ -624,8 +613,6 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane, } static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = { - .prepare_fb = tegra_plane_prepare_fb, - .cleanup_fb = tegra_plane_cleanup_fb, .atomic_check = tegra_plane_atomic_check, .atomic_update = tegra_plane_atomic_update, .atomic_disable = tegra_plane_atomic_disable, @@ -796,8 +783,6 @@ static const struct drm_plane_funcs tegra_cursor_plane_funcs = { }; static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = { - .prepare_fb = tegra_plane_prepare_fb, - .cleanup_fb = tegra_plane_cleanup_fb, .atomic_check = tegra_cursor_atomic_check, .atomic_update = tegra_cursor_atomic_update, .atomic_disable = tegra_cursor_atomic_disable, @@ -866,8 +851,6 @@ static const uint32_t tegra_overlay_plane_formats[] = { }; static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = { - .prepare_fb = tegra_plane_prepare_fb, - .cleanup_fb = tegra_plane_cleanup_fb, .atomic_check = tegra_plane_atomic_check, .atomic_update = tegra_plane_atomic_update, .atomic_disable = tegra_plane_atomic_disable, diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 29e4b400e25e..881bf489478b 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -735,8 +735,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) } static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { - .prepare_fb = NULL, - .cleanup_fb = NULL, .atomic_check = vc4_plane_atomic_check, .atomic_update = vc4_plane_atomic_update, }; From f5bef0b85e5d1586bb2f34035917d5e4c475cea2 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 19 Aug 2016 16:55:34 -0400 Subject: [PATCH 37/46] reservation: fix small comment typo Signed-off-by: Rob Clark [danvet: Mark up as function for proper cross-linking.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471640134-30888-1-git-send-email-robdclark@gmail.com --- drivers/dma-buf/reservation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 9566a62ad8e3..723d8af988e5 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -205,7 +205,7 @@ reservation_object_add_shared_replace(struct reservation_object *obj, * @fence: the shared fence to add * * Add a fence to a shared slot, obj->lock must be held, and - * reservation_object_reserve_shared_fence has been called. + * reservation_object_reserve_shared() has been called. */ void reservation_object_add_shared_fence(struct reservation_object *obj, struct fence *fence) From ec913f31a570b57e72e69b4122de70a6b2ef760f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 21 Aug 2016 19:56:19 +0200 Subject: [PATCH 38/46] drm: avoid exposing kernel stack in compat_drm_getstats The C standard does not specify the size of the integer used to store an enum. Hence in structure drm_stats32_t alignment bytes may exist. To avoid exposing bytes from the kernel stack it is necessary to initialize variable s32 completely. Signed-off-by: Heinrich Schuchardt Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471802179-2886-1-git-send-email-xypron.glpk@gmx.de --- drivers/gpu/drm/drm_ioc32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 57676f8d7ecf..32a489b0faff 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -346,6 +346,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, struct drm_stats __user *stats; int i, err; + memset(&s32, 0, sizeof(drm_stats32_t)); stats = compat_alloc_user_space(sizeof(*stats)); if (!stats) return -EFAULT; From b4ba97e76763c4e582e3af1079e220e93b1b0d76 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Aug 2016 08:37:50 +0100 Subject: [PATCH 39/46] drm: Avoid calling dev_printk(.dev = NULL) Since dev_printk likes to print "(NULL device *):" when passed in a NULL pointer, we have to manually call printk() ourselves. Fixes: c4e68a583202 ("drm: Introduce DRM_DEV_* log messages") Signed-off-by: Chris Wilson Cc: Eric Engestrom Cc: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/20160819073750.16610-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_drv.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index a7f628298365..acf6a5f38920 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -79,8 +79,11 @@ void drm_dev_printk(const struct device *dev, const char *level, vaf.fmt = format; vaf.va = &args; - dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, - &vaf); + if (dev) + dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, + &vaf); + else + printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); va_end(args); } From d1c151dcae628bf73b4aa2c2c5abeccf3d17e544 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Mon, 22 Aug 2016 23:17:34 +0100 Subject: [PATCH 40/46] drm/udl: Ensure channel is selected before using the device. Lift configuration command from udlfb. This appears to be essential for at least a Rextron VCUD-60, without which no URB communication occurs. Signed-off-by: Jamie Lentin Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471904254-26545-1-git-send-email-jm@lentin.co.uk --- drivers/gpu/drm/udl/udl_main.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 33dbfb2c4748..29f0207fa677 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -16,6 +16,8 @@ /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */ #define BULK_SIZE 512 +#define NR_USB_REQUEST_CHANNEL 0x12 + #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) #define WRITES_IN_FLIGHT (4) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 @@ -90,6 +92,26 @@ static int udl_parse_vendor_descriptor(struct drm_device *dev, return true; } +/* + * Need to ensure a channel is selected before submitting URBs + */ +static int udl_select_std_channel(struct udl_device *udl) +{ + int ret; + u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7, + 0x1C, 0x88, 0x5E, 0x15, + 0x60, 0xFE, 0xC6, 0x97, + 0x16, 0x3D, 0x47, 0xF2}; + + ret = usb_control_msg(udl->udev, + usb_sndctrlpipe(udl->udev, 0), + NR_USB_REQUEST_CHANNEL, + (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0, + set_def_chn, sizeof(set_def_chn), + USB_CTRL_SET_TIMEOUT); + return ret < 0 ? ret : 0; +} + static void udl_release_urb_work(struct work_struct *work) { struct urb_node *unode = container_of(work, struct urb_node, @@ -301,6 +323,9 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) goto err; } + if (udl_select_std_channel(udl)) + DRM_ERROR("Selecting channel failed\n"); + if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { DRM_ERROR("udl_alloc_urb_list failed\n"); goto err; From 0a3bfe29f81622f50fbd9a64ec7c705845516681 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Aug 2016 21:44:52 +0100 Subject: [PATCH 41/46] drm/fb-helper: Fix the dummy remove_conflicting_framebuffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always need to remove conflicting framebuffers if any other fb driver is enabled, and not just if we are setting up an fbdev ourselves. Unfortunately remove_conflicting_framebuffers() was incorrectly stubbed out if !fbdev rather than !fb leading to major memory corruption (and corrupt filesystems) upon boot. Fixes: 44adece57e26 ("drm/fb-helper: Add a dummy remove_conflicting_framebuffers") Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Tobias Jakobi Cc: Noralf Trønnes Cc: tomi.valkeinen@ti.com Cc: dh.herrmann@gmail.com Cc: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160822204452.2509-1-chris@chris-wilson.co.uk --- include/drm/drm_fb_helper.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 97889a90ff23..f811d755c254 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -282,12 +282,6 @@ drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); -static inline int -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) -{ - return remove_conflicting_framebuffers(a, name, primary); -} #else static inline int drm_fb_helper_modinit(void) { @@ -482,11 +476,17 @@ drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, return 0; } +#endif + static inline int drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { +#if IS_ENABLED(CONFIG_FB) + return remove_conflicting_framebuffers(a, name, primary); +#else return 0; +#endif } -#endif + #endif From cfe63423d9be3e7020296c3dfb512768a83cd099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 23 Aug 2016 13:54:06 +0200 Subject: [PATCH 42/46] drm/fb-helper: Add drm_fb_helper_set_suspend_unlocked() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a function that also takes the console lock before calling fb_set_suspend() in contrast to drm_fb_helper_set_suspend() which is a plain wrapper around fb_set_suspend(). Resume is run asynchronously using a worker if the console lock is already taken. This is modelled after the i915 driver. Signed-off-by: Noralf Trønnes Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1471953246-29602-1-git-send-email-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_helper.c | 62 ++++++++++++++++++++++++++++++++- include/drm/drm_fb_helper.h | 9 +++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c0d1066ea419..43491a6c6e4e 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -617,6 +618,16 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) kfree(helper->crtc_info); } +static void drm_fb_helper_resume_worker(struct work_struct *work) +{ + struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, + resume_work); + + console_lock(); + fb_set_suspend(helper->fbdev, 0); + console_unlock(); +} + static void drm_fb_helper_dirty_work(struct work_struct *work) { struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, @@ -648,6 +659,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, { INIT_LIST_HEAD(&helper->kernel_fb_list); spin_lock_init(&helper->dirty_lock); + INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker); INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work); helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0; helper->funcs = funcs; @@ -1025,7 +1037,9 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); * @fb_helper: driver-allocated fbdev helper * @state: desired state, zero to resume, non-zero to suspend * - * A wrapper around fb_set_suspend implemented by fbdev core + * A wrapper around fb_set_suspend implemented by fbdev core. + * Use drm_fb_helper_set_suspend_unlocked() if you don't need to take + * the lock yourself */ void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state) { @@ -1034,6 +1048,52 @@ void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state) } EXPORT_SYMBOL(drm_fb_helper_set_suspend); +/** + * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also + * takes the console lock + * @fb_helper: driver-allocated fbdev helper + * @state: desired state, zero to resume, non-zero to suspend + * + * A wrapper around fb_set_suspend() that takes the console lock. If the lock + * isn't available on resume, a worker is tasked with waiting for the lock + * to become available. The console lock can be pretty contented on resume + * due to all the printk activity. + * + * This function can be called multiple times with the same state since + * &fb_info->state is checked to see if fbdev is running or not before locking. + * + * Use drm_fb_helper_set_suspend() if you need to take the lock yourself. + */ +void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, + int suspend) +{ + if (!fb_helper || !fb_helper->fbdev) + return; + + /* make sure there's no pending/ongoing resume */ + flush_work(&fb_helper->resume_work); + + if (suspend) { + if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING) + return; + + console_lock(); + + } else { + if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING) + return; + + if (!console_trylock()) { + schedule_work(&fb_helper->resume_work); + return; + } + } + + fb_set_suspend(fb_helper->fbdev, suspend); + console_unlock(); +} +EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index f811d755c254..0c6e53d9ce68 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -177,6 +177,7 @@ struct drm_fb_helper_connector { * the screen buffer * @dirty_lock: spinlock protecting @dirty_clip * @dirty_work: worker used to flush the framebuffer + * @resume_work: worker used during resume if the console lock is already taken * * This is the main structure used by the fbdev helpers. Drivers supporting * fbdev emulation should embedded this into their overall driver structure. @@ -197,6 +198,7 @@ struct drm_fb_helper { struct drm_clip_rect dirty_clip; spinlock_t dirty_lock; struct work_struct dirty_work; + struct work_struct resume_work; /** * @kernel_fb_list: @@ -264,6 +266,8 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info, const struct fb_image *image); void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state); +void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, + int suspend); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); @@ -421,6 +425,11 @@ static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, { } +static inline void +drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, int suspend) +{ +} + static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { return 0; From 39a9ad8fed1b4d556accacbd4e02dac9e98b5be0 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Mon, 15 Aug 2016 16:12:29 -0700 Subject: [PATCH 43/46] drm/rockchip: Don't continue trying to enable crtc on failure If vop_enable fails, don't continue on, it causes system hangs. Reviewed-by: Yakir Yank Tested-by: Yakir Yank Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1471302749-2811-1-git-send-email-seanpaul@chromium.org --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index f417b49991dd..efbc41ad83b6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -428,7 +428,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(&vop->irq_lock, flags); } -static void vop_enable(struct drm_crtc *crtc) +static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); int ret; @@ -436,26 +436,20 @@ static void vop_enable(struct drm_crtc *crtc) ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); - return; + goto err_put_pm_runtime; } ret = clk_enable(vop->hclk); - if (ret < 0) { - dev_err(vop->dev, "failed to enable hclk - %d\n", ret); - return; - } + if (WARN_ON(ret < 0)) + goto err_put_pm_runtime; ret = clk_enable(vop->dclk); - if (ret < 0) { - dev_err(vop->dev, "failed to enable dclk - %d\n", ret); + if (WARN_ON(ret < 0)) goto err_disable_hclk; - } ret = clk_enable(vop->aclk); - if (ret < 0) { - dev_err(vop->dev, "failed to enable aclk - %d\n", ret); + if (WARN_ON(ret < 0)) goto err_disable_dclk; - } /* * Slave iommu shares power, irq and clock with vop. It was associated @@ -485,7 +479,7 @@ static void vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); - return; + return 0; err_disable_aclk: clk_disable(vop->aclk); @@ -493,6 +487,9 @@ static void vop_enable(struct drm_crtc *crtc) clk_disable(vop->dclk); err_disable_hclk: clk_disable(vop->hclk); +err_put_pm_runtime: + pm_runtime_put_sync(vop->dev); + return ret; } static void vop_crtc_disable(struct drm_crtc *crtc) @@ -912,10 +909,16 @@ static void vop_crtc_enable(struct drm_crtc *crtc) u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; u16 vact_end = vact_st + vdisplay; uint32_t val; + int ret; WARN_ON(vop->event); - vop_enable(crtc); + ret = vop_enable(crtc); + if (ret) { + DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); + return; + } + /* * If dclk rate is zero, mean that scanout is stop, * we don't need wait any more. From 79d0d27d8801ef48f209f7ee62bc432d6fe06cc6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 16 Aug 2016 13:52:19 +0200 Subject: [PATCH 44/46] drm/bridge: dw-hdmi: Delete unnecessary assignment for the field "owner" The field "owner" is set by the core. Thus delete an unneeded initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/7c97565d-eee3-45e9-b494-9e802977502c@users.sourceforge.net --- drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c index 122bb015f4a9..8f2d1379c880 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c @@ -640,7 +640,6 @@ static struct platform_driver snd_dw_hdmi_driver = { .remove = snd_dw_hdmi_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = PM_OPS, }, }; From 15d8bb4899d5adf39efd13e0a407c6df4055e7e4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 16 Aug 2016 14:25:35 +0200 Subject: [PATCH 45/46] drm/rockchip: Delete unnecessary assignment for the field "owner" The field "owner" is set by the core. Thus delete an unneeded initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/41e48fd3-f713-7225-1df2-3b1f4758f949@users.sourceforge.net --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 1 - drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 89aadbf465f8..0e63ee25bef8 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -445,7 +445,6 @@ static struct platform_driver rockchip_dp_driver = { .remove = rockchip_dp_remove, .driver = { .name = "rockchip-dp", - .owner = THIS_MODULE, .pm = &rockchip_dp_pm_ops, .of_match_table = of_match_ptr(rockchip_dp_dt_ids), }, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 919992cdc97e..b7f59c443730 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -305,7 +305,6 @@ static struct platform_driver vop_platform_driver = { .remove = vop_remove, .driver = { .name = "rockchip-vop", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(vop_driver_dt_match), }, }; From 28579f37467cd1a9130a6287cf8322986e0b56f9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Aug 2016 17:27:27 +0200 Subject: [PATCH 46/46] drm/fb-helper: Make docs for fb_set_suspend wrappers consistent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I figured I might as well go ocd and make them booleans and rename the locked version too. v2: Review from Noralf. Reported-by: kbuild test robot Cc: Noralf Trønnes Fixes: cfe63423d9be ("drm/fb-helper: Add drm_fb_helper_set_suspend_unlocked()") Acked-by: Noralf Trønnes Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160823152727.31788-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_fb_helper.c | 10 +++++----- include/drm/drm_fb_helper.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 43491a6c6e4e..c4d350086def 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1035,16 +1035,16 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); /** * drm_fb_helper_set_suspend - wrapper around fb_set_suspend * @fb_helper: driver-allocated fbdev helper - * @state: desired state, zero to resume, non-zero to suspend + * @suspend: whether to suspend or resume * * A wrapper around fb_set_suspend implemented by fbdev core. * Use drm_fb_helper_set_suspend_unlocked() if you don't need to take * the lock yourself */ -void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state) +void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend) { if (fb_helper && fb_helper->fbdev) - fb_set_suspend(fb_helper->fbdev, state); + fb_set_suspend(fb_helper->fbdev, suspend); } EXPORT_SYMBOL(drm_fb_helper_set_suspend); @@ -1052,7 +1052,7 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend); * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also * takes the console lock * @fb_helper: driver-allocated fbdev helper - * @state: desired state, zero to resume, non-zero to suspend + * @suspend: whether to suspend or resume * * A wrapper around fb_set_suspend() that takes the console lock. If the lock * isn't available on resume, a worker is tasked with waiting for the lock @@ -1065,7 +1065,7 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend); * Use drm_fb_helper_set_suspend() if you need to take the lock yourself. */ void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, - int suspend) + bool suspend) { if (!fb_helper || !fb_helper->fbdev) return; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 0c6e53d9ce68..edc6cfd3aa34 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -265,9 +265,9 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info, void drm_fb_helper_cfb_imageblit(struct fb_info *info, const struct fb_image *image); -void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state); +void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend); void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, - int suspend); + bool suspend); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); @@ -421,12 +421,12 @@ static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info, } static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, - int state) + bool suspend) { } static inline void -drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, int suspend) +drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend) { }