diff options
author | Dave Airlie <airlied@redhat.com> | 2019-10-30 06:10:59 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2019-10-30 06:11:47 +1000 |
commit | a24e4b09dc75357492ca19d74b02e1edebc282e8 (patch) | |
tree | d94d65004f9b9a2a5b6e1bc4a5d1f9c322645996 | |
parent | 60845e34f0c5c19a9e86af477b429993952f585b (diff) | |
parent | 9a42c7c647a9ad0f7ebb147a52eda3dcb7c84292 (diff) | |
download | linux-a24e4b09dc75357492ca19d74b02e1edebc282e8.tar.bz2 |
Merge tag 'drm-misc-next-2019-10-24-2' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.5:
UAPI Changes:
-syncobj: allow querying the last submitted timeline value (David)
-fourcc: explicitly defineDRM_FORMAT_BIG_ENDIAN as unsigned (Adam)
-omap: revert the OMAP_BO_* flags that were added -- no userspace (Sean)
Cross-subsystem Changes:
-MAINTAINERS: add Mihail as komeda co-maintainer (Mihail)
Core Changes:
-edid: a few cleanups, add AVI infoframe bar info (Ville)
-todo: remove i915 device_link item and add difficulty levels (Daniel)
-dp_helpers: add a few new helpers to parse dpcd (Thierry)
Driver Changes:
-gma500: fix a few memory disclosure leaks (Kangjie)
-qxl: convert to use the new drm_gem_object_funcs.mmap (Gerd)
-various: open code dp_link helpers in preparation for helper removal (Thierry)
Cc: Chunming Zhou <david1.zhou@amd.com>
Cc: Adam Jackson <ajax@redhat.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Kangjie Lu <kjlu@umn.edu>
Cc: Mihail Atanassov <mihail.atanassov@arm.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Thierry Reding <treding@nvidia.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Sean Paul <sean@poorly.run>
Link: https://patchwork.freedesktop.org/patch/msgid/20191024155535.GA10294@art_vandelay
137 files changed, 1859 insertions, 2019 deletions
diff --git a/Documentation/devicetree/bindings/display/arm,malidp.txt b/Documentation/devicetree/bindings/display/arm,malidp.txt index 2f7870983ef1..7a97a2b48c2a 100644 --- a/Documentation/devicetree/bindings/display/arm,malidp.txt +++ b/Documentation/devicetree/bindings/display/arm,malidp.txt @@ -37,6 +37,8 @@ Optional properties: Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) to be used for the framebuffer; if not present, the framebuffer may be located anywhere in memory. + - arm,malidp-arqos-high-level: integer of u32 value describing the ARQoS + levels of DP500's QoS signaling. Example: @@ -54,6 +56,7 @@ Example: clocks = <&oscclk2>, <&fpgaosc0>, <&fpgaosc1>, <&fpgaosc1>; clock-names = "pxlclk", "mclk", "aclk", "pclk"; arm,malidp-output-port-lines = /bits/ 8 <8 8 8>; + arm,malidp-arqos-high-level = <0xd000d000>; port { dp0_output: endpoint { remote-endpoint = <&tda998x_2_input>; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index 4f58c5a2d195..8b3a5f514205 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -20,6 +20,10 @@ Required properties: "rockchip,rk3228-vop"; "rockchip,rk3328-vop"; +- reg: Must contain one entry corresponding to the base address and length + of the register space. Can optionally contain a second entry + corresponding to the CRTC gamma LUT address. + - interrupts: should contain a list of all VOP IP block interrupts in the order: VSYNC, LCD_SYSTEM. The interrupt specifier format depends on the interrupt controller used. @@ -48,7 +52,7 @@ Example: SoC specific DT entry: vopb: vopb@ff930000 { compatible = "rockchip,rk3288-vop"; - reg = <0xff930000 0x19c>; + reg = <0x0 0xff930000 0x0 0x19c>, <0x0 0xff931000 0x0 0x1000>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>; clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 3868008db8a9..9668a7fe2408 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -77,9 +77,6 @@ Atomic State Reset and Initialization Atomic State Helper Reference ----------------------------- -.. kernel-doc:: include/drm/drm_atomic_state_helper.h - :internal: - .. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c :export: diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 8dc147c93c9c..73c51b5a0997 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -7,6 +7,22 @@ TODO list This section contains a list of smaller janitorial tasks in the kernel DRM graphics subsystem useful as newbie projects. Or for slow rainy days. +Difficulty +---------- + +To make it easier task are categorized into different levels: + +Starter: Good tasks to get started with the DRM subsystem. + +Intermediate: Tasks which need some experience with working in the DRM +subsystem, or some specific GPU/display graphics knowledge. For debugging issue +it's good to have the relevant hardware (or a virtual driver set up) available +for testing. + +Advanced: Tricky tasks that need fairly good understanding of the DRM subsystem +and graphics topics. Generally need the relevant hardware for development and +testing. + Subsystem-wide refactorings =========================== @@ -20,6 +36,8 @@ implementations), and then remove it. Contact: Daniel Vetter, respective driver maintainers +Level: Intermediate + Convert existing KMS drivers to atomic modesetting -------------------------------------------------- @@ -38,6 +56,8 @@ do by directly using the new atomic helper driver callbacks. Contact: Daniel Vetter, respective driver maintainers +Level: Advanced + Clean up the clipped coordination confusion around planes --------------------------------------------------------- @@ -50,6 +70,8 @@ helpers. Contact: Ville Syrjälä, Daniel Vetter, driver maintainers +Level: Advanced + Convert early atomic drivers to async commit helpers ---------------------------------------------------- @@ -63,6 +85,8 @@ events for atomic commits correctly. But fixing these bugs is good anyway. Contact: Daniel Vetter, respective driver maintainers +Level: Advanced + Fallout from atomic KMS ----------------------- @@ -91,6 +115,8 @@ interfaces to fix these issues: Contact: Daniel Vetter +Level: Intermediate + Get rid of dev->struct_mutex from GEM drivers --------------------------------------------- @@ -114,6 +140,8 @@ fine-grained per-buffer object and per-context lockings scheme. Currently only t Contact: Daniel Vetter, respective driver maintainers +Level: Advanced + Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent ---------------------------------------------------------------------------- @@ -129,6 +157,8 @@ are better. Contact: Sean Paul, Maintainer of the driver you plan to convert +Level: Starter + Convert drivers to use simple modeset suspend/resume ---------------------------------------------------- @@ -139,6 +169,8 @@ of the atomic suspend/resume code in older atomic modeset drivers. Contact: Maintainer of the driver you plan to convert +Level: Intermediate + Convert drivers to use drm_fb_helper_fbdev_setup/teardown() ----------------------------------------------------------- @@ -157,6 +189,8 @@ probably use drm_fb_helper_fbdev_teardown(). Contact: Maintainer of the driver you plan to convert +Level: Intermediate + Clean up mmap forwarding ------------------------ @@ -166,6 +200,8 @@ There's drm_gem_prime_mmap() for this now, but still needs to be rolled out. Contact: Daniel Vetter +Level: Intermediate + Generic fbdev defio support --------------------------- @@ -196,6 +232,8 @@ Might be good to also have some igt testcases for this. Contact: Daniel Vetter, Noralf Tronnes +Level: Advanced + idr_init_base() --------------- @@ -206,6 +244,8 @@ efficient. Contact: Daniel Vetter +Level: Starter + struct drm_gem_object_funcs --------------------------- @@ -216,6 +256,8 @@ We also need a 2nd version of the CMA define that doesn't require the vmapping to be present (different hook for prime importing). Plus this needs to be rolled out to all drivers using their own implementations, too. +Level: Intermediate + Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate --------------------------------------------------------- @@ -231,6 +273,8 @@ As a reference, take a look at the conversions already completed in drm core. Contact: Sean Paul, respective driver maintainers +Level: Starter + Rename CMA helpers to DMA helpers --------------------------------- @@ -241,6 +285,9 @@ no one knows what that means) since underneath they just use dma_alloc_coherent. Contact: Laurent Pinchart, Daniel Vetter +Level: Intermediate (mostly because it is a huge tasks without good partial +milestones, not technically itself that challenging) + Convert direct mode.vrefresh accesses to use drm_mode_vrefresh() ---------------------------------------------------------------- @@ -259,6 +306,8 @@ drm_display_mode to avoid future use. Contact: Sean Paul +Level: Starter + Remove drm_display_mode.hsync ----------------------------- @@ -269,6 +318,8 @@ it to use drm_mode_hsync() instead. Contact: Sean Paul +Level: Starter + drm_fb_helper tasks ------------------- @@ -284,6 +335,8 @@ drm_fb_helper tasks removed: drm_fb_helper_single_add_all_connectors(), drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector(). +Level: Intermediate + connector register/unregister fixes ----------------------------------- @@ -296,21 +349,11 @@ connector register/unregister fixes drm_dp_aux_init, and moving the actual registering into a late_register callback as recommended in the kerneldoc. +Level: Intermediate + Core refactorings ================= -Clean up the DRM header mess ----------------------------- - -The DRM subsystem originally had only one huge global header, ``drmP.h``. This -is now split up, but many source files still include it. The remaining part of -the cleanup work here is to replace any ``#include <drm/drmP.h>`` by only the -headers needed (and fixing up any missing pre-declarations in the headers). - -In the end no .c file should need to include ``drmP.h`` anymore. - -Contact: Daniel Vetter - Make panic handling work ------------------------ @@ -350,6 +393,8 @@ This is a really varied tasks with lots of little bits and pieces: Contact: Daniel Vetter +Level: Advanced + Clean up the debugfs support ---------------------------- @@ -379,6 +424,8 @@ There's a bunch of issues with it: Contact: Daniel Vetter +Level: Intermediate + KMS cleanups ------------ @@ -394,6 +441,8 @@ Some of these date from the very introduction of KMS in 2008 ... end, for which we could add drm_*_cleanup_kfree(). And then there's the (for historical reasons) misnamed drm_primary_helper_destroy() function. +Level: Intermediate + Better Testing ============== @@ -402,6 +451,8 @@ Enable trinity for DRM And fix up the fallout. Should be really interesting ... +Level: Advanced + Make KMS tests in i-g-t generic ------------------------------- @@ -415,6 +466,8 @@ converting things over. For modeset tests we also first need a bit of infrastructure to use dumb buffers for untiled buffers, to be able to run all the non-i915 specific modeset tests. +Level: Advanced + Extend virtual test driver (VKMS) --------------------------------- @@ -424,6 +477,8 @@ fit the available time. Contact: Daniel Vetter +Level: See details + Backlight Refactoring --------------------- @@ -437,6 +492,8 @@ Plan to fix this: Contact: Daniel Vetter +Level: Intermediate + Driver Specific =============== @@ -450,13 +507,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks. Contact: Harry Wentland, Alex Deucher -i915 ----- - -- Our early/late pm callbacks could be removed in favour of using - device_link_add to model the dependency between i915 and snd_had. See - https://dri.freedesktop.org/docs/drm/driver-api/device_link.html - Bootsplash ========== @@ -472,5 +522,36 @@ for fbdev. Contact: Sam Ravnborg +Level: Advanced + Outside DRM =========== + +Convert fbdev drivers to DRM +---------------------------- + +There are plenty of fbdev drivers for older hardware. Some hwardware has +become obsolete, but some still provides good(-enough) framebuffers. The +drivers that are still useful should be converted to DRM and afterwards +removed from fbdev. + +Very simple fbdev drivers can best be converted by starting with a new +DRM driver. Simple KMS helpers and SHMEM should be able to handle any +existing hardware. The new driver's call-back functions are filled from +existing fbdev code. + +More complex fbdev drivers can be refactored step-by-step into a DRM +driver with the help of the DRM fbconv helpers. [1] These helpers provide +the transition layer between the DRM core infrastructure and the fbdev +driver interface. Create a new DRM driver on top of the fbconv helpers, +copy over the fbdev driver, and hook it up to the DRM code. Examples for +several fbdev drivers are available at [1] and a tutorial of this process +available at [2]. The result is a primitive DRM driver that can run X11 +and Weston. + + - [1] https://gitlab.freedesktop.org/tzimmermann/linux/tree/fbconv + - [2] https://gitlab.freedesktop.org/tzimmermann/linux/blob/fbconv/drivers/gpu/drm/drm_fbconv_helper.c + +Contact: Thomas Zimmermann <tzimmermann@suse.de> + +Level: Advanced diff --git a/MAINTAINERS b/MAINTAINERS index e7391910c0c6..b63c291ad029 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,6 +1251,7 @@ F: Documentation/devicetree/bindings/display/arm,hdlcd.txt ARM KOMEDA DRM-KMS DRIVER M: James (Qian) Wang <james.qian.wang@arm.com> M: Liviu Dudau <liviu.dudau@arm.com> +M: Mihail Atanassov <mihail.atanassov@arm.com> L: Mali DP Maintainers <malidp@foss.arm.com> S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 852a59469688..dba57ca0c9d9 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -263,6 +263,7 @@ config DRM_VKMS tristate "Virtual KMS (EXPERIMENTAL)" depends on DRM select DRM_KMS_HELPER + select CRC32 default n help Virtual Kernel Mode-Setting (VKMS) is used for testing or for @@ -403,7 +404,7 @@ config DRM_R128 config DRM_I810 tristate "Intel I810" - # !PREEMPT because of missing ioctl locking + # !PREEMPTION because of missing ioctl locking depends on DRM && AGP && AGP_INTEL && (!PREEMPTION || BROKEN) help Choose this option if you have an Intel I810 graphics card. If M is diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index b8e5076e5e30..e3f16b49e970 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -1123,7 +1123,10 @@ void amdgpu_bo_fini(struct amdgpu_device *adev) int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, struct vm_area_struct *vma) { - return ttm_fbdev_mmap(vma, &bo->tbo); + if (vma->vm_pgoff != 0) + return -EACCES; + + return ttm_bo_mmap_obj(vma, &bo->tbo); } /** diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index c3d29c0b051b..f0ba26e282c3 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -106,6 +106,23 @@ static void dump_block_header(struct seq_file *sf, void __iomem *reg) i, hdr.output_ids[i]); } +/* On D71, we are using the global line size. From D32, every component have + * a line size register to indicate the fifo size. + */ +static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg, + u32 max_default) +{ + if (!d71->periph_addr) + max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE); + + return max_default; +} + +static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg) +{ + return __get_blk_line_size(d71, reg, d71->max_line_size); +} + static u32 to_rot_ctrl(u32 rot) { u32 lr_ctrl = 0; @@ -332,7 +349,56 @@ static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf) seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]); } +static int d71_layer_validate(struct komeda_component *c, + struct komeda_component_state *state) +{ + struct komeda_layer_state *st = to_layer_st(state); + struct komeda_layer *layer = to_layer(c); + struct drm_plane_state *plane_st; + struct drm_framebuffer *fb; + u32 fourcc, line_sz, max_line_sz; + + plane_st = drm_atomic_get_new_plane_state(state->obj.state, + state->plane); + fb = plane_st->fb; + fourcc = fb->format->format; + + if (drm_rotation_90_or_270(st->rot)) + line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b; + else + line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r; + + if (fb->modifier) { + if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == + AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) + max_line_sz = layer->line_sz; + else + max_line_sz = layer->line_sz / 2; + + if (line_sz > max_line_sz) { + DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n", + line_sz, max_line_sz); + return -EINVAL; + } + } + + if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) { + DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n", + line_sz); + return -EINVAL; + } + + if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) { + DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n", + line_sz); + return -EINVAL; + } + + return 0; +} + static const struct komeda_component_funcs d71_layer_funcs = { + .validate = d71_layer_validate, .update = d71_layer_update, .disable = d71_layer_disable, .dump_register = d71_layer_dump, @@ -365,7 +431,28 @@ static int d71_layer_init(struct d71_dev *d71, else layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER; - set_range(&layer->hsize_in, 4, d71->max_line_size); + if (!d71->periph_addr) { + /* D32 or newer product */ + layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE); + layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info); + } else if (d71->max_line_size > 2048) { + /* D71 4K */ + layer->line_sz = d71->max_line_size; + layer->yuv_line_sz = layer->line_sz / 2; + } else { + /* D71 2K */ + if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) { + /* rich layer is 4K configuration */ + layer->line_sz = d71->max_line_size * 2; + layer->yuv_line_sz = layer->line_sz / 2; + } else { + layer->line_sz = d71->max_line_size; + layer->yuv_line_sz = 0; + } + } + + set_range(&layer->hsize_in, 4, layer->line_sz); + set_range(&layer->vsize_in, 4, d71->max_vsize); malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP); @@ -456,9 +543,11 @@ static int d71_wb_layer_init(struct d71_dev *d71, wb_layer = to_layer(c); wb_layer->layer_type = KOMEDA_FMT_WB_LAYER; + wb_layer->line_sz = get_blk_line_size(d71, reg); + wb_layer->yuv_line_sz = wb_layer->line_sz; - set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size); - set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize); + set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz); + set_range(&wb_layer->vsize_in, 64, d71->max_vsize); return 0; } @@ -595,8 +684,8 @@ static int d71_compiz_init(struct d71_dev *d71, compiz = to_compiz(c); - set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size); - set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize); + set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg)); + set_range(&compiz->vsize, 64, d71->max_vsize); return 0; } @@ -703,7 +792,7 @@ static void d71_scaler_update(struct komeda_component *c, static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf) { - u32 v[9]; + u32 v[10]; dump_block_header(sf, c->reg); @@ -723,6 +812,18 @@ static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf) seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]); seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]); seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]); + + get_values_from_reg(c->reg, 0x130, 10, v); + seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]); + seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]); + seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]); + seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]); + seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]); + seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]); + seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]); + seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]); + seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]); + seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]); } static const struct komeda_component_funcs d71_scaler_funcs = { @@ -753,7 +854,7 @@ static int d71_scaler_init(struct d71_dev *d71, } scaler = to_scaler(c); - set_range(&scaler->hsize, 4, 2048); + set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048)); set_range(&scaler->vsize, 4, 4096); scaler->max_downscaling = 6; scaler->max_upscaling = 64; @@ -862,7 +963,7 @@ static int d71_splitter_init(struct d71_dev *d71, splitter = to_splitter(c); - set_range(&splitter->hsize, 4, d71->max_line_size); + set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg)); set_range(&splitter->vsize, 4, d71->max_vsize); return 0; @@ -933,7 +1034,8 @@ static int d71_merger_init(struct d71_dev *d71, merger = to_merger(c); - set_range(&merger->hsize_merged, 4, 4032); + set_range(&merger->hsize_merged, 4, + __get_blk_line_size(d71, reg, 4032)); set_range(&merger->vsize_merged, 4, 4096); return 0; @@ -944,13 +1046,26 @@ static void d71_improc_update(struct komeda_component *c, { struct komeda_improc_state *st = to_improc_st(state); u32 __iomem *reg = c->reg; - u32 index; + u32 index, mask = 0, ctrl = 0; for_each_changed_input(state, index) malidp_write32(reg, BLK_INPUT_ID0 + index * 4, to_d71_input_id(state, index)); malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); + malidp_write32(reg, IPS_DEPTH, st->color_depth); + + mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; + + /* config color format */ + if (st->color_format == DRM_COLOR_FORMAT_YCRCB420) + ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; + else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422) + ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; + else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444) + ctrl |= IPS_CTRL_YUV; + + malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); } static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf) diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h index 2d5e6d00b42c..1727dc993909 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h @@ -10,6 +10,7 @@ /* Common block registers offset */ #define BLK_BLOCK_INFO 0x000 #define BLK_PIPELINE_INFO 0x004 +#define BLK_MAX_LINE_SIZE 0x008 #define BLK_VALID_INPUT_ID0 0x020 #define BLK_OUTPUT_ID0 0x060 #define BLK_INPUT_ID0 0x080 @@ -321,6 +322,7 @@ #define L_INFO_RF BIT(0) #define L_INFO_CM BIT(1) #define L_INFO_ABUF_SIZE(x) (((x) >> 4) & 0x7) +#define L_INFO_YUV_MAX_LINESZ(x) (((x) >> 16) & 0xFFFF) /* Scaler registers */ #define SC_COEFFTAB 0x0DC @@ -494,13 +496,6 @@ enum d71_blk_type { #define D71_DEFAULT_PREPRETCH_LINE 5 #define D71_BUS_WIDTH_16_BYTES 16 -#define D71_MIN_LINE_SIZE 64 -#define D71_MIN_VERTICAL_SIZE 64 -#define D71_SC_MIN_LIN_SIZE 4 -#define D71_SC_MIN_VERTICAL_SIZE 4 -#define D71_SC_MAX_LIN_SIZE 2048 -#define D71_SC_MAX_VERTICAL_SIZE 4096 - #define D71_SC_MAX_UPSCALING 64 #define D71_SC_MAX_DOWNSCALING 6 #define D71_SC_SPLIT_OVERLAP 8 diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 75263d8cd0bd..252015210fbc 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -17,6 +17,33 @@ #include "komeda_dev.h" #include "komeda_kms.h" +void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, + u32 *color_depths, u32 *color_formats) +{ + struct drm_connector *conn; + struct drm_connector_state *conn_st; + u32 conn_color_formats = ~0u; + int i, min_bpc = 31, conn_bpc = 0; + + for_each_new_connector_in_state(crtc_st->state, conn, conn_st, i) { + if (conn_st->crtc != crtc_st->crtc) + continue; + + conn_bpc = conn->display_info.bpc ? conn->display_info.bpc : 8; + conn_color_formats &= conn->display_info.color_formats; + + if (conn_bpc < min_bpc) + min_bpc = conn_bpc; + } + + /* connector doesn't config any color_format, use RGB444 as default */ + if (!conn_color_formats) + conn_color_formats = DRM_COLOR_FORMAT_RGB444; + + *color_depths = GENMASK(min_bpc, 0); + *color_formats = conn_color_formats; +} + static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st) { u64 pxlclk, aclk; @@ -296,7 +323,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, struct komeda_crtc_state *old_st = to_kcrtc_st(old); struct komeda_pipeline *master = kcrtc->master; struct komeda_pipeline *slave = kcrtc->slave; - struct completion *disable_done = &crtc->state->commit->flip_done; + struct completion *disable_done; bool needs_phase2 = false; DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n", diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index 45c498e15e7a..456f3c435719 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -166,6 +166,8 @@ static inline bool has_flip_h(u32 rot) return !!(rotation & DRM_MODE_REFLECT_X); } +void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, + u32 *color_depths, u32 *color_formats); unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st); int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index b322f52ba8f2..bd6ca7c87037 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -227,6 +227,8 @@ struct komeda_layer { /* accepted h/v input range before rotation */ struct malidp_range hsize_in, vsize_in; u32 layer_type; /* RICH, SIMPLE or WB */ + u32 line_sz; + u32 yuv_line_sz; /* maximum line size for YUV422 and YUV420 */ u32 supported_rots; /* komeda supports layer split which splits a whole image to two parts * left and right and handle them by two individual layer processors @@ -323,6 +325,7 @@ struct komeda_improc { struct komeda_improc_state { struct komeda_component_state base; + u8 color_format, color_depth; u16 hsize, vsize; }; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index 0ba9c6aa3708..42bdc63dcffa 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -285,6 +285,7 @@ komeda_layer_check_cfg(struct komeda_layer *layer, struct komeda_data_flow_cfg *dflow) { u32 src_x, src_y, src_w, src_h; + u32 line_sz, max_line_sz; if (!komeda_fb_is_layer_supported(kfb, layer->layer_type, dflow->rot)) return -EINVAL; @@ -314,6 +315,22 @@ komeda_layer_check_cfg(struct komeda_layer *layer, return -EINVAL; } + if (drm_rotation_90_or_270(dflow->rot)) + line_sz = dflow->in_h; + else + line_sz = dflow->in_w; + + if (kfb->base.format->hsub > 1) + max_line_sz = layer->yuv_line_sz; + else + max_line_sz = layer->line_sz; + + if (line_sz > max_line_sz) { + DRM_DEBUG_ATOMIC("Required line_sz: %d exceeds the max size %d\n", + line_sz, max_line_sz); + return -EINVAL; + } + return 0; } @@ -743,6 +760,7 @@ komeda_improc_validate(struct komeda_improc *improc, struct komeda_data_flow_cfg *dflow) { struct drm_crtc *crtc = kcrtc_st->base.crtc; + struct drm_crtc_state *crtc_st = &kcrtc_st->base; struct komeda_component_state *c_st; struct komeda_improc_state *st; @@ -756,6 +774,34 @@ komeda_improc_validate(struct komeda_improc *improc, st->hsize = dflow->in_w; st->vsize = dflow->in_h; + if (drm_atomic_crtc_needs_modeset(crtc_st)) { + u32 output_depths, output_formats; + u32 avail_depths, avail_formats; + + komeda_crtc_get_color_config(crtc_st, &output_depths, + &output_formats); + + avail_depths = output_depths & improc->supported_color_depths; + if (avail_depths == 0) { + DRM_DEBUG_ATOMIC("No available color depths, conn depths: 0x%x & display: 0x%x\n", + output_depths, + improc->supported_color_depths); + return -EINVAL; + } + + avail_formats = output_formats & + improc->supported_color_formats; + if (!avail_formats) { + DRM_DEBUG_ATOMIC("No available color_formats, conn formats 0x%x & display: 0x%x\n", + output_formats, + improc->supported_color_formats); + return -EINVAL; + } + + st->color_depth = __fls(avail_depths); + st->color_format = BIT(__ffs(avail_formats)); + } + komeda_component_add_input(&st->base, &dflow->input, 0); komeda_component_set_output(&dflow->input, &improc->base, 0); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c index b72840c06ab7..e465cc4879c9 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c @@ -141,6 +141,7 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms, struct komeda_dev *mdev = kms->base.dev_private; struct komeda_wb_connector *kwb_conn; struct drm_writeback_connector *wb_conn; + struct drm_display_info *info; u32 *formats, n_formats = 0; int err; @@ -172,6 +173,10 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms, drm_connector_helper_add(&wb_conn->base, &komeda_wb_conn_helper_funcs); + info = &kwb_conn->base.base.display_info; + info->bpc = __fls(kcrtc->master->improc->supported_color_depths); + info->color_formats = kcrtc->master->improc->supported_color_formats; + kcrtc->wb_conn = kwb_conn; return 0; diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 333b88a5efb0..37d92a06318e 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -368,7 +368,7 @@ malidp_verify_afbc_framebuffer(struct drm_device *dev, struct drm_file *file, return false; } -struct drm_framebuffer * +static struct drm_framebuffer * malidp_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) { @@ -491,9 +491,9 @@ void malidp_error(struct malidp_drm *malidp, spin_unlock_irqrestore(&malidp->errors_lock, irqflags); } -void malidp_error_stats_dump(const char *prefix, - struct malidp_error_stats error_stats, - struct seq_file *m) +static void malidp_error_stats_dump(const char *prefix, + struct malidp_error_stats error_stats, + struct seq_file *m) { seq_printf(m, "[%s] num_errors : %d\n", prefix, error_stats.num_errors); @@ -665,7 +665,7 @@ static ssize_t core_id_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%08x\n", malidp->core_id); } -DEVICE_ATTR_RO(core_id); +static DEVICE_ATTR_RO(core_id); static int malidp_init_sysfs(struct device *dev) { @@ -817,6 +817,12 @@ static int malidp_bind(struct device *dev) malidp->core_id = version; + ret = of_property_read_u32(dev->of_node, + "arm,malidp-arqos-value", + &hwdev->arqos_value); + if (ret) + hwdev->arqos_value = 0x0; + /* set the number of lines used for output of RGB data */ ret = of_property_read_u8_array(dev->of_node, "arm,malidp-output-port-lines", diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index bd8265f02e0b..ca570b135478 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -379,6 +379,15 @@ static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode * malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); else malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); + + /* + * Program the RQoS register to avoid high resolutions flicker + * issue on the LS1028A. + */ + if (hwdev->arqos_value) { + val = hwdev->arqos_value; + malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY); + } } int malidp_format_get_bpp(u32 fmt) diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 968a65eed371..e4c36bc90bda 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -251,6 +251,9 @@ struct malidp_hw_device { /* size of memory used for rotating layers, up to two banks available */ u32 rotation_memory[2]; + + /* priority level of RQOS register used for driven the ARQOS signal */ + u32 arqos_value; }; static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 993031542fa1..514c50dcb74d 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -210,6 +210,16 @@ #define MALIDP500_CONFIG_VALID 0x00f00 #define MALIDP500_CONFIG_ID 0x00fd4 +/* + * The quality of service (QoS) register on the DP500. RQOS register values + * are driven by the ARQOS signal, using AXI transacations, dependent on the + * FIFO input level. + * The RQOS register can also set QoS levels for: + * - RED_ARQOS @ A 4-bit signal value for close to underflow conditions + * - GREEN_ARQOS @ A 4-bit signal value for normal conditions + */ +#define MALIDP500_RQOS_QUALITY 0x00500 + /* register offsets and bits specific to DP550/DP650 */ #define MALIDP550_ADDR_SPACE_SIZE 0x10000 #define MALIDP550_DE_CONTROL 0x00010 diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index e0e8770462bc..1f17794b0890 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -200,10 +200,7 @@ static struct pci_driver ast_pci_driver = { .driver.pm = &ast_pm_ops, }; -static const struct file_operations ast_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(ast_fops); static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 89f5a756fa37..034f202dfe8f 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -601,7 +601,6 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, struct drm_framebuffer *fb = state->base.fb; const struct drm_display_mode *mode; struct drm_crtc_state *crtc_state; - unsigned int tmp; int ret; int i; @@ -694,9 +693,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, * Swap width and size in case of 90 or 270 degrees rotation */ if (drm_rotation_90_or_270(state->base.rotation)) { - tmp = state->src_w; - state->src_w = state->src_h; - state->src_h = tmp; + swap(state->src_w, state->src_h); } if (!desc->layout.size && diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 3b9b0d9bbc14..10460878414e 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -58,10 +58,7 @@ err: return ret; } -static const struct file_operations bochs_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(bochs_fops); static struct drm_driver bochs_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 1cc9f502c1f2..34362976cd6f 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -87,8 +87,7 @@ config DRM_SIL_SII8620 depends on OF select DRM_KMS_HELPER imply EXTCON - select INPUT - select RC_CORE + depends on RC_CORE || !RC_CORE help Silicon Image SII8620 HDMI/MHL bridge chip driver. diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 31118d385580..274989f96a91 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -39,12 +39,20 @@ #define AUX_CH_BUFFER_SIZE 16 #define AUX_WAIT_TIMEOUT_MS 15 -static const u8 anx78xx_i2c_addresses[] = { - [I2C_IDX_TX_P0] = TX_P0, - [I2C_IDX_TX_P1] = TX_P1, - [I2C_IDX_TX_P2] = TX_P2, - [I2C_IDX_RX_P0] = RX_P0, - [I2C_IDX_RX_P1] = RX_P1, +static const u8 anx7808_i2c_addresses[] = { + [I2C_IDX_TX_P0] = 0x78, + [I2C_IDX_TX_P1] = 0x7a, + [I2C_IDX_TX_P2] = 0x72, + [I2C_IDX_RX_P0] = 0x7e, + [I2C_IDX_RX_P1] = 0x80, +}; + +static const u8 anx781x_i2c_addresses[] = { + [I2C_IDX_TX_P0] = 0x70, + [I2C_IDX_TX_P1] = 0x7a, + [I2C_IDX_TX_P2] = 0x72, + [I2C_IDX_RX_P0] = 0x7e, + [I2C_IDX_RX_P1] = 0x80, }; struct anx78xx_platform_data { @@ -63,7 +71,6 @@ struct anx78xx { struct i2c_client *client; struct edid *edid; struct drm_connector connector; - struct drm_dp_link link; struct anx78xx_platform_data pdata; struct mutex lock; @@ -740,7 +747,7 @@ static int anx78xx_init_pdata(struct anx78xx *anx78xx) static int anx78xx_dp_link_training(struct anx78xx *anx78xx) { - u8 dp_bw, value; + u8 dp_bw, dpcd[2]; int err; err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_HDMI_MUTE_CTRL_REG, @@ -793,18 +800,34 @@ static int anx78xx_dp_link_training(struct anx78xx *anx78xx) if (err) return err; - /* Check link capabilities */ - err = drm_dp_link_probe(&anx78xx->aux, &anx78xx->link); - if (err < 0) { - DRM_ERROR("Failed to probe link capabilities: %d\n", err); - return err; - } + /* + * Power up the sink (DP_SET_POWER register is only available on DPCD + * v1.1 and later). + */ + if (anx78xx->dpcd[DP_DPCD_REV] >= 0x11) { + err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SET_POWER, &dpcd[0]); + if (err < 0) { + DRM_ERROR("Failed to read DP_SET_POWER register: %d\n", + err); + return err; + } - /* Power up the sink */ - err = drm_dp_link_power_up(&anx78xx->aux, &anx78xx->link); - if (err < 0) { - DRM_ERROR("Failed to power up DisplayPort link: %d\n", err); - return err; + dpcd[0] &= ~DP_SET_POWER_MASK; + dpcd[0] |= DP_SET_POWER_D0; + + err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_SET_POWER, dpcd[0]); + if (err < 0) { + DRM_ERROR("Failed to power up DisplayPort link: %d\n", + err); + return err; + } + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); } /* Possibly enable downspread on the sink */ @@ -843,15 +866,22 @@ static int anx78xx_dp_link_training(struct anx78xx *anx78xx) if (err) return err; - value = drm_dp_link_rate_to_bw_code(anx78xx->link.rate); + dpcd[0] = drm_dp_max_link_rate(anx78xx->dpcd); + dpcd[0] = drm_dp_link_rate_to_bw_code(dpcd[0]); err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], - SP_DP_MAIN_LINK_BW_SET_REG, value); + SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]); if (err) return err; - err = drm_dp_link_configure(&anx78xx->aux, &anx78xx->link); + dpcd[1] = drm_dp_max_lane_count(anx78xx->dpcd); + + if (drm_dp_enhanced_frame_cap(anx78xx->dpcd)) + dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + err = drm_dp_dpcd_write(&anx78xx->aux, DP_LINK_BW_SET, dpcd, + sizeof(dpcd)); if (err < 0) { - DRM_ERROR("Failed to configure DisplayPort link: %d\n", err); + DRM_ERROR("Failed to configure link: %d\n", err); return err; } @@ -1316,6 +1346,7 @@ static int anx78xx_i2c_probe(struct i2c_client *client, struct anx78xx *anx78xx; struct anx78xx_platform_data *pdata; unsigned int i, idl, idh, version; + const u8 *i2c_addresses; bool found = false; int err; @@ -1355,15 +1386,16 @@ static int anx78xx_i2c_probe(struct i2c_client *client, } /* Map slave addresses of ANX7814 */ + i2c_addresses = device_get_match_data(&client->dev); for (i = 0; i < I2C_NUM_ADDRESSES; i++) { struct i2c_client *i2c_dummy; i2c_dummy = i2c_new_dummy_device(client->adapter, - anx78xx_i2c_addresses[i] >> 1); + i2c_addresses[i] >> 1); if (IS_ERR(i2c_dummy)) { err = PTR_ERR(i2c_dummy); DRM_ERROR("Failed to reserve I2C bus %02x: %d\n", - anx78xx_i2c_addresses[i], err); + i2c_addresses[i], err); goto err_unregister_i2c; } @@ -1373,7 +1405,7 @@ static int anx78xx_i2c_probe(struct i2c_client *client, if (IS_ERR(anx78xx->map[i])) { err = PTR_ERR(anx78xx->map[i]); DRM_ERROR("Failed regmap initialization %02x\n", - anx78xx_i2c_addresses[i]); + i2c_addresses[i]); goto err_unregister_i2c; } } @@ -1472,10 +1504,10 @@ MODULE_DEVICE_TABLE(i2c, anx78xx_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id anx78xx_match_table[] = { - { .compatible = "analogix,anx7808", }, - { .compatible = "analogix,anx7812", }, - { .compatible = "analogix,anx7814", }, - { .compatible = "analogix,anx7818", }, + { .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses }, + { .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses }, + { .compatible = "analogix,anx7814", .data = anx781x_i2c_addresses }, + { .compatible = "analogix,anx7818", .data = anx781x_i2c_addresses }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, anx78xx_match_table); diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.h b/drivers/gpu/drm/bridge/analogix-anx78xx.h index 25e063bcecbc..55d6c2109740 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.h +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.h @@ -6,15 +6,8 @@ #ifndef __ANX78xx_H #define __ANX78xx_H -#define TX_P0 0x70 -#define TX_P1 0x7a -#define TX_P2 0x72 - -#define RX_P0 0x7e -#define RX_P1 0x80 - /***************************************************************/ -/* Register definition of device address 0x7e */ +/* Register definitions for RX_PO */ /***************************************************************/ /* @@ -171,7 +164,7 @@ #define SP_VSI_RCVD BIT(1) /***************************************************************/ -/* Register definition of device address 0x80 */ +/* Register definitions for RX_P1 */ /***************************************************************/ /* HDCP BCAPS Shadow Register */ @@ -217,7 +210,7 @@ #define SP_SET_AVMUTE BIT(0) /***************************************************************/ -/* Register definition of device address 0x70 */ +/* Register definitions for TX_P0 */ /***************************************************************/ /* HDCP Status Register */ @@ -451,7 +444,7 @@ #define SP_DP_BUF_DATA0_REG 0xf0 /***************************************************************/ -/* Register definition of device address 0x72 */ +/* Register definitions for TX_P2 */ /***************************************************************/ /* @@ -674,7 +667,7 @@ #define SP_INT_CTRL_REG 0xff /***************************************************************/ -/* Register definition of device address 0x7a */ +/* Register definitions for TX_P1 */ /***************************************************************/ /* DP TX Link Training Control Register */ diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index ad00d841ed9e..f81f81b7051f 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -842,39 +842,28 @@ static int sii9234_init_resources(struct sii9234 *ctx, ctx->client[I2C_MHL] = client; - ctx->client[I2C_TPI] = i2c_new_dummy(adapter, I2C_TPI_ADDR); - if (!ctx->client[I2C_TPI]) { + ctx->client[I2C_TPI] = devm_i2c_new_dummy_device(&client->dev, adapter, + I2C_TPI_ADDR); + if (IS_ERR(ctx->client[I2C_TPI])) { dev_err(ctx->dev, "failed to create TPI client\n"); - return -ENODEV; + return PTR_ERR(ctx->client[I2C_TPI]); } - ctx->client[I2C_HDMI] = i2c_new_dummy(adapter, I2C_HDMI_ADDR); - if (!ctx->client[I2C_HDMI]) { + ctx->client[I2C_HDMI] = devm_i2c_new_dummy_device(&client->dev, adapter, + I2C_HDMI_ADDR); + if (IS_ERR(ctx->client[I2C_HDMI])) { dev_err(ctx->dev, "failed to create HDMI RX client\n"); - goto fail_tpi; + return PTR_ERR(ctx->client[I2C_HDMI]); } - ctx->client[I2C_CBUS] = i2c_new_dummy(adapter, I2C_CBUS_ADDR); - if (!ctx->client[I2C_CBUS]) { + ctx->client[I2C_CBUS] = devm_i2c_new_dummy_device(&client->dev, adapter, + I2C_CBUS_ADDR); + if (IS_ERR(ctx->client[I2C_CBUS])) { dev_err(ctx->dev, "failed to create CBUS client\n"); - goto fail_hdmi; + return PTR_ERR(ctx->client[I2C_CBUS]); } return 0; - -fail_hdmi: - i2c_unregister_device(ctx->client[I2C_HDMI]); -fail_tpi: - i2c_unregister_device(ctx->client[I2C_TPI]); - - return -ENODEV; -} - -static void sii9234_deinit_resources(struct sii9234 *ctx) -{ - i2c_unregister_device(ctx->client[I2C_CBUS]); - i2c_unregister_device(ctx->client[I2C_HDMI]); - i2c_unregister_device(ctx->client[I2C_TPI]); } static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge) @@ -951,7 +940,6 @@ static int sii9234_remove(struct i2c_client *client) sii9234_cable_out(ctx); drm_bridge_remove(&ctx->bridge); - sii9234_deinit_resources(ctx); return 0; } diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 14643923a721..4c0eef406eb1 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -1760,10 +1760,8 @@ static bool sii8620_rcp_consume(struct sii8620 *ctx, u8 scancode) scancode &= MHL_RCP_KEY_ID_MASK; - if (!ctx->rc_dev) { - dev_dbg(ctx->dev, "RCP input device not initialized\n"); + if (!IS_ENABLED(CONFIG_RC_CORE) || !ctx->rc_dev) return false; - } if (pressed) rc_keydown(ctx->rc_dev, RC_PROTO_CEC, scancode, 0); @@ -2100,6 +2098,9 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) struct rc_dev *rc_dev; int ret; + if (!IS_ENABLED(CONFIG_RC_CORE)) + return; + rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); if (!rc_dev) { dev_err(ctx->dev, "Failed to allocate RC device\n"); @@ -2214,6 +2215,9 @@ static void sii8620_detach(struct drm_bridge *bridge) { struct sii8620 *ctx = bridge_to_sii8620(bridge); + if (!IS_ENABLED(CONFIG_RC_CORE)) + return; + rc_unregister_device(ctx->rc_dev); } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index a15fbf71b9d7..dbe38a54870b 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -25,6 +25,7 @@ #include <uapi/linux/videodev2.h> #include <drm/bridge/dw_hdmi.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_edid.h> @@ -1743,6 +1744,41 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, HDMI_FC_DATAUTO0_VSD_MASK); } +static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) +{ + const struct drm_connector_state *conn_state = hdmi->connector.state; + struct hdmi_drm_infoframe frame; + u8 buffer[30]; + ssize_t err; + int i; + + if (!hdmi->plat_data->use_drm_infoframe) + return; + + hdmi_modb(hdmi, HDMI_FC_PACKET_TX_EN_DRM_DISABLE, + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); + + err = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state); + if (err < 0) + return; + + err = hdmi_drm_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (err < 0) { + dev_err(hdmi->dev, "Failed to pack drm infoframe: %zd\n", err); + return; + } + + hdmi_writeb(hdmi, frame.version, HDMI_FC_DRM_HB0); + hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1); + + for (i = 0; i < frame.length; i++) + hdmi_writeb(hdmi, buffer[4 + i], HDMI_FC_DRM_PB0 + i); + + hdmi_writeb(hdmi, 1, HDMI_FC_DRM_UP); + hdmi_modb(hdmi, HDMI_FC_PACKET_TX_EN_DRM_ENABLE, + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); +} + static void hdmi_av_composer(struct dw_hdmi *hdmi, const struct drm_display_mode *mode) { @@ -2054,7 +2090,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* HDMI Initialization Step E - Configure audio */ hdmi_clk_regenerator_update_pixel_clock(hdmi); - hdmi_enable_audio_clk(hdmi, true); + hdmi_enable_audio_clk(hdmi, hdmi->audio_enable); } /* not for DVI mode */ @@ -2064,6 +2100,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* HDMI Initialization Step F - Configure AVI InfoFrame */ hdmi_config_AVI(hdmi, mode); hdmi_config_vendor_specific_infoframe(hdmi, mode); + hdmi_config_drm_infoframe(hdmi); } else { dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); } @@ -2230,6 +2267,45 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } +static bool hdr_metadata_equal(const struct drm_connector_state *old_state, + const struct drm_connector_state *new_state) +{ + struct drm_property_blob *old_blob = old_state->hdr_output_metadata; + struct drm_property_blob *new_blob = new_state->hdr_output_metadata; + + if (!old_blob || !new_blob) + return old_blob == new_blob; + + if (old_blob->length != new_blob->length) + return false; + + return !memcmp(old_blob->data, new_blob->data, old_blob->length); +} + +static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *old_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_connector_state *new_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_crtc *crtc = new_state->crtc; + struct drm_crtc_state *crtc_state; + + if (!crtc) + return 0; + + if (!hdr_metadata_equal(old_state, new_state)) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->mode_changed = true; + } + + return 0; +} + static void dw_hdmi_connector_force(struct drm_connector *connector) { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, @@ -2254,6 +2330,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .get_modes = dw_hdmi_connector_get_modes, + .atomic_check = dw_hdmi_connector_atomic_check, }; static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) @@ -2274,6 +2351,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) DRM_MODE_CONNECTOR_HDMIA, hdmi->ddc); + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.hdr_output_metadata_property, 0); + drm_connector_attach_encoder(connector, encoder); cec_fill_conn_info_from_drm(&conn_info, connector); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index fcff5059db24..1999db05bc3b 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h @@ -254,6 +254,7 @@ #define HDMI_FC_POL2 0x10DB #define HDMI_FC_PRCONF 0x10E0 #define HDMI_FC_SCRAMBLER_CTRL 0x10E1 +#define HDMI_FC_PACKET_TX_EN 0x10E3 #define HDMI_FC_GMD_STAT 0x1100 #define HDMI_FC_GMD_EN 0x1101 @@ -289,6 +290,37 @@ #define HDMI_FC_GMD_PB26 0x111F #define HDMI_FC_GMD_PB27 0x1120 +#define HDMI_FC_DRM_UP 0x1167 +#define HDMI_FC_DRM_HB0 0x1168 +#define HDMI_FC_DRM_HB1 0x1169 +#define HDMI_FC_DRM_PB0 0x116A +#define HDMI_FC_DRM_PB1 0x116B +#define HDMI_FC_DRM_PB2 0x116C +#define HDMI_FC_DRM_PB3 0x116D +#define HDMI_FC_DRM_PB4 0x116E +#define HDMI_FC_DRM_PB5 0x116F +#define HDMI_FC_DRM_PB6 0x1170 +#define HDMI_FC_DRM_PB7 0x1171 +#define HDMI_FC_DRM_PB8 0x1172 +#define HDMI_FC_DRM_PB9 0x1173 +#define HDMI_FC_DRM_PB10 0x1174 +#define HDMI_FC_DRM_PB11 0x1175 +#define HDMI_FC_DRM_PB12 0x1176 +#define HDMI_FC_DRM_PB13 0x1177 +#define HDMI_FC_DRM_PB14 0x1178 +#define HDMI_FC_DRM_PB15 0x1179 +#define HDMI_FC_DRM_PB16 0x117A +#define HDMI_FC_DRM_PB17 0x117B +#define HDMI_FC_DRM_PB18 0x117C +#define HDMI_FC_DRM_PB19 0x117D +#define HDMI_FC_DRM_PB20 0x117E +#define HDMI_FC_DRM_PB21 0x117F +#define HDMI_FC_DRM_PB22 0x1180 +#define HDMI_FC_DRM_PB23 0x1181 +#define HDMI_FC_DRM_PB24 0x1182 +#define HDMI_FC_DRM_PB25 0x1183 +#define HDMI_FC_DRM_PB26 0x1184 + #define HDMI_FC_DBGFORCE 0x1200 #define HDMI_FC_DBGAUD0CH0 0x1201 #define HDMI_FC_DBGAUD1CH0 0x1202 @@ -744,6 +776,11 @@ enum { HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F, HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0, +/* FC_PACKET_TX_EN field values */ + HDMI_FC_PACKET_TX_EN_DRM_MASK = 0x80, + HDMI_FC_PACKET_TX_EN_DRM_ENABLE = 0x80, + HDMI_FC_PACKET_TX_EN_DRM_DISABLE = 0x00, + /* FC_AVICONF0-FC_AVICONF3 field values */ HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03, HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00, diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index da7e35b0893d..8029478ffebb 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -229,7 +229,9 @@ static bool tc_test_pattern; module_param_named(test, tc_test_pattern, bool, 0644); struct tc_edp_link { - struct drm_dp_link base; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + unsigned int rate; + u8 num_lanes; u8 assr; bool scrambler_dis; bool spread; @@ -438,9 +440,9 @@ static u32 tc_srcctrl(struct tc_data *tc) reg |= DP0_SRCCTRL_SCRMBLDIS; /* Scrambler Disabled */ if (tc->link.spread) reg |= DP0_SRCCTRL_SSCG; /* Spread Spectrum Enable */ - if (tc->link.base.num_lanes == 2) + if (tc->link.num_lanes == 2) reg |= DP0_SRCCTRL_LANES_2; /* Two Main Channel Lanes */ - if (tc->link.base.rate != 162000) + if (tc->link.rate != 162000) reg |= DP0_SRCCTRL_BW27; /* 2.7 Gbps link */ return reg; } @@ -663,23 +665,35 @@ err: static int tc_get_display_props(struct tc_data *tc) { + u8 revision, num_lanes; + unsigned int rate; int ret; u8 reg; /* Read DP Rx Link Capability */ - ret = drm_dp_link_probe(&tc->aux, &tc->link.base); + ret = drm_dp_dpcd_read(&tc->aux, DP_DPCD_REV, tc->link.dpcd, + DP_RECEIVER_CAP_SIZE); if (ret < 0) goto err_dpcd_read; - if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) { + + revision = tc->link.dpcd[DP_DPCD_REV]; + rate = drm_dp_max_link_rate(tc->link.dpcd); + num_lanes = drm_dp_max_lane_count(tc->link.dpcd); + + if (rate != 162000 && rate != 270000) { dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n"); - tc->link.base.rate = 270000; + rate = 270000; } - if (tc->link.base.num_lanes > 2) { + tc->link.rate = rate; + + if (num_lanes > 2) { dev_dbg(tc->dev, "Falling to 2 lanes\n"); - tc->link.base.num_lanes = 2; + num_lanes = 2; } + tc->link.num_lanes = num_lanes; + ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, ®); if (ret < 0) goto err_dpcd_read; @@ -697,11 +711,11 @@ static int tc_get_display_props(struct tc_data *tc) tc->link.assr = reg & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE; dev_dbg(tc->dev, "DPCD rev: %d.%d, rate: %s, lanes: %d, framing: %s\n", - tc->link.base.revision >> 4, tc->link.base.revision & 0x0f, - (tc->link.base.rate == 162000) ? "1.62Gbps" : "2.7Gbps", - tc->link.base.num_lanes, - (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? - "enhanced" : "non-enhanced"); + revision >> 4, revision & 0x0f, + (tc->link.rate == 162000) ? "1.62Gbps" : "2.7Gbps", + tc->link.num_lanes, + drm_dp_enhanced_frame_cap(tc->link.dpcd) ? + "enhanced" : "default"); dev_dbg(tc->dev, "Downspread: %s, scrambler: %s\n", tc->link.spread ? "0.5%" : "0.0%", tc->link.scrambler_dis ? "disabled" : "enabled"); @@ -740,7 +754,7 @@ static int tc_set_video_mode(struct tc_data *tc, */ in_bw = mode->clock * bits_per_pixel / 8; - out_bw = tc->link.base.num_lanes * tc->link.base.rate; + out_bw = tc->link.num_lanes * tc->link.rate; max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw); dev_dbg(tc->dev, "set mode %dx%d\n", @@ -902,7 +916,7 @@ static int tc_main_link_enable(struct tc_data *tc) /* SSCG and BW27 on DP1 must be set to the same as on DP0 */ ret = regmap_write(tc->regmap, DP1_SRCCTRL, (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) | - ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); + ((tc->link.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); if (ret) return ret; @@ -912,7 +926,7 @@ static int tc_main_link_enable(struct tc_data *tc) /* Setup Main Link */ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN; - if (tc->link.base.num_lanes == 2) + if (tc->link.num_lanes == 2) dp_phy_ctrl |= PHY_2LANE; ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl); @@ -975,7 +989,13 @@ static int tc_main_link_enable(struct tc_data *tc) } /* Setup Link & DPRx Config for Training */ - ret = drm_dp_link_configure(aux, &tc->link.base); + tmp[0] = drm_dp_link_rate_to_bw_code(tc->link.rate); + tmp[1] = tc->link.num_lanes; + + if (drm_dp_enhanced_frame_cap(tc->link.dpcd)) + tmp[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + ret = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, tmp, 2); if (ret < 0) goto err_dpcd_write; @@ -1019,9 +1039,8 @@ static int tc_main_link_enable(struct tc_data *tc) /* Enable DP0 to start Link Training */ ret = regmap_write(tc->regmap, DP0CTL, - ((tc->link.base.capabilities & - DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) | - DP_EN); + (drm_dp_enhanced_frame_cap(tc->link.dpcd) ? + EF_EN : 0) | DP_EN); if (ret) return ret; @@ -1100,7 +1119,7 @@ static int tc_main_link_enable(struct tc_data *tc) ret = -ENODEV; } - if (tc->link.base.num_lanes == 2) { + if (tc->link.num_lanes == 2) { value = (tmp[0] >> 4) & DP_CHANNEL_EQ_BITS; if (value != DP_CHANNEL_EQ_BITS) { @@ -1171,7 +1190,7 @@ static int tc_stream_enable(struct tc_data *tc) return ret; value = VID_MN_GEN | DP_EN; - if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + if (drm_dp_enhanced_frame_cap(tc->link.dpcd)) value |= EF_EN; ret = regmap_write(tc->regmap, DP0CTL, value); if (ret) @@ -1297,7 +1316,7 @@ static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge, return MODE_CLOCK_HIGH; req = mode->clock * bits_per_pixel / 8; - avail = tc->link.base.num_lanes * tc->link.base.rate; + avail = tc->link.num_lanes * tc->link.rate; if (req > avail) return MODE_BAD; diff --git a/drivers/gpu/drm/cirrus/cirrus.c b/drivers/gpu/drm/cirrus/cirrus.c index 89d9e6fdeb8c..7d08d067e1a4 100644 --- a/drivers/gpu/drm/cirrus/cirrus.c +++ b/drivers/gpu/drm/cirrus/cirrus.c @@ -510,7 +510,7 @@ static void cirrus_mode_config_init(struct cirrus_device *cirrus) /* ------------------------------------------------------------------ */ -DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops); +DEFINE_DRM_GEM_FOPS(cirrus_fops); static struct drm_driver cirrus_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h deleted file mode 100644 index 1f73916e528e..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ /dev/null @@ -1,247 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright 2012 Red Hat - * - * Authors: Matthew Garrett - * Dave Airlie - */ -#ifndef __CIRRUS_DRV_H__ -#define __CIRRUS_DRV_H__ - -#include <video/vga.h> - -#include <drm/drm_encoder.h> -#include <drm/drm_fb_helper.h> - -#include <drm/ttm/ttm_bo_api.h> -#include <drm/ttm/ttm_bo_driver.h> -#include <drm/ttm/ttm_placement.h> -#include <drm/ttm/ttm_memory.h> -#include <drm/ttm/ttm_module.h> - -#include <drm/drm_gem.h> - -#define DRIVER_AUTHOR "Matthew Garrett" - -#define DRIVER_NAME "cirrus" -#define DRIVER_DESC "qemu Cirrus emulation" -#define DRIVER_DATE "20110418" - -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 0 - -#define CIRRUSFB_CONN_LIMIT 1 - -#define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg)) -#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg)) -#define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg)) -#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg)) - -#define SEQ_INDEX 4 -#define SEQ_DATA 5 - -#define WREG_SEQ(reg, v) \ - do { \ - WREG8(SEQ_INDEX, reg); \ - WREG8(SEQ_DATA, v); \ - } while (0) \ - -#define CRT_INDEX 0x14 -#define CRT_DATA 0x15 - -#define WREG_CRT(reg, v) \ - do { \ - WREG8(CRT_INDEX, reg); \ - WREG8(CRT_DATA, v); \ - } while (0) \ - -#define GFX_INDEX 0xe -#define GFX_DATA 0xf - -#define WREG_GFX(reg, v) \ - do { \ - WREG8(GFX_INDEX, reg); \ - WREG8(GFX_DATA, v); \ - } while (0) \ - -/* - * Cirrus has a "hidden" DAC register that can be accessed by writing to - * the pixel mask register to reset the state, then reading from the register - * four times. The next write will then pass to the DAC - */ -#define VGA_DAC_MASK 0x6 - -#define WREG_HDR(v) \ - do { \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - WREG8(VGA_DAC_MASK, v); \ - } while (0) \ - - -#define CIRRUS_MAX_FB_HEIGHT 4096 -#define CIRRUS_MAX_FB_WIDTH 4096 - -#define CIRRUS_DPMS_CLEARED (-1) - -#define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base) -#define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base) - -struct cirrus_crtc { - struct drm_crtc base; - int last_dpms; - bool enabled; -}; - -struct cirrus_fbdev; -struct cirrus_mode_info { - struct cirrus_crtc *crtc; - /* pointer to fbdev info structure */ - struct cirrus_fbdev *gfbdev; -}; - -struct cirrus_encoder { - struct drm_encoder base; - int last_dpms; -}; - -struct cirrus_connector { - struct drm_connector base; -}; - -struct cirrus_mc { - resource_size_t vram_size; - resource_size_t vram_base; -}; - -struct cirrus_device { - struct drm_device *dev; - unsigned long flags; - - resource_size_t rmmio_base; - resource_size_t rmmio_size; - void __iomem *rmmio; - - struct cirrus_mc mc; - struct cirrus_mode_info mode_info; - - int num_crtc; - int fb_mtrr; - - struct { - struct ttm_bo_device bdev; - } ttm; - bool mm_inited; -}; - - -struct cirrus_fbdev { - struct drm_fb_helper helper; /* must be first */ - struct drm_framebuffer *gfb; - void *sysram; - int size; - int x1, y1, x2, y2; /* dirty rect */ - spinlock_t dirty_lock; -}; - -struct cirrus_bo { - struct ttm_buffer_object bo; - struct ttm_placement placement; - struct ttm_bo_kmap_obj kmap; - struct drm_gem_object gem; - struct ttm_place placements[3]; - int pin_count; -}; -#define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem) - -static inline struct cirrus_bo * -cirrus_bo(struct ttm_buffer_object *bo) -{ - return container_of(bo, struct cirrus_bo, bo); -} - - -#define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base) - - /* cirrus_main.c */ -int cirrus_device_init(struct cirrus_device *cdev, - struct drm_device *ddev, - struct pci_dev *pdev, - uint32_t flags); -void cirrus_device_fini(struct cirrus_device *cdev); -void cirrus_gem_free_object(struct drm_gem_object *obj); -int cirrus_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, - uint64_t *offset); -int cirrus_gem_create(struct drm_device *dev, - u32 size, bool iskernel, - struct drm_gem_object **obj); -int cirrus_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args); - -int cirrus_framebuffer_init(struct drm_device *dev, - struct drm_framebuffer *gfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); - -bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, - int bpp, int pitch); - - /* cirrus_display.c */ -int cirrus_modeset_init(struct cirrus_device *cdev); -void cirrus_modeset_fini(struct cirrus_device *cdev); - - /* cirrus_fbdev.c */ -int cirrus_fbdev_init(struct cirrus_device *cdev); -void cirrus_fbdev_fini(struct cirrus_device *cdev); - - - - /* cirrus_irq.c */ -void cirrus_driver_irq_preinstall(struct drm_device *dev); -int cirrus_driver_irq_postinstall(struct drm_device *dev); -void cirrus_driver_irq_uninstall(struct drm_device *dev); -irqreturn_t cirrus_driver_irq_handler(int irq, void *arg); - - /* cirrus_kms.c */ -int cirrus_driver_load(struct drm_device *dev, unsigned long flags); -void cirrus_driver_unload(struct drm_device *dev); -extern struct drm_ioctl_desc cirrus_ioctls[]; -extern int cirrus_max_ioctl; - -int cirrus_mm_init(struct cirrus_device *cirrus); -void cirrus_mm_fini(struct cirrus_device *cirrus); -void cirrus_ttm_placement(struct cirrus_bo *bo, int domain); -int cirrus_bo_create(struct drm_device *dev, int size, int align, - uint32_t flags, struct cirrus_bo **pcirrusbo); -int cirrus_mmap(struct file *filp, struct vm_area_struct *vma); - -static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) -{ - int ret; - - ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); - if (ret) { - if (ret != -ERESTARTSYS && ret != -EBUSY) - DRM_ERROR("reserve failed %p\n", bo); - return ret; - } - return 0; -} - -static inline void cirrus_bo_unreserve(struct cirrus_bo *bo) -{ - ttm_bo_unreserve(&bo->bo); -} - -int cirrus_bo_push_sysram(struct cirrus_bo *bo); -int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr); - -extern int cirrus_bpp; - -#endif /* __CIRRUS_DRV_H__ */ diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index d02709dd2d4a..121481f6aa71 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -132,10 +132,10 @@ * planes. Without this property the primary plane is always below the cursor * plane, and ordering between all other planes is undefined. The positive * Z axis points towards the user, i.e. planes with lower Z position values - * are underneath planes with higher Z position values. Note that the Z - * position value can also be immutable, to inform userspace about the - * hard-coded stacking of overlay planes, see - * drm_plane_create_zpos_immutable_property(). + * are underneath planes with higher Z position values. Two planes with the + * same Z position value have undefined ordering. Note that the Z position + * value can also be immutable, to inform userspace about the hard-coded + * stacking of planes, see drm_plane_create_zpos_immutable_property(). * * pixel blend mode: * Pixel blend mode is set up with drm_plane_create_blend_mode_property(). diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c index b457c16c3a8b..3ab2609f9ec7 100644 --- a/drivers/gpu/drm/drm_dp_cec.c +++ b/drivers/gpu/drm/drm_dp_cec.c @@ -8,10 +8,12 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> + +#include <media/cec.h> + #include <drm/drm_connector.h> +#include <drm/drm_device.h> #include <drm/drm_dp_helper.h> -#include <drm/drmP.h> -#include <media/cec.h> /* * Unfortunately it turns out that we have a chicken-and-egg situation diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f373798d82f6..2c7870aef469 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,33 +120,49 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); -void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; +u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane) +{ + unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2; + u8 value = dp_link_status(link_status, offset); + + return (value >> (lane << 1)) & 0x3; +} +EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor); + +void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n", + DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n", rd_interval); if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) - udelay(100); + rd_interval = 100; else - mdelay(rd_interval * 4); + rd_interval *= 4 * USEC_PER_MSEC; + + usleep_range(rd_interval, rd_interval * 2); } EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); -void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n", + DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n", rd_interval); if (rd_interval == 0) - udelay(400); + rd_interval = 400; else - mdelay(rd_interval * 4); + rd_interval *= 4 * USEC_PER_MSEC; + + usleep_range(rd_interval, rd_interval * 2); } EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); @@ -220,7 +236,6 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, } ret = aux->transfer(aux, &msg); - if (ret >= 0) { native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK; if (native_reply == DP_AUX_NATIVE_REPLY_ACK) { @@ -337,134 +352,6 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); /** - * drm_dp_link_probe() - probe a DisplayPort link for capabilities - * @aux: DisplayPort AUX channel - * @link: pointer to structure in which to return link capabilities - * - * The structure filled in by this function can usually be passed directly - * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and - * configure the link based on the link's capabilities. - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 values[3]; - int err; - - memset(link, 0, sizeof(*link)); - - err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); - if (err < 0) - return err; - - link->revision = values[0]; - link->rate = drm_dp_bw_code_to_link_rate(values[1]); - link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; - - if (values[2] & DP_ENHANCED_FRAME_CAP) - link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_probe); - -/** - * drm_dp_link_power_up() - power up a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 value; - int err; - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (link->revision < 0x11) - return 0; - - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D0; - - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; - - /* - * According to the DP 1.1 specification, a "Sink Device must exit the - * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink - * Control Field" (register 0x600). - */ - usleep_range(1000, 2000); - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_power_up); - -/** - * drm_dp_link_power_down() - power down a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 value; - int err; - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (link->revision < 0x11) - return 0; - - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D3; - - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_power_down); - -/** - * drm_dp_link_configure() - configure a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 values[2]; - int err; - - values[0] = drm_dp_link_rate_to_bw_code(link->rate); - values[1] = link->num_lanes; - - if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) - values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - - err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); - if (err < 0) - return err; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_configure); - -/** * drm_dp_downstream_max_clock() - extract branch device max * pixel rate for legacy VGA * converter or max TMDS clock diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 6b14b63b8d62..b854a422a523 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3540,7 +3540,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, { struct drm_dp_mst_topology_state *topology_state; struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; - int prev_slots, req_slots, ret; + int prev_slots, req_slots; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) @@ -3587,8 +3587,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, } vcpi->vcpi = req_slots; - ret = req_slots; - return ret; + return req_slots; } EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); @@ -4184,9 +4183,6 @@ EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr) { - struct drm_device *dev = mgr->dev; - - WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); return to_dp_mst_topology_state(drm_atomic_get_private_obj_state(state, &mgr->base)); } EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 88a6548fdfbd..474ac04d5600 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2192,7 +2192,8 @@ static int standard_timing_level(struct edid *edid) return LEVEL_CVT; if (drm_gtf2_hbreak(edid)) return LEVEL_GTF2; - return LEVEL_GTF; + if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) + return LEVEL_GTF; } return LEVEL_DMT; } @@ -3208,18 +3209,10 @@ static bool drm_valid_cea_vic(u8 vic) return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); } -/** - * drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to - * the input VIC from the CEA mode list - * @video_code: ID given to each of the CEA modes - * - * Returns picture aspect ratio - */ -enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) +static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) { return edid_cea_modes[video_code].picture_aspect_ratio; } -EXPORT_SYMBOL(drm_get_cea_aspect_ratio); /* * Calculate the alternate clock for HDMI modes (those from the HDMI vendor @@ -5171,6 +5164,49 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, } EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); +static u8 drm_mode_hdmi_vic(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + bool has_hdmi_infoframe = connector ? + connector->display_info.has_hdmi_infoframe : false; + + if (!has_hdmi_infoframe) + return 0; + + /* No HDMI VIC when signalling 3D video format */ + if (mode->flags & DRM_MODE_FLAG_3D_MASK) + return 0; + + return drm_match_hdmi_mode(mode); +} + +static u8 drm_mode_cea_vic(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + u8 vic; + + /* + * HDMI spec says if a mode is found in HDMI 1.4b 4K modes + * we should send its VIC in vendor infoframes, else send the + * VIC in AVI infoframes. Lets check if this mode is present in + * HDMI 1.4b 4K modes + */ + if (drm_mode_hdmi_vic(connector, mode)) + return 0; + + vic = drm_match_cea_mode(mode); + + /* + * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but + * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we + * have to make sure we dont break HDMI 1.4 sinks. + */ + if (!is_hdmi2_sink(connector) && vic > 64) + return 0; + + return vic; +} + /** * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with * data from a DRM display mode @@ -5198,29 +5234,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, if (mode->flags & DRM_MODE_FLAG_DBLCLK) frame->pixel_repeat = 1; - frame->video_code = drm_match_cea_mode(mode); - - /* - * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but - * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we - * have to make sure we dont break HDMI 1.4 sinks. - */ - if (!is_hdmi2_sink(connector) && frame->video_code > 64) - frame->video_code = 0; - - /* - * HDMI spec says if a mode is found in HDMI 1.4b 4K modes - * we should send its VIC in vendor infoframes, else send the - * VIC in AVI infoframes. Lets check if this mode is present in - * HDMI 1.4b 4K modes - */ - if (frame->video_code) { - u8 vendor_if_vic = drm_match_hdmi_mode(mode); - bool is_s3d = mode->flags & DRM_MODE_FLAG_3D_MASK; - - if (drm_valid_hdmi_vic(vendor_if_vic) && !is_s3d) - frame->video_code = 0; - } + frame->video_code = drm_mode_cea_vic(connector, mode); frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; @@ -5385,6 +5399,23 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, } EXPORT_SYMBOL(drm_hdmi_avi_infoframe_quant_range); +/** + * drm_hdmi_avi_infoframe_bars() - fill the HDMI AVI infoframe + * bar information + * @frame: HDMI AVI infoframe + * @conn_state: connector state + */ +void +drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state) +{ + frame->right_bar = conn_state->tv.margins.right; + frame->left_bar = conn_state->tv.margins.left; + frame->top_bar = conn_state->tv.margins.top; + frame->bottom_bar = conn_state->tv.margins.bottom; +} +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_bars); + static enum hdmi_3d_structure s3d_structure_from_display_mode(const struct drm_display_mode *mode) { @@ -5437,8 +5468,6 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, bool has_hdmi_infoframe = connector ? connector->display_info.has_hdmi_infoframe : false; int err; - u32 s3d_flags; - u8 vic; if (!frame || !mode) return -EINVAL; @@ -5446,8 +5475,9 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, if (!has_hdmi_infoframe) return -EINVAL; - vic = drm_match_hdmi_mode(mode); - s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; + err = hdmi_vendor_infoframe_init(frame); + if (err < 0) + return err; /* * Even if it's not absolutely necessary to send the infoframe @@ -5458,15 +5488,7 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, * mode if the source simply stops sending the infoframe when * it wants to switch from 3D to 2D. */ - - if (vic && s3d_flags) - return -EINVAL; - - err = hdmi_vendor_infoframe_init(frame); - if (err < 0) - return err; - - frame->vic = vic; + frame->vic = drm_mode_hdmi_vic(connector, mode); frame->s3d_struct = s3d_structure_from_display_mode(mode); return 0; diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 6854f5867d51..56f42e0f2584 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1099,22 +1099,31 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, struct vm_area_struct *vma) { struct drm_device *dev = obj->dev; + int ret; /* Check for valid size. */ if (obj_size < vma->vm_end - vma->vm_start) return -EINVAL; - if (obj->funcs && obj->funcs->vm_ops) - vma->vm_ops = obj->funcs->vm_ops; - else if (dev->driver->gem_vm_ops) - vma->vm_ops = dev->driver->gem_vm_ops; - else - return -EINVAL; + if (obj->funcs && obj->funcs->mmap) { + ret = obj->funcs->mmap(obj, vma); + if (ret) + return ret; + WARN_ON(!(vma->vm_flags & VM_DONTEXPAND)); + } else { + if (obj->funcs && obj->funcs->vm_ops) + vma->vm_ops = obj->funcs->vm_ops; + else if (dev->driver->gem_vm_ops) + vma->vm_ops = dev->driver->gem_vm_ops; + else + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + } - vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_private_data = obj; - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); /* Take a ref for this mapping of the object, so that the fault * handler can dereference the mmap offset's pointer to the object. diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index f5918707672f..3bc69b1ffa7d 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -32,7 +32,7 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { .get_sg_table = drm_gem_shmem_get_sg_table, .vmap = drm_gem_shmem_vmap, .vunmap = drm_gem_shmem_vunmap, - .vm_ops = &drm_gem_shmem_vm_ops, + .mmap = drm_gem_shmem_mmap, }; /** @@ -505,39 +505,30 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma) drm_gem_vm_close(vma); } -const struct vm_operations_struct drm_gem_shmem_vm_ops = { +static const struct vm_operations_struct drm_gem_shmem_vm_ops = { .fault = drm_gem_shmem_fault, .open = drm_gem_shmem_vm_open, .close = drm_gem_shmem_vm_close, }; -EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops); /** * drm_gem_shmem_mmap - Memory-map a shmem GEM object - * @filp: File object + * @obj: gem object * @vma: VMA for the area to be mapped * * This function implements an augmented version of the GEM DRM file mmap * operation for shmem objects. Drivers which employ the shmem helpers should - * use this function as their &file_operations.mmap handler in the DRM device file's - * file_operations structure. - * - * Instead of directly referencing this function, drivers should use the - * DEFINE_DRM_GEM_SHMEM_FOPS() macro. + * use this function as their &drm_gem_object_funcs.mmap handler. * * Returns: * 0 on success or a negative error code on failure. */ -int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma) +int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { struct drm_gem_shmem_object *shmem; int ret; - ret = drm_gem_mmap(filp, vma); - if (ret) - return ret; - - shmem = to_drm_gem_shmem_obj(vma->vm_private_data); + shmem = to_drm_gem_shmem_obj(obj); ret = drm_gem_shmem_get_pages(shmem); if (ret) { @@ -545,9 +536,10 @@ int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } - /* VM_PFNMAP was set by drm_gem_mmap() */ - vma->vm_flags &= ~VM_PFNMAP; - vma->vm_flags |= VM_MIXEDMAP; + vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND; + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + vma->vm_ops = &drm_gem_shmem_vm_ops; /* Remove the fake offset */ vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node); diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c index a534104d8bee..7412bfc5c05a 100644 --- a/drivers/gpu/drm/drm_gem_ttm_helper.c +++ b/drivers/gpu/drm/drm_gem_ttm_helper.c @@ -52,5 +52,22 @@ void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent, } EXPORT_SYMBOL(drm_gem_ttm_print_info); +/** + * drm_gem_ttm_mmap() - mmap &ttm_buffer_object + * @gem: GEM object. + * @vma: vm area. + * + * This function can be used as &drm_gem_object_funcs.mmap + * callback. + */ +int drm_gem_ttm_mmap(struct drm_gem_object *gem, + struct vm_area_struct *vma) +{ + struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); + + return ttm_bo_mmap_obj(vma, bo); +} +EXPORT_SYMBOL(drm_gem_ttm_mmap); + MODULE_DESCRIPTION("DRM gem ttm helpers"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index dc7942981f4a..b86fe0fa9d05 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -552,13 +552,6 @@ static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo, *pl = gbo->placement; } -static int drm_gem_vram_bo_driver_verify_access(struct drm_gem_vram_object *gbo, - struct file *filp) -{ - return drm_vma_node_verify_access(&gbo->bo.base.vma_node, - filp->private_data); -} - static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo, bool evict, struct ttm_mem_reg *new_mem) @@ -737,6 +730,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs = { .unpin = drm_gem_vram_object_unpin, .vmap = drm_gem_vram_object_vmap, .vunmap = drm_gem_vram_object_vunmap, + .mmap = drm_gem_ttm_mmap, .print_info = drm_gem_ttm_print_info, }; @@ -822,20 +816,6 @@ static void bo_driver_evict_flags(struct ttm_buffer_object *bo, drm_gem_vram_bo_driver_evict_flags(gbo, placement); } -static int bo_driver_verify_access(struct ttm_buffer_object *bo, - struct file *filp) -{ - struct drm_gem_vram_object *gbo; - - /* TTM may pass BOs that are not GEM VRAM BOs. */ - if (!drm_is_gem_vram(bo)) - return -EINVAL; - - gbo = drm_gem_vram_of_bo(bo); - - return drm_gem_vram_bo_driver_verify_access(gbo, filp); -} - static void bo_driver_move_notify(struct ttm_buffer_object *bo, bool evict, struct ttm_mem_reg *new_mem) @@ -892,7 +872,6 @@ static struct ttm_bo_driver bo_driver = { .init_mem_type = bo_driver_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = bo_driver_evict_flags, - .verify_access = bo_driver_verify_access, .move_notify = bo_driver_move_notify, .io_mem_reserve = bo_driver_io_mem_reserve, .io_mem_free = bo_driver_io_mem_free, @@ -971,12 +950,6 @@ static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm) ttm_bo_device_release(&vmm->bdev); } -static int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma, - struct drm_vram_mm *vmm) -{ - return ttm_bo_mmap(filp, vma, &vmm->bdev); -} - /* * Helpers for integration with struct drm_device */ @@ -1032,30 +1005,3 @@ void drm_vram_helper_release_mm(struct drm_device *dev) dev->vram_mm = NULL; } EXPORT_SYMBOL(drm_vram_helper_release_mm); - -/* - * Helpers for &struct file_operations - */ - -/** - * drm_vram_mm_file_operations_mmap() - \ - Implements &struct file_operations.mmap() - * @filp: the mapping's file structure - * @vma: the mapping's memory area - * - * Returns: - * 0 on success, or - * a negative error code otherwise. - */ -int drm_vram_mm_file_operations_mmap( - struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->minor->dev; - - if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) - return -EINVAL; - - return drm_vram_mm_mmap(filp, vma, dev->vram_mm); -} -EXPORT_SYMBOL(drm_vram_mm_file_operations_mmap); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index ccfb5b33c5e3..e34058c721be 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -1021,7 +1021,7 @@ static int mipi_dbi_typec3_command_read(struct mipi_dbi *dbi, u8 *cmd, unsigned int i; for (i = 0; i < len; i++) - data[i] = (buf[i] << 1) | !!(buf[i + 1] & BIT(7)); + data[i] = (buf[i] << 1) | (buf[i + 1] >> 7); } MIPI_DBI_DEBUG_COMMAND(*cmd, data, len); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 7bc03c3c154f..3b570a404933 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -428,8 +428,6 @@ EXPORT_SYMBOL(drm_mode_config_init); * Note that since this /should/ happen single-threaded at driver/device * teardown time, no locking is required. It's the driver's job to ensure that * this guarantee actually holds true. - * - * FIXME: cleanup any dangling user buffer objects too */ void drm_mode_config_cleanup(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 0a2316e0e812..0814211b0f3f 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -713,6 +713,15 @@ int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) struct file *fil; int ret; + if (obj->funcs && obj->funcs->mmap) { + ret = obj->funcs->mmap(obj, vma); + if (ret) + return ret; + vma->vm_private_data = obj; + drm_gem_object_get(obj); + return 0; + } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); fil = kzalloc(sizeof(*fil), GFP_KERNEL); if (!priv || !fil) { diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 9ec334663c2d..669c93fe2500 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -1280,7 +1280,7 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->pad != 0) + if (args->flags != 0) return -EINVAL; if (args->count_handles == 0) @@ -1351,7 +1351,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->pad != 0) + if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) return -EINVAL; if (args->count_handles == 0) @@ -1372,25 +1372,32 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, fence = drm_syncobj_fence_get(syncobjs[i]); chain = to_dma_fence_chain(fence); if (chain) { - struct dma_fence *iter, *last_signaled = NULL; - - dma_fence_chain_for_each(iter, fence) { - if (iter->context != fence->context) { - dma_fence_put(iter); - /* It is most likely that timeline has - * unorder points. */ - break; + struct dma_fence *iter, *last_signaled = + dma_fence_get(fence); + + if (args->flags & + DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) { + point = fence->seqno; + } else { + dma_fence_chain_for_each(iter, fence) { + if (iter->context != fence->context) { + dma_fence_put(iter); + /* It is most likely that timeline has + * unorder points. */ + break; + } + dma_fence_put(last_signaled); + last_signaled = dma_fence_get(iter); } - dma_fence_put(last_signaled); - last_signaled = dma_fence_get(iter); + point = dma_fence_is_signaled(last_signaled) ? + last_signaled->seqno : + to_dma_fence_chain(last_signaled)->prev_seqno; } - point = dma_fence_is_signaled(last_signaled) ? - last_signaled->seqno : - to_dma_fence_chain(last_signaled)->prev_seqno; dma_fence_put(last_signaled); } else { point = 0; } + dma_fence_put(fence); ret = copy_to_user(&points[i], &point, sizeof(uint64_t)); ret = ret ? -EFAULT : 0; if (ret) diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 4f7962b6427b..1659b13b178c 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -1610,7 +1610,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, unsigned int flags, pipe, high_pipe; if (!dev->irq_enabled) - return -EINVAL; + return -EOPNOTSUPP; if (vblwait->request.type & _DRM_VBLANK_SIGNAL) return -EINVAL; @@ -1876,7 +1876,7 @@ int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, return -EOPNOTSUPP; if (!dev->irq_enabled) - return -EINVAL; + return -EOPNOTSUPP; crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id); if (!crtc) @@ -1934,7 +1934,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, return -EOPNOTSUPP; if (!dev->irq_enabled) - return -EINVAL; + return -EOPNOTSUPP; crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id); if (!crtc) diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index f56852a503e8..8b784947ed3b 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -405,6 +405,8 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct gma_clock_t clock; + memset(&clock, 0, sizeof(clock)); + switch (refclk) { case 27000: if (target < 200000) { diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index 167c10767dd4..900e5499249d 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -129,6 +129,7 @@ static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit, s32 freq_error, min_error = 100000; memset(best_clock, 0, sizeof(*best_clock)); + memset(&clock, 0, sizeof(clock)); for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { for (clock.n = limit->n.min; clock.n <= limit->n.max; @@ -185,6 +186,7 @@ static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, int err = target; memset(best_clock, 0, sizeof(*best_clock)); + memset(&clock, 0, sizeof(clock)); for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 4f52c83b9b4c..2fd4ca91a62d 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -26,10 +26,7 @@ #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" -static const struct file_operations hibmc_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(hibmc_fops); static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) { diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 6c218bace2ce..a63790d32d75 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -806,8 +806,8 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) tda998x_edid_delay_start(priv); } else { schedule_work(&priv->detect_work); - cec_notifier_set_phys_addr(priv->cec_notify, - CEC_PHYS_ADDR_INVALID); + cec_notifier_phys_addr_invalidate( + priv->cec_notify); } handled = true; @@ -1791,8 +1791,7 @@ static void tda998x_destroy(struct device *dev) i2c_unregister_device(priv->cec); - if (priv->cec_notify) - cec_notifier_put(priv->cec_notify); + cec_notifier_conn_unregister(priv->cec_notify); } static int tda998x_create(struct device *dev) @@ -1917,7 +1916,7 @@ static int tda998x_create(struct device *dev) cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD); } - priv->cec_notify = cec_notifier_get(dev); + priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL); if (!priv->cec_notify) { ret = -ENOMEM; goto fail; diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig index bb4ddc6bb0a6..571dc369a7e9 100644 --- a/drivers/gpu/drm/lima/Kconfig +++ b/drivers/gpu/drm/lima/Kconfig @@ -9,5 +9,6 @@ config DRM_LIMA depends on COMMON_CLK depends on OF select DRM_SCHED + select DRM_GEM_SHMEM_HELPER help DRM driver for ARM Mali 400/450 GPUs. diff --git a/drivers/gpu/drm/lima/Makefile b/drivers/gpu/drm/lima/Makefile index 38cc70281ba5..a85444b0a1d4 100644 --- a/drivers/gpu/drm/lima/Makefile +++ b/drivers/gpu/drm/lima/Makefile @@ -13,9 +13,7 @@ lima-y := \ lima_vm.o \ lima_sched.o \ lima_ctx.o \ - lima_gem_prime.o \ lima_dlbu.o \ - lima_bcast.o \ - lima_object.o + lima_bcast.o obj-$(CONFIG_DRM_LIMA) += lima.o diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c index e3e0ca11382e..19829b543024 100644 --- a/drivers/gpu/drm/lima/lima_device.c +++ b/drivers/gpu/drm/lima/lima_device.c @@ -314,7 +314,7 @@ int lima_device_init(struct lima_device *ldev) ldev->va_end = LIMA_VA_RESERVE_START; ldev->dlbu_cpu = dma_alloc_wc( ldev->dev, LIMA_PAGE_SIZE, - &ldev->dlbu_dma, GFP_KERNEL); + &ldev->dlbu_dma, GFP_KERNEL | __GFP_NOWARN); if (!ldev->dlbu_cpu) { err = -ENOMEM; goto err_out2; diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c index 75ec703d22e0..124efe4fa97b 100644 --- a/drivers/gpu/drm/lima/lima_drv.c +++ b/drivers/gpu/drm/lima/lima_drv.c @@ -12,7 +12,6 @@ #include "lima_drv.h" #include "lima_gem.h" -#include "lima_gem_prime.h" #include "lima_vm.h" int lima_sched_timeout_ms; @@ -240,16 +239,7 @@ static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { DRM_IOCTL_DEF_DRV(LIMA_CTX_FREE, lima_ioctl_ctx_free, DRM_RENDER_ALLOW), }; -static const struct file_operations lima_drm_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .mmap = lima_gem_mmap, -}; +DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops); static struct drm_driver lima_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, @@ -258,10 +248,6 @@ static struct drm_driver lima_drm_driver = { .ioctls = lima_drm_driver_ioctls, .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls), .fops = &lima_drm_driver_fops, - .gem_free_object_unlocked = lima_gem_free_object, - .gem_open_object = lima_gem_object_open, - .gem_close_object = lima_gem_object_close, - .gem_vm_ops = &lima_gem_vm_ops, .name = "lima", .desc = "lima DRM", .date = "20190217", @@ -269,11 +255,11 @@ static struct drm_driver lima_drm_driver = { .minor = 0, .patchlevel = 0, + .gem_create_object = lima_gem_create_object, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import_sg_table = lima_gem_prime_import_sg_table, + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .gem_prime_get_sg_table = lima_gem_prime_get_sg_table, - .gem_prime_mmap = lima_gem_prime_mmap, + .gem_prime_mmap = drm_gem_prime_mmap, }; static int lima_pdev_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index 4da21353c3a2..d0059d8c97d8 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c @@ -3,7 +3,7 @@ #include <linux/mm.h> #include <linux/sync_file.h> -#include <linux/pfn_t.h> +#include <linux/pagemap.h> #include <drm/drm_file.h> #include <drm/drm_syncobj.h> @@ -13,40 +13,55 @@ #include "lima_drv.h" #include "lima_gem.h" -#include "lima_gem_prime.h" #include "lima_vm.h" -#include "lima_object.h" int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, u32 size, u32 flags, u32 *handle) { int err; - struct lima_bo *bo; - struct lima_device *ldev = to_lima_dev(dev); + gfp_t mask; + struct drm_gem_shmem_object *shmem; + struct drm_gem_object *obj; + struct sg_table *sgt; + + shmem = drm_gem_shmem_create(dev, size); + if (IS_ERR(shmem)) + return PTR_ERR(shmem); + + obj = &shmem->base; - bo = lima_bo_create(ldev, size, flags, NULL); - if (IS_ERR(bo)) - return PTR_ERR(bo); + /* Mali Utgard GPU can only support 32bit address space */ + mask = mapping_gfp_mask(obj->filp->f_mapping); + mask &= ~__GFP_HIGHMEM; + mask |= __GFP_DMA32; + mapping_set_gfp_mask(obj->filp->f_mapping, mask); - err = drm_gem_handle_create(file, &bo->gem, handle); + sgt = drm_gem_shmem_get_pages_sgt(obj); + if (IS_ERR(sgt)) { + err = PTR_ERR(sgt); + goto out; + } + + err = drm_gem_handle_create(file, obj, handle); +out: /* drop reference from allocate - handle holds it now */ - drm_gem_object_put_unlocked(&bo->gem); + drm_gem_object_put_unlocked(obj); return err; } -void lima_gem_free_object(struct drm_gem_object *obj) +static void lima_gem_free_object(struct drm_gem_object *obj) { struct lima_bo *bo = to_lima_bo(obj); if (!list_empty(&bo->va)) dev_err(obj->dev->dev, "lima gem free bo still has va\n"); - lima_bo_destroy(bo); + drm_gem_shmem_free_object(obj); } -int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file) +static int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file) { struct lima_bo *bo = to_lima_bo(obj); struct lima_drm_priv *priv = to_lima_drm_priv(file); @@ -55,7 +70,7 @@ int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file) return lima_vm_bo_add(vm, bo, true); } -void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file) +static void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file) { struct lima_bo *bo = to_lima_bo(obj); struct lima_drm_priv *priv = to_lima_drm_priv(file); @@ -64,13 +79,41 @@ void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file) lima_vm_bo_del(vm, bo); } +static const struct drm_gem_object_funcs lima_gem_funcs = { + .free = lima_gem_free_object, + .open = lima_gem_object_open, + .close = lima_gem_object_close, + .print_info = drm_gem_shmem_print_info, + .pin = drm_gem_shmem_pin, + .unpin = drm_gem_shmem_unpin, + .get_sg_table = drm_gem_shmem_get_sg_table, + .vmap = drm_gem_shmem_vmap, + .vunmap = drm_gem_shmem_vunmap, + .mmap = drm_gem_shmem_mmap, +}; + +struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size) +{ + struct lima_bo *bo; + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + if (!bo) + return NULL; + + mutex_init(&bo->lock); + INIT_LIST_HEAD(&bo->va); + + bo->base.base.funcs = &lima_gem_funcs; + + return &bo->base.base; +} + int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset) { struct drm_gem_object *obj; struct lima_bo *bo; struct lima_drm_priv *priv = to_lima_drm_priv(file); struct lima_vm *vm = priv->vm; - int err; obj = drm_gem_object_lookup(file, handle); if (!obj) @@ -80,53 +123,9 @@ int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset) *va = lima_vm_get_va(vm, bo); - err = drm_gem_create_mmap_offset(obj); - if (!err) - *offset = drm_vma_node_offset_addr(&obj->vma_node); + *offset = drm_vma_node_offset_addr(&obj->vma_node); drm_gem_object_put_unlocked(obj); - return err; -} - -static vm_fault_t lima_gem_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_gem_object *obj = vma->vm_private_data; - struct lima_bo *bo = to_lima_bo(obj); - pfn_t pfn; - pgoff_t pgoff; - - /* We don't use vmf->pgoff since that has the fake offset: */ - pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; - pfn = __pfn_to_pfn_t(page_to_pfn(bo->pages[pgoff]), PFN_DEV); - - return vmf_insert_mixed(vma, vmf->address, pfn); -} - -const struct vm_operations_struct lima_gem_vm_ops = { - .fault = lima_gem_fault, - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, -}; - -void lima_set_vma_flags(struct vm_area_struct *vma) -{ - pgprot_t prot = vm_get_page_prot(vma->vm_flags); - - vma->vm_flags |= VM_MIXEDMAP; - vma->vm_flags &= ~VM_PFNMAP; - vma->vm_page_prot = pgprot_writecombine(prot); -} - -int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int ret; - - ret = drm_gem_mmap(filp, vma); - if (ret) - return ret; - - lima_set_vma_flags(vma); return 0; } @@ -136,7 +135,7 @@ static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo, int err = 0; if (!write) { - err = dma_resv_reserve_shared(bo->gem.resv, 1); + err = dma_resv_reserve_shared(lima_bo_resv(bo), 1); if (err) return err; } @@ -145,62 +144,7 @@ static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo, if (explicit) return 0; - return drm_gem_fence_array_add_implicit(&task->deps, &bo->gem, write); -} - -static int lima_gem_lock_bos(struct lima_bo **bos, u32 nr_bos, - struct ww_acquire_ctx *ctx) -{ - int i, ret = 0, contended, slow_locked = -1; - - ww_acquire_init(ctx, &reservation_ww_class); - -retry: - for (i = 0; i < nr_bos; i++) { - if (i == slow_locked) { - slow_locked = -1; - continue; - } - - ret = ww_mutex_lock_interruptible(&bos[i]->gem.resv->lock, ctx); - if (ret < 0) { - contended = i; - goto err; - } - } - - ww_acquire_done(ctx); - return 0; - -err: - for (i--; i >= 0; i--) - ww_mutex_unlock(&bos[i]->gem.resv->lock); - - if (slow_locked >= 0) - ww_mutex_unlock(&bos[slow_locked]->gem.resv->lock); - - if (ret == -EDEADLK) { - /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible( - &bos[contended]->gem.resv->lock, ctx); - if (!ret) { - slow_locked = contended; - goto retry; - } - } - ww_acquire_fini(ctx); - - return ret; -} - -static void lima_gem_unlock_bos(struct lima_bo **bos, u32 nr_bos, - struct ww_acquire_ctx *ctx) -{ - int i; - - for (i = 0; i < nr_bos; i++) - ww_mutex_unlock(&bos[i]->gem.resv->lock); - ww_acquire_fini(ctx); + return drm_gem_fence_array_add_implicit(&task->deps, &bo->base.base, write); } static int lima_gem_add_deps(struct drm_file *file, struct lima_submit *submit) @@ -268,7 +212,8 @@ int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) bos[i] = bo; } - err = lima_gem_lock_bos(bos, submit->nr_bos, &ctx); + err = drm_gem_lock_reservations((struct drm_gem_object **)bos, + submit->nr_bos, &ctx); if (err) goto err_out0; @@ -296,15 +241,16 @@ int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) for (i = 0; i < submit->nr_bos; i++) { if (submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE) - dma_resv_add_excl_fence(bos[i]->gem.resv, fence); + dma_resv_add_excl_fence(lima_bo_resv(bos[i]), fence); else - dma_resv_add_shared_fence(bos[i]->gem.resv, fence); + dma_resv_add_shared_fence(lima_bo_resv(bos[i]), fence); } - lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); + drm_gem_unlock_reservations((struct drm_gem_object **)bos, + submit->nr_bos, &ctx); for (i = 0; i < submit->nr_bos; i++) - drm_gem_object_put_unlocked(&bos[i]->gem); + drm_gem_object_put_unlocked(&bos[i]->base.base); if (out_sync) { drm_syncobj_replace_fence(out_sync, fence); @@ -318,13 +264,14 @@ int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) err_out2: lima_sched_task_fini(submit->task); err_out1: - lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); + drm_gem_unlock_reservations((struct drm_gem_object **)bos, + submit->nr_bos, &ctx); err_out0: for (i = 0; i < submit->nr_bos; i++) { if (!bos[i]) break; lima_vm_bo_del(vm, bos[i]); - drm_gem_object_put_unlocked(&bos[i]->gem); + drm_gem_object_put_unlocked(&bos[i]->base.base); } if (out_sync) drm_syncobj_put(out_sync); diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h index 556111a01135..1800feb3e47f 100644 --- a/drivers/gpu/drm/lima/lima_gem.h +++ b/drivers/gpu/drm/lima/lima_gem.h @@ -4,19 +4,37 @@ #ifndef __LIMA_GEM_H__ #define __LIMA_GEM_H__ -struct lima_bo; +#include <drm/drm_gem_shmem_helper.h> + struct lima_submit; -extern const struct vm_operations_struct lima_gem_vm_ops; +struct lima_bo { + struct drm_gem_shmem_object base; + + struct mutex lock; + struct list_head va; +}; + +static inline struct lima_bo * +to_lima_bo(struct drm_gem_object *obj) +{ + return container_of(to_drm_gem_shmem_obj(obj), struct lima_bo, base); +} + +static inline size_t lima_bo_size(struct lima_bo *bo) +{ + return bo->base.base.size; +} + +static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo) +{ + return bo->base.base.resv; +} -struct lima_bo *lima_gem_create_bo(struct drm_device *dev, u32 size, u32 flags); +struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size); int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, u32 size, u32 flags, u32 *handle); -void lima_gem_free_object(struct drm_gem_object *obj); -int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file); -void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file); int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset); -int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma); int lima_gem_submit(struct drm_file *file, struct lima_submit *submit); int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns); diff --git a/drivers/gpu/drm/lima/lima_gem_prime.c b/drivers/gpu/drm/lima/lima_gem_prime.c deleted file mode 100644 index e3eb251e0a12..000000000000 --- a/drivers/gpu/drm/lima/lima_gem_prime.c +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */ - -#include <linux/dma-buf.h> -#include <drm/drm_prime.h> -#include <drm/drm_drv.h> -#include <drm/drm_file.h> - -#include "lima_device.h" -#include "lima_object.h" -#include "lima_gem.h" -#include "lima_gem_prime.h" - -struct drm_gem_object *lima_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *sgt) -{ - struct lima_device *ldev = to_lima_dev(dev); - struct lima_bo *bo; - - bo = lima_bo_create(ldev, attach->dmabuf->size, 0, sgt); - if (IS_ERR(bo)) - return ERR_CAST(bo); - - return &bo->gem; -} - -struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - struct lima_bo *bo = to_lima_bo(obj); - int npages = obj->size >> PAGE_SHIFT; - - return drm_prime_pages_to_sg(bo->pages, npages); -} - -int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -{ - int ret; - - ret = drm_gem_mmap_obj(obj, obj->size, vma); - if (ret) - return ret; - - lima_set_vma_flags(vma); - return 0; -} diff --git a/drivers/gpu/drm/lima/lima_gem_prime.h b/drivers/gpu/drm/lima/lima_gem_prime.h deleted file mode 100644 index 34b4d35c21e3..000000000000 --- a/drivers/gpu/drm/lima/lima_gem_prime.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -/* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */ - -#ifndef __LIMA_GEM_PRIME_H__ -#define __LIMA_GEM_PRIME_H__ - -struct drm_gem_object *lima_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *sgt); -struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj); -int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); - -#endif diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c index 8e1651d6a61f..97ec09dee572 100644 --- a/drivers/gpu/drm/lima/lima_mmu.c +++ b/drivers/gpu/drm/lima/lima_mmu.c @@ -8,7 +8,6 @@ #include "lima_device.h" #include "lima_mmu.h" #include "lima_vm.h" -#include "lima_object.h" #include "lima_regs.h" #define mmu_write(reg, data) writel(data, ip->iomem + reg) diff --git a/drivers/gpu/drm/lima/lima_object.c b/drivers/gpu/drm/lima/lima_object.c deleted file mode 100644 index 87123b1d083c..000000000000 --- a/drivers/gpu/drm/lima/lima_object.c +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */ - -#include <drm/drm_prime.h> -#include <linux/pagemap.h> -#include <linux/dma-mapping.h> - -#include "lima_object.h" - -void lima_bo_destroy(struct lima_bo *bo) -{ - if (bo->sgt) { - kfree(bo->pages); - drm_prime_gem_destroy(&bo->gem, bo->sgt); - } else { - if (bo->pages_dma_addr) { - int i, npages = bo->gem.size >> PAGE_SHIFT; - - for (i = 0; i < npages; i++) { - if (bo->pages_dma_addr[i]) - dma_unmap_page(bo->gem.dev->dev, - bo->pages_dma_addr[i], - PAGE_SIZE, DMA_BIDIRECTIONAL); - } - } - - if (bo->pages) - drm_gem_put_pages(&bo->gem, bo->pages, true, true); - } - - kfree(bo->pages_dma_addr); - drm_gem_object_release(&bo->gem); - kfree(bo); -} - -static struct lima_bo *lima_bo_create_struct(struct lima_device *dev, u32 size, u32 flags) -{ - struct lima_bo *bo; - int err; - - size = PAGE_ALIGN(size); - - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - if (!bo) - return ERR_PTR(-ENOMEM); - - mutex_init(&bo->lock); - INIT_LIST_HEAD(&bo->va); - - err = drm_gem_object_init(dev->ddev, &bo->gem, size); - if (err) { - kfree(bo); - return ERR_PTR(err); - } - - return bo; -} - -struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, - u32 flags, struct sg_table *sgt) -{ - int i, err; - size_t npages; - struct lima_bo *bo, *ret; - - bo = lima_bo_create_struct(dev, size, flags); - if (IS_ERR(bo)) - return bo; - - npages = bo->gem.size >> PAGE_SHIFT; - - bo->pages_dma_addr = kcalloc(npages, sizeof(dma_addr_t), GFP_KERNEL); - if (!bo->pages_dma_addr) { - ret = ERR_PTR(-ENOMEM); - goto err_out; - } - - if (sgt) { - bo->sgt = sgt; - - bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL); - if (!bo->pages) { - ret = ERR_PTR(-ENOMEM); - goto err_out; - } - - err = drm_prime_sg_to_page_addr_arrays( - sgt, bo->pages, bo->pages_dma_addr, npages); - if (err) { - ret = ERR_PTR(err); - goto err_out; - } - } else { - mapping_set_gfp_mask(bo->gem.filp->f_mapping, GFP_DMA32); - bo->pages = drm_gem_get_pages(&bo->gem); - if (IS_ERR(bo->pages)) { - ret = ERR_CAST(bo->pages); - bo->pages = NULL; - goto err_out; - } - - for (i = 0; i < npages; i++) { - dma_addr_t addr = dma_map_page(dev->dev, bo->pages[i], 0, - PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev->dev, addr)) { - ret = ERR_PTR(-EFAULT); - goto err_out; - } - bo->pages_dma_addr[i] = addr; - } - - } - - return bo; - -err_out: - lima_bo_destroy(bo); - return ret; -} diff --git a/drivers/gpu/drm/lima/lima_object.h b/drivers/gpu/drm/lima/lima_object.h deleted file mode 100644 index 31ca2d8dc0a1..000000000000 --- a/drivers/gpu/drm/lima/lima_object.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -/* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */ - -#ifndef __LIMA_OBJECT_H__ -#define __LIMA_OBJECT_H__ - -#include <drm/drm_gem.h> - -#include "lima_device.h" - -struct lima_bo { - struct drm_gem_object gem; - - struct page **pages; - dma_addr_t *pages_dma_addr; - struct sg_table *sgt; - void *vaddr; - - struct mutex lock; - struct list_head va; -}; - -static inline struct lima_bo * -to_lima_bo(struct drm_gem_object *obj) -{ - return container_of(obj, struct lima_bo, gem); -} - -struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, - u32 flags, struct sg_table *sgt); -void lima_bo_destroy(struct lima_bo *bo); -void *lima_bo_vmap(struct lima_bo *bo); -void lima_bo_vunmap(struct lima_bo *bo); - -#endif diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index 4127cacac454..f522c5f99729 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -10,7 +10,7 @@ #include "lima_vm.h" #include "lima_mmu.h" #include "lima_l2_cache.h" -#include "lima_object.h" +#include "lima_gem.h" struct lima_fence { struct dma_fence base; @@ -117,7 +117,7 @@ int lima_sched_task_init(struct lima_sched_task *task, return -ENOMEM; for (i = 0; i < num_bos; i++) - drm_gem_object_get(&bos[i]->gem); + drm_gem_object_get(&bos[i]->base.base); err = drm_sched_job_init(&task->base, &context->base, vm); if (err) { @@ -148,7 +148,7 @@ void lima_sched_task_fini(struct lima_sched_task *task) if (task->bos) { for (i = 0; i < task->num_bos; i++) - drm_gem_object_put_unlocked(&task->bos[i]->gem); + drm_gem_object_put_unlocked(&task->bos[i]->base.base); kfree(task->bos); } diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c index 19e88ca16527..840e2350d872 100644 --- a/drivers/gpu/drm/lima/lima_vm.c +++ b/drivers/gpu/drm/lima/lima_vm.c @@ -6,7 +6,7 @@ #include "lima_device.h" #include "lima_vm.h" -#include "lima_object.h" +#include "lima_gem.h" #include "lima_regs.h" struct lima_bo_va { @@ -32,7 +32,7 @@ struct lima_bo_va { #define LIMA_BTE(va) ((va & LIMA_VM_BT_MASK) >> LIMA_VM_BT_SHIFT) -static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end) +static void lima_vm_unmap_range(struct lima_vm *vm, u32 start, u32 end) { u32 addr; @@ -44,41 +44,32 @@ static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end) } } -static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma, - u32 start, u32 end) +static int lima_vm_map_page(struct lima_vm *vm, dma_addr_t pa, u32 va) { - u64 addr; - int i = 0; - - for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { - u32 pbe = LIMA_PBE(addr); - u32 bte = LIMA_BTE(addr); - - if (!vm->bts[pbe].cpu) { - dma_addr_t pts; - u32 *pd; - int j; - - vm->bts[pbe].cpu = dma_alloc_wc( - vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, - &vm->bts[pbe].dma, GFP_KERNEL | __GFP_ZERO); - if (!vm->bts[pbe].cpu) { - if (addr != start) - lima_vm_unmap_page_table(vm, start, addr - 1); - return -ENOMEM; - } - - pts = vm->bts[pbe].dma; - pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT); - for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { - pd[j] = pts | LIMA_VM_FLAG_PRESENT; - pts += LIMA_PAGE_SIZE; - } + u32 pbe = LIMA_PBE(va); + u32 bte = LIMA_BTE(va); + + if (!vm->bts[pbe].cpu) { + dma_addr_t pts; + u32 *pd; + int j; + + vm->bts[pbe].cpu = dma_alloc_wc( + vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, + &vm->bts[pbe].dma, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!vm->bts[pbe].cpu) + return -ENOMEM; + + pts = vm->bts[pbe].dma; + pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT); + for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { + pd[j] = pts | LIMA_VM_FLAG_PRESENT; + pts += LIMA_PAGE_SIZE; } - - vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE; } + vm->bts[pbe].cpu[bte] = pa | LIMA_VM_FLAGS_CACHE; + return 0; } @@ -100,7 +91,8 @@ lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo) int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) { struct lima_bo_va *bo_va; - int err; + struct sg_dma_page_iter sg_iter; + int offset = 0, err; mutex_lock(&bo->lock); @@ -128,14 +120,18 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) mutex_lock(&vm->lock); - err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size); + err = drm_mm_insert_node(&vm->mm, &bo_va->node, lima_bo_size(bo)); if (err) goto err_out1; - err = lima_vm_map_page_table(vm, bo->pages_dma_addr, bo_va->node.start, - bo_va->node.start + bo_va->node.size - 1); - if (err) - goto err_out2; + for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter, bo->base.sgt->nents, 0) { + err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter), + bo_va->node.start + offset); + if (err) + goto err_out2; + + offset += PAGE_SIZE; + } mutex_unlock(&vm->lock); @@ -145,6 +141,8 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) return 0; err_out2: + if (offset) + lima_vm_unmap_range(vm, bo_va->node.start, bo_va->node.start + offset - 1); drm_mm_remove_node(&bo_va->node); err_out1: mutex_unlock(&vm->lock); @@ -168,8 +166,8 @@ void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) mutex_lock(&vm->lock); - lima_vm_unmap_page_table(vm, bo_va->node.start, - bo_va->node.start + bo_va->node.size - 1); + lima_vm_unmap_range(vm, bo_va->node.start, + bo_va->node.start + bo_va->node.size - 1); drm_mm_remove_node(&bo_va->node); @@ -210,14 +208,13 @@ struct lima_vm *lima_vm_create(struct lima_device *dev) kref_init(&vm->refcount); vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma, - GFP_KERNEL | __GFP_ZERO); + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); if (!vm->pd.cpu) goto err_out0; if (dev->dlbu_cpu) { - int err = lima_vm_map_page_table( - vm, &dev->dlbu_dma, LIMA_VA_RESERVE_DLBU, - LIMA_VA_RESERVE_DLBU + LIMA_PAGE_SIZE - 1); + int err = lima_vm_map_page( + vm, dev->dlbu_dma, LIMA_VA_RESERVE_DLBU); if (err) goto err_out1; } diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 022286dc6ab2..3bb7ffe5fc39 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -977,6 +977,11 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; + if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || + dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || + dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) + dw_plat_data->use_drm_infoframe = true; + platform_set_drvdata(pdev, meson_dw_hdmi); meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 4f9df3b93598..397f8b0a9af8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -58,10 +58,7 @@ static void mga_pci_remove(struct pci_dev *pdev) drm_put_dev(dev); } -static const struct file_operations mgag200_driver_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(mgag200_driver_fops); static struct drm_driver driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET, diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 7f3dd3ffe2c9..0d9657cc70db 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -89,7 +89,6 @@ struct edp_ctrl { /* edid raw data */ struct edid *edid; - struct drm_dp_link dp_link; struct drm_dp_aux *drm_aux; /* dpcd raw data */ @@ -403,7 +402,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) u32 prate; u32 lrate; u32 bpp; - u8 max_lane = ctrl->dp_link.num_lanes; + u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); u8 lane; prate = ctrl->pixel_rate; @@ -413,7 +412,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) * By default, use the maximum link rate and minimum lane count, * so that we can do rate down shift during link training. */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; prate *= bpp; prate /= 8; /* in kByte */ @@ -439,7 +438,7 @@ static void edp_config_ctrl(struct edp_ctrl *ctrl) data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1); - if (ctrl->dp_link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING; depth = EDP_6BIT; @@ -701,7 +700,7 @@ static int edp_link_rate_down_shift(struct edp_ctrl *ctrl) rate = ctrl->link_rate; lane = ctrl->lane_cnt; - max_lane = ctrl->dp_link.num_lanes; + max_lane = drm_dp_max_lane_count(ctrl->dpcd); bpp = ctrl->color_depth * 3; prate = ctrl->pixel_rate; @@ -751,18 +750,22 @@ static int edp_clear_training_pattern(struct edp_ctrl *ctrl) static int edp_do_link_train(struct edp_ctrl *ctrl) { + u8 values[2]; int ret; - struct drm_dp_link dp_link; DBG(""); /* * Set the current link rate and lane cnt to panel. They may have been * adjusted and the values are different from them in DPCD CAP */ - dp_link.num_lanes = ctrl->lane_cnt; - dp_link.rate = drm_dp_bw_code_to_link_rate(ctrl->link_rate); - dp_link.capabilities = ctrl->dp_link.capabilities; - if (drm_dp_link_configure(ctrl->drm_aux, &dp_link) < 0) + values[0] = ctrl->lane_cnt; + values[1] = ctrl->link_rate; + + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, + sizeof(values)) < 0) return EDP_TRAIN_FAIL; ctrl->v_level = 0; /* start from default level */ @@ -952,6 +955,7 @@ static void edp_ctrl_on_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, on_work); + u8 value; int ret; mutex_lock(&ctrl->dev_mutex); @@ -965,9 +969,27 @@ static void edp_ctrl_on_worker(struct work_struct *work) edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); - ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link); - if (ret) - goto fail; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret < 0) + goto fail; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + if (ret < 0) + goto fail; + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + } ctrl->power_on = true; @@ -1011,7 +1033,19 @@ static void edp_ctrl_off_worker(struct work_struct *work) edp_state_ctrl(ctrl, 0); - drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link); + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + u8 value; + int ret; + + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret > 0) { + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D3; + + drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + } + } edp_ctrl_irq_enable(ctrl, 0); @@ -1225,14 +1259,8 @@ int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, edp_ctrl_irq_enable(ctrl, 1); } - ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link); - if (ret) { - pr_err("%s: read dpcd cap failed, %d\n", __func__, ret); - goto disable_ret; - } - /* Initialize link rate as panel max link rate */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); if (!ctrl->edid) { diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 12421567af89..b69ace8bf526 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c @@ -95,8 +95,11 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) reg = readl(mxsfb->base + LCDC_CTRL); - if (mxsfb->connector.display_info.num_bus_formats) - bus_format = mxsfb->connector.display_info.bus_formats[0]; + if (mxsfb->connector->display_info.num_bus_formats) + bus_format = mxsfb->connector->display_info.bus_formats[0]; + + DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", + bus_format); reg &= ~CTRL_BUS_WIDTH_MASK; switch (bus_format) { @@ -204,8 +207,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) { + struct drm_device *drm = mxsfb->pipe.crtc.dev; struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; - const u32 bus_flags = mxsfb->connector.display_info.bus_flags; + u32 bus_flags = mxsfb->connector->display_info.bus_flags; u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; int err; @@ -229,6 +233,16 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); + if (mxsfb->bridge && mxsfb->bridge->timings) + bus_flags = mxsfb->bridge->timings->input_bus_flags; + + DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", + m->crtc_clock, + (int)(clk_get_rate(mxsfb->clk) / 1000)); + DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", + bus_flags); + DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); + writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), mxsfb->base + mxsfb->devdata->transfer_count); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index e8506335cd15..497cf443a9af 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -101,9 +101,25 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) { + struct drm_connector *connector; struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); struct drm_device *drm = pipe->plane.dev; + if (!mxsfb->connector) { + list_for_each_entry(connector, + &drm->mode_config.connector_list, + head) + if (connector->encoder == &mxsfb->pipe.encoder) { + mxsfb->connector = connector; + break; + } + } + + if (!mxsfb->connector) { + dev_warn(drm->dev, "No connector attached, using default\n"); + mxsfb->connector = &mxsfb->panel_connector; + } + pm_runtime_get_sync(drm->dev); drm_panel_prepare(mxsfb->panel); mxsfb_crtc_enable(mxsfb); @@ -129,6 +145,9 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) drm_crtc_send_vblank_event(crtc, event); } spin_unlock_irq(&drm->event_lock); + + if (mxsfb->connector != &mxsfb->panel_connector) + mxsfb->connector = NULL; } static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, @@ -226,16 +245,33 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL, - &mxsfb->connector); + mxsfb->connector); if (ret < 0) { dev_err(drm->dev, "Cannot setup simple display pipe\n"); goto err_vblank; } - ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector); - if (ret) { - dev_err(drm->dev, "Cannot connect panel\n"); - goto err_vblank; + /* + * Attach panel only if there is one. + * If there is no panel attach, it must be a bridge. In this case, we + * need a reference to its connector for a proper initialization. + * We will do this check in pipe->enable(), since the connector won't + * be attached to an encoder until then. + */ + + if (mxsfb->panel) { + ret = drm_panel_attach(mxsfb->panel, mxsfb->connector); + if (ret) { + dev_err(drm->dev, "Cannot connect panel: %d\n", ret); + goto err_vblank; + } + } else if (mxsfb->bridge) { + ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe, + mxsfb->bridge); + if (ret) { + dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); + goto err_vblank; + } } drm->mode_config.min_width = MXSFB_MIN_XRES; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index d975300dca05..0b65b5194a9c 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -27,8 +27,10 @@ struct mxsfb_drm_private { struct clk *clk_disp_axi; struct drm_simple_display_pipe pipe; - struct drm_connector connector; + struct drm_connector panel_connector; + struct drm_connector *connector; struct drm_panel *panel; + struct drm_bridge *bridge; }; int mxsfb_setup_crtc(struct drm_device *dev); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index be36f4d6cc96..4eb94744c526 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -21,7 +21,8 @@ static struct mxsfb_drm_private * drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) { - return container_of(connector, struct mxsfb_drm_private, connector); + return container_of(connector, struct mxsfb_drm_private, + panel_connector); } static int mxsfb_panel_get_modes(struct drm_connector *connector) @@ -76,22 +77,23 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = { int mxsfb_create_output(struct drm_device *drm) { struct mxsfb_drm_private *mxsfb = drm->dev_private; - struct drm_panel *panel; int ret; - ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL); + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, + &mxsfb->panel, &mxsfb->bridge); if (ret) return ret; - mxsfb->connector.dpms = DRM_MODE_DPMS_OFF; - mxsfb->connector.polled = 0; - drm_connector_helper_add(&mxsfb->connector, - &mxsfb_panel_connector_helper_funcs); - ret = drm_connector_init(drm, &mxsfb->connector, - &mxsfb_panel_connector_funcs, - DRM_MODE_CONNECTOR_Unknown); - if (!ret) - mxsfb->panel = panel; + if (mxsfb->panel) { + mxsfb->connector = &mxsfb->panel_connector; + mxsfb->connector->dpms = DRM_MODE_DPMS_OFF; + mxsfb->connector->polled = 0; + drm_connector_helper_add(mxsfb->connector, + &mxsfb_panel_connector_helper_funcs); + ret = drm_connector_init(drm, mxsfb->connector, + &mxsfb_panel_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + } return ret; } diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index b30fcaa2d0f5..da16ea095f13 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -3548,7 +3548,7 @@ static int dsi_proto_config(struct dsi_data *dsi) static void dsi_proto_timings(struct dsi_data *dsi) { - unsigned int tlpx, tclk_zero, tclk_prepare, tclk_trail; + unsigned int tlpx, tclk_zero, tclk_prepare; unsigned int tclk_pre, tclk_post; unsigned int ths_prepare, ths_prepare_ths_zero, ths_zero; unsigned int ths_trail, ths_exit; @@ -3567,7 +3567,6 @@ static void dsi_proto_timings(struct dsi_data *dsi) r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tlpx = FLD_GET(r, 20, 16) * 2; - tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index c4ffe96e28bc..ea5d5c228534 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -676,7 +676,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config acore; - int err, n, cts, channel_count; + int n, cts, channel_count; unsigned int fs_nr; bool word_length_16b = false; @@ -738,7 +738,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, return -EINVAL; } - err = hdmi_compute_acr(pclk, fs_nr, &n, &cts); + hdmi_compute_acr(pclk, fs_nr, &n, &cts); /* Audio clock regeneration settings */ acore.n = n; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index 96f5cd17768c..ff4d35c8771f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -807,7 +807,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config core_cfg; - int err, n, cts, channel_count; + int n, cts, channel_count; unsigned int fs_nr; bool word_length_16b = false; @@ -850,7 +850,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, return -EINVAL; } - err = hdmi_compute_acr(pclk, fs_nr, &n, &cts); + hdmi_compute_acr(pclk, fs_nr, &n, &cts); core_cfg.n = n; core_cfg.cts = cts; diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h index 835e6654fa82..43c1d096b021 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h @@ -113,7 +113,7 @@ extern struct platform_driver omap_dmm_driver; /* GEM bo flags -> tiler fmt */ static inline enum tiler_fmt gem2fmt(u32 flags) { - switch (flags & OMAP_BO_TILED) { + switch (flags & OMAP_BO_TILED_MASK) { case OMAP_BO_TILED_8: return TILFMT_8BIT; case OMAP_BO_TILED_16: diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 1b8b5108caf8..9aeab81dfb90 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -95,7 +95,7 @@ static u32 get_linear_addr(struct drm_framebuffer *fb, bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) { - return omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED; + return omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED_MASK; } /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */ @@ -135,7 +135,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct drm_format_info *format = omap_fb->format; - struct plane *plane = &omap_fb->planes[0]; u32 x, y, orient = 0; info->fourcc = fb->format->format; @@ -154,7 +153,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, x = state->src_x >> 16; y = state->src_y >> 16; - if (omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED) { + if (omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED_MASK) { u32 w = state->src_w >> 16; u32 h = state->src_h >> 16; @@ -209,10 +208,8 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, info->screen_width /= format->cpp[0]; if (fb->format->format == DRM_FORMAT_NV12) { - plane = &omap_fb->planes[1]; - if (info->rotation_type == OMAP_DSS_ROT_TILER) { - WARN_ON(!(omap_gem_flags(fb->obj[1]) & OMAP_BO_TILED)); + WARN_ON(!(omap_gem_flags(fb->obj[1]) & OMAP_BO_TILED_MASK)); omap_gem_rotated_dma_addr(fb->obj[1], orient, x/2, y/2, &info->p_uv_addr); } else { diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 08f539efddfb..e518d93ca6df 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -67,7 +67,7 @@ struct omap_gem_object { /** * # of users of dma_addr */ - u32 dma_addr_cnt; + refcount_t dma_addr_cnt; /** * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag @@ -196,7 +196,7 @@ static void omap_gem_evict(struct drm_gem_object *obj) struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private; - if (omap_obj->flags & OMAP_BO_TILED) { + if (omap_obj->flags & OMAP_BO_TILED_MASK) { enum tiler_fmt fmt = gem2fmt(omap_obj->flags); int i; @@ -324,7 +324,7 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) struct omap_gem_object *omap_obj = to_omap_bo(obj); size_t size = obj->size; - if (omap_obj->flags & OMAP_BO_TILED) { + if (omap_obj->flags & OMAP_BO_TILED_MASK) { /* for tiled buffers, the virtual size has stride rounded up * to 4kb.. (to hide the fact that row n+1 might start 16kb or * 32kb later!). But we don't back the entire buffer with @@ -513,7 +513,7 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) * probably trigger put_pages()? */ - if (omap_obj->flags & OMAP_BO_TILED) + if (omap_obj->flags & OMAP_BO_TILED_MASK) ret = omap_gem_fault_2d(obj, vma, vmf); else ret = omap_gem_fault_1d(obj, vma, vmf); @@ -773,18 +773,20 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) mutex_lock(&omap_obj->lock); if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { - if (omap_obj->dma_addr_cnt == 0) { + if (refcount_read(&omap_obj->dma_addr_cnt) == 0) { u32 npages = obj->size >> PAGE_SHIFT; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct tiler_block *block; BUG_ON(omap_obj->block); + refcount_set(&omap_obj->dma_addr_cnt, 1); + ret = omap_gem_attach_pages(obj); if (ret) goto fail; - if (omap_obj->flags & OMAP_BO_TILED) { + if (omap_obj->flags & OMAP_BO_TILED_MASK) { block = tiler_reserve_2d(fmt, omap_obj->width, omap_obj->height, 0); @@ -813,13 +815,15 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) omap_obj->block = block; DBG("got dma address: %pad", &omap_obj->dma_addr); + } else { + refcount_inc(&omap_obj->dma_addr_cnt); } - omap_obj->dma_addr_cnt++; - - *dma_addr = omap_obj->dma_addr; + if (dma_addr) + *dma_addr = omap_obj->dma_addr; } else if (omap_gem_is_contiguous(omap_obj)) { - *dma_addr = omap_obj->dma_addr; + if (dma_addr) + *dma_addr = omap_obj->dma_addr; } else { ret = -EINVAL; goto fail; @@ -832,38 +836,46 @@ fail: } /** + * omap_gem_unpin_locked() - Unpin a GEM object from memory + * @obj: the GEM object + * + * omap_gem_unpin() without locking. + */ +static void omap_gem_unpin_locked(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret; + + if (refcount_dec_and_test(&omap_obj->dma_addr_cnt)) { + ret = tiler_unpin(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not unpin pages: %d\n", ret); + } + ret = tiler_release(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not release unmap: %d\n", ret); + } + omap_obj->dma_addr = 0; + omap_obj->block = NULL; + } +} + +/** * omap_gem_unpin() - Unpin a GEM object from memory * @obj: the GEM object * * Unpin the given GEM object previously pinned with omap_gem_pin(). Pins are - * reference-counted, the actualy unpin will only be performed when the number + * reference-counted, the actual unpin will only be performed when the number * of calls to this function matches the number of calls to omap_gem_pin(). */ void omap_gem_unpin(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret; mutex_lock(&omap_obj->lock); - - if (omap_obj->dma_addr_cnt > 0) { - omap_obj->dma_addr_cnt--; - if (omap_obj->dma_addr_cnt == 0) { - ret = tiler_unpin(omap_obj->block); - if (ret) { - dev_err(obj->dev->dev, - "could not unpin pages: %d\n", ret); - } - ret = tiler_release(omap_obj->block); - if (ret) { - dev_err(obj->dev->dev, - "could not release unmap: %d\n", ret); - } - omap_obj->dma_addr = 0; - omap_obj->block = NULL; - } - } - + omap_gem_unpin_locked(obj); mutex_unlock(&omap_obj->lock); } @@ -879,8 +891,8 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, mutex_lock(&omap_obj->lock); - if ((omap_obj->dma_addr_cnt > 0) && omap_obj->block && - (omap_obj->flags & OMAP_BO_TILED)) { + if ((refcount_read(&omap_obj->dma_addr_cnt) > 0) && omap_obj->block && + (omap_obj->flags & OMAP_BO_TILED_MASK)) { *dma_addr = tiler_tsptr(omap_obj->block, orient, x, y); ret = 0; } @@ -895,7 +907,7 @@ int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient) { struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; - if (omap_obj->flags & OMAP_BO_TILED) + if (omap_obj->flags & OMAP_BO_TILED_MASK) ret = tiler_stride(gem2fmt(omap_obj->flags), orient); return ret; } @@ -1030,10 +1042,11 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", omap_obj->flags, obj->name, kref_read(&obj->refcount), - off, &omap_obj->dma_addr, omap_obj->dma_addr_cnt, + off, &omap_obj->dma_addr, + refcount_read(&omap_obj->dma_addr_cnt), omap_obj->vaddr, omap_obj->roll); - if (omap_obj->flags & OMAP_BO_TILED) { + if (omap_obj->flags & OMAP_BO_TILED_MASK) { seq_printf(m, " %dx%d", omap_obj->width, omap_obj->height); if (omap_obj->block) { struct tcm_area *area = &omap_obj->block->area; @@ -1093,7 +1106,7 @@ void omap_gem_free_object(struct drm_gem_object *obj) mutex_lock(&omap_obj->lock); /* The object should not be pinned. */ - WARN_ON(omap_obj->dma_addr_cnt > 0); + WARN_ON(refcount_read(&omap_obj->dma_addr_cnt) > 0); if (omap_obj->pages) { if (omap_obj->flags & OMAP_BO_MEM_DMABUF) @@ -1120,6 +1133,38 @@ void omap_gem_free_object(struct drm_gem_object *obj) kfree(omap_obj); } +static bool omap_gem_validate_flags(struct drm_device *dev, u32 flags) +{ + struct omap_drm_private *priv = dev->dev_private; + + switch (flags & OMAP_BO_CACHE_MASK) { + case OMAP_BO_CACHED: + case OMAP_BO_WC: + case OMAP_BO_CACHE_MASK: + break; + + default: + return false; + } + + if (flags & OMAP_BO_TILED_MASK) { + if (!priv->usergart) + return false; + + switch (flags & OMAP_BO_TILED_MASK) { + case OMAP_BO_TILED_8: + case OMAP_BO_TILED_16: + case OMAP_BO_TILED_32: + break; + + default: + return false; + } + } + + return true; +} + /* GEM buffer object constructor */ struct drm_gem_object *omap_gem_new(struct drm_device *dev, union omap_gem_size gsize, u32 flags) @@ -1131,18 +1176,15 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, size_t size; int ret; - /* Validate the flags and compute the memory and cache flags. */ - if (flags & OMAP_BO_TILED) { - if (!priv->usergart) { - dev_err(dev->dev, "Tiled buffers require DMM\n"); - return NULL; - } + if (!omap_gem_validate_flags(dev, flags)) + return NULL; + /* Validate the flags and compute the memory and cache flags. */ + if (flags & OMAP_BO_TILED_MASK) { /* * Tiled buffers are always shmem paged backed. When they are * scanned out, they are remapped into DMM/TILER. */ - flags &= ~OMAP_BO_SCANOUT; flags |= OMAP_BO_MEM_SHMEM; /* @@ -1153,9 +1195,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, flags |= tiler_get_cpu_cache_flags(); } else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { /* - * OMAP_BO_SCANOUT hints that the buffer doesn't need to be - * tiled. However, to lower the pressure on memory allocation, - * use contiguous memory only if no TILER is available. + * If we don't have DMM, we must allocate scanout buffers + * from contiguous DMA memory. */ flags |= OMAP_BO_MEM_DMA_API; } else if (!(flags & OMAP_BO_MEM_DMABUF)) { @@ -1174,7 +1215,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, omap_obj->flags = flags; mutex_init(&omap_obj->lock); - if (flags & OMAP_BO_TILED) { + if (flags & OMAP_BO_TILED_MASK) { /* * For tiled buffers align dimensions to slot boundaries and * calculate size based on aligned dimensions. diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index e8c3ae7ac77e..7344bb61936c 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -67,7 +67,7 @@ static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, { struct drm_gem_object *obj = buffer->priv; struct page **pages; - if (omap_gem_flags(obj) & OMAP_BO_TILED) { + if (omap_gem_flags(obj) & OMAP_BO_TILED_MASK) { /* TODO we would need to pin at least part of the buffer to * get de-tiled view. For now just reject it. */ diff --git a/drivers/gpu/drm/panfrost/TODO b/drivers/gpu/drm/panfrost/TODO index 536a0d4f8d29..8c811a9e683b 100644 --- a/drivers/gpu/drm/panfrost/TODO +++ b/drivers/gpu/drm/panfrost/TODO @@ -10,3 +10,5 @@ - Compute job support. So called 'compute only' jobs need to be plumbed up to userspace. + +- Support core dump on job failure diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index c1eb8cfe6aeb..12ff77dacc95 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -53,10 +53,8 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, if (err) { dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate, err); - if (pfdev->regulator) - regulator_set_voltage(pfdev->regulator, - pfdev->devfreq.cur_volt, - pfdev->devfreq.cur_volt); + regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt, + pfdev->devfreq.cur_volt); return err; } diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index bc2ddeb55f5d..9d086133a84e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -470,7 +470,7 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), }; -DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops); +DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); /* * Panfrost driver version: diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index acb07fe06580..deca0c30bbd4 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -112,7 +112,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { .get_sg_table = drm_gem_shmem_get_sg_table, .vmap = drm_gem_shmem_vmap, .vunmap = drm_gem_shmem_vunmap, - .vm_ops = &drm_gem_shmem_vm_ops, + .mmap = drm_gem_shmem_mmap, }; /** diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 21f34d44aac2..33bf25ba506e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -404,8 +404,6 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) } spin_unlock_irqrestore(&pfdev->js->job_lock, flags); - /* panfrost_core_dump(pfdev); */ - panfrost_devfreq_record_transition(pfdev, js); panfrost_device_reset(pfdev); diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig index d0d691b31f4a..ca3f51c2a8fe 100644 --- a/drivers/gpu/drm/qxl/Kconfig +++ b/drivers/gpu/drm/qxl/Kconfig @@ -4,6 +4,7 @@ config DRM_QXL depends on DRM && PCI && MMU select DRM_KMS_HELPER select DRM_TTM + select DRM_TTM_HELPER select CRC32 help QXL virtual GPU for Spice virtualization desktop integration. diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 483b4c57554a..1d601f57a6ba 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -150,15 +150,7 @@ qxl_pci_remove(struct pci_dev *pdev) drm_dev_put(dev); } -static const struct file_operations qxl_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .poll = drm_poll, - .read = drm_read, - .mmap = qxl_mmap, -}; +DEFINE_DRM_GEM_FOPS(qxl_fops); static int qxl_drm_freeze(struct drm_device *dev) { diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index d4051409ce64..a5cb3864d686 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -355,7 +355,6 @@ int qxl_mode_dumb_mmap(struct drm_file *filp, /* qxl ttm */ int qxl_ttm_init(struct qxl_device *qdev); void qxl_ttm_fini(struct qxl_device *qdev); -int qxl_mmap(struct file *filp, struct vm_area_struct *vma); /* qxl image */ diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index c013c516f561..ad336c98a0cf 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -54,9 +54,14 @@ bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo) void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned) { u32 c = 0; - u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0; + u32 pflag = 0; unsigned int i; + if (pinned) + pflag |= TTM_PL_FLAG_NO_EVICT; + if (qbo->tbo.base.size <= PAGE_SIZE) + pflag |= TTM_PL_FLAG_TOPDOWN; + qbo->placement.placement = qbo->placements; qbo->placement.busy_placement = qbo->placements; if (domain == QXL_GEM_DOMAIN_VRAM) @@ -86,6 +91,7 @@ static const struct drm_gem_object_funcs qxl_object_funcs = { .get_sg_table = qxl_gem_prime_get_sg_table, .vmap = qxl_gem_prime_vmap, .vunmap = qxl_gem_prime_vunmap, + .mmap = drm_gem_ttm_mmap, .print_info = drm_gem_ttm_print_info, }; diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index cbc6c2ba8630..54cc5a5b607e 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -48,47 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) return qdev; } -static struct vm_operations_struct qxl_ttm_vm_ops; -static const struct vm_operations_struct *ttm_vm_ops; - -static vm_fault_t qxl_ttm_fault(struct vm_fault *vmf) -{ - struct ttm_buffer_object *bo; - vm_fault_t ret; - - bo = (struct ttm_buffer_object *)vmf->vma->vm_private_data; - if (bo == NULL) - return VM_FAULT_NOPAGE; - ret = ttm_vm_ops->fault(vmf); - return ret; -} - -int qxl_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int r; - struct drm_file *file_priv = filp->private_data; - struct qxl_device *qdev = file_priv->minor->dev->dev_private; - - if (qdev == NULL) { - DRM_ERROR( - "filp->private_data->minor->dev->dev_private == NULL\n"); - return -EINVAL; - } - DRM_DEBUG_DRIVER("filp->private_data = 0x%p, vma->vm_pgoff = %lx\n", - filp->private_data, vma->vm_pgoff); - - r = ttm_bo_mmap(filp, vma, &qdev->mman.bdev); - if (unlikely(r != 0)) - return r; - if (unlikely(ttm_vm_ops == NULL)) { - ttm_vm_ops = vma->vm_ops; - qxl_ttm_vm_ops = *ttm_vm_ops; - qxl_ttm_vm_ops.fault = &qxl_ttm_fault; - } - vma->vm_ops = &qxl_ttm_vm_ops; - return 0; -} - static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) { return 0; @@ -151,14 +110,6 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo, *placement = qbo->placement; } -static int qxl_verify_access(struct ttm_buffer_object *bo, struct file *filp) -{ - struct qxl_bo *qbo = to_qxl_bo(bo); - - return drm_vma_node_verify_access(&qbo->tbo.base.vma_node, - filp->private_data); -} - static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { @@ -310,7 +261,6 @@ static struct ttm_bo_driver qxl_bo_driver = { .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = &qxl_evict_flags, .move = &qxl_bo_move, - .verify_access = &qxl_verify_access, .io_mem_reserve = &qxl_ttm_io_mem_reserve, .io_mem_free = &qxl_ttm_io_mem_free, .move_notify = &qxl_bo_move_notify, diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index d505ea7d5384..eed594bd38d3 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -477,8 +477,8 @@ static int cdn_dp_disable(struct cdn_dp_device *dp) cdn_dp_set_firmware_active(dp, false); cdn_dp_clk_disable(dp); dp->active = false; - dp->link.rate = 0; - dp->link.num_lanes = 0; + dp->max_lanes = 0; + dp->max_rate = 0; if (!dp->connected) { kfree(dp->edid); dp->edid = NULL; @@ -570,7 +570,7 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) struct cdn_dp_port *port = cdn_dp_connected_port(dp); u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd); - if (!port || !dp->link.rate || !dp->link.num_lanes) + if (!port || !dp->max_rate || !dp->max_lanes) return false; if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, @@ -952,8 +952,8 @@ static void cdn_dp_pd_event_work(struct work_struct *work) /* Enabled and connected with a sink, re-train if requested */ } else if (!cdn_dp_check_link_status(dp)) { - unsigned int rate = dp->link.rate; - unsigned int lanes = dp->link.num_lanes; + unsigned int rate = dp->max_rate; + unsigned int lanes = dp->max_lanes; struct drm_display_mode *mode = &dp->mode; DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n"); @@ -966,7 +966,7 @@ static void cdn_dp_pd_event_work(struct work_struct *work) /* If training result is changed, update the video config */ if (mode->clock && - (rate != dp->link.rate || lanes != dp->link.num_lanes)) { + (rate != dp->max_rate || lanes != dp->max_lanes)) { ret = cdn_dp_config_video(dp); if (ret) { dp->connected = false; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index b85ea89eb60b..83c4586665b4 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -92,9 +92,10 @@ struct cdn_dp_device { struct reset_control *core_rst; struct audio_info audio_info; struct video_info video_info; - struct drm_dp_link link; struct cdn_dp_port *port[MAX_PHY]; u8 ports; + u8 max_lanes; + u8 max_rate; u8 lanes; int active_port; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 077c87021908..7361c07cb4a7 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -535,8 +535,8 @@ static int cdn_dp_get_training_status(struct cdn_dp_device *dp) if (ret) goto err_get_training_status; - dp->link.rate = drm_dp_bw_code_to_link_rate(status[0]); - dp->link.num_lanes = status[1]; + dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); + dp->max_lanes = status[1]; err_get_training_status: if (ret) @@ -560,8 +560,8 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) return ret; } - DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, - dp->link.num_lanes); + DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate, + dp->max_lanes); return ret; } @@ -639,7 +639,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? (video->color_depth * 2) : (video->color_depth * 3); - link_rate = dp->link.rate / 1000; + link_rate = dp->max_rate / 1000; ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); if (ret) @@ -659,14 +659,13 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) do { tu_size_reg += 2; symbol = tu_size_reg * mode->clock * bit_per_pix; - do_div(symbol, dp->link.num_lanes * link_rate * 8); + do_div(symbol, dp->max_lanes * link_rate * 8); rem = do_div(symbol, 1000); if (tu_size_reg > 64) { ret = -EINVAL; DRM_DEV_ERROR(dp->dev, "tu error, clk:%d, lanes:%d, rate:%d\n", - mode->clock, dp->link.num_lanes, - link_rate); + mode->clock, dp->max_lanes, link_rate); goto err_config_video; } } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || @@ -680,7 +679,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) /* set the FIFO Buffer size */ val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; - val /= (dp->link.num_lanes * link_rate); + val /= (dp->max_lanes * link_rate); val = div_u64(8 * (symbol + 1), bit_per_pix) - val; val += 2; ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); @@ -833,7 +832,7 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, u32 val; if (audio->channels == 2) { - if (dp->link.num_lanes == 1) + if (dp->max_lanes == 1) sub_pckt_num = 2; else sub_pckt_num = 4; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 906891b03a38..7f56d8c3491d 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -450,6 +450,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { .phy_ops = &rk3328_hdmi_phy_ops, .phy_name = "inno_dw_hdmi_phy2", .phy_force_vendor = true, + .use_drm_infoframe = true, }; static struct rockchip_hdmi_chip_data rk3399_chip_data = { @@ -464,6 +465,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, .phy_data = &rk3399_chip_data, + .use_drm_infoframe = true, }; static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 85fc5f01f761..cdb401f4283d 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -743,7 +743,6 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct rk3066_hdmi *hdmi; - struct resource *iores; int irq; int ret; @@ -753,12 +752,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master, hdmi->dev = dev; hdmi->drm_dev = drm; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -ENXIO; - - hdmi->regs = devm_ioremap_resource(dev, iores); + hdmi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 291e89b4045f..7582d0e6a60a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -294,7 +294,7 @@ static void rockchip_gem_release_object(struct rockchip_gem_object *rk_obj) kfree(rk_obj); } -struct rockchip_gem_object * +static struct rockchip_gem_object * rockchip_gem_alloc_object(struct drm_device *drm, unsigned int size) { struct rockchip_gem_object *rk_obj; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 613404f86668..d04b3492bdac 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -139,6 +139,7 @@ struct vop { uint32_t *regsbak; void __iomem *regs; + void __iomem *lut_regs; /* physical map length of vop register */ uint32_t len; @@ -1040,14 +1041,118 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode) { struct vop *vop = to_vop(crtc); + unsigned long rate; - adjusted_mode->clock = - DIV_ROUND_UP(clk_round_rate(vop->dclk, - adjusted_mode->clock * 1000), 1000); + /* + * Clock craziness. + * + * Key points: + * + * - DRM works in in kHz. + * - Clock framework works in Hz. + * - Rockchip's clock driver picks the clock rate that is the + * same _OR LOWER_ than the one requested. + * + * Action plan: + * + * 1. When DRM gives us a mode, we should add 999 Hz to it. That way + * if the clock we need is 60000001 Hz (~60 MHz) and DRM tells us to + * make 60000 kHz then the clock framework will actually give us + * the right clock. + * + * NOTE: if the PLL (maybe through a divider) could actually make + * a clock rate 999 Hz higher instead of the one we want then this + * could be a problem. Unfortunately there's not much we can do + * since it's baked into DRM to use kHz. It shouldn't matter in + * practice since Rockchip PLLs are controlled by tables and + * even if there is a divider in the middle I wouldn't expect PLL + * rates in the table that are just a few kHz different. + * + * 2. Get the clock framework to round the rate for us to tell us + * what it will actually make. + * + * 3. Store the rounded up rate so that we don't need to worry about + * this in the actual clk_set_rate(). + */ + rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000 + 999); + adjusted_mode->clock = DIV_ROUND_UP(rate, 1000); return true; } +static bool vop_dsp_lut_is_enabled(struct vop *vop) +{ + return vop_read_reg(vop, 0, &vop->data->common->dsp_lut_en); +} + +static void vop_crtc_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc) +{ + struct drm_color_lut *lut = crtc->state->gamma_lut->data; + unsigned int i; + + for (i = 0; i < crtc->gamma_size; i++) { + u32 word; + + word = (drm_color_lut_extract(lut[i].red, 10) << 20) | + (drm_color_lut_extract(lut[i].green, 10) << 10) | + drm_color_lut_extract(lut[i].blue, 10); + writel(word, vop->lut_regs + i * 4); + } +} + +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct drm_crtc_state *state = crtc->state; + unsigned int idle; + int ret; + + if (!vop->lut_regs) + return; + /* + * To disable gamma (gamma_lut is null) or to write + * an update to the LUT, clear dsp_lut_en. + */ + spin_lock(&vop->reg_lock); + VOP_REG_SET(vop, common, dsp_lut_en, 0); + vop_cfg_done(vop); + spin_unlock(&vop->reg_lock); + + /* + * In order to write the LUT to the internal memory, + * we need to first make sure the dsp_lut_en bit is cleared. + */ + ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop, + idle, !idle, 5, 30 * 1000); + if (ret) { + DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n"); + return; + } + + if (!state->gamma_lut) + return; + + spin_lock(&vop->reg_lock); + vop_crtc_write_gamma_lut(vop, crtc); + VOP_REG_SET(vop, common, dsp_lut_en, 1); + vop_cfg_done(vop); + spin_unlock(&vop->reg_lock); +} + +static void vop_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct vop *vop = to_vop(crtc); + + /* + * Only update GAMMA if the 'active' flag is not changed, + * otherwise it's updated by .atomic_enable. + */ + if (crtc->state->color_mgmt_changed && + !crtc->state->active_changed) + vop_crtc_gamma_set(vop, crtc, old_crtc_state); +} + static void vop_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -1075,6 +1180,14 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, return; } + /* + * If we have a GAMMA LUT in the state, then let's make sure + * it's updated. We might be coming out of suspend, + * which means the LUT internal memory needs to be re-written. + */ + if (crtc->state->gamma_lut) + vop_crtc_gamma_set(vop, crtc, old_state); + mutex_lock(&vop->vop_lock); WARN_ON(vop->event); @@ -1085,9 +1198,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); return; } - - pin_pol = BIT(DCLK_INVERT); - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? + pin_pol = (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIT(HSYNC_POSITIVE) : 0; pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIT(VSYNC_POSITIVE) : 0; @@ -1096,25 +1207,29 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, switch (s->output_type) { case DRM_MODE_CONNECTOR_LVDS: - VOP_REG_SET(vop, output, rgb_en, 1); + VOP_REG_SET(vop, output, rgb_dclk_pol, 1); VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol); + VOP_REG_SET(vop, output, rgb_en, 1); break; case DRM_MODE_CONNECTOR_eDP: + VOP_REG_SET(vop, output, edp_dclk_pol, 1); VOP_REG_SET(vop, output, edp_pin_pol, pin_pol); VOP_REG_SET(vop, output, edp_en, 1); break; case DRM_MODE_CONNECTOR_HDMIA: + VOP_REG_SET(vop, output, hdmi_dclk_pol, 1); VOP_REG_SET(vop, output, hdmi_pin_pol, pin_pol); VOP_REG_SET(vop, output, hdmi_en, 1); break; case DRM_MODE_CONNECTOR_DSI: + VOP_REG_SET(vop, output, mipi_dclk_pol, 1); VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); VOP_REG_SET(vop, output, mipi_en, 1); VOP_REG_SET(vop, output, mipi_dual_channel_en, !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL)); break; case DRM_MODE_CONNECTOR_DisplayPort: - pin_pol &= ~BIT(DCLK_INVERT); + VOP_REG_SET(vop, output, dp_dclk_pol, 0); VOP_REG_SET(vop, output, dp_pin_pol, pin_pol); VOP_REG_SET(vop, output, dp_en, 1); break; @@ -1191,6 +1306,26 @@ static void vop_wait_for_irq_handler(struct vop *vop) synchronize_irq(vop->irq); } +static int vop_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct vop *vop = to_vop(crtc); + + if (vop->lut_regs && crtc_state->color_mgmt_changed && + crtc_state->gamma_lut) { + unsigned int len; + + len = drm_color_lut_size(crtc_state->gamma_lut); + if (len != crtc->gamma_size) { + DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n", + len, crtc->gamma_size); + return -EINVAL; + } + } + + return 0; +} + static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -1243,6 +1378,8 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { .mode_fixup = vop_crtc_mode_fixup, + .atomic_check = vop_crtc_atomic_check, + .atomic_begin = vop_crtc_atomic_begin, .atomic_flush = vop_crtc_atomic_flush, .atomic_enable = vop_crtc_atomic_enable, .atomic_disable = vop_crtc_atomic_disable, @@ -1361,6 +1498,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { .disable_vblank = vop_crtc_disable_vblank, .set_crc_source = vop_crtc_set_crc_source, .verify_crc_source = vop_crtc_verify_crc_source, + .gamma_set = drm_atomic_helper_legacy_gamma_set, }; static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) @@ -1518,6 +1656,10 @@ static int vop_create_crtc(struct vop *vop) goto err_cleanup_planes; drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); + if (vop->lut_regs) { + drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size); + drm_crtc_enable_color_mgmt(crtc, 0, false, vop_data->lut_size); + } /* * Create drm_planes for overlay windows with possible_crtcs restricted @@ -1822,6 +1964,17 @@ static int vop_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(vop->regs)) return PTR_ERR(vop->regs); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + if (!vop_data->lut_size) { + DRM_DEV_ERROR(dev, "no gamma LUT size defined\n"); + return -EINVAL; + } + vop->lut_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(vop->lut_regs)) + return PTR_ERR(vop->lut_regs); + } + vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL); if (!vop->regsbak) return -ENOMEM; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 2149a889c29d..0b3d18c457b2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -46,10 +46,15 @@ struct vop_modeset { struct vop_output { struct vop_reg pin_pol; struct vop_reg dp_pin_pol; + struct vop_reg dp_dclk_pol; struct vop_reg edp_pin_pol; + struct vop_reg edp_dclk_pol; struct vop_reg hdmi_pin_pol; + struct vop_reg hdmi_dclk_pol; struct vop_reg mipi_pin_pol; + struct vop_reg mipi_dclk_pol; struct vop_reg rgb_pin_pol; + struct vop_reg rgb_dclk_pol; struct vop_reg dp_en; struct vop_reg edp_en; struct vop_reg hdmi_en; @@ -67,6 +72,7 @@ struct vop_common { struct vop_reg dither_down_mode; struct vop_reg dither_down_en; struct vop_reg dither_up; + struct vop_reg dsp_lut_en; struct vop_reg gate_en; struct vop_reg mmu_en; struct vop_reg out_mode; @@ -170,6 +176,7 @@ struct vop_data { const struct vop_win_yuv2yuv_data *win_yuv2yuv; const struct vop_win_data *win; unsigned int win_size; + unsigned int lut_size; #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) #define VOP_FEATURE_INTERNAL_RGB BIT(1) @@ -294,8 +301,7 @@ enum dither_down_mode_sel { enum vop_pol { HSYNC_POSITIVE = 0, VSYNC_POSITIVE = 1, - DEN_NEGATIVE = 2, - DCLK_INVERT = 3 + DEN_NEGATIVE = 2 }; #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index d1494be14471..7a9d979c8d5d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -16,6 +16,7 @@ #include "rockchip_drm_vop.h" #include "rockchip_vop_reg.h" +#include "rockchip_drm_drv.h" #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \ { \ @@ -214,9 +215,11 @@ static const struct vop_modeset px30_modeset = { }; static const struct vop_output px30_output = { - .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 1), - .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 25), + .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1), + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2), .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26), .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), }; @@ -598,6 +601,7 @@ static const struct vop_common rk3288_common = { .dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2), .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1), .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), + .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0), .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19), .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), @@ -646,6 +650,7 @@ static const struct vop_data rk3288_vop = { .output = &rk3288_output, .win = rk3288_vop_win_data, .win_size = ARRAY_SIZE(rk3288_vop_win_data), + .lut_size = 1024, }; static const int rk3368_vop_intrs[] = { @@ -717,10 +722,14 @@ static const struct vop_win_data rk3368_vop_win_data[] = { }; static const struct vop_output rk3368_output = { - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28), + .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31), + .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28), .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), @@ -764,11 +773,16 @@ static const struct vop_data rk3366_vop = { }; static const struct vop_output rk3399_output = { - .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28), + .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), + .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31), + .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), + .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28), .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), @@ -872,14 +886,18 @@ static const struct vop_modeset rk3328_modeset = { }; static const struct vop_output rk3328_output = { + .rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31), .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13), .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14), .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15), - .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28), + .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28), }; static const struct vop_misc rk3328_misc = { diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index 54977408f574..8b45c3a1b84e 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -128,13 +128,13 @@ static void drm_sched_fence_release_finished(struct dma_fence *f) dma_fence_put(&fence->scheduled); } -const struct dma_fence_ops drm_sched_fence_ops_scheduled = { +static const struct dma_fence_ops drm_sched_fence_ops_scheduled = { .get_driver_name = drm_sched_fence_get_driver_name, .get_timeline_name = drm_sched_fence_get_timeline_name, .release = drm_sched_fence_release_scheduled, }; -const struct dma_fence_ops drm_sched_fence_ops_finished = { +static const struct dma_fence_ops drm_sched_fence_ops_finished = { .get_driver_name = drm_sched_fence_get_driver_name, .get_timeline_name = drm_sched_fence_get_timeline_name, .release = drm_sched_fence_release_finished, diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index a44dca4b0219..e8a317d5ba19 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -226,6 +226,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, sun8i_hdmi_phy_init(hdmi->phy); plat_data->mode_valid = hdmi->quirks->mode_valid; + plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe; sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data); platform_set_drvdata(pdev, hdmi); @@ -300,6 +301,7 @@ static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = { static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { .mode_valid = sun8i_dw_hdmi_mode_valid_h6, + .use_drm_infoframe = true, }; static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index d707c9171824..8e64945167e9 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -179,6 +179,7 @@ struct sun8i_dw_hdmi_quirks { enum drm_mode_status (*mode_valid)(struct drm_connector *connector, const struct drm_display_mode *mode); unsigned int set_rate : 1; + unsigned int use_drm_infoframe : 1; }; struct sun8i_dw_hdmi { diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 33c463e8d49f..d6cf202414f0 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -5,6 +5,7 @@ tegra-drm-y := \ drm.o \ gem.o \ fb.o \ + dp.o \ hub.o \ plane.o \ dc.o \ diff --git a/drivers/gpu/drm/tegra/dp.c b/drivers/gpu/drm/tegra/dp.c new file mode 100644 index 000000000000..50ba967ebcbd --- /dev/null +++ b/drivers/gpu/drm/tegra/dp.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2013-2019 NVIDIA Corporation + * Copyright (C) 2015 Rob Clark + */ + +#include <drm/drm_dp_helper.h> + +#include "dp.h" + +/** + * drm_dp_link_probe() - probe a DisplayPort link for capabilities + * @aux: DisplayPort AUX channel + * @link: pointer to structure in which to return link capabilities + * + * The structure filled in by this function can usually be passed directly + * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and + * configure the link based on the link's capabilities. + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 values[3]; + int err; + + memset(link, 0, sizeof(*link)); + + err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); + if (err < 0) + return err; + + link->revision = values[0]; + link->rate = drm_dp_bw_code_to_link_rate(values[1]); + link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; + + if (values[2] & DP_ENHANCED_FRAME_CAP) + link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; + + return 0; +} + +/** + * drm_dp_link_power_up() - power up a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 value; + int err; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (link->revision < 0x11) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (err < 0) + return err; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + if (err < 0) + return err; + + /* + * According to the DP 1.1 specification, a "Sink Device must exit the + * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink + * Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + + return 0; +} + +/** + * drm_dp_link_power_down() - power down a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 value; + int err; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (link->revision < 0x11) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (err < 0) + return err; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D3; + + err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + if (err < 0) + return err; + + return 0; +} + +/** + * drm_dp_link_configure() - configure a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 values[2]; + int err; + + values[0] = drm_dp_link_rate_to_bw_code(link->rate); + values[1] = link->num_lanes; + + if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); + if (err < 0) + return err; + + return 0; +} diff --git a/drivers/gpu/drm/tegra/dp.h b/drivers/gpu/drm/tegra/dp.h new file mode 100644 index 000000000000..88842fd25abf --- /dev/null +++ b/drivers/gpu/drm/tegra/dp.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2013-2019 NVIDIA Corporation. + * Copyright (C) 2015 Rob Clark + */ + +#ifndef DRM_TEGRA_DP_H +#define DRM_TEGRA_DP_H 1 + +struct drm_dp_aux; + +#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) + +struct drm_dp_link { + unsigned char revision; + unsigned int rate; + unsigned int num_lanes; + unsigned long capabilities; +}; + +int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); + +#endif diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index a0f6f9b0d258..1144605c9737 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -22,6 +22,7 @@ #include <drm/drm_dp_helper.h> #include <drm/drm_panel.h> +#include "dp.h" #include "dpaux.h" #include "drm.h" #include "trace.h" diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index e1669ada0a40..fbbb974c1e1a 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -25,6 +25,7 @@ #include <drm/drm_scdc_helper.h> #include "dc.h" +#include "dp.h" #include "drm.h" #include "hda.h" #include "sor.h" diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index 03d0e2df6774..94fb1f593564 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -649,7 +649,7 @@ static void gm12u320_driver_release(struct drm_device *dev) kfree(gm12u320); } -DEFINE_DRM_GEM_SHMEM_FOPS(gm12u320_fops); +DEFINE_DRM_GEM_FOPS(gm12u320_fops); static struct drm_driver gm12u320_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 4869049deaa1..79f01c5ff65e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -424,6 +424,28 @@ static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev, return bo; } +static void ttm_bo_mmap_vma_setup(struct ttm_buffer_object *bo, struct vm_area_struct *vma) +{ + vma->vm_ops = &ttm_bo_vm_ops; + + /* + * Note: We're transferring the bo reference to + * vma->vm_private_data here. + */ + + vma->vm_private_data = bo; + + /* + * We'd like to use VM_PFNMAP on shared mappings, where + * (vma->vm_flags & VM_SHARED) != 0, for performance reasons, + * but for some reason VM_PFNMAP + x86 PAT + write-combine is very + * bad for performance. Until that has been sorted out, use + * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719 + */ + vma->vm_flags |= VM_MIXEDMAP; + vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; +} + int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, struct ttm_bo_device *bdev) { @@ -447,24 +469,7 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, if (unlikely(ret != 0)) goto out_unref; - vma->vm_ops = &ttm_bo_vm_ops; - - /* - * Note: We're transferring the bo reference to - * vma->vm_private_data here. - */ - - vma->vm_private_data = bo; - - /* - * We'd like to use VM_PFNMAP on shared mappings, where - * (vma->vm_flags & VM_SHARED) != 0, for performance reasons, - * but for some reason VM_PFNMAP + x86 PAT + write-combine is very - * bad for performance. Until that has been sorted out, use - * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719 - */ - vma->vm_flags |= VM_MIXEDMAP; - vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; + ttm_bo_mmap_vma_setup(bo, vma); return 0; out_unref: ttm_bo_put(bo); @@ -472,17 +477,10 @@ out_unref: } EXPORT_SYMBOL(ttm_bo_mmap); -int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) +int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo) { - if (vma->vm_pgoff != 0) - return -EACCES; - ttm_bo_get(bo); - - vma->vm_ops = &ttm_bo_vm_ops; - vma->vm_private_data = bo; - vma->vm_flags |= VM_MIXEDMAP; - vma->vm_flags |= VM_IO | VM_DONTEXPAND; + ttm_bo_mmap_vma_setup(bo, vma); return 0; } -EXPORT_SYMBOL(ttm_fbdev_mmap); +EXPORT_SYMBOL(ttm_bo_mmap_obj); diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index a22b75a3a533..edd299ab53d8 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -58,7 +58,7 @@ static const struct drm_gem_object_funcs v3d_gem_funcs = { .get_sg_table = drm_gem_shmem_get_sg_table, .vmap = drm_gem_shmem_vmap, .vunmap = drm_gem_shmem_vunmap, - .vm_ops = &drm_gem_shmem_vm_ops, + .mmap = drm_gem_shmem_mmap, }; /* gem_create_object function for allocating a BO struct and doing diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index e94bf75368be..1a07462b4528 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -172,7 +172,7 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) kfree(v3d_priv); } -DEFINE_DRM_GEM_SHMEM_FOPS(v3d_drm_fops); +DEFINE_DRM_GEM_FOPS(v3d_drm_fops); /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP * protection between clients. Note that render nodes would be be diff --git a/drivers/gpu/drm/vboxvideo/Makefile b/drivers/gpu/drm/vboxvideo/Makefile index 55d798c76b21..f2e968b5ffa6 100644 --- a/drivers/gpu/drm/vboxvideo/Makefile +++ b/drivers/gpu/drm/vboxvideo/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 vboxvideo-y := hgsmi_base.o modesetting.o vbva_base.o \ - vbox_drv.o vbox_fb.o vbox_hgsmi.o vbox_irq.o vbox_main.o \ + vbox_drv.o vbox_hgsmi.o vbox_irq.o vbox_main.o \ vbox_mode.o vbox_ttm.o obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo.o diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c index 862db495d111..8512d970a09f 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.c +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c @@ -14,6 +14,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> @@ -32,10 +33,6 @@ static const struct pci_device_id pciidlist[] = { }; MODULE_DEVICE_TABLE(pci, pciidlist); -static const struct drm_fb_helper_funcs vbox_fb_helper_funcs = { - .fb_probe = vboxfb_create, -}; - static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct vbox_private *vbox; @@ -79,20 +76,16 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto err_mode_fini; - ret = drm_fb_helper_fbdev_setup(&vbox->ddev, &vbox->fb_helper, - &vbox_fb_helper_funcs, 32, - vbox->num_crtcs); + ret = drm_fbdev_generic_setup(&vbox->ddev, 32); if (ret) goto err_irq_fini; ret = drm_dev_register(&vbox->ddev, 0); if (ret) - goto err_fbdev_fini; + goto err_irq_fini; return 0; -err_fbdev_fini: - vbox_fbdev_fini(vbox); err_irq_fini: vbox_irq_fini(vbox); err_mode_fini: @@ -113,7 +106,6 @@ static void vbox_pci_remove(struct pci_dev *pdev) struct vbox_private *vbox = pci_get_drvdata(pdev); drm_dev_unregister(&vbox->ddev); - vbox_fbdev_fini(vbox); vbox_irq_fini(vbox); vbox_mode_fini(vbox); vbox_mm_fini(vbox); @@ -189,10 +181,7 @@ static struct pci_driver vbox_pci_driver = { #endif }; -static const struct file_operations vbox_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(vbox_fops); static struct drm_driver driver = { .driver_features = diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.h b/drivers/gpu/drm/vboxvideo/vbox_drv.h index fb436ec760ea..87421903816c 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.h +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.h @@ -16,7 +16,6 @@ #include <linux/string.h> #include <drm/drm_encoder.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/drm_gem_vram_helper.h> @@ -46,16 +45,9 @@ sizeof(struct hgsmi_host_flags)) #define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE -struct vbox_framebuffer { - struct drm_framebuffer base; - struct drm_gem_object *obj; -}; - struct vbox_private { /* Must be first; or we must define our own release callback */ struct drm_device ddev; - struct drm_fb_helper fb_helper; - struct vbox_framebuffer afb; u8 __iomem *guest_heap; u8 __iomem *vbva_buffers; @@ -135,7 +127,6 @@ struct vbox_encoder { #define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base) #define to_vbox_connector(x) container_of(x, struct vbox_connector, base) #define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base) -#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base) bool vbox_check_supported(u16 id); int vbox_hw_init(struct vbox_private *vbox); @@ -146,25 +137,9 @@ void vbox_mode_fini(struct vbox_private *vbox); void vbox_report_caps(struct vbox_private *vbox); -void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb, - struct drm_clip_rect *rects, - unsigned int num_rects); - -int vbox_framebuffer_init(struct vbox_private *vbox, - struct vbox_framebuffer *vbox_fb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); - -int vboxfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes); -void vbox_fbdev_fini(struct vbox_private *vbox); - int vbox_mm_init(struct vbox_private *vbox); void vbox_mm_fini(struct vbox_private *vbox); -int vbox_gem_create(struct vbox_private *vbox, - u32 size, bool iskernel, struct drm_gem_object **obj); - /* vbox_irq.c */ int vbox_irq_init(struct vbox_private *vbox); void vbox_irq_fini(struct vbox_private *vbox); diff --git a/drivers/gpu/drm/vboxvideo/vbox_fb.c b/drivers/gpu/drm/vboxvideo/vbox_fb.c deleted file mode 100644 index 8f74bcffc034..000000000000 --- a/drivers/gpu/drm/vboxvideo/vbox_fb.c +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 2013-2017 Oracle Corporation - * This file is based on ast_fb.c - * Copyright 2012 Red Hat Inc. - * Authors: Dave Airlie <airlied@redhat.com> - * Michael Thayer <michael.thayer@oracle.com, - */ -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/sysrq.h> -#include <linux/tty.h> - -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_fourcc.h> - -#include "vbox_drv.h" -#include "vboxvideo.h" - -#ifdef CONFIG_DRM_KMS_FB_HELPER -static struct fb_deferred_io vbox_defio = { - .delay = HZ / 30, - .deferred_io = drm_fb_helper_deferred_io, -}; -#endif - -static struct fb_ops vboxfb_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, -}; - -int vboxfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct vbox_private *vbox = - container_of(helper, struct vbox_private, fb_helper); - struct pci_dev *pdev = vbox->ddev.pdev; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_framebuffer *fb; - struct fb_info *info; - struct drm_gem_object *gobj; - struct drm_gem_vram_object *gbo; - int size, ret; - s64 gpu_addr; - u32 pitch; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - pitch = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - mode_cmd.pitches[0] = pitch; - - size = pitch * mode_cmd.height; - - ret = vbox_gem_create(vbox, size, true, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object %d\n", ret); - return ret; - } - - ret = vbox_framebuffer_init(vbox, &vbox->afb, &mode_cmd, gobj); - if (ret) - return ret; - - gbo = drm_gem_vram_of_gem(gobj); - - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) - return ret; - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) - return PTR_ERR(info); - - info->screen_size = size; - info->screen_base = (char __iomem *)drm_gem_vram_kmap(gbo, true, NULL); - if (IS_ERR(info->screen_base)) - return PTR_ERR(info->screen_base); - - fb = &vbox->afb.base; - helper->fb = fb; - - info->fbops = &vboxfb_ops; - - /* - * This seems to be done for safety checking that the framebuffer - * is not registered twice by different drivers. - */ - info->apertures->ranges[0].base = pci_resource_start(pdev, 0); - info->apertures->ranges[0].size = pci_resource_len(pdev, 0); - - drm_fb_helper_fill_info(info, helper, sizes); - - gpu_addr = drm_gem_vram_offset(gbo); - if (gpu_addr < 0) - return (int)gpu_addr; - info->fix.smem_start = info->apertures->ranges[0].base + gpu_addr; - info->fix.smem_len = vbox->available_vram_size - gpu_addr; - -#ifdef CONFIG_DRM_KMS_FB_HELPER - info->fbdefio = &vbox_defio; - fb_deferred_io_init(info); -#endif - - info->pixmap.flags = FB_PIXMAP_SYSTEM; - - DRM_DEBUG_KMS("allocated %dx%d\n", fb->width, fb->height); - - return 0; -} - -void vbox_fbdev_fini(struct vbox_private *vbox) -{ - struct vbox_framebuffer *afb = &vbox->afb; - -#ifdef CONFIG_DRM_KMS_FB_HELPER - if (vbox->fb_helper.fbdev && vbox->fb_helper.fbdev->fbdefio) - fb_deferred_io_cleanup(vbox->fb_helper.fbdev); -#endif - - drm_fb_helper_unregister_fbi(&vbox->fb_helper); - - if (afb->obj) { - struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(afb->obj); - - drm_gem_vram_kunmap(gbo); - drm_gem_vram_unpin(gbo); - - drm_gem_object_put_unlocked(afb->obj); - afb->obj = NULL; - } - drm_fb_helper_fini(&vbox->fb_helper); - - drm_framebuffer_unregister_private(&afb->base); - drm_framebuffer_cleanup(&afb->base); -} diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c b/drivers/gpu/drm/vboxvideo/vbox_main.c index 02fa8277ff1e..9dcab115a261 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_main.c +++ b/drivers/gpu/drm/vboxvideo/vbox_main.c @@ -11,22 +11,12 @@ #include <linux/vbox_err.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_damage_helper.h> #include "vbox_drv.h" #include "vboxvideo_guest.h" #include "vboxvideo_vbe.h" -static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb); - - if (vbox_fb->obj) - drm_gem_object_put_unlocked(vbox_fb->obj); - - drm_framebuffer_cleanup(fb); - kfree(fb); -} - void vbox_report_caps(struct vbox_private *vbox) { u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION | @@ -38,87 +28,6 @@ void vbox_report_caps(struct vbox_private *vbox) hgsmi_send_caps_info(vbox->guest_pool, caps); } -/* Send information about dirty rectangles to VBVA. */ -void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb, - struct drm_clip_rect *rects, - unsigned int num_rects) -{ - struct vbox_private *vbox = fb->dev->dev_private; - struct drm_display_mode *mode; - struct drm_crtc *crtc; - int crtc_x, crtc_y; - unsigned int i; - - mutex_lock(&vbox->hw_mutex); - list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) { - if (crtc->primary->state->fb != fb) - continue; - - mode = &crtc->state->mode; - crtc_x = crtc->primary->state->src_x >> 16; - crtc_y = crtc->primary->state->src_y >> 16; - - for (i = 0; i < num_rects; ++i) { - struct vbva_cmd_hdr cmd_hdr; - unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id; - - if (rects[i].x1 > crtc_x + mode->hdisplay || - rects[i].y1 > crtc_y + mode->vdisplay || - rects[i].x2 < crtc_x || - rects[i].y2 < crtc_y) - continue; - - cmd_hdr.x = (s16)rects[i].x1; - cmd_hdr.y = (s16)rects[i].y1; - cmd_hdr.w = (u16)rects[i].x2 - rects[i].x1; - cmd_hdr.h = (u16)rects[i].y2 - rects[i].y1; - - if (!vbva_buffer_begin_update(&vbox->vbva_info[crtc_id], - vbox->guest_pool)) - continue; - - vbva_write(&vbox->vbva_info[crtc_id], vbox->guest_pool, - &cmd_hdr, sizeof(cmd_hdr)); - vbva_buffer_end_update(&vbox->vbva_info[crtc_id]); - } - } - mutex_unlock(&vbox->hw_mutex); -} - -static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *rects, - unsigned int num_rects) -{ - vbox_framebuffer_dirty_rectangles(fb, rects, num_rects); - - return 0; -} - -static const struct drm_framebuffer_funcs vbox_fb_funcs = { - .destroy = vbox_user_framebuffer_destroy, - .dirty = vbox_user_framebuffer_dirty, -}; - -int vbox_framebuffer_init(struct vbox_private *vbox, - struct vbox_framebuffer *vbox_fb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - int ret; - - drm_helper_mode_fill_fb_struct(&vbox->ddev, &vbox_fb->base, mode_cmd); - vbox_fb->obj = obj; - ret = drm_framebuffer_init(&vbox->ddev, &vbox_fb->base, &vbox_fb_funcs); - if (ret) { - DRM_ERROR("framebuffer init failed %d\n", ret); - return ret; - } - - return 0; -} - static int vbox_accel_init(struct vbox_private *vbox) { struct vbva_buffer *vbva; @@ -270,29 +179,3 @@ void vbox_hw_fini(struct vbox_private *vbox) gen_pool_destroy(vbox->guest_pool); pci_iounmap(vbox->ddev.pdev, vbox->guest_heap); } - -int vbox_gem_create(struct vbox_private *vbox, - u32 size, bool iskernel, struct drm_gem_object **obj) -{ - struct drm_gem_vram_object *gbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - gbo = drm_gem_vram_create(&vbox->ddev, &vbox->ddev.vram_mm->bdev, - size, 0, false); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object\n"); - return ret; - } - - *obj = &gbo->bo.base; - - return 0; -} diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index e1e48ba919eb..b5604d32122e 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -13,7 +13,9 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -133,7 +135,7 @@ static bool vbox_set_up_input_mapping(struct vbox_private *vbox) if (!fb1) { fb1 = fb; - if (to_vbox_framebuffer(fb1) == &vbox->afb) + if (fb1 == vbox->ddev.fb_helper->fb) break; } else if (fb != fb1) { single_framebuffer = false; @@ -172,8 +174,7 @@ static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y) { - struct drm_gem_vram_object *gbo = - drm_gem_vram_of_gem(to_vbox_framebuffer(fb)->obj); + struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(fb->obj[0]); struct vbox_private *vbox = crtc->dev->dev_private; struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc); bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state); @@ -283,10 +284,43 @@ static void vbox_primary_atomic_update(struct drm_plane *plane, { struct drm_crtc *crtc = plane->state->crtc; struct drm_framebuffer *fb = plane->state->fb; + struct vbox_private *vbox = fb->dev->dev_private; + struct drm_mode_rect *clips; + uint32_t num_clips, i; vbox_crtc_set_base_and_mode(crtc, fb, plane->state->src_x >> 16, plane->state->src_y >> 16); + + /* Send information about dirty rectangles to VBVA. */ + + clips = drm_plane_get_damage_clips(plane->state); + num_clips = drm_plane_get_damage_clips_count(plane->state); + + if (!num_clips) + return; + + mutex_lock(&vbox->hw_mutex); + + for (i = 0; i < num_clips; ++i, ++clips) { + struct vbva_cmd_hdr cmd_hdr; + unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id; + + cmd_hdr.x = (s16)clips->x1; + cmd_hdr.y = (s16)clips->y1; + cmd_hdr.w = (u16)clips->x2 - clips->x1; + cmd_hdr.h = (u16)clips->y2 - clips->y1; + + if (!vbva_buffer_begin_update(&vbox->vbva_info[crtc_id], + vbox->guest_pool)) + continue; + + vbva_write(&vbox->vbva_info[crtc_id], vbox->guest_pool, + &cmd_hdr, sizeof(cmd_hdr)); + vbva_buffer_end_update(&vbox->vbva_info[crtc_id]); + } + + mutex_unlock(&vbox->hw_mutex); } static void vbox_primary_atomic_disable(struct drm_plane *plane, @@ -309,7 +343,7 @@ static int vbox_primary_prepare_fb(struct drm_plane *plane, if (!new_state->fb) return 0; - gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(new_state->fb)->obj); + gbo = drm_gem_vram_of_gem(new_state->fb->obj[0]); ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); if (ret) DRM_WARN("Error %d pinning new fb, out of video mem?\n", ret); @@ -325,7 +359,7 @@ static void vbox_primary_cleanup_fb(struct drm_plane *plane, if (!old_state->fb) return; - gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(old_state->fb)->obj); + gbo = drm_gem_vram_of_gem(old_state->fb->obj[0]); drm_gem_vram_unpin(gbo); } @@ -386,8 +420,7 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, container_of(plane->dev, struct vbox_private, ddev); struct vbox_crtc *vbox_crtc = to_vbox_crtc(plane->state->crtc); struct drm_framebuffer *fb = plane->state->fb; - struct drm_gem_vram_object *gbo = - drm_gem_vram_of_gem(to_vbox_framebuffer(fb)->obj); + struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(fb->obj[0]); u32 width = plane->state->crtc_w; u32 height = plane->state->crtc_h; size_t data_size, mask_size; @@ -467,7 +500,7 @@ static int vbox_cursor_prepare_fb(struct drm_plane *plane, if (!new_state->fb) return 0; - gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(new_state->fb)->obj); + gbo = drm_gem_vram_of_gem(new_state->fb->obj[0]); return drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_SYSTEM); } @@ -479,7 +512,7 @@ static void vbox_cursor_cleanup_fb(struct drm_plane *plane, if (!plane->state->fb) return; - gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(plane->state->fb)->obj); + gbo = drm_gem_vram_of_gem(plane->state->fb->obj[0]); drm_gem_vram_unpin(gbo); } @@ -856,40 +889,8 @@ static int vbox_connector_init(struct drm_device *dev, return 0; } -static struct drm_framebuffer *vbox_user_framebuffer_create( - struct drm_device *dev, - struct drm_file *filp, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct vbox_private *vbox = - container_of(dev, struct vbox_private, ddev); - struct drm_gem_object *obj; - struct vbox_framebuffer *vbox_fb; - int ret = -ENOMEM; - - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL); - if (!vbox_fb) - goto err_unref_obj; - - ret = vbox_framebuffer_init(vbox, vbox_fb, mode_cmd, obj); - if (ret) - goto err_free_vbox_fb; - - return &vbox_fb->base; - -err_free_vbox_fb: - kfree(vbox_fb); -err_unref_obj: - drm_gem_object_put_unlocked(obj); - return ERR_PTR(ret); -} - static const struct drm_mode_config_funcs vbox_mode_funcs = { - .fb_create = vbox_user_framebuffer_create, + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 0853b980bcb3..1c62c6c9244b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -398,10 +398,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL); - frame.avi.right_bar = cstate->tv.margins.right; - frame.avi.left_bar = cstate->tv.margins.left; - frame.avi.top_bar = cstate->tv.margins.top; - frame.avi.bottom_bar = cstate->tv.margins.bottom; + drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); vc4_hdmi_write_infoframe(encoder, &frame); } diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index a5cb58754f7d..8dee698c90ff 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -184,7 +184,7 @@ MODULE_AUTHOR("Dave Airlie <airlied@redhat.com>"); MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); MODULE_AUTHOR("Alon Levy"); -DEFINE_DRM_GEM_SHMEM_FOPS(virtio_gpu_driver_fops); +DEFINE_DRM_GEM_FOPS(virtio_gpu_driver_fops); static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 314e02f94d9c..0b56ba005e25 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -267,8 +267,8 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev, uint32_t resource_id); void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, uint64_t offset, - __le32 width, __le32 height, - __le32 x, __le32 y, + uint32_t width, uint32_t height, + uint32_t x, uint32_t y, struct virtio_gpu_object_array *objs, struct virtio_gpu_fence *fence); void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev, diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 0b3cdb0d83b0..2f5773e43557 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -155,16 +155,15 @@ int virtio_gpu_init(struct drm_device *dev) #ifdef __LITTLE_ENDIAN if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL)) vgdev->has_virgl_3d = true; - DRM_INFO("virgl 3d acceleration %s\n", - vgdev->has_virgl_3d ? "enabled" : "not supported by host"); -#else - DRM_INFO("virgl 3d acceleration not supported by guest\n"); #endif if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) { vgdev->has_edid = true; - DRM_INFO("EDID support available.\n"); } + DRM_INFO("features: %cvirgl %cedid\n", + vgdev->has_virgl_3d ? '+' : '-', + vgdev->has_edid ? '+' : '-'); + ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); if (ret) { DRM_ERROR("failed to find virt queues\n"); diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 69a3d310ff70..017a9e0fc3bb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -86,7 +86,7 @@ static const struct drm_gem_object_funcs virtio_gpu_gem_funcs = { .get_sg_table = drm_gem_shmem_get_sg_table, .vmap = drm_gem_shmem_vmap, .vunmap = drm_gem_shmem_vunmap, - .vm_ops = &drm_gem_shmem_vm_ops, + .mmap = &drm_gem_shmem_mmap, }; struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev, diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index f4b7360282ce..390524143139 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -132,10 +132,10 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); virtio_gpu_cmd_transfer_to_host_2d (vgdev, 0, - cpu_to_le32(plane->state->src_w >> 16), - cpu_to_le32(plane->state->src_h >> 16), - cpu_to_le32(plane->state->src_x >> 16), - cpu_to_le32(plane->state->src_y >> 16), + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->src_x >> 16, + plane->state->src_y >> 16, objs, NULL); } } else { @@ -234,8 +234,8 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); virtio_gpu_cmd_transfer_to_host_2d (vgdev, 0, - cpu_to_le32(plane->state->crtc_w), - cpu_to_le32(plane->state->crtc_h), + plane->state->crtc_w, + plane->state->crtc_h, 0, 0, objs, vgfb->fence); dma_fence_wait(&vgfb->fence->f, true); dma_fence_put(&vgfb->fence->f); diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 80176f379ad5..74ad3bc3ebe8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -549,8 +549,8 @@ void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, uint64_t offset, - __le32 width, __le32 height, - __le32 x, __le32 y, + uint32_t width, uint32_t height, + uint32_t x, uint32_t y, struct virtio_gpu_object_array *objs, struct virtio_gpu_fence *fence) { @@ -571,10 +571,10 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D); cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle); cmd_p->offset = cpu_to_le64(offset); - cmd_p->r.width = width; - cmd_p->r.height = height; - cmd_p->r.x = x; - cmd_p->r.y = y; + cmd_p->r.width = cpu_to_le32(width); + cmd_p->r.height = cpu_to_le32(height); + cmd_p->r.x = cpu_to_le32(x); + cmd_p->r.y = cpu_to_le32(y); virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 80524a22412a..d1fe144aa289 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -11,13 +11,14 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <drm/drm_gem.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_file.h> -#include <drm/drm_gem.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_probe_helper.h> @@ -103,6 +104,8 @@ static struct drm_driver vkms_driver = { .gem_vm_ops = &vkms_gem_vm_ops, .gem_free_object_unlocked = vkms_gem_free_object, .get_vblank_timestamp = vkms_get_vblank_timestamp, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import_sg_table = vkms_prime_import_sg_table, .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -157,6 +160,14 @@ static int __init vkms_init(void) if (ret) goto out_unregister; + ret = dma_coerce_mask_and_coherent(vkms_device->drm.dev, + DMA_BIT_MASK(64)); + + if (ret) { + DRM_ERROR("Could not initialize DMA support\n"); + goto out_fini; + } + vkms_device->drm.irq_enabled = true; ret = drm_vblank_init(&vkms_device->drm, 1); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 5a95100fa18b..7d52e24564db 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -137,6 +137,12 @@ int vkms_gem_vmap(struct drm_gem_object *obj); void vkms_gem_vunmap(struct drm_gem_object *obj); +/* Prime */ +struct drm_gem_object * +vkms_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sg); + /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, size_t *count); diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c index 6489bfe0a149..2e01186fb943 100644 --- a/drivers/gpu/drm/vkms/vkms_gem.c +++ b/drivers/gpu/drm/vkms/vkms_gem.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0+ +#include <linux/dma-buf.h> #include <linux/shmem_fs.h> #include <linux/vmalloc.h> +#include <drm/drm_prime.h> #include "vkms_drv.h" @@ -218,3 +220,28 @@ out: mutex_unlock(&vkms_obj->pages_lock); return ret; } + +struct drm_gem_object * +vkms_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sg) +{ + struct vkms_gem_object *obj; + int npages; + + obj = __vkms_gem_create(dev, attach->dmabuf->size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + + npages = PAGE_ALIGN(attach->dmabuf->size) / PAGE_SIZE; + DRM_DEBUG_PRIME("Importing %d pages\n", npages); + + obj->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); + if (!obj->pages) { + vkms_gem_free_object(&obj->gem); + return ERR_PTR(-ENOMEM); + } + + drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages); + return &obj->gem; +} diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 4b3e863c4f8a..fbf3812c4326 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -126,6 +126,7 @@ struct dw_hdmi_plat_data { const struct drm_display_mode *mode); unsigned long input_bus_format; unsigned long input_bus_encoding; + bool use_drm_infoframe; /* Vendor PHY support */ const struct dw_hdmi_phy_ops *phy_ops; diff --git a/include/drm/drmP.h b/include/drm/drmP.h deleted file mode 100644 index 037b1f7a87a5..000000000000 --- a/include/drm/drmP.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Internal Header for the Direct Rendering Manager - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright (c) 2009-2010, Code Aurora Forum. - * All rights reserved. - * - * Author: Rickard E. (Rik) Faith <faith@valinux.com> - * Author: Gareth Hughes <gareth@valinux.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * 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 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 - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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_P_H_ -#define _DRM_P_H_ - -#include <linux/agp_backend.h> -#include <linux/cdev.h> -#include <linux/dma-mapping.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/highmem.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/kref.h> -#include <linux/miscdevice.h> -#include <linux/mm.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/poll.h> -#include <linux/ratelimit.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/workqueue.h> -#include <linux/dma-fence.h> -#include <linux/module.h> -#include <linux/mman.h> -#include <asm/pgalloc.h> -#include <linux/uaccess.h> - -#include <uapi/drm/drm.h> -#include <uapi/drm/drm_mode.h> - -#include <drm/drm_agpsupport.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_hashtab.h> -#include <drm/drm_mm.h> -#include <drm/drm_os_linux.h> -#include <drm/drm_sarea.h> -#include <drm/drm_drv.h> -#include <drm/drm_prime.h> -#include <drm/drm_print.h> -#include <drm/drm_pci.h> -#include <drm/drm_file.h> -#include <drm/drm_debugfs.h> -#include <drm/drm_ioctl.h> -#include <drm/drm_sysfs.h> -#include <drm/drm_vblank.h> -#include <drm/drm_irq.h> -#include <drm/drm_device.h> - -struct module; - -struct device_node; -struct videomode; -struct dma_resv; -struct dma_buf_attachment; - -struct pci_dev; -struct pci_controller; - -/* - * NOTE: drmP.h is obsolete - do NOT add anything to this file - * - * Do not include drmP.h in new files. - * Work is ongoing to remove drmP.h includes from existing files - */ - -#endif diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index ed1a985745ba..51ecb5112ef8 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -23,9 +23,9 @@ #ifndef _DRM_DP_HELPER_H_ #define _DRM_DP_HELPER_H_ -#include <linux/types.h> -#include <linux/i2c.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/types.h> /* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that @@ -137,6 +137,7 @@ # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */ #define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0) #define DP_DOWN_STREAM_PORT_COUNT 0x007 # define DP_PORT_COUNT_MASK 0x0f @@ -604,6 +605,14 @@ # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 #define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +# define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +# define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +# define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +# define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +# define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +# define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +# define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +# define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6 #define DP_TEST_REQUEST 0x218 # define DP_TEST_LINK_TRAINING (1 << 0) @@ -1008,6 +1017,36 @@ #define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 #define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 +/* Link Training (LT)-tunable PHY Repeaters */ +#define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */ +#define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */ +#define DP_PHY_REPEATER_CNT 0xf0002 /* 1.3 */ +#define DP_PHY_REPEATER_MODE 0xf0003 /* 1.3 */ +#define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ +#define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ +#define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ +#define DP_TRAINING_PATTERN_SET_PHY_REPEATER1 0xf0010 /* 1.3 */ +#define DP_TRAINING_LANE0_SET_PHY_REPEATER1 0xf0011 /* 1.3 */ +#define DP_TRAINING_LANE1_SET_PHY_REPEATER1 0xf0012 /* 1.3 */ +#define DP_TRAINING_LANE2_SET_PHY_REPEATER1 0xf0013 /* 1.3 */ +#define DP_TRAINING_LANE3_SET_PHY_REPEATER1 0xf0014 /* 1.3 */ +#define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0020 /* 1.4a */ +#define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1 0xf0021 /* 1.4a */ +#define DP_LANE0_1_STATUS_PHY_REPEATER1 0xf0030 /* 1.3 */ +#define DP_LANE2_3_STATUS_PHY_REPEATER1 0xf0031 /* 1.3 */ +#define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1 0xf0032 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 0xf0033 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1 0xf0034 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE0_PHY_REPEATER1 0xf0035 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE1_PHY_REPEATER1 0xf0037 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE2_PHY_REPEATER1 0xf0039 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE3_PHY_REPEATER1 0xf003b /* 1.3 */ +#define DP_FEC_STATUS_PHY_REPEATER1 0xf0290 /* 1.4 */ + +/* Repeater modes */ +#define DP_PHY_REPEATER_MODE_TRANSPARENT 0x55 /* 1.3 */ +#define DP_PHY_REPEATER_MODE_NON_TRANSPARENT 0xaa /* 1.3 */ + /* DP HDCP message start offsets in DPCD address space */ #define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET #define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET @@ -1091,6 +1130,8 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); +u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane); #define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf @@ -1186,6 +1227,13 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } static inline bool +drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING); +} + +static inline bool drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { return dpcd[DP_DPCD_REV] >= 0x12 && @@ -1250,6 +1298,19 @@ drm_dp_sink_supports_fec(const u8 fec_capable) return fec_capable & DP_FEC_CAPABLE; } +static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; +} + +static inline bool +drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_EDP_CONFIGURATION_CAP] & + DP_ALTERNATE_SCRAMBLER_RESET_CAP; +} + /* * DisplayPort AUX channel */ @@ -1394,22 +1455,6 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, u8 status[DP_LINK_STATUS_SIZE]); -/* - * DisplayPort link - */ -#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) - -struct drm_dp_link { - unsigned char revision; - unsigned int rate; - unsigned int num_lanes; - unsigned long capabilities; -}; - -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b9719418c3d2..f0b03d401c27 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -368,6 +368,10 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state); void +drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); + +void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, struct drm_connector *connector, const struct drm_display_mode *mode, @@ -481,7 +485,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); int drm_add_override_edid_modes(struct drm_connector *connector); u8 drm_match_cea_mode(const struct drm_display_mode *to_match); -enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); bool drm_detect_hdmi_monitor(struct edid *edid); bool drm_detect_monitor_audio(struct edid *edid); enum hdmi_quantization_range diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 6aaba14f5972..e71f75a2ab57 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -151,6 +151,20 @@ struct drm_gem_object_funcs { void (*vunmap)(struct drm_gem_object *obj, void *vaddr); /** + * @mmap: + * + * Handle mmap() of the gem object, setup vma accordingly. + * + * This callback is optional. + * + * The callback is used by by both drm_gem_mmap_obj() and + * drm_gem_prime_mmap(). When @mmap is present @vm_ops is not + * used, the @mmap callback must set vma->vm_ops instead. + * + */ + int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma); + + /** * @vm_ops: * * Virtual memory operations used with mmap. diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 01f514521687..6748379a0b44 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -88,32 +88,6 @@ struct drm_gem_shmem_object { #define to_drm_gem_shmem_obj(obj) \ container_of(obj, struct drm_gem_shmem_object, base) -/** - * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers - * @name: name for the generated structure - * - * This macro autogenerates a suitable &struct file_operations for shmem based - * drivers, which can be assigned to &drm_driver.fops. Note that this structure - * cannot be shared between drivers, because it contains a reference to the - * current module using THIS_MODULE. - * - * Note that the declaration is already marked as static - if you need a - * non-static version of this you're probably doing it wrong and will break the - * THIS_MODULE reference by accident. - */ -#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \ - static const struct file_operations name = {\ - .owner = THIS_MODULE,\ - .open = drm_open,\ - .release = drm_release,\ - .unlocked_ioctl = drm_ioctl,\ - .compat_ioctl = drm_compat_ioctl,\ - .poll = drm_poll,\ - .read = drm_read,\ - .llseek = noop_llseek,\ - .mmap = drm_gem_shmem_mmap, \ - } - struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); void drm_gem_shmem_free_object(struct drm_gem_object *obj); @@ -143,9 +117,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv, int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); -int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma); - -extern const struct vm_operations_struct drm_gem_shmem_vm_ops; +int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj); diff --git a/include/drm/drm_gem_ttm_helper.h b/include/drm/drm_gem_ttm_helper.h index 6268f89c5a48..118cef76f84f 100644 --- a/include/drm/drm_gem_ttm_helper.h +++ b/include/drm/drm_gem_ttm_helper.h @@ -15,5 +15,7 @@ void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *gem); +int drm_gem_ttm_mmap(struct drm_gem_object *gem, + struct vm_area_struct *vma); #endif diff --git a/include/drm/drm_gem_vram_helper.h b/include/drm/drm_gem_vram_helper.h index 354a9cd358a3..b8ad4531ebb4 100644 --- a/include/drm/drm_gem_vram_helper.h +++ b/include/drm/drm_gem_vram_helper.h @@ -184,29 +184,4 @@ struct drm_vram_mm *drm_vram_helper_alloc_mm( struct drm_device *dev, uint64_t vram_base, size_t vram_size); void drm_vram_helper_release_mm(struct drm_device *dev); -/* - * Helpers for &struct file_operations - */ - -int drm_vram_mm_file_operations_mmap( - struct file *filp, struct vm_area_struct *vma); - -/** - * define DRM_VRAM_MM_FILE_OPERATIONS - default callback functions for \ - &struct file_operations - * - * Drivers that use VRAM MM can use this macro to initialize - * &struct file_operations with default functions. - */ -#define DRM_VRAM_MM_FILE_OPERATIONS \ - .llseek = no_llseek, \ - .read = drm_read, \ - .poll = drm_poll, \ - .unlocked_ioctl = drm_ioctl, \ - .compat_ioctl = drm_compat_ioctl, \ - .mmap = drm_vram_mm_file_operations_mmap, \ - .open = drm_open, \ - .release = drm_release \ - - #endif diff --git a/include/drm/drm_os_linux.h b/include/drm/drm_os_linux.h deleted file mode 100644 index ee8d61b64f29..000000000000 --- a/include/drm/drm_os_linux.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/** - * \file drm_os_linux.h - * OS abstraction macros. - */ - -#include <linux/interrupt.h> /* For task queue support */ -#include <linux/sched/signal.h> -#include <linux/delay.h> -#include <linux/io-64-nonatomic-lo-hi.h> - -/** Current process ID */ -#define DRM_CURRENTPID task_pid_nr(current) -#define DRM_UDELAY(d) udelay(d) -/** Read a byte from a MMIO region */ -#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) -/** Read a word from a MMIO region */ -#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset)) -/** Read a dword from a MMIO region */ -#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset)) -/** Write a byte into a MMIO region */ -#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset)) -/** Write a word into a MMIO region */ -#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset)) -/** Write a dword into a MMIO region */ -#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset)) - -/** Read a qword from a MMIO region - be careful using these unless you really understand them */ -#define DRM_READ64(map, offset) readq(((void __iomem *)(map)->handle) + (offset)) -/** Write a qword into a MMIO region */ -#define DRM_WRITE64(map, offset, val) writeq(val, ((void __iomem *)(map)->handle) + (offset)) - -#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ -do { \ - DECLARE_WAITQUEUE(entry, current); \ - unsigned long end = jiffies + (timeout); \ - add_wait_queue(&(queue), &entry); \ - \ - for (;;) { \ - __set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (time_after_eq(jiffies, end)) { \ - ret = -EBUSY; \ - break; \ - } \ - schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ - if (signal_pending(current)) { \ - ret = -EINTR; \ - break; \ - } \ - } \ - __set_current_state(TASK_RUNNING); \ - remove_wait_queue(&(queue), &entry); \ -} while (0) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index cd5903ad33f7..3f396d94afe4 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -140,10 +140,11 @@ struct drm_plane_state { * @zpos: * Priority of the given plane on crtc (optional). * - * Note that multiple active planes on the same crtc can have an - * identical zpos value. The rule to solving the conflict is to compare - * the plane object IDs; the plane with a higher ID must be stacked on - * top of a plane with a lower ID. + * User-space may set mutable zpos properties so that multiple active + * planes on the same CRTC have identical zpos values. This is a + * user-space bug, but drivers can solve the conflict by comparing the + * plane object IDs; the plane with a higher ID is stacked on top of a + * plane with a lower ID. * * See drm_plane_create_zpos_property() and * drm_plane_create_zpos_immutable_property() for more details. @@ -183,8 +184,26 @@ struct drm_plane_state { */ struct drm_property_blob *fb_damage_clips; - /** @src: clipped source coordinates of the plane (in 16.16) */ - /** @dst: clipped destination coordinates of the plane */ + /** + * @src: + * + * source coordinates of the plane (in 16.16). + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ + /** + * @dst: + * + * clipped destination coordinates of the plane. + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ struct drm_rect src, dst; /** diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 43c4929a2171..d2277e06316d 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -710,16 +710,14 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map); /** - * ttm_fbdev_mmap - mmap fbdev memory backed by a ttm buffer object. + * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object. * * @vma: vma as input from the fbdev mmap method. - * @bo: The bo backing the address space. The address space will - * have the same size as the bo, and start at offset 0. + * @bo: The bo backing the address space. * - * This function is intended to be called by the fbdev mmap method - * if the fbdev address space is to be backed by a bo. + * Maps a buffer object. */ -int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); +int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo); /** * ttm_bo_mmap - mmap out of the ttm device address space. diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 8a5b2f8f8eb9..868bf7996c0f 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -778,11 +778,12 @@ struct drm_syncobj_array { __u32 pad; }; +#define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */ struct drm_syncobj_timeline_array { __u64 handles; __u64 points; __u32 count_handles; - __u32 pad; + __u32 flags; }; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 2376d36ea573..8caaaf7ff91b 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -69,7 +69,7 @@ extern "C" { #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ((__u32)(c) << 16) | ((__u32)(d) << 24)) -#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ +#define DRM_FORMAT_BIG_ENDIAN (1U<<31) /* format is big endian instead of little endian */ /* Reserve 0 for the invalid format specifier */ #define DRM_FORMAT_INVALID 0 diff --git a/include/uapi/drm/omap_drm.h b/include/uapi/drm/omap_drm.h index 1fccffef9e27..5a142fad473c 100644 --- a/include/uapi/drm/omap_drm.h +++ b/include/uapi/drm/omap_drm.h @@ -38,20 +38,20 @@ struct drm_omap_param { __u64 value; /* in (set_param), out (get_param) */ }; -#define OMAP_BO_SCANOUT 0x00000001 /* scanout capable (phys contiguous) */ -#define OMAP_BO_CACHE_MASK 0x00000006 /* cache type mask, see cache modes */ -#define OMAP_BO_TILED_MASK 0x00000f00 /* tiled mapping mask, see tiled modes */ +/* Scanout buffer, consumable by DSS */ +#define OMAP_BO_SCANOUT 0x00000001 -/* cache modes */ -#define OMAP_BO_CACHED 0x00000000 /* default */ -#define OMAP_BO_WC 0x00000002 /* write-combine */ -#define OMAP_BO_UNCACHED 0x00000004 /* strongly-ordered (uncached) */ +/* Buffer CPU caching mode: cached, write-combining or uncached. */ +#define OMAP_BO_CACHED 0x00000000 +#define OMAP_BO_WC 0x00000002 +#define OMAP_BO_UNCACHED 0x00000004 +#define OMAP_BO_CACHE_MASK 0x00000006 -/* tiled modes */ +/* Use TILER for the buffer. The TILER container unit can be 8, 16 or 32 bits. */ #define OMAP_BO_TILED_8 0x00000100 #define OMAP_BO_TILED_16 0x00000200 #define OMAP_BO_TILED_32 0x00000300 -#define OMAP_BO_TILED (OMAP_BO_TILED_8 | OMAP_BO_TILED_16 | OMAP_BO_TILED_32) +#define OMAP_BO_TILED_MASK 0x00000f00 union omap_gem_size { __u32 bytes; /* (for non-tiled formats) */ |