summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml3
-rw-r--r--Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml22
-rw-r--r--Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml59
-rw-r--r--Documentation/devicetree/bindings/display/sitronix,st7735r.yaml6
-rw-r--r--Documentation/gpu/drm-mm.rst9
-rw-r--r--Documentation/gpu/drm-uapi.rst4
-rw-r--r--MAINTAINERS11
-rw-r--r--arch/x86/Kconfig6
-rw-r--r--arch/x86/boot/video-vesa.c4
-rw-r--r--drivers/dma-buf/dma-buf.c2
-rw-r--r--drivers/dma-buf/dma-resv.c142
-rw-r--r--drivers/dma-buf/st-dma-resv.c64
-rw-r--r--drivers/firmware/Kconfig6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c53
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c49
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c78
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c2
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_plane.c13
-rw-r--r--drivers/gpu/drm/bridge/Kconfig2
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c1
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c20
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.c36
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c497
-rw-r--r--drivers/gpu/drm/bridge/ite-it66121.c629
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9611.c49
-rw-r--r--drivers/gpu/drm/bridge/nwl-dsi.c30
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c7
-rw-r--r--drivers/gpu/drm/bridge/panel.c3
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c7
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8640.c9
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c51
-rw-r--r--drivers/gpu/drm/bridge/tc358762.c9
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c104
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c585
-rw-r--r--drivers/gpu/drm/bridge/tc358775.c11
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c17
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c8
-rw-r--r--drivers/gpu/drm/drm_atomic.c20
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c4
-rw-r--r--drivers/gpu/drm/drm_blend.c2
-rw-r--r--drivers/gpu/drm/drm_bridge_connector.c4
-rw-r--r--drivers/gpu/drm/drm_edid.c620
-rw-r--r--drivers/gpu/drm/drm_format_helper.c76
-rw-r--r--drivers/gpu/drm/drm_gem.c80
-rw-r--r--drivers/gpu/drm/drm_gem_atomic_helper.c18
-rw-r--r--drivers/gpu/drm/drm_gem_vram_helper.c2
-rw-r--r--drivers/gpu/drm/drm_modes.c17
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.h5
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c67
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c63
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c241
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c22
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c11
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c6
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c9
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_dp.c6
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c5
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_lvds.c5
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c10
-rw-r--r--drivers/gpu/drm/gma500/gem.c161
-rw-r--r--drivers/gpu/drm/gma500/gem.h13
-rw-r--r--drivers/gpu/drm/gma500/gma_display.c53
-rw-r--r--drivers/gpu/drm/gma500/gma_display.h10
-rw-r--r--drivers/gpu/drm/gma500/gtt.c295
-rw-r--r--drivers/gpu/drm/gma500/gtt.h8
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_crtc.c25
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_device.c1
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c1
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c16
-rw-r--r--drivers/gpu/drm/gma500/opregion.c5
-rw-r--r--drivers/gpu/drm/gma500/power.c15
-rw-r--r--drivers/gpu/drm/gma500/psb_device.c29
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c29
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h90
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c39
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_lvds.c5
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c6
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.c94
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.h19
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_clflush.c3
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c10
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c6
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_migrate.c5
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c10
-rw-r--r--drivers/gpu/drm/i915/selftests/intel_memory_region.c7
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c3
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c34
-rw-r--r--drivers/gpu/drm/lima/lima_gem.c10
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi.c43
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c12
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c18
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/atom.h6
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/crc.c27
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.c14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c198
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.h3
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c5
-rw-r--r--drivers/gpu/drm/omapdrm/omap_overlay.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig9
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-abt-y030xx067a.c30
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c2
-rw-r--r--drivers/gpu/drm/panel/panel-innolux-ej030na.c31
-rw-r--r--drivers/gpu/drm/panel/panel-newvision-nv3052c.c482
-rw-r--r--drivers/gpu/drm/panel/panel-truly-nt35597.c3
-rw-r--r--drivers/gpu/drm/panel/panel-visionox-rm69299.c4
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_job.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c2
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c2
-rw-r--r--drivers/gpu/drm/selftests/test-drm_buddy.c10
-rw-r--r--drivers/gpu/drm/solomon/Kconfig2
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c42
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c8
-rw-r--r--drivers/gpu/drm/tiny/repaper.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_agp_backend.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c225
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c13
-rw-r--r--drivers/gpu/drm/ttm/ttm_device.c82
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c15
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c197
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c12
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c15
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c14
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h15
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c442
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.h23
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi_phy.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi_regs.h6
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c127
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c48
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h28
-rw-r--r--drivers/gpu/drm/vc4/vc4_trace.h95
-rw-r--r--drivers/gpu/drm/vgem/vgem_fence.c12
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c9
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ioctl.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c16
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h23
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c28
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c27
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c81
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c445
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h29
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c36
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c19
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c17
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c27
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c2
-rw-r--r--drivers/infiniband/core/umem_dmabuf.c8
-rw-r--r--drivers/video/fbdev/Kconfig14
-rw-r--r--drivers/video/fbdev/core/fb_defio.c9
-rw-r--r--include/drm/drm_atomic.h27
-rw-r--r--include/drm/drm_edid.h12
-rw-r--r--include/drm/drm_file.h2
-rw-r--r--include/drm/drm_format_helper.h5
-rw-r--r--include/drm/drm_gem.h5
-rw-r--r--include/drm/drm_mipi_dsi.h2
-rw-r--r--include/drm/drm_modes.h2
-rw-r--r--include/drm/drm_modeset_helper_vtables.h2
-rw-r--r--include/drm/gpu_scheduler.h1
-rw-r--r--include/drm/ttm/ttm_bo_api.h62
-rw-r--r--include/drm/ttm/ttm_bo_driver.h29
-rw-r--r--include/drm/ttm/ttm_device.h11
-rw-r--r--include/drm/ttm/ttm_resource.h74
-rw-r--r--include/drm/ttm/ttm_tt.h4
-rw-r--r--include/linux/dma-buf.h4
-rw-r--r--include/linux/dma-resv.h73
-rw-r--r--include/linux/efi.h4
-rw-r--r--include/uapi/drm/vmwgfx_drm.h9
195 files changed, 5768 insertions, 2763 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
index 6ec1d5fbb8bc..c6e81f532215 100644
--- a/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
@@ -38,6 +38,9 @@ properties:
interrupts:
maxItems: 1
+ "#sound-dai-cells":
+ const: 0
+
ports:
$ref: /schemas/graph.yaml#/properties/ports
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml
index f1541cc05297..ed280053ec62 100644
--- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml
@@ -53,16 +53,32 @@ properties:
properties:
port@0:
- $ref: /schemas/graph.yaml#/properties/port
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
description: |
DSI input port. The remote endpoint phandle should be a
reference to a valid DSI output endpoint node
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ description: array of physical DSI data lane indexes.
+ minItems: 1
+ items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: |
- DPI input port. The remote endpoint phandle should be a
- reference to a valid DPI output endpoint node
+ DPI input/output port. The remote endpoint phandle should be a
+ reference to a valid DPI output or input endpoint node.
port@2:
$ref: /schemas/graph.yaml#/properties/port
diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml
new file mode 100644
index 000000000000..817a9bed7d5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/leadtek,ltk035c5444t.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Leadtek ltk035c5444t 3.5" (640x480 pixels) 24-bit IPS LCD panel
+
+maintainers:
+ - Paul Cercueil <paul@crapouillou.net>
+ - Christophe Branchereau <cbranchereau@gmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: leadtek,ltk035c5444t
+
+ backlight: true
+ port: true
+ power-supply: true
+ reg: true
+ reset-gpios: true
+
+required:
+ - compatible
+ - power-supply
+ - reset-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ panel@0 {
+ compatible = "leadtek,ltk035c5444t";
+ reg = <0>;
+
+ spi-3wire;
+ spi-max-frequency = <3125000>;
+
+ reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>;
+
+ backlight = <&backlight>;
+ power-supply = <&vcc>;
+
+ port {
+ panel_input: endpoint {
+ remote-endpoint = <&panel_output>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml b/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
index 0cebaaefda03..157b1a7b18f9 100644
--- a/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
+++ b/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
@@ -32,15 +32,13 @@ properties:
- okaya,rh128128t
- const: sitronix,st7715r
- spi-max-frequency:
- maximum: 32000000
-
dc-gpios:
maxItems: 1
description: Display data/command selection (D/CX)
backlight: true
reg: true
+ spi-max-frequency: true
reset-gpios: true
rotation: true
@@ -48,7 +46,6 @@ required:
- compatible
- reg
- dc-gpios
- - reset-gpios
additionalProperties: false
@@ -72,6 +69,7 @@ examples:
dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>;
rotation = <270>;
+ backlight = <&backlight>;
};
};
diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index 198bcc1affa1..f32ccce5722d 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -466,6 +466,15 @@ DRM MM Range Allocator Function References
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
:export:
+DRM Buddy Allocator
+===================
+
+DRM Buddy Function References
+-----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_buddy.c
+ :export:
+
DRM Cache Handling and Fast WC memcpy()
=======================================
diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst
index 199afb503ab1..ce47b4292481 100644
--- a/Documentation/gpu/drm-uapi.rst
+++ b/Documentation/gpu/drm-uapi.rst
@@ -148,7 +148,9 @@ clients together with the legacy drmAuth authentication procedure.
If a driver advertises render node support, DRM core will create a
separate render node called renderD<num>. There will be one render node
per device. No ioctls except PRIME-related ioctls will be allowed on
-this node. Especially GEM_OPEN will be explicitly prohibited. Render
+this node. Especially GEM_OPEN will be explicitly prohibited. For a
+complete list of driver-independent ioctls that can be used on render
+nodes, see the ioctls marked DRM_RENDER_ALLOW in drm_ioctl.c Render
nodes are designed to avoid the buffer-leaks, which occur if clients
guess the flink names or mmap offsets on the legacy interface.
Additionally to this basic interface, drivers must mark their
diff --git a/MAINTAINERS b/MAINTAINERS
index 61d9f114c37f..9b2b0dc44506 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6308,6 +6308,11 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.yaml
F: drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
+DRM DRIVER FOR PARADE PS8640 BRIDGE CHIP
+R: Douglas Anderson <dianders@chromium.org>
+F: Documentation/devicetree/bindings/display/bridge/ps8640.yaml
+F: drivers/gpu/drm/bridge/parade-ps8640.c
+
DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
M: Noralf Trønnes <noralf@tronnes.org>
S: Maintained
@@ -6421,6 +6426,11 @@ DRM DRIVER FOR TDFX VIDEO CARDS
S: Orphan / Obsolete
F: drivers/gpu/drm/tdfx/
+DRM DRIVER FOR TI SN65DSI86 BRIDGE CHIP
+R: Douglas Anderson <dianders@chromium.org>
+F: Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml
+F: drivers/gpu/drm/bridge/ti-sn65dsi86.c
+
DRM DRIVER FOR TPO TPG110 PANELS
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
@@ -6540,6 +6550,7 @@ R: Jonas Karlman <jonas@kwiboo.se>
R: Jernej Skrabec <jernej.skrabec@gmail.com>
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
+F: Documentation/devicetree/bindings/display/bridge/
F: drivers/gpu/drm/bridge/
DRM DRIVERS FOR EXYNOS
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b0142e01002e..374d3e85c1f1 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -940,6 +940,12 @@ config GART_IOMMU
If unsure, say Y.
+config BOOT_VESA_SUPPORT
+ bool
+ help
+ If true, at least one selected framebuffer driver can take advantage
+ of VESA video modes set at an early boot stage via the vga= parameter.
+
config MAXSMP
bool "Enable Maximum number of SMP Processors and NUMA Nodes"
depends on X86_64 && SMP && DEBUG_KERNEL
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 7e185977a984..c2c6d35e3a43 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -83,7 +83,7 @@ static int vesa_probe(void)
(vminfo.memory_layout == 4 ||
vminfo.memory_layout == 6) &&
vminfo.memory_planes == 1) {
-#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
+#ifdef CONFIG_BOOT_VESA_SUPPORT
/* Graphics mode, color, linear frame buffer
supported. Only register the mode if
if framebuffer is configured, however,
@@ -121,7 +121,7 @@ static int vesa_set_mode(struct mode_info *mode)
if ((vminfo.mode_attr & 0x15) == 0x05) {
/* It's a supported text mode */
is_graphic = 0;
-#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
+#ifdef CONFIG_BOOT_VESA_SUPPORT
} else if ((vminfo.mode_attr & 0x99) == 0x99) {
/* It's a graphics mode with linear frame buffer */
is_graphic = 1;
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index df23239b04fc..775d3afb4169 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -443,7 +443,7 @@ err_alloc_file:
* as a file descriptor by calling dma_buf_fd().
*
* 2. Userspace passes this file-descriptors to all drivers it wants this buffer
- * to share with: First the filedescriptor is converted to a &dma_buf using
+ * to share with: First the file descriptor is converted to a &dma_buf using
* dma_buf_get(). Then the buffer is attached to the device using
* dma_buf_attach().
*
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index b51416405e86..8c650b96357a 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -34,6 +34,7 @@
*/
#include <linux/dma-resv.h>
+#include <linux/dma-fence-array.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/sched/mm.h>
@@ -56,6 +57,12 @@
DEFINE_WD_CLASS(reservation_ww_class);
EXPORT_SYMBOL(reservation_ww_class);
+struct dma_resv_list {
+ struct rcu_head rcu;
+ u32 shared_count, shared_max;
+ struct dma_fence __rcu *shared[];
+};
+
/**
* dma_resv_list_alloc - allocate fence list
* @shared_max: number of fences we need space for
@@ -133,8 +140,19 @@ void dma_resv_fini(struct dma_resv *obj)
}
EXPORT_SYMBOL(dma_resv_fini);
+static inline struct dma_fence *
+dma_resv_excl_fence(struct dma_resv *obj)
+{
+ return rcu_dereference_check(obj->fence_excl, dma_resv_held(obj));
+}
+
+static inline struct dma_resv_list *dma_resv_shared_list(struct dma_resv *obj)
+{
+ return rcu_dereference_check(obj->fence, dma_resv_held(obj));
+}
+
/**
- * dma_resv_reserve_shared - Reserve space to add shared fences to
+ * dma_resv_reserve_fences - Reserve space to add shared fences to
* a dma_resv.
* @obj: reservation object
* @num_fences: number of fences we want to add
@@ -149,7 +167,7 @@ EXPORT_SYMBOL(dma_resv_fini);
* RETURNS
* Zero for success, or -errno
*/
-int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
+int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences)
{
struct dma_resv_list *old, *new;
unsigned int i, j, k, max;
@@ -212,7 +230,7 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
return 0;
}
-EXPORT_SYMBOL(dma_resv_reserve_shared);
+EXPORT_SYMBOL(dma_resv_reserve_fences);
#ifdef CONFIG_DEBUG_MUTEXES
/**
@@ -220,7 +238,7 @@ EXPORT_SYMBOL(dma_resv_reserve_shared);
* @obj: the dma_resv object to reset
*
* Reset the number of pre-reserved shared slots to test that drivers do
- * correct slot allocation using dma_resv_reserve_shared(). See also
+ * correct slot allocation using dma_resv_reserve_fences(). See also
* &dma_resv_list.shared_max.
*/
void dma_resv_reset_shared_max(struct dma_resv *obj)
@@ -242,7 +260,7 @@ EXPORT_SYMBOL(dma_resv_reset_shared_max);
* @fence: the shared fence to add
*
* Add a fence to a shared slot, @obj must be locked with dma_resv_lock(), and
- * dma_resv_reserve_shared() has been called.
+ * dma_resv_reserve_fences() has been called.
*
* See also &dma_resv.fence for a discussion of the semantics.
*/
@@ -290,40 +308,71 @@ replace:
EXPORT_SYMBOL(dma_resv_add_shared_fence);
/**
+ * dma_resv_replace_fences - replace fences in the dma_resv obj
+ * @obj: the reservation object
+ * @context: the context of the fences to replace
+ * @replacement: the new fence to use instead
+ *
+ * Replace fences with a specified context with a new fence. Only valid if the
+ * operation represented by the original fence has no longer access to the
+ * resources represented by the dma_resv object when the new fence completes.
+ *
+ * And example for using this is replacing a preemption fence with a page table
+ * update fence which makes the resource inaccessible.
+ */
+void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
+ struct dma_fence *replacement)
+{
+ struct dma_resv_list *list;
+ struct dma_fence *old;
+ unsigned int i;
+
+ dma_resv_assert_held(obj);
+
+ write_seqcount_begin(&obj->seq);
+
+ old = dma_resv_excl_fence(obj);
+ if (old->context == context) {
+ RCU_INIT_POINTER(obj->fence_excl, dma_fence_get(replacement));
+ dma_fence_put(old);
+ }
+
+ list = dma_resv_shared_list(obj);
+ for (i = 0; list && i < list->shared_count; ++i) {
+ old = rcu_dereference_protected(list->shared[i],
+ dma_resv_held(obj));
+ if (old->context != context)
+ continue;
+
+ rcu_assign_pointer(list->shared[i], dma_fence_get(replacement));
+ dma_fence_put(old);
+ }
+
+ write_seqcount_end(&obj->seq);
+}
+EXPORT_SYMBOL(dma_resv_replace_fences);
+
+/**
* dma_resv_add_excl_fence - Add an exclusive fence.
* @obj: the reservation object
* @fence: the exclusive fence to add
*
* Add a fence to the exclusive slot. @obj must be locked with dma_resv_lock().
- * Note that this function replaces all fences attached to @obj, see also
- * &dma_resv.fence_excl for a discussion of the semantics.
+ * See also &dma_resv.fence_excl for a discussion of the semantics.
*/
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
{
struct dma_fence *old_fence = dma_resv_excl_fence(obj);
- struct dma_resv_list *old;
- u32 i = 0;
dma_resv_assert_held(obj);
- old = dma_resv_shared_list(obj);
- if (old)
- i = old->shared_count;
-
dma_fence_get(fence);
write_seqcount_begin(&obj->seq);
/* write_seqcount_begin provides the necessary memory barrier */
RCU_INIT_POINTER(obj->fence_excl, fence);
- if (old)
- old->shared_count = 0;
write_seqcount_end(&obj->seq);
- /* inplace update, no shared fences */
- while (i--)
- dma_fence_put(rcu_dereference_protected(old->shared[i],
- dma_resv_held(obj)));
-
dma_fence_put(old_fence);
}
EXPORT_SYMBOL(dma_resv_add_excl_fence);
@@ -595,6 +644,59 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
EXPORT_SYMBOL_GPL(dma_resv_get_fences);
/**
+ * dma_resv_get_singleton - Get a single fence for all the fences
+ * @obj: the reservation object
+ * @write: true if we should return all fences
+ * @fence: the resulting fence
+ *
+ * Get a single fence representing all the fences inside the resv object.
+ * Returns either 0 for success or -ENOMEM.
+ *
+ * Warning: This can't be used like this when adding the fence back to the resv
+ * object since that can lead to stack corruption when finalizing the
+ * dma_fence_array.
+ *
+ * Returns 0 on success and negative error values on failure.
+ */
+int dma_resv_get_singleton(struct dma_resv *obj, bool write,
+ struct dma_fence **fence)
+{
+ struct dma_fence_array *array;
+ struct dma_fence **fences;
+ unsigned count;
+ int r;
+
+ r = dma_resv_get_fences(obj, write, &count, &fences);
+ if (r)
+ return r;
+
+ if (count == 0) {
+ *fence = NULL;
+ return 0;
+ }
+
+ if (count == 1) {
+ *fence = fences[0];
+ kfree(fences);
+ return 0;
+ }
+
+ array = dma_fence_array_create(count, fences,
+ dma_fence_context_alloc(1),
+ 1, false);
+ if (!array) {
+ while (count--)
+ dma_fence_put(fences[count]);
+ kfree(fences);
+ return -ENOMEM;
+ }
+
+ *fence = &array->base;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dma_resv_get_singleton);
+
+/**
* dma_resv_wait_timeout - Wait on reservation's objects
* shared and/or exclusive fences.
* @obj: the reservation object
diff --git a/drivers/dma-buf/st-dma-resv.c b/drivers/dma-buf/st-dma-resv.c
index cbe999c6e7a6..d2e61f6ae989 100644
--- a/drivers/dma-buf/st-dma-resv.c
+++ b/drivers/dma-buf/st-dma-resv.c
@@ -75,17 +75,16 @@ static int test_signaling(void *arg, bool shared)
goto err_free;
}
- if (shared) {
- r = dma_resv_reserve_shared(&resv, 1);
- if (r) {
- pr_err("Resv shared slot allocation failed\n");
- goto err_unlock;
- }
+ r = dma_resv_reserve_fences(&resv, 1);
+ if (r) {
+ pr_err("Resv shared slot allocation failed\n");
+ goto err_unlock;
+ }
+ if (shared)
dma_resv_add_shared_fence(&resv, f);
- } else {
+ else
dma_resv_add_excl_fence(&resv, f);
- }
if (dma_resv_test_signaled(&resv, shared)) {
pr_err("Resv unexpectedly signaled\n");
@@ -134,17 +133,16 @@ static int test_for_each(void *arg, bool shared)
goto err_free;
}
- if (shared) {
- r = dma_resv_reserve_shared(&resv, 1);
- if (r) {
- pr_err("Resv shared slot allocation failed\n");
- goto err_unlock;
- }
+ r = dma_resv_reserve_fences(&resv, 1);
+ if (r) {
+ pr_err("Resv shared slot allocation failed\n");
+ goto err_unlock;
+ }
+ if (shared)
dma_resv_add_shared_fence(&resv, f);
- } else {
+ else
dma_resv_add_excl_fence(&resv, f);
- }
r = -ENOENT;
dma_resv_for_each_fence(&cursor, &resv, shared, fence) {
@@ -206,18 +204,17 @@ static int test_for_each_unlocked(void *arg, bool shared)
goto err_free;
}
- if (shared) {
- r = dma_resv_reserve_shared(&resv, 1);
- if (r) {
- pr_err("Resv shared slot allocation failed\n");
- dma_resv_unlock(&resv);
- goto err_free;
- }
+ r = dma_resv_reserve_fences(&resv, 1);
+ if (r) {
+ pr_err("Resv shared slot allocation failed\n");
+ dma_resv_unlock(&resv);
+ goto err_free;
+ }
+ if (shared)
dma_resv_add_shared_fence(&resv, f);
- } else {
+ else
dma_resv_add_excl_fence(&resv, f);
- }
dma_resv_unlock(&resv);
r = -ENOENT;
@@ -290,18 +287,17 @@ static int test_get_fences(void *arg, bool shared)
goto err_resv;
}
- if (shared) {
- r = dma_resv_reserve_shared(&resv, 1);
- if (r) {
- pr_err("Resv shared slot allocation failed\n");
- dma_resv_unlock(&resv);
- goto err_resv;
- }
+ r = dma_resv_reserve_fences(&resv, 1);
+ if (r) {
+ pr_err("Resv shared slot allocation failed\n");
+ dma_resv_unlock(&resv);
+ goto err_resv;
+ }
+ if (shared)
dma_resv_add_shared_fence(&resv, f);
- } else {
+ else
dma_resv_add_excl_fence(&resv, f);
- }
dma_resv_unlock(&resv);
r = dma_resv_get_fences(&resv, shared, &i, &fences);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index e5cfb01353d8..d65964996e8d 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -219,12 +219,12 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
config SYSFB
bool
- default y
- depends on X86 || EFI
+ select BOOT_VESA_SUPPORT
config SYSFB_SIMPLEFB
bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
- depends on SYSFB
+ depends on X86 || EFI
+ select SYSFB
help
Firmwares often provide initial graphics framebuffers so the BIOS,
bootloader or kernel can show basic video-output during boot for
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index cd89d2e46852..98b1736bb221 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -253,53 +253,18 @@ void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo)
static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
struct amdgpu_amdkfd_fence *ef)
{
- struct dma_resv *resv = bo->tbo.base.resv;
- struct dma_resv_list *old, *new;
- unsigned int i, j, k;
+ struct dma_fence *replacement;
if (!ef)
return -EINVAL;
- old = dma_resv_shared_list(resv);
- if (!old)
- return 0;
-
- new = kmalloc(struct_size(new, shared, old->shared_max), GFP_KERNEL);
- if (!new)
- return -ENOMEM;
-
- /* Go through all the shared fences in the resevation object and sort
- * the interesting ones to the end of the list.
+ /* TODO: Instead of block before we should use the fence of the page
+ * table update and TLB flush here directly.
*/
- for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) {
- struct dma_fence *f;
-
- f = rcu_dereference_protected(old->shared[i],
- dma_resv_held(resv));
-
- if (f->context == ef->base.context)
- RCU_INIT_POINTER(new->shared[--j], f);
- else
- RCU_INIT_POINTER(new->shared[k++], f);
- }
- new->shared_max = old->shared_max;
- new->shared_count = k;
-
- /* Install the new fence list, seqcount provides the barriers */
- write_seqcount_begin(&resv->seq);
- RCU_INIT_POINTER(resv->fence, new);
- write_seqcount_end(&resv->seq);
-
- /* Drop the references to the removed fences or move them to ef_list */
- for (i = j; i < old->shared_count; ++i) {
- struct dma_fence *f;
-
- f = rcu_dereference_protected(new->shared[i],
- dma_resv_held(resv));
- dma_fence_put(f);
- }
- kfree_rcu(old, rcu);
-
+ replacement = dma_fence_get_stub();
+ dma_resv_replace_fences(bo->tbo.base.resv, ef->base.context,
+ replacement);
+ dma_fence_put(replacement);
return 0;
}
@@ -1268,7 +1233,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
AMDGPU_FENCE_OWNER_KFD, false);
if (ret)
goto wait_pd_fail;
- ret = dma_resv_reserve_shared(vm->root.bo->tbo.base.resv, 1);
+ ret = dma_resv_reserve_fences(vm->root.bo->tbo.base.resv, 1);
if (ret)
goto reserve_shared_fail;
amdgpu_bo_fence(vm->root.bo,
@@ -2606,7 +2571,7 @@ int amdgpu_amdkfd_add_gws_to_process(void *info, void *gws, struct kgd_mem **mem
* Add process eviction fence to bo so they can
* evict each other.
*/
- ret = dma_resv_reserve_shared(gws_bo->tbo.base.resv, 1);
+ ret = dma_resv_reserve_fences(gws_bo->tbo.base.resv, 1);
if (ret)
goto reserve_shared_fail;
amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 970b065e9a6b..e85e347eb670 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -1275,18 +1275,23 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
struct dma_resv *resv = e->tv.bo->base.resv;
struct dma_fence_chain *chain = e->chain;
+ struct dma_resv_iter cursor;
+ struct dma_fence *fence;
if (!chain)
continue;
/*
- * Work around dma_resv shortcomings by wrapping up the
- * submission in a dma_fence_chain and add it as exclusive
+ * Temporary workaround dma_resv shortcommings by wrapping up
+ * the submission in a dma_fence_chain and add it as exclusive
* fence.
+ *
+ * TODO: Remove together with dma_resv rework.
*/
- dma_fence_chain_init(chain, dma_resv_excl_fence(resv),
- dma_fence_get(p->fence), 1);
-
+ dma_resv_for_each_fence(&cursor, resv, false, fence) {
+ break;
+ }
+ dma_fence_chain_init(chain, fence, dma_fence_get(p->fence), 1);
rcu_assign_pointer(resv->fence_excl, &chain->base);
e->chain = NULL;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index dd78402e3cb0..8c6b2284cf56 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -26,23 +26,12 @@
#include "amdgpu.h"
-struct amdgpu_gtt_node {
- struct ttm_buffer_object *tbo;
- struct ttm_range_mgr_node base;
-};
-
static inline struct amdgpu_gtt_mgr *
to_gtt_mgr(struct ttm_resource_manager *man)
{
return container_of(man, struct amdgpu_gtt_mgr, manager);
}
-static inline struct amdgpu_gtt_node *
-to_amdgpu_gtt_node(struct ttm_resource *res)
-{
- return container_of(res, struct amdgpu_gtt_node, base.base);
-}
-
/**
* DOC: mem_info_gtt_total
*
@@ -106,9 +95,9 @@ const struct attribute_group amdgpu_gtt_mgr_attr_group = {
*/
bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
{
- struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
+ struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
- return drm_mm_node_allocated(&node->base.mm_nodes[0]);
+ return drm_mm_node_allocated(&node->mm_nodes[0]);
}
/**
@@ -128,15 +117,14 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
{
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
uint32_t num_pages = PFN_UP(tbo->base.size);
- struct amdgpu_gtt_node *node;
+ struct ttm_range_mgr_node *node;
int r;
- node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL);
+ node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
if (!node)
return -ENOMEM;
- node->tbo = tbo;
- ttm_resource_init(tbo, place, &node->base.base);
+ ttm_resource_init(tbo, place, &node->base);
if (!(place->flags & TTM_PL_FLAG_TEMPORARY) &&
ttm_resource_manager_usage(man) > man->size) {
r = -ENOSPC;
@@ -145,8 +133,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
if (place->lpfn) {
spin_lock(&mgr->lock);
- r = drm_mm_insert_node_in_range(&mgr->mm,
- &node->base.mm_nodes[0],
+ r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
num_pages, tbo->page_alignment,
0, place->fpfn, place->lpfn,
DRM_MM_INSERT_BEST);
@@ -154,18 +141,18 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
if (unlikely(r))
goto err_free;
- node->base.base.start = node->base.mm_nodes[0].start;
+ node->base.start = node->mm_nodes[0].start;
} else {
- node->base.mm_nodes[0].start = 0;
- node->base.mm_nodes[0].size = node->base.base.num_pages;
- node->base.base.start = AMDGPU_BO_INVALID_OFFSET;
+ node->mm_nodes[0].start = 0;
+ node->mm_nodes[0].size = node->base.num_pages;
+ node->base.start = AMDGPU_BO_INVALID_OFFSET;
}
- *res = &node->base.base;
+ *res = &node->base;
return 0;
err_free:
- ttm_resource_fini(man, &node->base.base);
+ ttm_resource_fini(man, &node->base);
kfree(node);
return r;
}
@@ -181,12 +168,12 @@ err_free:
static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
struct ttm_resource *res)
{
- struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
+ struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
spin_lock(&mgr->lock);
- if (drm_mm_node_allocated(&node->base.mm_nodes[0]))
- drm_mm_remove_node(&node->base.mm_nodes[0]);
+ if (drm_mm_node_allocated(&node->mm_nodes[0]))
+ drm_mm_remove_node(&node->mm_nodes[0]);
spin_unlock(&mgr->lock);
ttm_resource_fini(man, res);
@@ -202,15 +189,15 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
*/
void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
{
- struct amdgpu_gtt_node *node;
+ struct ttm_range_mgr_node *node;
struct drm_mm_node *mm_node;
struct amdgpu_device *adev;
adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
spin_lock(&mgr->lock);
drm_mm_for_each_node(mm_node, &mgr->mm) {
- node = container_of(mm_node, typeof(*node), base.mm_nodes[0]);
- amdgpu_ttm_recover_gart(node->tbo);
+ node = container_of(mm_node, typeof(*node), mm_nodes[0]);
+ amdgpu_ttm_recover_gart(node->base.bo);
}
spin_unlock(&mgr->lock);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 92a70fb57fa3..81207737c716 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -107,36 +107,19 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence,
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
u32 pasid)
{
- struct dma_fence *fence, **fences;
struct amdgpu_pasid_cb *cb;
- unsigned count;
+ struct dma_fence *fence;
int r;
- r = dma_resv_get_fences(resv, true, &count, &fences);
+ r = dma_resv_get_singleton(resv, true, &fence);
if (r)
goto fallback;
- if (count == 0) {
+ if (!fence) {
amdgpu_pasid_free(pasid);
return;
}
- if (count == 1) {
- fence = fences[0];
- kfree(fences);
- } else {
- uint64_t context = dma_fence_context_alloc(1);
- struct dma_fence_array *array;
-
- array = dma_fence_array_create(count, fences, context,
- 1, false);
- if (!array) {
- kfree(fences);
- goto fallback;
- }
- fence = &array->base;
- }
-
cb = kmalloc(sizeof(*cb), GFP_KERNEL);
if (!cb) {
/* Last resort when we are OOM */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 940752488330..dd6693fff280 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -1390,6 +1390,14 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
bool shared)
{
struct dma_resv *resv = bo->tbo.base.resv;
+ int r;
+
+ r = dma_resv_reserve_fences(resv, 1);
+ if (r) {
+ /* As last resort on OOM we block for the fence */
+ dma_fence_wait(fence, false);
+ return;
+ }
if (shared)
dma_resv_add_shared_fence(resv, fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 4b9ee6e27f74..f7f149588432 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1547,7 +1547,6 @@ static struct ttm_device_funcs amdgpu_bo_driver = {
.io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
.io_mem_pfn = amdgpu_ttm_io_mem_pfn,
.access_memory = &amdgpu_ttm_access_memory,
- .del_from_lru_notify = &amdgpu_vm_del_from_lru_notify
};
/*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index fc4563cf2828..b13451255e8b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -377,7 +377,7 @@ static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base,
dma_resv_assert_held(vm->root.bo->tbo.base.resv);
- vm->bulk_moveable = false;
+ ttm_bo_set_bulk_move(&bo->tbo, &vm->lru_bulk_move);
if (bo->tbo.type == ttm_bo_type_kernel && bo->parent)
amdgpu_vm_bo_relocated(base);
else
@@ -640,36 +640,6 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
}
/**
- * amdgpu_vm_del_from_lru_notify - update bulk_moveable flag
- *
- * @bo: BO which was removed from the LRU
- *
- * Make sure the bulk_moveable flag is updated when a BO is removed from the
- * LRU.
- */
-void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo)
-{
- struct amdgpu_bo *abo;
- struct amdgpu_vm_bo_base *bo_base;
-
- if (!amdgpu_bo_is_amdgpu_bo(bo))
- return;
-
- if (bo->pin_count)
- return;
-
- abo = ttm_to_amdgpu_bo(bo);
- if (!abo->parent)
- return;
- for (bo_base = abo->vm_bo; bo_base; bo_base = bo_base->next) {
- struct amdgpu_vm *vm = bo_base->vm;
-
- if (abo->tbo.base.resv == vm->root.bo->tbo.base.resv)
- vm->bulk_moveable = false;
- }
-
-}
-/**
* amdgpu_vm_move_to_lru_tail - move all BOs to the end of LRU
*
* @adev: amdgpu device pointer
@@ -681,35 +651,9 @@ void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo)
void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
struct amdgpu_vm *vm)
{
- struct amdgpu_vm_bo_base *bo_base;
-
- if (vm->bulk_moveable) {
- spin_lock(&adev->mman.bdev.lru_lock);
- ttm_bo_bulk_move_lru_tail(&vm->lru_bulk_move);
- spin_unlock(&adev->mman.bdev.lru_lock);
- return;
- }
-
- memset(&vm->lru_bulk_move, 0, sizeof(vm->lru_bulk_move));
-
spin_lock(&adev->mman.bdev.lru_lock);
- list_for_each_entry(bo_base, &vm->idle, vm_status) {
- struct amdgpu_bo *bo = bo_base->bo;
- struct amdgpu_bo *shadow = amdgpu_bo_shadowed(bo);
-
- if (!bo->parent)
- continue;
-
- ttm_bo_move_to_lru_tail(&bo->tbo, bo->tbo.resource,
- &vm->lru_bulk_move);
- if (shadow)
- ttm_bo_move_to_lru_tail(&shadow->tbo,
- shadow->tbo.resource,
- &vm->lru_bulk_move);
- }
+ ttm_lru_bulk_move_tail(&vm->lru_bulk_move);
spin_unlock(&adev->mman.bdev.lru_lock);
-
- vm->bulk_moveable = true;
}
/**
@@ -732,8 +676,6 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct amdgpu_vm_bo_base *bo_base, *tmp;
int r;
- vm->bulk_moveable &= list_empty(&vm->evicted);
-
list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) {
struct amdgpu_bo *bo = bo_base->bo;
struct amdgpu_bo *shadow = amdgpu_bo_shadowed(bo);
@@ -1057,10 +999,16 @@ static void amdgpu_vm_free_table(struct amdgpu_vm_bo_base *entry)
if (!entry->bo)
return;
+
shadow = amdgpu_bo_shadowed(entry->bo);
+ if (shadow) {
+ ttm_bo_set_bulk_move(&shadow->tbo, NULL);
+ amdgpu_bo_unref(&shadow);
+ }
+
+ ttm_bo_set_bulk_move(&entry->bo->tbo, NULL);
entry->bo->vm_bo = NULL;
list_del(&entry->vm_status);
- amdgpu_bo_unref(&shadow);
amdgpu_bo_unref(&entry->bo);
}
@@ -1080,8 +1028,6 @@ static void amdgpu_vm_free_pts(struct amdgpu_device *adev,
struct amdgpu_vm_pt_cursor cursor;
struct amdgpu_vm_bo_base *entry;
- vm->bulk_moveable = false;
-
for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)
amdgpu_vm_free_table(entry);
@@ -2665,7 +2611,7 @@ void amdgpu_vm_bo_del(struct amdgpu_device *adev,
if (bo) {
dma_resv_assert_held(bo->tbo.base.resv);
if (bo->tbo.base.resv == vm->root.bo->tbo.base.resv)
- vm->bulk_moveable = false;
+ ttm_bo_set_bulk_move(&bo->tbo, NULL);
for (base = &bo_va->base.bo->vm_bo; *base;
base = &(*base)->next) {
@@ -2980,7 +2926,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
if (r)
goto error_free_root;
- r = dma_resv_reserve_shared(root_bo->tbo.base.resv, 1);
+ r = dma_resv_reserve_fences(root_bo->tbo.base.resv, 1);
if (r)
goto error_unreserve;
@@ -3423,7 +3369,7 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
value = 0;
}
- r = dma_resv_reserve_shared(root->tbo.base.resv, 1);
+ r = dma_resv_reserve_fences(root->tbo.base.resv, 1);
if (r) {
pr_debug("failed %d to reserve fence slot\n", r);
goto error_unlock;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index a40a6a993bb0..bd7892482bbf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -317,8 +317,6 @@ struct amdgpu_vm {
/* Store positions of group of BOs */
struct ttm_lru_bulk_move lru_bulk_move;
- /* mark whether can do the bulk move */
- bool bulk_moveable;
/* Flag to indicate if VM is used for compute */
bool is_compute_context;
};
@@ -454,7 +452,6 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
struct amdgpu_vm *vm);
-void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo);
void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem,
uint64_t *gtt_mem, uint64_t *cpu_mem);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 3b8856b4cece..b3fc3e958227 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -548,7 +548,7 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange,
goto reserve_bo_failed;
}
- r = dma_resv_reserve_shared(bo->tbo.base.resv, 1);
+ r = dma_resv_reserve_fences(bo->tbo.base.resv, 1);
if (r) {
pr_debug("failed %d to reserve bo\n", r);
amdgpu_bo_unreserve(bo);
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
index d63d83800a8a..541949f2d44a 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -135,7 +135,6 @@ static void komeda_plane_destroy(struct drm_plane *plane)
static void komeda_plane_reset(struct drm_plane *plane)
{
struct komeda_plane_state *state;
- struct komeda_plane *kplane = to_kplane(plane);
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
@@ -144,16 +143,8 @@ static void komeda_plane_reset(struct drm_plane *plane)
plane->state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (state) {
- state->base.rotation = DRM_MODE_ROTATE_0;
- state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
- state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
- state->base.zpos = kplane->layer->base.id;
- state->base.color_encoding = DRM_COLOR_YCBCR_BT601;
- state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
- plane->state = &state->base;
- plane->state->plane = plane;
- }
+ if (state)
+ __drm_atomic_helper_plane_reset(plane, &state->base);
}
static struct drm_plane_state *
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 007e5a282f67..658837caaf39 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -77,6 +77,7 @@ config DRM_DISPLAY_CONNECTOR
config DRM_ITE_IT6505
tristate "ITE IT6505 DisplayPort bridge"
depends on OF
+ select DRM_DP_HELPER
select DRM_KMS_HELPER
select EXTCON
help
@@ -265,6 +266,7 @@ config DRM_TOSHIBA_TC358767
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
+ select DRM_MIPI_DSI
select DRM_PANEL
help
Toshiba TC358767 eDP bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 005bf18682ff..668dcefbae17 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1313,6 +1313,7 @@ err_unregister_audio:
adv7511_audio_exit(adv7511);
drm_bridge_remove(&adv7511->bridge);
err_unregister_cec:
+ cec_unregister_adapter(adv7511->cec_adap);
i2c_unregister_device(adv7511->i2c_cec);
clk_disable_unprepare(adv7511->cec_clk);
err_i2c_unregister_packet:
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index eb590fb8e8d0..c5afccd46440 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1119,9 +1119,7 @@ static int analogix_dp_get_modes(struct drm_connector *connector)
return 0;
}
- pm_runtime_get_sync(dp->dev);
edid = drm_get_edid(connector, &dp->aux.ddc);
- pm_runtime_put(dp->dev);
if (edid) {
drm_connector_update_edid_property(&dp->connector,
edid);
@@ -1632,8 +1630,20 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct analogix_dp_device *dp = to_dp(aux);
+ int ret;
+
+ pm_runtime_get_sync(dp->dev);
+
+ ret = analogix_dp_detect_hpd(dp);
+ if (ret)
+ goto out;
- return analogix_dp_transfer(dp, msg);
+ ret = analogix_dp_transfer(dp, msg);
+out:
+ pm_runtime_mark_last_busy(dp->dev);
+ pm_runtime_put_autosuspend(dp->dev);
+
+ return ret;
}
struct analogix_dp_device *
@@ -1764,6 +1774,8 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
if (ret)
return ret;
+ pm_runtime_use_autosuspend(dp->dev);
+ pm_runtime_set_autosuspend_delay(dp->dev, 100);
pm_runtime_enable(dp->dev);
ret = analogix_dp_create_bridge(drm_dev, dp);
@@ -1775,6 +1787,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
return 0;
err_disable_pm_runtime:
+ pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
drm_dp_aux_unregister(&dp->aux);
@@ -1793,6 +1806,7 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
}
drm_dp_aux_unregister(&dp->aux);
+ pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
}
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 31ecf5626f1d..6516f9570b86 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -874,7 +874,10 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx)
}
/* Read downstream capability */
- anx7625_aux_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap);
+ ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap);
+ if (ret < 0)
+ return ret;
+
if (!(bcap & 0x01)) {
pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap);
return 0;
@@ -921,12 +924,20 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
{
int ret;
struct device *dev = &ctx->client->dev;
+ u8 data;
if (!ctx->display_timing_valid) {
DRM_DEV_ERROR(dev, "mipi not set display timing yet.\n");
return;
}
+ dev_dbg(dev, "set downstream sink into normal\n");
+ /* Downstream sink enter into normal mode */
+ data = 1;
+ ret = anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data);
+ if (ret < 0)
+ dev_err(dev, "IO error : set sink into normal mode fail\n");
+
/* Disable HDCP */
anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
@@ -1608,8 +1619,6 @@ static int anx7625_parse_dt(struct device *dev,
struct anx7625_platform_data *pdata)
{
struct device_node *np = dev->of_node, *ep0;
- struct drm_panel *panel;
- int ret;
int bus_type, mipi_lanes;
anx7625_get_swing_setting(dev, pdata);
@@ -1646,18 +1655,14 @@ static int anx7625_parse_dt(struct device *dev,
if (of_property_read_bool(np, "analogix,audio-enable"))
pdata->audio_en = 1;
- ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
- if (ret < 0) {
- if (ret == -ENODEV)
+ pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
+ if (IS_ERR(pdata->panel_bridge)) {
+ if (PTR_ERR(pdata->panel_bridge) == -ENODEV)
return 0;
- return ret;
- }
- if (!panel)
- return -ENODEV;
- pdata->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- if (IS_ERR(pdata->panel_bridge))
return PTR_ERR(pdata->panel_bridge);
+ }
+
DRM_DEV_DEBUG_DRIVER(dev, "get panel node.\n");
return 0;
@@ -2011,7 +2016,8 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
- MIPI_DSI_MODE_VIDEO_HSE;
+ MIPI_DSI_MODE_VIDEO_HSE |
+ MIPI_DSI_HS_PKT_END_ALIGNED;
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret) {
@@ -2654,7 +2660,7 @@ static int anx7625_i2c_probe(struct i2c_client *client,
if (ret) {
if (ret != -EPROBE_DEFER)
DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret);
- return ret;
+ goto free_wq;
}
if (anx7625_register_i2c_dummy_clients(platform, client) != 0) {
@@ -2669,7 +2675,7 @@ static int anx7625_i2c_probe(struct i2c_client *client,
pm_suspend_ignore_children(dev, true);
ret = devm_add_action_or_reset(dev, anx7625_runtime_disable, dev);
if (ret)
- return ret;
+ goto free_wq;
if (!platform->pdata.low_power_mode) {
anx7625_disable_pd_protocol(platform);
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index d9b7f48b99fb..b72aa3f3b5c2 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -11,12 +11,24 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
-#include <video/mipi_display.h>
-
+#define VENDOR_ID 0x00
+#define DEVICE_ID_H 0x01
+#define DEVICE_ID_L 0x02
+#define VERSION_ID 0x03
+#define FIRMWARE_VERSION 0x08
+#define CONFIG_FINISH 0x09
+#define PD_CTRL(n) (0x0a + ((n) & 0x3)) /* 0..3 */
+#define RST_CTRL(n) (0x0e + ((n) & 0x1)) /* 0..1 */
+#define SYS_CTRL(n) (0x10 + ((n) & 0x7)) /* 0..4 */
+#define RGB_DRV(n) (0x18 + ((n) & 0x3)) /* 0..3 */
+#define RGB_DLY(n) (0x1c + ((n) & 0x1)) /* 0..1 */
+#define RGB_TEST_CTRL 0x1e
+#define ATE_PLL_EN 0x1f
#define HACTIVE_LI 0x20
#define VACTIVE_LI 0x21
#define VACTIVE_HACTIVE_HI 0x22
@@ -24,19 +36,114 @@
#define HSYNC_LI 0x24
#define HBP_LI 0x25
#define HFP_HSW_HBP_HI 0x26
+#define HFP_HSW_HBP_HI_HFP(n) (((n) & 0x300) >> 4)
+#define HFP_HSW_HBP_HI_HS(n) (((n) & 0x300) >> 6)
+#define HFP_HSW_HBP_HI_HBP(n) (((n) & 0x300) >> 8)
#define VFP 0x27
#define VSYNC 0x28
#define VBP 0x29
+#define BIST_POL 0x2a
+#define BIST_POL_BIST_MODE(n) (((n) & 0xf) << 4)
+#define BIST_POL_BIST_GEN BIT(3)
+#define BIST_POL_HSYNC_POL BIT(2)
+#define BIST_POL_VSYNC_POL BIT(1)
+#define BIST_POL_DE_POL BIT(0)
+#define BIST_RED 0x2b
+#define BIST_GREEN 0x2c
+#define BIST_BLUE 0x2d
+#define BIST_CHESS_X 0x2e
+#define BIST_CHESS_Y 0x2f
+#define BIST_CHESS_XY_H 0x30
+#define BIST_FRAME_TIME_L 0x31
+#define BIST_FRAME_TIME_H 0x32
+#define FIFO_MAX_ADDR_LOW 0x33
+#define SYNC_EVENT_DLY 0x34
+#define HSW_MIN 0x35
+#define HFP_MIN 0x36
+#define LOGIC_RST_NUM 0x37
+#define OSC_CTRL(n) (0x48 + ((n) & 0x7)) /* 0..5 */
+#define BG_CTRL 0x4e
+#define LDO_PLL 0x4f
+#define PLL_CTRL(n) (0x50 + ((n) & 0xf)) /* 0..15 */
+#define PLL_CTRL_6_EXTERNAL 0x90
+#define PLL_CTRL_6_MIPI_CLK 0x92
+#define PLL_CTRL_6_INTERNAL 0x93
+#define PLL_REM(n) (0x60 + ((n) & 0x3)) /* 0..2 */
+#define PLL_DIV(n) (0x63 + ((n) & 0x3)) /* 0..2 */
+#define PLL_FRAC(n) (0x66 + ((n) & 0x3)) /* 0..2 */
+#define PLL_INT(n) (0x69 + ((n) & 0x1)) /* 0..1 */
+#define PLL_REF_DIV 0x6b
+#define PLL_REF_DIV_P(n) ((n) & 0xf)
+#define PLL_REF_DIV_Pe BIT(4)
+#define PLL_REF_DIV_S(n) (((n) & 0x7) << 5)
+#define PLL_SSC_P(n) (0x6c + ((n) & 0x3)) /* 0..2 */
+#define PLL_SSC_STEP(n) (0x6f + ((n) & 0x3)) /* 0..2 */
+#define PLL_SSC_OFFSET(n) (0x72 + ((n) & 0x3)) /* 0..3 */
+#define GPIO_OEN 0x79
+#define MIPI_CFG_PW 0x7a
+#define MIPI_CFG_PW_CONFIG_DSI 0xc1
+#define MIPI_CFG_PW_CONFIG_I2C 0x3e
+#define GPIO_SEL(n) (0x7b + ((n) & 0x1)) /* 0..1 */
+#define IRQ_SEL 0x7d
+#define DBG_SEL 0x7e
+#define DBG_SIGNAL 0x7f
+#define MIPI_ERR_VECTOR_L 0x80
+#define MIPI_ERR_VECTOR_H 0x81
+#define MIPI_ERR_VECTOR_EN_L 0x82
+#define MIPI_ERR_VECTOR_EN_H 0x83
+#define MIPI_MAX_SIZE_L 0x84
+#define MIPI_MAX_SIZE_H 0x85
+#define DSI_CTRL 0x86
+#define DSI_CTRL_UNKNOWN 0x28
+#define DSI_CTRL_DSI_LANES(n) ((n) & 0x3)
+#define MIPI_PN_SWAP 0x87
+#define MIPI_PN_SWAP_CLK BIT(4)
+#define MIPI_PN_SWAP_D(n) BIT((n) & 0x3)
+#define MIPI_SOT_SYNC_BIT_(n) (0x88 + ((n) & 0x1)) /* 0..1 */
+#define MIPI_ULPS_CTRL 0x8a
+#define MIPI_CLK_CHK_VAR 0x8e
+#define MIPI_CLK_CHK_INI 0x8f
+#define MIPI_T_TERM_EN 0x90
+#define MIPI_T_HS_SETTLE 0x91
+#define MIPI_T_TA_SURE_PRE 0x92
+#define MIPI_T_LPX_SET 0x94
+#define MIPI_T_CLK_MISS 0x95
+#define MIPI_INIT_TIME_L 0x96
+#define MIPI_INIT_TIME_H 0x97
+#define MIPI_T_CLK_TERM_EN 0x99
+#define MIPI_T_CLK_SETTLE 0x9a
+#define MIPI_TO_HS_RX_L 0x9e
+#define MIPI_TO_HS_RX_H 0x9f
+#define MIPI_PHY_(n) (0xa0 + ((n) & 0x7)) /* 0..5 */
+#define MIPI_PD_RX 0xb0
+#define MIPI_PD_TERM 0xb1
+#define MIPI_PD_HSRX 0xb2
+#define MIPI_PD_LPTX 0xb3
+#define MIPI_PD_LPRX 0xb4
+#define MIPI_PD_CK_LANE 0xb5
+#define MIPI_FORCE_0 0xb6
+#define MIPI_RST_CTRL 0xb7
+#define MIPI_RST_NUM 0xb8
+#define MIPI_DBG_SET_(n) (0xc0 + ((n) & 0xf)) /* 0..9 */
+#define MIPI_DBG_SEL 0xe0
+#define MIPI_DBG_DATA 0xe1
+#define MIPI_ATE_TEST_SEL 0xe2
+#define MIPI_ATE_STATUS_(n) (0xe3 + ((n) & 0x1)) /* 0..1 */
+#define MIPI_ATE_STATUS_1 0xe4
+#define ICN6211_MAX_REGISTER MIPI_ATE_STATUS(1)
struct chipone {
struct device *dev;
+ struct i2c_client *client;
struct drm_bridge bridge;
struct drm_display_mode mode;
struct drm_bridge *panel_bridge;
+ struct mipi_dsi_device *dsi;
struct gpio_desc *enable_gpio;
struct regulator *vdd1;
struct regulator *vdd2;
struct regulator *vdd3;
+ bool interface_i2c;
};
static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
@@ -44,70 +151,199 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
return container_of(bridge, struct chipone, bridge);
}
-static inline int chipone_dsi_write(struct chipone *icn, const void *seq,
- size_t len)
+static void chipone_readb(struct chipone *icn, u8 reg, u8 *val)
{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(icn->dev);
+ if (icn->interface_i2c)
+ *val = i2c_smbus_read_byte_data(icn->client, reg);
+ else
+ mipi_dsi_generic_read(icn->dsi, (u8[]){reg, 1}, 2, val, 1);
+}
- return mipi_dsi_generic_write(dsi, seq, len);
+static int chipone_writeb(struct chipone *icn, u8 reg, u8 val)
+{
+ if (icn->interface_i2c)
+ return i2c_smbus_write_byte_data(icn->client, reg, val);
+ else
+ return mipi_dsi_generic_write(icn->dsi, (u8[]){reg, val}, 2);
}
-#define ICN6211_DSI(icn, seq...) \
- { \
- const u8 d[] = { seq }; \
- chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \
+static void chipone_configure_pll(struct chipone *icn,
+ const struct drm_display_mode *mode)
+{
+ unsigned int best_p = 0, best_m = 0, best_s = 0;
+ unsigned int mode_clock = mode->clock * 1000;
+ unsigned int delta, min_delta = 0xffffffff;
+ unsigned int freq_p, freq_s, freq_out;
+ unsigned int p_min, p_max;
+ unsigned int p, m, s;
+ unsigned int fin;
+ bool best_p_pot;
+ u8 ref_div;
+
+ /*
+ * DSI byte clock frequency (input into PLL) is calculated as:
+ * DSI_CLK = mode clock * bpp / dsi_data_lanes / 8
+ *
+ * DPI pixel clock frequency (output from PLL) is mode clock.
+ *
+ * The chip contains fractional PLL which works as follows:
+ * DPI_CLK = ((DSI_CLK / P) * M) / S
+ * P is pre-divider, register PLL_REF_DIV[3:0] is 1:n divider
+ * register PLL_REF_DIV[4] is extra 1:2 divider
+ * M is integer multiplier, register PLL_INT(0) is multiplier
+ * S is post-divider, register PLL_REF_DIV[7:5] is 2^(n+1) divider
+ *
+ * It seems the PLL input clock after applying P pre-divider have
+ * to be lower than 20 MHz.
+ */
+ fin = mode_clock * mipi_dsi_pixel_format_to_bpp(icn->dsi->format) /
+ icn->dsi->lanes / 8; /* in Hz */
+
+ /* Minimum value of P predivider for PLL input in 5..20 MHz */
+ p_min = clamp(DIV_ROUND_UP(fin, 20000000), 1U, 31U);
+ p_max = clamp(fin / 5000000, 1U, 31U);
+
+ for (p = p_min; p < p_max; p++) { /* PLL_REF_DIV[4,3:0] */
+ if (p > 16 && p & 1) /* P > 16 uses extra /2 */
+ continue;
+ freq_p = fin / p;
+ if (freq_p == 0) /* Divider too high */
+ break;
+
+ for (s = 0; s < 0x7; s++) { /* PLL_REF_DIV[7:5] */
+ freq_s = freq_p / BIT(s + 1);
+ if (freq_s == 0) /* Divider too high */
+ break;
+
+ m = mode_clock / freq_s;
+
+ /* Multiplier is 8 bit */
+ if (m > 0xff)
+ continue;
+
+ /* Limit PLL VCO frequency to 1 GHz */
+ freq_out = (fin * m) / p;
+ if (freq_out > 1000000000)
+ continue;
+
+ /* Apply post-divider */
+ freq_out /= BIT(s + 1);
+
+ delta = abs(mode_clock - freq_out);
+ if (delta < min_delta) {
+ best_p = p;
+ best_m = m;
+ best_s = s;
+ min_delta = delta;
+ }
+ }
}
+ best_p_pot = !(best_p & 1);
+
+ dev_dbg(icn->dev,
+ "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in=%d Hz ; DPI f_out=%d Hz\n",
+ best_p >> best_p_pot, best_p_pot, best_m, best_s + 1,
+ min_delta, fin, (fin * best_m) / (best_p << (best_s + 1)));
+
+ ref_div = PLL_REF_DIV_P(best_p >> best_p_pot) | PLL_REF_DIV_S(best_s);
+ if (best_p_pot) /* Prefer /2 pre-divider */
+ ref_div |= PLL_REF_DIV_Pe;
+
+ /* Clock source selection fixed to MIPI DSI clock lane */
+ chipone_writeb(icn, PLL_CTRL(6), PLL_CTRL_6_MIPI_CLK);
+ chipone_writeb(icn, PLL_REF_DIV, ref_div);
+ chipone_writeb(icn, PLL_INT(0), best_m);
+}
+
static void chipone_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
+ struct drm_atomic_state *state = old_bridge_state->base.state;
struct drm_display_mode *mode = &icn->mode;
+ const struct drm_bridge_state *bridge_state;
+ u16 hfp, hbp, hsync;
+ u32 bus_flags;
+ u8 pol, id[4];
+
+ chipone_readb(icn, VENDOR_ID, id);
+ chipone_readb(icn, DEVICE_ID_H, id + 1);
+ chipone_readb(icn, DEVICE_ID_L, id + 2);
+ chipone_readb(icn, VERSION_ID, id + 3);
+
+ dev_dbg(icn->dev,
+ "Chip IDs: Vendor=0x%02x Device=0x%02x:0x%02x Version=0x%02x\n",
+ id[0], id[1], id[2], id[3]);
+
+ if (id[0] != 0xc1 || id[1] != 0x62 || id[2] != 0x11) {
+ dev_dbg(icn->dev, "Invalid Chip IDs, aborting configuration\n");
+ return;
+ }
+
+ /* Get the DPI flags from the bridge state. */
+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+ bus_flags = bridge_state->output_bus_cfg.flags;
- ICN6211_DSI(icn, 0x7a, 0xc1);
+ if (icn->interface_i2c)
+ chipone_writeb(icn, MIPI_CFG_PW, MIPI_CFG_PW_CONFIG_I2C);
+ else
+ chipone_writeb(icn, MIPI_CFG_PW, MIPI_CFG_PW_CONFIG_DSI);
- ICN6211_DSI(icn, HACTIVE_LI, mode->hdisplay & 0xff);
+ chipone_writeb(icn, HACTIVE_LI, mode->hdisplay & 0xff);
- ICN6211_DSI(icn, VACTIVE_LI, mode->vdisplay & 0xff);
+ chipone_writeb(icn, VACTIVE_LI, mode->vdisplay & 0xff);
- /**
+ /*
* lsb nibble: 2nd nibble of hdisplay
* msb nibble: 2nd nibble of vdisplay
*/
- ICN6211_DSI(icn, VACTIVE_HACTIVE_HI,
- ((mode->hdisplay >> 8) & 0xf) |
- (((mode->vdisplay >> 8) & 0xf) << 4));
+ chipone_writeb(icn, VACTIVE_HACTIVE_HI,
+ ((mode->hdisplay >> 8) & 0xf) |
+ (((mode->vdisplay >> 8) & 0xf) << 4));
- ICN6211_DSI(icn, HFP_LI, mode->hsync_start - mode->hdisplay);
+ hfp = mode->hsync_start - mode->hdisplay;
+ hsync = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
- ICN6211_DSI(icn, HSYNC_LI, mode->hsync_end - mode->hsync_start);
+ chipone_writeb(icn, HFP_LI, hfp & 0xff);
+ chipone_writeb(icn, HSYNC_LI, hsync & 0xff);
+ chipone_writeb(icn, HBP_LI, hbp & 0xff);
+ /* Top two bits of Horizontal Front porch/Sync/Back porch */
+ chipone_writeb(icn, HFP_HSW_HBP_HI,
+ HFP_HSW_HBP_HI_HFP(hfp) |
+ HFP_HSW_HBP_HI_HS(hsync) |
+ HFP_HSW_HBP_HI_HBP(hbp));
- ICN6211_DSI(icn, HBP_LI, mode->htotal - mode->hsync_end);
+ chipone_writeb(icn, VFP, mode->vsync_start - mode->vdisplay);
- ICN6211_DSI(icn, HFP_HSW_HBP_HI, 0x00);
+ chipone_writeb(icn, VSYNC, mode->vsync_end - mode->vsync_start);
- ICN6211_DSI(icn, VFP, mode->vsync_start - mode->vdisplay);
+ chipone_writeb(icn, VBP, mode->vtotal - mode->vsync_end);
- ICN6211_DSI(icn, VSYNC, mode->vsync_end - mode->vsync_start);
+ /* dsi specific sequence */
+ chipone_writeb(icn, SYNC_EVENT_DLY, 0x80);
+ chipone_writeb(icn, HFP_MIN, hfp & 0xff);
+ chipone_writeb(icn, MIPI_PD_CK_LANE, 0xa0);
+ chipone_writeb(icn, PLL_CTRL(12), 0xff);
+ chipone_writeb(icn, MIPI_PN_SWAP, 0x00);
- ICN6211_DSI(icn, VBP, mode->vtotal - mode->vsync_end);
+ /* DPI HS/VS/DE polarity */
+ pol = ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIST_POL_HSYNC_POL : 0) |
+ ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIST_POL_VSYNC_POL : 0) |
+ ((bus_flags & DRM_BUS_FLAG_DE_HIGH) ? BIST_POL_DE_POL : 0);
+ chipone_writeb(icn, BIST_POL, pol);
- /* dsi specific sequence */
- ICN6211_DSI(icn, MIPI_DCS_SET_TEAR_OFF, 0x80);
- ICN6211_DSI(icn, MIPI_DCS_SET_ADDRESS_MODE, 0x28);
- ICN6211_DSI(icn, 0xb5, 0xa0);
- ICN6211_DSI(icn, 0x5c, 0xff);
- ICN6211_DSI(icn, MIPI_DCS_SET_COLUMN_ADDRESS, 0x01);
- ICN6211_DSI(icn, MIPI_DCS_GET_POWER_SAVE, 0x92);
- ICN6211_DSI(icn, 0x6b, 0x71);
- ICN6211_DSI(icn, 0x69, 0x2b);
- ICN6211_DSI(icn, MIPI_DCS_ENTER_SLEEP_MODE, 0x40);
- ICN6211_DSI(icn, MIPI_DCS_EXIT_SLEEP_MODE, 0x98);
+ /* Configure PLL settings */
+ chipone_configure_pll(icn, mode);
+
+ chipone_writeb(icn, SYS_CTRL(0), 0x40);
+ chipone_writeb(icn, SYS_CTRL(1), 0x88);
/* icn6211 specific sequence */
- ICN6211_DSI(icn, 0xb6, 0x20);
- ICN6211_DSI(icn, 0x51, 0x20);
- ICN6211_DSI(icn, 0x09, 0x10);
+ chipone_writeb(icn, MIPI_FORCE_0, 0x20);
+ chipone_writeb(icn, PLL_CTRL(1), 0x20);
+ chipone_writeb(icn, CONFIG_FINISH, 0x10);
usleep_range(10000, 11000);
}
@@ -168,6 +404,67 @@ static void chipone_mode_set(struct drm_bridge *bridge,
struct chipone *icn = bridge_to_chipone(bridge);
drm_mode_copy(&icn->mode, adjusted_mode);
+};
+
+static int chipone_dsi_attach(struct chipone *icn)
+{
+ struct mipi_dsi_device *dsi = icn->dsi;
+ int ret;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0)
+ dev_err(icn->dev, "failed to attach dsi\n");
+
+ return ret;
+}
+
+static int chipone_dsi_host_attach(struct chipone *icn)
+{
+ struct device *dev = icn->dev;
+ struct device_node *host_node;
+ struct device_node *endpoint;
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *host;
+ int ret = 0;
+
+ const struct mipi_dsi_device_info info = {
+ .type = "chipone",
+ .channel = 0,
+ .node = NULL,
+ };
+
+ endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
+ host_node = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+
+ if (!host_node)
+ return -EINVAL;
+
+ host = of_find_mipi_dsi_host_by_node(host_node);
+ of_node_put(host_node);
+ if (!host) {
+ dev_err(dev, "failed to find dsi host\n");
+ return -EPROBE_DEFER;
+ }
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi)) {
+ return dev_err_probe(dev, PTR_ERR(dsi),
+ "failed to create dsi device\n");
+ }
+
+ icn->dsi = dsi;
+
+ ret = chipone_dsi_attach(icn);
+ if (ret < 0)
+ mipi_dsi_device_unregister(dsi);
+
+ return ret;
}
static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
@@ -177,6 +474,32 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag
return drm_bridge_attach(bridge->encoder, icn->panel_bridge, bridge, flags);
}
+#define MAX_INPUT_SEL_FORMATS 1
+
+static u32 *
+chipone_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
+ GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ /* This is the DSI-end bus format */
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+ *num_input_fmts = 1;
+
+ return input_fmts;
+}
+
static const struct drm_bridge_funcs chipone_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -186,6 +509,7 @@ static const struct drm_bridge_funcs chipone_bridge_funcs = {
.atomic_post_disable = chipone_atomic_post_disable,
.mode_set = chipone_mode_set,
.attach = chipone_attach,
+ .atomic_get_input_bus_fmts = chipone_atomic_get_input_bus_fmts,
};
static int chipone_parse_dt(struct chipone *icn)
@@ -233,9 +557,8 @@ static int chipone_parse_dt(struct chipone *icn)
return 0;
}
-static int chipone_probe(struct mipi_dsi_device *dsi)
+static int chipone_common_probe(struct device *dev, struct chipone **icnr)
{
- struct device *dev = &dsi->dev;
struct chipone *icn;
int ret;
@@ -243,7 +566,6 @@ static int chipone_probe(struct mipi_dsi_device *dsi)
if (!icn)
return -ENOMEM;
- mipi_dsi_set_drvdata(dsi, icn);
icn->dev = dev;
ret = chipone_parse_dt(icn);
@@ -254,22 +576,57 @@ static int chipone_probe(struct mipi_dsi_device *dsi)
icn->bridge.type = DRM_MODE_CONNECTOR_DPI;
icn->bridge.of_node = dev->of_node;
- drm_bridge_add(&icn->bridge);
+ *icnr = icn;
- dsi->lanes = 4;
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ return ret;
+}
- ret = mipi_dsi_attach(dsi);
- if (ret < 0) {
+static int chipone_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct chipone *icn;
+ int ret;
+
+ ret = chipone_common_probe(dev, &icn);
+ if (ret)
+ return ret;
+
+ icn->interface_i2c = false;
+ icn->dsi = dsi;
+
+ mipi_dsi_set_drvdata(dsi, icn);
+
+ drm_bridge_add(&icn->bridge);
+
+ ret = chipone_dsi_attach(icn);
+ if (ret)
drm_bridge_remove(&icn->bridge);
- dev_err(dev, "failed to attach dsi\n");
- }
return ret;
}
-static int chipone_remove(struct mipi_dsi_device *dsi)
+static int chipone_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct chipone *icn;
+ int ret;
+
+ ret = chipone_common_probe(dev, &icn);
+ if (ret)
+ return ret;
+
+ icn->interface_i2c = true;
+ icn->client = client;
+ dev_set_drvdata(dev, icn);
+ i2c_set_clientdata(client, icn);
+
+ drm_bridge_add(&icn->bridge);
+
+ return chipone_dsi_host_attach(icn);
+}
+
+static int chipone_dsi_remove(struct mipi_dsi_device *dsi)
{
struct chipone *icn = mipi_dsi_get_drvdata(dsi);
@@ -285,16 +642,48 @@ static const struct of_device_id chipone_of_match[] = {
};
MODULE_DEVICE_TABLE(of, chipone_of_match);
-static struct mipi_dsi_driver chipone_driver = {
- .probe = chipone_probe,
- .remove = chipone_remove,
+static struct mipi_dsi_driver chipone_dsi_driver = {
+ .probe = chipone_dsi_probe,
+ .remove = chipone_dsi_remove,
.driver = {
.name = "chipone-icn6211",
.owner = THIS_MODULE,
.of_match_table = chipone_of_match,
},
};
-module_mipi_dsi_driver(chipone_driver);
+
+static struct i2c_device_id chipone_i2c_id[] = {
+ { "chipone,icn6211" },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);
+
+static struct i2c_driver chipone_i2c_driver = {
+ .probe = chipone_i2c_probe,
+ .id_table = chipone_i2c_id,
+ .driver = {
+ .name = "chipone-icn6211-i2c",
+ .of_match_table = chipone_of_match,
+ },
+};
+
+static int __init chipone_init(void)
+{
+ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+ mipi_dsi_driver_register(&chipone_dsi_driver);
+
+ return i2c_add_driver(&chipone_i2c_driver);
+}
+module_init(chipone_init);
+
+static void __exit chipone_exit(void)
+{
+ i2c_del_driver(&chipone_i2c_driver);
+
+ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+ mipi_dsi_driver_unregister(&chipone_dsi_driver);
+}
+module_exit(chipone_exit);
MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
MODULE_DESCRIPTION("Chipone ICN6211 MIPI-DSI to RGB Converter Bridge");
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 69288cf894b9..448c58e60c11 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -27,6 +27,8 @@
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
+#include <sound/hdmi-codec.h>
+
#define IT66121_VENDOR_ID0_REG 0x00
#define IT66121_VENDOR_ID1_REG 0x01
#define IT66121_DEVICE_ID0_REG 0x02
@@ -155,6 +157,9 @@
#define IT66121_AV_MUTE_ON BIT(0)
#define IT66121_AV_MUTE_BLUESCR BIT(1)
+#define IT66121_PKT_CTS_CTRL_REG 0xC5
+#define IT66121_PKT_CTS_CTRL_SEL BIT(1)
+
#define IT66121_PKT_GEN_CTRL_REG 0xC6
#define IT66121_PKT_GEN_CTRL_ON BIT(0)
#define IT66121_PKT_GEN_CTRL_RPT BIT(1)
@@ -202,6 +207,89 @@
#define IT66121_EDID_SLEEP_US 20000
#define IT66121_EDID_TIMEOUT_US 200000
#define IT66121_EDID_FIFO_SIZE 32
+
+#define IT66121_CLK_CTRL0_REG 0x58
+#define IT66121_CLK_CTRL0_AUTO_OVER_SAMPLING BIT(4)
+#define IT66121_CLK_CTRL0_EXT_MCLK_MASK GENMASK(3, 2)
+#define IT66121_CLK_CTRL0_EXT_MCLK_128FS (0 << 2)
+#define IT66121_CLK_CTRL0_EXT_MCLK_256FS BIT(2)
+#define IT66121_CLK_CTRL0_EXT_MCLK_512FS (2 << 2)
+#define IT66121_CLK_CTRL0_EXT_MCLK_1024FS (3 << 2)
+#define IT66121_CLK_CTRL0_AUTO_IPCLK BIT(0)
+#define IT66121_CLK_STATUS1_REG 0x5E
+#define IT66121_CLK_STATUS2_REG 0x5F
+
+#define IT66121_AUD_CTRL0_REG 0xE0
+#define IT66121_AUD_SWL (3 << 6)
+#define IT66121_AUD_16BIT (0 << 6)
+#define IT66121_AUD_18BIT BIT(6)
+#define IT66121_AUD_20BIT (2 << 6)
+#define IT66121_AUD_24BIT (3 << 6)
+#define IT66121_AUD_SPDIFTC BIT(5)
+#define IT66121_AUD_SPDIF BIT(4)
+#define IT66121_AUD_I2S (0 << 4)
+#define IT66121_AUD_EN_I2S3 BIT(3)
+#define IT66121_AUD_EN_I2S2 BIT(2)
+#define IT66121_AUD_EN_I2S1 BIT(1)
+#define IT66121_AUD_EN_I2S0 BIT(0)
+#define IT66121_AUD_CTRL0_AUD_SEL BIT(4)
+
+#define IT66121_AUD_CTRL1_REG 0xE1
+#define IT66121_AUD_FIFOMAP_REG 0xE2
+#define IT66121_AUD_CTRL3_REG 0xE3
+#define IT66121_AUD_SRCVALID_FLAT_REG 0xE4
+#define IT66121_AUD_FLAT_SRC0 BIT(4)
+#define IT66121_AUD_FLAT_SRC1 BIT(5)
+#define IT66121_AUD_FLAT_SRC2 BIT(6)
+#define IT66121_AUD_FLAT_SRC3 BIT(7)
+#define IT66121_AUD_HDAUDIO_REG 0xE5
+
+#define IT66121_AUD_PKT_CTS0_REG 0x130
+#define IT66121_AUD_PKT_CTS1_REG 0x131
+#define IT66121_AUD_PKT_CTS2_REG 0x132
+#define IT66121_AUD_PKT_N0_REG 0x133
+#define IT66121_AUD_PKT_N1_REG 0x134
+#define IT66121_AUD_PKT_N2_REG 0x135
+
+#define IT66121_AUD_CHST_MODE_REG 0x191
+#define IT66121_AUD_CHST_CAT_REG 0x192
+#define IT66121_AUD_CHST_SRCNUM_REG 0x193
+#define IT66121_AUD_CHST_CHTNUM_REG 0x194
+#define IT66121_AUD_CHST_CA_FS_REG 0x198
+#define IT66121_AUD_CHST_OFS_WL_REG 0x199
+
+#define IT66121_AUD_PKT_CTS_CNT0_REG 0x1A0
+#define IT66121_AUD_PKT_CTS_CNT1_REG 0x1A1
+#define IT66121_AUD_PKT_CTS_CNT2_REG 0x1A2
+
+#define IT66121_AUD_FS_22P05K 0x4
+#define IT66121_AUD_FS_44P1K 0x0
+#define IT66121_AUD_FS_88P2K 0x8
+#define IT66121_AUD_FS_176P4K 0xC
+#define IT66121_AUD_FS_24K 0x6
+#define IT66121_AUD_FS_48K 0x2
+#define IT66121_AUD_FS_96K 0xA
+#define IT66121_AUD_FS_192K 0xE
+#define IT66121_AUD_FS_768K 0x9
+#define IT66121_AUD_FS_32K 0x3
+#define IT66121_AUD_FS_OTHER 0x1
+
+#define IT66121_AUD_SWL_21BIT 0xD
+#define IT66121_AUD_SWL_24BIT 0xB
+#define IT66121_AUD_SWL_23BIT 0x9
+#define IT66121_AUD_SWL_22BIT 0x5
+#define IT66121_AUD_SWL_20BIT 0x3
+#define IT66121_AUD_SWL_17BIT 0xC
+#define IT66121_AUD_SWL_19BIT 0x8
+#define IT66121_AUD_SWL_18BIT 0x4
+#define IT66121_AUD_SWL_16BIT 0x2
+#define IT66121_AUD_SWL_NOT_INDICATED 0x0
+
+#define IT66121_VENDOR_ID0 0x54
+#define IT66121_VENDOR_ID1 0x49
+#define IT66121_DEVICE_ID0 0x12
+#define IT66121_DEVICE_ID1 0x06
+#define IT66121_DEVICE_MASK 0x0F
#define IT66121_AFE_CLK_HIGH 80000 /* Khz */
struct it66121_ctx {
@@ -216,6 +304,13 @@ struct it66121_ctx {
u32 bus_width;
struct mutex lock; /* Protects fields below and device registers */
struct hdmi_avi_infoframe hdmi_avi_infoframe;
+ struct {
+ struct platform_device *pdev;
+ u8 ch_enable;
+ u8 fs;
+ u8 swl;
+ bool auto_cts;
+ } audio;
};
static const struct regmap_range_cfg it66121_regmap_banks[] = {
@@ -227,7 +322,7 @@ static const struct regmap_range_cfg it66121_regmap_banks[] = {
.selector_mask = 0x1,
.selector_shift = 0,
.window_start = 0x00,
- .window_len = 0x130,
+ .window_len = 0x100,
},
};
@@ -886,6 +981,536 @@ unlock:
return IRQ_HANDLED;
}
+static int it661221_set_chstat(struct it66121_ctx *ctx, u8 iec60958_chstat[])
+{
+ int ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CHST_MODE_REG, iec60958_chstat[0] & 0x7C);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CHST_CAT_REG, iec60958_chstat[1]);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CHST_SRCNUM_REG, iec60958_chstat[2] & 0x0F);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CHST_CHTNUM_REG,
+ (iec60958_chstat[2] >> 4) & 0x0F);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CHST_CA_FS_REG, iec60958_chstat[3]);
+ if (ret)
+ return ret;
+
+ return regmap_write(ctx->regmap, IT66121_AUD_CHST_OFS_WL_REG, iec60958_chstat[4]);
+}
+
+static int it661221_set_lpcm_audio(struct it66121_ctx *ctx, u8 audio_src_num, u8 audio_swl)
+{
+ int ret;
+ unsigned int audio_enable = 0;
+ unsigned int audio_format = 0;
+
+ switch (audio_swl) {
+ case 16:
+ audio_enable |= IT66121_AUD_16BIT;
+ break;
+ case 18:
+ audio_enable |= IT66121_AUD_18BIT;
+ break;
+ case 20:
+ audio_enable |= IT66121_AUD_20BIT;
+ break;
+ case 24:
+ default:
+ audio_enable |= IT66121_AUD_24BIT;
+ break;
+ }
+
+ audio_format |= 0x40;
+ switch (audio_src_num) {
+ case 4:
+ audio_enable |= IT66121_AUD_EN_I2S3 | IT66121_AUD_EN_I2S2 |
+ IT66121_AUD_EN_I2S1 | IT66121_AUD_EN_I2S0;
+ break;
+ case 3:
+ audio_enable |= IT66121_AUD_EN_I2S2 | IT66121_AUD_EN_I2S1 |
+ IT66121_AUD_EN_I2S0;
+ break;
+ case 2:
+ audio_enable |= IT66121_AUD_EN_I2S1 | IT66121_AUD_EN_I2S0;
+ break;
+ case 1:
+ default:
+ audio_format &= ~0x40;
+ audio_enable |= IT66121_AUD_EN_I2S0;
+ break;
+ }
+
+ audio_format |= 0x01;
+ ctx->audio.ch_enable = audio_enable;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL0_REG, audio_enable & 0xF0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL1_REG, audio_format);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_FIFOMAP_REG, 0xE4);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL3_REG, 0x00);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_SRCVALID_FLAT_REG, 0x00);
+ if (ret)
+ return ret;
+
+ return regmap_write(ctx->regmap, IT66121_AUD_HDAUDIO_REG, 0x00);
+}
+
+static int it661221_set_ncts(struct it66121_ctx *ctx, u8 fs)
+{
+ int ret;
+ unsigned int n;
+
+ switch (fs) {
+ case IT66121_AUD_FS_32K:
+ n = 4096;
+ break;
+ case IT66121_AUD_FS_44P1K:
+ n = 6272;
+ break;
+ case IT66121_AUD_FS_48K:
+ n = 6144;
+ break;
+ case IT66121_AUD_FS_88P2K:
+ n = 12544;
+ break;
+ case IT66121_AUD_FS_96K:
+ n = 12288;
+ break;
+ case IT66121_AUD_FS_176P4K:
+ n = 25088;
+ break;
+ case IT66121_AUD_FS_192K:
+ n = 24576;
+ break;
+ case IT66121_AUD_FS_768K:
+ n = 24576;
+ break;
+ default:
+ n = 6144;
+ break;
+ }
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N0_REG, (u8)((n) & 0xFF));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N1_REG, (u8)((n >> 8) & 0xFF));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N2_REG, (u8)((n >> 16) & 0xF));
+ if (ret)
+ return ret;
+
+ if (ctx->audio.auto_cts) {
+ u8 loop_cnt = 255;
+ u8 cts_stable_cnt = 0;
+ unsigned int sum_cts = 0;
+ unsigned int cts = 0;
+ unsigned int last_cts = 0;
+ unsigned int diff;
+ unsigned int val;
+
+ while (loop_cnt--) {
+ msleep(30);
+ regmap_read(ctx->regmap, IT66121_AUD_PKT_CTS_CNT2_REG, &val);
+ cts = val << 12;
+ regmap_read(ctx->regmap, IT66121_AUD_PKT_CTS_CNT1_REG, &val);
+ cts |= val << 4;
+ regmap_read(ctx->regmap, IT66121_AUD_PKT_CTS_CNT0_REG, &val);
+ cts |= val >> 4;
+ if (cts == 0) {
+ continue;
+ } else {
+ if (last_cts > cts)
+ diff = last_cts - cts;
+ else
+ diff = cts - last_cts;
+ last_cts = cts;
+ if (diff < 5) {
+ cts_stable_cnt++;
+ sum_cts += cts;
+ } else {
+ cts_stable_cnt = 0;
+ sum_cts = 0;
+ continue;
+ }
+
+ if (cts_stable_cnt >= 32) {
+ last_cts = (sum_cts >> 5);
+ break;
+ }
+ }
+ }
+
+ regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS0_REG, (u8)((last_cts) & 0xFF));
+ regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS1_REG, (u8)((last_cts >> 8) & 0xFF));
+ regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS2_REG, (u8)((last_cts >> 16) & 0x0F));
+ }
+
+ ret = regmap_write(ctx->regmap, 0xF8, 0xC3);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, 0xF8, 0xA5);
+ if (ret)
+ return ret;
+
+ if (ctx->audio.auto_cts) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_PKT_CTS_CTRL_REG,
+ IT66121_PKT_CTS_CTRL_SEL,
+ 1);
+ } else {
+ ret = regmap_write_bits(ctx->regmap, IT66121_PKT_CTS_CTRL_REG,
+ IT66121_PKT_CTS_CTRL_SEL,
+ 0);
+ }
+
+ if (ret)
+ return ret;
+
+ return regmap_write(ctx->regmap, 0xF8, 0xFF);
+}
+
+static int it661221_audio_output_enable(struct it66121_ctx *ctx, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG,
+ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF,
+ 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL0_REG,
+ IT66121_AUD_EN_I2S3 | IT66121_AUD_EN_I2S2 |
+ IT66121_AUD_EN_I2S1 | IT66121_AUD_EN_I2S0,
+ ctx->audio.ch_enable);
+ } else {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL0_REG,
+ IT66121_AUD_EN_I2S3 | IT66121_AUD_EN_I2S2 |
+ IT66121_AUD_EN_I2S1 | IT66121_AUD_EN_I2S0,
+ ctx->audio.ch_enable & 0xF0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG,
+ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF,
+ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF);
+ }
+
+ return ret;
+}
+
+static int it661221_audio_ch_enable(struct it66121_ctx *ctx, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ ret = regmap_write(ctx->regmap, IT66121_AUD_SRCVALID_FLAT_REG, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL0_REG, ctx->audio.ch_enable);
+ } else {
+ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL0_REG, ctx->audio.ch_enable & 0xF0);
+ }
+
+ return ret;
+}
+
+static int it66121_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ u8 fs;
+ u8 swl;
+ int ret;
+ struct it66121_ctx *ctx = dev_get_drvdata(dev);
+ static u8 iec60958_chstat[5];
+ unsigned int channels = params->channels;
+ unsigned int sample_rate = params->sample_rate;
+ unsigned int sample_width = params->sample_width;
+
+ mutex_lock(&ctx->lock);
+ dev_dbg(dev, "%s: %u, %u, %u, %u\n", __func__,
+ daifmt->fmt, sample_rate, sample_width, channels);
+
+ switch (daifmt->fmt) {
+ case HDMI_I2S:
+ dev_dbg(dev, "Using HDMI I2S\n");
+ break;
+ default:
+ dev_err(dev, "Invalid or unsupported DAI format %d\n", daifmt->fmt);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ // Set audio clock recovery (N/CTS)
+ ret = regmap_write(ctx->regmap, IT66121_CLK_CTRL0_REG,
+ IT66121_CLK_CTRL0_AUTO_OVER_SAMPLING |
+ IT66121_CLK_CTRL0_EXT_MCLK_256FS |
+ IT66121_CLK_CTRL0_AUTO_IPCLK);
+ if (ret)
+ goto out;
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL0_REG,
+ IT66121_AUD_CTRL0_AUD_SEL, 0); // remove spdif selection
+ if (ret)
+ goto out;
+
+ switch (sample_rate) {
+ case 44100L:
+ fs = IT66121_AUD_FS_44P1K;
+ break;
+ case 88200L:
+ fs = IT66121_AUD_FS_88P2K;
+ break;
+ case 176400L:
+ fs = IT66121_AUD_FS_176P4K;
+ break;
+ case 32000L:
+ fs = IT66121_AUD_FS_32K;
+ break;
+ case 48000L:
+ fs = IT66121_AUD_FS_48K;
+ break;
+ case 96000L:
+ fs = IT66121_AUD_FS_96K;
+ break;
+ case 192000L:
+ fs = IT66121_AUD_FS_192K;
+ break;
+ case 768000L:
+ fs = IT66121_AUD_FS_768K;
+ break;
+ default:
+ fs = IT66121_AUD_FS_48K;
+ break;
+ }
+
+ ctx->audio.fs = fs;
+ ret = it661221_set_ncts(ctx, fs);
+ if (ret) {
+ dev_err(dev, "Failed to set N/CTS: %d\n", ret);
+ goto out;
+ }
+
+ // Set audio format register (except audio channel enable)
+ ret = it661221_set_lpcm_audio(ctx, (channels + 1) / 2, sample_width);
+ if (ret) {
+ dev_err(dev, "Failed to set LPCM audio: %d\n", ret);
+ goto out;
+ }
+
+ // Set audio channel status
+ iec60958_chstat[0] = 0;
+ if ((channels + 1) / 2 == 1)
+ iec60958_chstat[0] |= 0x1;
+ iec60958_chstat[0] &= ~(1 << 1);
+ iec60958_chstat[1] = 0;
+ iec60958_chstat[2] = (channels + 1) / 2;
+ iec60958_chstat[2] |= (channels << 4) & 0xF0;
+ iec60958_chstat[3] = fs;
+
+ switch (sample_width) {
+ case 21L:
+ swl = IT66121_AUD_SWL_21BIT;
+ break;
+ case 24L:
+ swl = IT66121_AUD_SWL_24BIT;
+ break;
+ case 23L:
+ swl = IT66121_AUD_SWL_23BIT;
+ break;
+ case 22L:
+ swl = IT66121_AUD_SWL_22BIT;
+ break;
+ case 20L:
+ swl = IT66121_AUD_SWL_20BIT;
+ break;
+ case 17L:
+ swl = IT66121_AUD_SWL_17BIT;
+ break;
+ case 19L:
+ swl = IT66121_AUD_SWL_19BIT;
+ break;
+ case 18L:
+ swl = IT66121_AUD_SWL_18BIT;
+ break;
+ case 16L:
+ swl = IT66121_AUD_SWL_16BIT;
+ break;
+ default:
+ swl = IT66121_AUD_SWL_NOT_INDICATED;
+ break;
+ }
+
+ iec60958_chstat[4] = (((~fs) << 4) & 0xF0) | swl;
+ ret = it661221_set_chstat(ctx, iec60958_chstat);
+ if (ret) {
+ dev_err(dev, "Failed to set channel status: %d\n", ret);
+ goto out;
+ }
+
+ // Enable audio channel enable while input clock stable (if SPDIF).
+ ret = it661221_audio_ch_enable(ctx, true);
+ if (ret) {
+ dev_err(dev, "Failed to enable audio channel: %d\n", ret);
+ goto out;
+ }
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG,
+ IT66121_INT_MASK1_AUD_OVF,
+ 0);
+ if (ret)
+ goto out;
+
+ dev_dbg(dev, "HDMI audio enabled.\n");
+out:
+ mutex_unlock(&ctx->lock);
+
+ return ret;
+}
+
+static int it66121_audio_startup(struct device *dev, void *data)
+{
+ int ret;
+ struct it66121_ctx *ctx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ mutex_lock(&ctx->lock);
+ ret = it661221_audio_output_enable(ctx, true);
+ if (ret)
+ dev_err(dev, "Failed to enable audio output: %d\n", ret);
+
+ mutex_unlock(&ctx->lock);
+
+ return ret;
+}
+
+static void it66121_audio_shutdown(struct device *dev, void *data)
+{
+ int ret;
+ struct it66121_ctx *ctx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ mutex_lock(&ctx->lock);
+ ret = it661221_audio_output_enable(ctx, false);
+ if (ret)
+ dev_err(dev, "Failed to disable audio output: %d\n", ret);
+
+ mutex_unlock(&ctx->lock);
+}
+
+static int it66121_audio_mute(struct device *dev, void *data,
+ bool enable, int direction)
+{
+ int ret;
+ struct it66121_ctx *ctx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s: enable=%s, direction=%d\n",
+ __func__, enable ? "true" : "false", direction);
+
+ mutex_lock(&ctx->lock);
+
+ if (enable) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_SRCVALID_FLAT_REG,
+ IT66121_AUD_FLAT_SRC0 | IT66121_AUD_FLAT_SRC1 |
+ IT66121_AUD_FLAT_SRC2 | IT66121_AUD_FLAT_SRC3,
+ IT66121_AUD_FLAT_SRC0 | IT66121_AUD_FLAT_SRC1 |
+ IT66121_AUD_FLAT_SRC2 | IT66121_AUD_FLAT_SRC3);
+ } else {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_SRCVALID_FLAT_REG,
+ IT66121_AUD_FLAT_SRC0 | IT66121_AUD_FLAT_SRC1 |
+ IT66121_AUD_FLAT_SRC2 | IT66121_AUD_FLAT_SRC3,
+ 0);
+ }
+
+ mutex_unlock(&ctx->lock);
+
+ return ret;
+}
+
+static int it66121_audio_get_eld(struct device *dev, void *data,
+ u8 *buf, size_t len)
+{
+ struct it66121_ctx *ctx = dev_get_drvdata(dev);
+
+ mutex_lock(&ctx->lock);
+
+ memcpy(buf, ctx->connector->eld,
+ min(sizeof(ctx->connector->eld), len));
+
+ mutex_unlock(&ctx->lock);
+
+ return 0;
+}
+
+static const struct hdmi_codec_ops it66121_audio_codec_ops = {
+ .hw_params = it66121_audio_hw_params,
+ .audio_startup = it66121_audio_startup,
+ .audio_shutdown = it66121_audio_shutdown,
+ .mute_stream = it66121_audio_mute,
+ .get_eld = it66121_audio_get_eld,
+ .no_capture_mute = 1,
+};
+
+static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &it66121_audio_codec_ops,
+ .i2s = 1, /* Only i2s support for now */
+ .spdif = 0,
+ .max_i2s_channels = 8,
+ };
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+ dev_info(dev, "No \"#sound-dai-cells\", no audio\n");
+ return 0;
+ }
+
+ ctx->audio.pdev = platform_device_register_data(dev,
+ HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data,
+ sizeof(codec_data));
+
+ if (IS_ERR(ctx->audio.pdev)) {
+ dev_err(dev, "Failed to initialize HDMI audio codec: %d\n",
+ PTR_ERR_OR_ZERO(ctx->audio.pdev));
+ }
+
+ return PTR_ERR_OR_ZERO(ctx->audio.pdev);
+}
+
static int it66121_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -988,6 +1613,8 @@ static int it66121_probe(struct i2c_client *client,
return ret;
}
+ it66121_audio_codec_init(ctx, dev);
+
drm_bridge_add(&ctx->bridge);
dev_info(ctx->dev, "IT66121 revision %d probed\n", revision_id);
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index 63df2e8a8abc..7ef8fe5abc12 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -700,7 +700,9 @@ lt9611_connector_mode_valid(struct drm_connector *connector,
}
/* bridge funcs */
-static void lt9611_bridge_enable(struct drm_bridge *bridge)
+static void
+lt9611_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
@@ -721,7 +723,9 @@ static void lt9611_bridge_enable(struct drm_bridge *bridge)
regmap_write(lt9611->regmap, 0x8130, 0xea);
}
-static void lt9611_bridge_disable(struct drm_bridge *bridge)
+static void
+lt9611_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
int ret;
@@ -856,7 +860,9 @@ static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
lt9611->sleep = false;
}
-static void lt9611_bridge_post_disable(struct drm_bridge *bridge)
+static void
+lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
@@ -916,16 +922,47 @@ static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge)
lt9611_enable_hpd_interrupts(lt9611);
}
+#define MAX_INPUT_SEL_FORMATS 1
+
+static u32 *
+lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
+ GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ /* This is the DSI-end bus format */
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+ *num_input_fmts = 1;
+
+ return input_fmts;
+}
+
static const struct drm_bridge_funcs lt9611_bridge_funcs = {
.attach = lt9611_bridge_attach,
.mode_valid = lt9611_bridge_mode_valid,
- .enable = lt9611_bridge_enable,
- .disable = lt9611_bridge_disable,
- .post_disable = lt9611_bridge_post_disable,
.mode_set = lt9611_bridge_mode_set,
.detect = lt9611_bridge_detect,
.get_edid = lt9611_bridge_get_edid,
.hpd_enable = lt9611_bridge_hpd_enable,
+
+ .atomic_enable = lt9611_bridge_atomic_enable,
+ .atomic_disable = lt9611_bridge_atomic_disable,
+ .atomic_post_disable = lt9611_bridge_atomic_post_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
};
static int lt9611_parse_dt(struct device *dev,
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index d5945501a5ee..ad74e6558eb3 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -26,7 +26,6 @@
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <video/mipi_display.h>
@@ -853,7 +852,7 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
/* Save the new desired phy config */
memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg));
- memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
+ drm_mode_copy(&dsi->mode, adjusted_mode);
drm_mode_debug_printmodeline(adjusted_mode);
if (pm_runtime_resume_and_get(dev) < 0)
@@ -910,32 +909,14 @@ static int nwl_dsi_bridge_attach(struct drm_bridge *bridge,
{
struct nwl_dsi *dsi = bridge_to_dsi(bridge);
struct drm_bridge *panel_bridge;
- struct drm_panel *panel;
- int ret;
- ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
- &panel_bridge);
- if (ret)
- return ret;
-
- if (panel) {
- panel_bridge = drm_panel_bridge_add(panel);
- if (IS_ERR(panel_bridge))
- return PTR_ERR(panel_bridge);
- }
-
- if (!panel_bridge)
- return -EPROBE_DEFER;
+ panel_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags);
}
-static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
-{ struct nwl_dsi *dsi = bridge_to_dsi(bridge);
-
- drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
-}
-
static u32 *nwl_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
@@ -981,7 +962,6 @@ static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
.mode_set = nwl_dsi_bridge_mode_set,
.mode_valid = nwl_dsi_bridge_mode_valid,
.attach = nwl_dsi_bridge_attach,
- .detach = nwl_dsi_bridge_detach,
};
static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
@@ -1153,7 +1133,7 @@ MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids);
static const struct soc_device_attribute nwl_dsi_quirks_match[] = {
{ .soc_id = "i.MX8MQ", .revision = "2.0",
.data = (void *)E11418_HS_MODE_QUIRK },
- { /* sentinel. */ },
+ { /* sentinel. */ }
};
static int nwl_dsi_probe(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index e941c1132598..1ab91f4e057b 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -263,7 +263,6 @@ static int ptn3460_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct ptn3460_bridge *ptn_bridge;
struct drm_bridge *panel_bridge;
- struct drm_panel *panel;
int ret;
ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
@@ -271,11 +270,7 @@ static int ptn3460_probe(struct i2c_client *client,
return -ENOMEM;
}
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
- if (ret)
- return ret;
-
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 5be057575183..ff1c37b2e6e5 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -83,6 +83,9 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
drm_connector_attach_encoder(&panel_bridge->connector,
bridge->encoder);
+ if (connector->funcs->reset)
+ connector->funcs->reset(connector);
+
return 0;
}
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index 614b19f0f1b7..37b308850b4e 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -452,18 +452,13 @@ static int ps8622_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct ps8622_bridge *ps8622;
struct drm_bridge *panel_bridge;
- struct drm_panel *panel;
int ret;
ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
if (!ps8622)
return -ENOMEM;
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
- if (ret)
- return ret;
-
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index 3f17337ee389..9766cbbd62ad 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -589,7 +589,6 @@ static int ps8640_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
struct ps8640 *ps_bridge;
- struct drm_panel *panel;
int ret;
u32 i;
@@ -674,13 +673,7 @@ static int ps8640_probe(struct i2c_client *client)
devm_of_dp_aux_populate_ep_devices(&ps_bridge->aux);
/* port@1 is ps8640 output port */
- ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
- if (ret < 0)
- return ret;
- if (!panel)
- return -ENODEV;
-
- ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ ps_bridge->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
if (IS_ERR(ps_bridge->panel_bridge))
return PTR_ERR(ps_bridge->panel_bridge);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 4befc104d220..a563460f8d20 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2830,7 +2830,7 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
mutex_lock(&hdmi->mutex);
/* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+ drm_mode_copy(&hdmi->previous_mode, mode);
mutex_unlock(&hdmi->mutex);
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 11d20b8638cd..b2efecf7d160 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -246,7 +246,6 @@ struct dw_mipi_dsi {
struct clk *pclk;
- bool device_found;
unsigned int lane_mbps; /* per lane */
u32 channel;
u32 lanes;
@@ -310,37 +309,12 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
return readl(dsi->base + reg);
}
-static int dw_mipi_dsi_panel_or_bridge(struct dw_mipi_dsi *dsi,
- struct device_node *node)
-{
- struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
- if (ret)
- return ret;
-
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
- }
-
- dsi->panel_bridge = bridge;
-
- if (!dsi->panel_bridge)
- return -EPROBE_DEFER;
-
- return 0;
-}
-
static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
+ struct drm_bridge *bridge;
int ret;
if (device->lanes > dsi->plat_data->max_data_lanes) {
@@ -354,13 +328,13 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
- if (!dsi->device_found) {
- ret = dw_mipi_dsi_panel_or_bridge(dsi, host->dev->of_node);
- if (ret)
- return ret;
+ bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
- dsi->device_found = true;
- }
+ dsi->panel_bridge = bridge;
+
+ drm_bridge_add(&dsi->bridge);
if (pdata->host_ops && pdata->host_ops->attach) {
ret = pdata->host_ops->attach(pdata->priv_data, device);
@@ -1021,16 +995,6 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
/* Set the encoder type as caller does not know it */
bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
- if (!dsi->device_found) {
- int ret;
-
- ret = dw_mipi_dsi_panel_or_bridge(dsi, dsi->dev->of_node);
- if (ret)
- return ret;
-
- dsi->device_found = true;
- }
-
/* Attach the panel-bridge to the dsi bridge */
return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
flags);
@@ -1217,7 +1181,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
#ifdef CONFIG_OF
dsi->bridge.of_node = pdev->dev.of_node;
#endif
- drm_bridge_add(&dsi->bridge);
return dsi;
}
diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c
index 1bfdfc6affaf..7870aceb0a6d 100644
--- a/drivers/gpu/drm/bridge/tc358762.c
+++ b/drivers/gpu/drm/bridge/tc358762.c
@@ -179,15 +179,8 @@ static int tc358762_parse_dt(struct tc358762 *ctx)
{
struct drm_bridge *panel_bridge;
struct device *dev = ctx->dev;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
- if (ret)
- return ret;
-
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index c1e35bdf9232..dca41ed32f8a 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -16,14 +16,9 @@
#include <video/mipi_display.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_bridge.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
@@ -153,10 +148,9 @@ static const char * const tc358764_supplies[] = {
struct tc358764 {
struct device *dev;
struct drm_bridge bridge;
- struct drm_connector connector;
+ struct drm_bridge *next_bridge;
struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
struct gpio_desc *gpio_reset;
- struct drm_panel *panel;
int error;
};
@@ -210,12 +204,6 @@ static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
return container_of(bridge, struct tc358764, bridge);
}
-static inline
-struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
-{
- return container_of(connector, struct tc358764, connector);
-}
-
static int tc358764_init(struct tc358764 *ctx)
{
u32 v = 0;
@@ -278,43 +266,11 @@ static void tc358764_reset(struct tc358764 *ctx)
usleep_range(1000, 2000);
}
-static int tc358764_get_modes(struct drm_connector *connector)
-{
- struct tc358764 *ctx = connector_to_tc358764(connector);
-
- return drm_panel_get_modes(ctx->panel, connector);
-}
-
-static const
-struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
- .get_modes = tc358764_get_modes,
-};
-
-static const struct drm_connector_funcs tc358764_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static void tc358764_disable(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel);
-
- if (ret < 0)
- dev_err(ctx->dev, "error disabling panel (%d)\n", ret);
-}
-
static void tc358764_post_disable(struct drm_bridge *bridge)
{
struct tc358764 *ctx = bridge_to_tc358764(bridge);
int ret;
- ret = drm_panel_unprepare(ctx->panel);
- if (ret < 0)
- dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret);
tc358764_reset(ctx);
usleep_range(10000, 15000);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
@@ -335,72 +291,25 @@ static void tc358764_pre_enable(struct drm_bridge *bridge)
ret = tc358764_init(ctx);
if (ret < 0)
dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
- ret = drm_panel_prepare(ctx->panel);
- if (ret < 0)
- dev_err(ctx->dev, "error preparing panel (%d)\n", ret);
-}
-
-static void tc358764_enable(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- int ret = drm_panel_enable(ctx->panel);
-
- if (ret < 0)
- dev_err(ctx->dev, "error enabling panel (%d)\n", ret);
}
static int tc358764_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct tc358764 *ctx = bridge_to_tc358764(bridge);
- struct drm_device *drm = bridge->dev;
- int ret;
-
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
- }
-
- ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(drm, &ctx->connector,
- &tc358764_connector_funcs,
- DRM_MODE_CONNECTOR_LVDS);
- if (ret) {
- DRM_ERROR("Failed to initialize connector\n");
- return ret;
- }
-
- drm_connector_helper_add(&ctx->connector,
- &tc358764_connector_helper_funcs);
- drm_connector_attach_encoder(&ctx->connector, bridge->encoder);
- ctx->connector.funcs->reset(&ctx->connector);
- drm_connector_register(&ctx->connector);
-
- return 0;
-}
-
-static void tc358764_detach(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- drm_connector_unregister(&ctx->connector);
- ctx->panel = NULL;
- drm_connector_put(&ctx->connector);
+ return drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags);
}
static const struct drm_bridge_funcs tc358764_bridge_funcs = {
- .disable = tc358764_disable,
.post_disable = tc358764_post_disable,
- .enable = tc358764_enable,
.pre_enable = tc358764_pre_enable,
.attach = tc358764_attach,
- .detach = tc358764_detach,
};
static int tc358764_parse_dt(struct tc358764 *ctx)
{
struct device *dev = ctx->dev;
- int ret;
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->gpio_reset)) {
@@ -408,12 +317,11 @@ static int tc358764_parse_dt(struct tc358764 *ctx)
return PTR_ERR(ctx->gpio_reset);
}
- ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel,
- NULL);
- if (ret && ret != -EPROBE_DEFER)
- dev_err(dev, "cannot find panel (%d)\n", ret);
+ ctx->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(ctx->next_bridge))
+ return PTR_ERR(ctx->next_bridge);
- return ret;
+ return 0;
}
static int tc358764_configure_regulators(struct tc358764 *ctx)
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index c23e0abc65e8..12355daf45ef 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1,6 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * tc358767 eDP bridge driver
+ * TC358767/TC358867/TC9595 DSI/DPI-to-DPI/(e)DP bridge driver
+ *
+ * The TC358767/TC358867/TC9595 can operate in multiple modes.
+ * The following modes are supported:
+ * DPI->(e)DP -- supported
+ * DSI->DPI .... supported
+ * DSI->(e)DP .. NOT supported
*
* Copyright (C) 2016 CogentEmbedded Inc
* Author: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
@@ -29,6 +35,7 @@
#include <drm/drm_bridge.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
@@ -36,7 +43,35 @@
/* Registers */
-/* Display Parallel Interface */
+/* PPI layer registers */
+#define PPI_STARTPPI 0x0104 /* START control bit */
+#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
+#define LPX_PERIOD 3
+#define PPI_LANEENABLE 0x0134
+#define PPI_TX_RX_TA 0x013c
+#define TTA_GET 0x40000
+#define TTA_SURE 6
+#define PPI_D0S_ATMR 0x0144
+#define PPI_D1S_ATMR 0x0148
+#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */
+#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */
+#define PPI_D2S_CLRSIPOCOUNT 0x016c /* Assertion timer for Lane 2 */
+#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* Assertion timer for Lane 3 */
+#define PPI_START_FUNCTION BIT(0)
+
+/* DSI layer registers */
+#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
+#define DSI_LANEENABLE 0x0210 /* Enables each lane */
+#define DSI_RX_START BIT(0)
+
+/* Lane enable PPI and DSI register bits */
+#define LANEENABLE_CLEN BIT(0)
+#define LANEENABLE_L0EN BIT(1)
+#define LANEENABLE_L1EN BIT(2)
+#define LANEENABLE_L2EN BIT(1)
+#define LANEENABLE_L3EN BIT(2)
+
+/* Display Parallel Input Interface */
#define DPIPXLFMT 0x0440
#define VS_POL_ACTIVE_LOW (1 << 10)
#define HS_POL_ACTIVE_LOW (1 << 9)
@@ -48,6 +83,14 @@
#define DPI_BPP_RGB666 (1 << 0)
#define DPI_BPP_RGB565 (2 << 0)
+/* Display Parallel Output Interface */
+#define POCTRL 0x0448
+#define POCTRL_S2P BIT(7)
+#define POCTRL_PCLK_POL BIT(3)
+#define POCTRL_VS_POL BIT(2)
+#define POCTRL_HS_POL BIT(1)
+#define POCTRL_DE_POL BIT(0)
+
/* Video Path */
#define VPCTRL0 0x0450
#define VSDELAY GENMASK(31, 20)
@@ -247,6 +290,9 @@ struct tc_data {
struct drm_bridge *panel_bridge;
struct drm_connector connector;
+ struct mipi_dsi_device *dsi;
+ u8 dsi_lanes;
+
/* link settings */
struct tc_edp_link link;
@@ -469,10 +515,24 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
int mul, best_mul = 1;
int delta, best_delta;
int ext_div[] = {1, 2, 3, 5, 7};
+ int clk_min, clk_max;
int best_pixelclock = 0;
int vco_hi = 0;
u32 pxl_pllparam;
+ /*
+ * refclk * mul / (ext_pre_div * pre_div) should be in range:
+ * - DPI ..... 0 to 100 MHz
+ * - (e)DP ... 150 to 650 MHz
+ */
+ if (tc->bridge.type == DRM_MODE_CONNECTOR_DPI) {
+ clk_min = 0;
+ clk_max = 100000000;
+ } else {
+ clk_min = 150000000;
+ clk_max = 650000000;
+ }
+
dev_dbg(tc->dev, "PLL: requested %d pixelclock, ref %d\n", pixelclock,
refclk);
best_delta = pixelclock;
@@ -499,11 +559,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
continue;
clk = (refclk / ext_div[i_pre] / div) * mul;
- /*
- * refclk * mul / (ext_pre_div * pre_div)
- * should be in the 150 to 650 MHz range
- */
- if ((clk > 650000000) || (clk < 150000000))
+ if ((clk > clk_max) || (clk < clk_min))
continue;
clk = clk / ext_div[i_post];
@@ -656,6 +712,12 @@ static int tc_aux_link_setup(struct tc_data *tc)
if (ret)
goto err;
+ /* Register DP AUX channel */
+ tc->aux.name = "TC358767 AUX i2c adapter";
+ tc->aux.dev = tc->dev;
+ tc->aux.transfer = tc_aux_transfer;
+ drm_dp_aux_init(&tc->aux);
+
return 0;
err:
dev_err(tc->dev, "tc_aux_link_setup failed: %d\n", ret);
@@ -728,33 +790,16 @@ err_dpcd_read:
return ret;
}
-static int tc_set_video_mode(struct tc_data *tc,
- const struct drm_display_mode *mode)
+static int tc_set_common_video_mode(struct tc_data *tc,
+ const struct drm_display_mode *mode)
{
- int ret;
- int vid_sync_dly;
- int max_tu_symbol;
-
int left_margin = mode->htotal - mode->hsync_end;
int right_margin = mode->hsync_start - mode->hdisplay;
int hsync_len = mode->hsync_end - mode->hsync_start;
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
- u32 dp0_syncval;
- u32 bits_per_pixel = 24;
- u32 in_bw, out_bw;
-
- /*
- * Recommended maximum number of symbols transferred in a transfer unit:
- * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
- * (output active video bandwidth in bytes))
- * Must be less than tu_size.
- */
-
- in_bw = mode->clock * bits_per_pixel / 8;
- out_bw = tc->link.num_lanes * tc->link.rate;
- max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw);
+ int ret;
dev_dbg(tc->dev, "set mode %dx%d\n",
mode->hdisplay, mode->vdisplay);
@@ -812,8 +857,49 @@ static int tc_set_video_mode(struct tc_data *tc,
FIELD_PREP(COLOR_B, 99) |
ENI2CFILTER |
FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
- if (ret)
- return ret;
+
+ return ret;
+}
+
+static int tc_set_dpi_video_mode(struct tc_data *tc,
+ const struct drm_display_mode *mode)
+{
+ u32 value = POCTRL_S2P;
+
+ if (tc->mode.flags & DRM_MODE_FLAG_NHSYNC)
+ value |= POCTRL_HS_POL;
+
+ if (tc->mode.flags & DRM_MODE_FLAG_NVSYNC)
+ value |= POCTRL_VS_POL;
+
+ return regmap_write(tc->regmap, POCTRL, value);
+}
+
+static int tc_set_edp_video_mode(struct tc_data *tc,
+ const struct drm_display_mode *mode)
+{
+ int ret;
+ int vid_sync_dly;
+ int max_tu_symbol;
+
+ int left_margin = mode->htotal - mode->hsync_end;
+ int hsync_len = mode->hsync_end - mode->hsync_start;
+ int upper_margin = mode->vtotal - mode->vsync_end;
+ int vsync_len = mode->vsync_end - mode->vsync_start;
+ u32 dp0_syncval;
+ u32 bits_per_pixel = 24;
+ u32 in_bw, out_bw;
+
+ /*
+ * Recommended maximum number of symbols transferred in a transfer unit:
+ * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
+ * (output active video bandwidth in bytes))
+ * Must be less than tu_size.
+ */
+
+ in_bw = mode->clock * bits_per_pixel / 8;
+ out_bw = tc->link.num_lanes * tc->link.rate;
+ max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw);
/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
@@ -863,10 +949,7 @@ static int tc_set_video_mode(struct tc_data *tc,
FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
BPC_8);
- if (ret)
- return ret;
-
- return 0;
+ return ret;
}
static int tc_wait_link_training(struct tc_data *tc)
@@ -1164,7 +1247,86 @@ static int tc_main_link_disable(struct tc_data *tc)
return regmap_write(tc->regmap, DP0CTL, 0);
}
-static int tc_stream_enable(struct tc_data *tc)
+static int tc_dpi_stream_enable(struct tc_data *tc)
+{
+ int ret;
+ u32 value;
+
+ dev_dbg(tc->dev, "enable video stream\n");
+
+ /* Setup PLL */
+ ret = tc_set_syspllparam(tc);
+ if (ret)
+ return ret;
+
+ /*
+ * Initially PLLs are in bypass. Force PLL parameter update,
+ * disable PLL bypass, enable PLL
+ */
+ ret = tc_pllupdate(tc, DP0_PLLCTRL);
+ if (ret)
+ return ret;
+
+ ret = tc_pllupdate(tc, DP1_PLLCTRL);
+ if (ret)
+ return ret;
+
+ /* Pixel PLL must always be enabled for DPI mode */
+ ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
+ 1000 * tc->mode.clock);
+ if (ret)
+ return ret;
+
+ regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 3);
+ regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 3);
+ regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 3);
+ regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 3);
+ regmap_write(tc->regmap, PPI_D0S_ATMR, 0);
+ regmap_write(tc->regmap, PPI_D1S_ATMR, 0);
+ regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
+ regmap_write(tc->regmap, PPI_LPTXTIMECNT, LPX_PERIOD);
+
+ value = ((LANEENABLE_L0EN << tc->dsi_lanes) - LANEENABLE_L0EN) |
+ LANEENABLE_CLEN;
+ regmap_write(tc->regmap, PPI_LANEENABLE, value);
+ regmap_write(tc->regmap, DSI_LANEENABLE, value);
+
+ ret = tc_set_common_video_mode(tc, &tc->mode);
+ if (ret)
+ return ret;
+
+ ret = tc_set_dpi_video_mode(tc, &tc->mode);
+ if (ret)
+ return ret;
+
+ /* Set input interface */
+ value = DP0_AUDSRC_NO_INPUT;
+ if (tc_test_pattern)
+ value |= DP0_VIDSRC_COLOR_BAR;
+ else
+ value |= DP0_VIDSRC_DSI_RX;
+ ret = regmap_write(tc->regmap, SYSCTRL, value);
+ if (ret)
+ return ret;
+
+ usleep_range(120, 150);
+
+ regmap_write(tc->regmap, PPI_STARTPPI, PPI_START_FUNCTION);
+ regmap_write(tc->regmap, DSI_STARTDSI, DSI_RX_START);
+
+ return 0;
+}
+
+static int tc_dpi_stream_disable(struct tc_data *tc)
+{
+ dev_dbg(tc->dev, "disable video stream\n");
+
+ tc_pxl_pll_dis(tc);
+
+ return 0;
+}
+
+static int tc_edp_stream_enable(struct tc_data *tc)
{
int ret;
u32 value;
@@ -1179,7 +1341,11 @@ static int tc_stream_enable(struct tc_data *tc)
return ret;
}
- ret = tc_set_video_mode(tc, &tc->mode);
+ ret = tc_set_common_video_mode(tc, &tc->mode);
+ if (ret)
+ return ret;
+
+ ret = tc_set_edp_video_mode(tc, &tc->mode);
if (ret)
return ret;
@@ -1219,7 +1385,7 @@ static int tc_stream_enable(struct tc_data *tc)
return 0;
}
-static int tc_stream_disable(struct tc_data *tc)
+static int tc_edp_stream_disable(struct tc_data *tc)
{
int ret;
@@ -1234,7 +1400,37 @@ static int tc_stream_disable(struct tc_data *tc)
return 0;
}
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static void
+tc_dpi_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ int ret;
+
+ ret = tc_dpi_stream_enable(tc);
+ if (ret < 0) {
+ dev_err(tc->dev, "main link stream start error: %d\n", ret);
+ tc_main_link_disable(tc);
+ return;
+ }
+}
+
+static void
+tc_dpi_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ int ret;
+
+ ret = tc_dpi_stream_disable(tc);
+ if (ret < 0)
+ dev_err(tc->dev, "main link stream stop error: %d\n", ret);
+}
+
+static void
+tc_edp_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct tc_data *tc = bridge_to_tc(bridge);
int ret;
@@ -1251,7 +1447,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
return;
}
- ret = tc_stream_enable(tc);
+ ret = tc_edp_stream_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link stream start error: %d\n", ret);
tc_main_link_disable(tc);
@@ -1259,12 +1455,14 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
}
}
-static void tc_bridge_disable(struct drm_bridge *bridge)
+static void
+tc_edp_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct tc_data *tc = bridge_to_tc(bridge);
int ret;
- ret = tc_stream_disable(tc);
+ ret = tc_edp_stream_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link stream stop error: %d\n", ret);
@@ -1285,9 +1483,57 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
return true;
}
-static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
+static int tc_common_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ const unsigned int max_khz)
+{
+ tc_bridge_mode_fixup(bridge, &crtc_state->mode,
+ &crtc_state->adjusted_mode);
+
+ if (crtc_state->adjusted_mode.clock > max_khz)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tc_dpi_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ /* DSI->DPI interface clock limitation: upto 100 MHz */
+ return tc_common_atomic_check(bridge, bridge_state, crtc_state,
+ conn_state, 100000);
+}
+
+static int tc_edp_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ /* DPI->(e)DP interface clock limitation: upto 154 MHz */
+ return tc_common_atomic_check(bridge, bridge_state, crtc_state,
+ conn_state, 154000);
+}
+
+static enum drm_mode_status
+tc_dpi_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ /* DPI interface clock limitation: upto 100 MHz */
+ if (mode->clock > 100000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static enum drm_mode_status
+tc_edp_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
{
struct tc_data *tc = bridge_to_tc(bridge);
u32 req, avail;
@@ -1312,7 +1558,7 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge,
{
struct tc_data *tc = bridge_to_tc(bridge);
- tc->mode = *mode;
+ drm_mode_copy(&tc->mode, mode);
}
static struct edid *tc_get_edid(struct drm_bridge *bridge,
@@ -1395,8 +1641,20 @@ static const struct drm_connector_funcs tc_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static int tc_bridge_attach(struct drm_bridge *bridge,
- enum drm_bridge_attach_flags flags)
+static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+
+ if (!tc->panel_bridge)
+ return 0;
+
+ return drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ &tc->bridge, flags);
+}
+
+static int tc_edp_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct tc_data *tc = bridge_to_tc(bridge);
@@ -1448,21 +1706,64 @@ aux_unregister:
return ret;
}
-static void tc_bridge_detach(struct drm_bridge *bridge)
+static void tc_edp_bridge_detach(struct drm_bridge *bridge)
{
drm_dp_aux_unregister(&bridge_to_tc(bridge)->aux);
}
-static const struct drm_bridge_funcs tc_bridge_funcs = {
- .attach = tc_bridge_attach,
- .detach = tc_bridge_detach,
- .mode_valid = tc_mode_valid,
+#define MAX_INPUT_SEL_FORMATS 1
+
+static u32 *
+tc_dpi_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
+ GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ /* This is the DSI-end bus format */
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+ *num_input_fmts = 1;
+
+ return input_fmts;
+}
+
+static const struct drm_bridge_funcs tc_dpi_bridge_funcs = {
+ .attach = tc_dpi_bridge_attach,
+ .mode_valid = tc_dpi_mode_valid,
.mode_set = tc_bridge_mode_set,
- .enable = tc_bridge_enable,
- .disable = tc_bridge_disable,
+ .atomic_check = tc_dpi_atomic_check,
+ .atomic_enable = tc_dpi_bridge_atomic_enable,
+ .atomic_disable = tc_dpi_bridge_atomic_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_get_input_bus_fmts = tc_dpi_atomic_get_input_bus_fmts,
+};
+
+static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
+ .attach = tc_edp_bridge_attach,
+ .detach = tc_edp_bridge_detach,
+ .mode_valid = tc_edp_mode_valid,
+ .mode_set = tc_bridge_mode_set,
+ .atomic_check = tc_edp_atomic_check,
+ .atomic_enable = tc_edp_bridge_atomic_enable,
+ .atomic_disable = tc_edp_bridge_atomic_disable,
.mode_fixup = tc_bridge_mode_fixup,
.detect = tc_bridge_detect,
.get_edid = tc_get_edid,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
};
static bool tc_readable_reg(struct device *dev, unsigned int reg)
@@ -1549,18 +1850,87 @@ static irqreturn_t tc_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int tc_mipi_dsi_host_attach(struct tc_data *tc)
{
- struct device *dev = &client->dev;
+ struct device *dev = tc->dev;
+ struct device_node *host_node;
+ struct device_node *endpoint;
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *host;
+ const struct mipi_dsi_device_info info = {
+ .type = "tc358767",
+ .channel = 0,
+ .node = NULL,
+ };
+ int dsi_lanes, ret;
+
+ endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+ dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
+ host_node = of_graph_get_remote_port_parent(endpoint);
+ host = of_find_mipi_dsi_host_by_node(host_node);
+ of_node_put(host_node);
+ of_node_put(endpoint);
+
+ if (dsi_lanes < 0 || dsi_lanes > 4)
+ return -EINVAL;
+
+ if (!host)
+ return -EPROBE_DEFER;
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi))
+ return dev_err_probe(dev, PTR_ERR(dsi),
+ "failed to create dsi device\n");
+
+ tc->dsi = dsi;
+
+ tc->dsi_lanes = dsi_lanes;
+ dsi->lanes = tc->dsi_lanes;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "failed to attach dsi to host: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
+{
+ struct device *dev = tc->dev;
struct drm_panel *panel;
- struct tc_data *tc;
int ret;
- tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
- if (!tc)
- return -ENOMEM;
+ /* port@1 is the DPI input/output port */
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
+ if (ret && ret != -ENODEV)
+ return ret;
- tc->dev = dev;
+ if (panel) {
+ struct drm_bridge *panel_bridge;
+
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ tc->panel_bridge = panel_bridge;
+ tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
+ tc->bridge.funcs = &tc_dpi_bridge_funcs;
+
+ return 0;
+ }
+
+ return ret;
+}
+
+static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
+{
+ struct device *dev = tc->dev;
+ struct drm_panel *panel;
+ int ret;
/* port@2 is the output port */
ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
@@ -1580,6 +1950,74 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
}
+ tc->bridge.funcs = &tc_edp_bridge_funcs;
+ if (tc->hpd_pin >= 0)
+ tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
+ tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+
+ return ret;
+}
+
+static int tc_probe_bridge_endpoint(struct tc_data *tc)
+{
+ struct device *dev = tc->dev;
+ struct of_endpoint endpoint;
+ struct device_node *node = NULL;
+ const u8 mode_dpi_to_edp = BIT(1) | BIT(2);
+ const u8 mode_dsi_to_edp = BIT(0) | BIT(2);
+ const u8 mode_dsi_to_dpi = BIT(0) | BIT(1);
+ u8 mode = 0;
+
+ /*
+ * Determine bridge configuration.
+ *
+ * Port allocation:
+ * port@0 - DSI input
+ * port@1 - DPI input/output
+ * port@2 - eDP output
+ *
+ * Possible connections:
+ * DPI -> port@1 -> port@2 -> eDP :: [port@0 is not connected]
+ * DSI -> port@0 -> port@2 -> eDP :: [port@1 is not connected]
+ * DSI -> port@0 -> port@1 -> DPI :: [port@2 is not connected]
+ */
+
+ for_each_endpoint_of_node(dev->of_node, node) {
+ of_graph_parse_endpoint(node, &endpoint);
+ if (endpoint.port > 2)
+ return -EINVAL;
+
+ mode |= BIT(endpoint.port);
+ }
+
+ if (mode == mode_dpi_to_edp)
+ return tc_probe_edp_bridge_endpoint(tc);
+ else if (mode == mode_dsi_to_dpi)
+ return tc_probe_dpi_bridge_endpoint(tc);
+ else if (mode == mode_dsi_to_edp)
+ dev_warn(dev, "The mode DSI-to-(e)DP is not supported!\n");
+ else
+ dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode);
+
+ return -EINVAL;
+}
+
+static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct tc_data *tc;
+ int ret;
+
+ tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
+ if (!tc)
+ return -ENOMEM;
+
+ tc->dev = dev;
+
+ ret = tc_probe_bridge_endpoint(tc);
+ if (ret)
+ return ret;
+
/* Shut down GPIO is optional */
tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
if (IS_ERR(tc->sd_gpio))
@@ -1686,26 +2124,25 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
- ret = tc_aux_link_setup(tc);
- if (ret)
- return ret;
-
- /* Register DP AUX channel */
- tc->aux.name = "TC358767 AUX i2c adapter";
- tc->aux.dev = tc->dev;
- tc->aux.transfer = tc_aux_transfer;
- drm_dp_aux_init(&tc->aux);
-
- tc->bridge.funcs = &tc_bridge_funcs;
- if (tc->hpd_pin >= 0)
- tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
- tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+ if (tc->bridge.type != DRM_MODE_CONNECTOR_DPI) { /* (e)DP output */
+ ret = tc_aux_link_setup(tc);
+ if (ret)
+ return ret;
+ }
tc->bridge.of_node = dev->of_node;
drm_bridge_add(&tc->bridge);
i2c_set_clientdata(client, tc);
+ if (tc->bridge.type == DRM_MODE_CONNECTOR_DPI) { /* DPI output */
+ ret = tc_mipi_dsi_host_attach(tc);
+ if (ret) {
+ drm_bridge_remove(&tc->bridge);
+ return ret;
+ }
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
index 695af3badcc7..b987e5ac80f0 100644
--- a/drivers/gpu/drm/bridge/tc358775.c
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -649,7 +649,6 @@ static int tc_attach_host(struct tc_data *tc)
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
- struct drm_panel *panel;
struct tc_data *tc;
int ret;
@@ -660,14 +659,8 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
tc->dev = dev;
tc->i2c = client;
- ret = drm_of_find_panel_or_bridge(dev->of_node, TC358775_LVDS_OUT0,
- 0, &panel, NULL);
- if (ret < 0)
- return ret;
- if (!panel)
- return -ENODEV;
-
- tc->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ tc->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node,
+ TC358775_LVDS_OUT0, 0);
if (IS_ERR(tc->panel_bridge))
return PTR_ERR(tc->panel_bridge);
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 19daaddd29a4..2831f0813c3a 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -488,6 +488,11 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
/* Clear all errors that got asserted during initialization. */
regmap_read(ctx->regmap, REG_IRQ_STAT, &pval);
regmap_write(ctx->regmap, REG_IRQ_STAT, pval);
+
+ usleep_range(10000, 12000);
+ regmap_read(ctx->regmap, REG_IRQ_STAT, &pval);
+ if (pval)
+ dev_err(ctx->dev, "Unexpected link status 0x%02x\n", pval);
}
static void sn65dsi83_atomic_disable(struct drm_bridge *bridge,
@@ -565,7 +570,6 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
struct drm_bridge *panel_bridge;
struct device *dev = ctx->dev;
struct device_node *endpoint;
- struct drm_panel *panel;
int ret;
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
@@ -605,15 +609,10 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
}
}
- ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge);
- if (ret < 0)
+ panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
+ if (IS_ERR(panel_bridge)) {
+ ret = PTR_ERR(panel_bridge);
goto err_put_node;
- if (panel) {
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- if (IS_ERR(panel_bridge)) {
- ret = PTR_ERR(panel_bridge);
- goto err_put_node;
- }
}
ctx->panel_bridge = panel_bridge;
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index fb6c588b0f71..28d91ea5f9fd 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -1188,15 +1188,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
{
struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
struct device_node *np = pdata->dev->of_node;
- struct drm_panel *panel;
int ret;
- ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
- if (ret)
- return dev_err_probe(&adev->dev, ret,
- "could not find any panel node\n");
-
- pdata->next_bridge = devm_drm_panel_bridge_add(pdata->dev, panel);
+ pdata->next_bridge = devm_drm_of_get_bridge(pdata->dev, np, 1, 0);
if (IS_ERR(pdata->next_bridge)) {
DRM_ERROR("failed to create panel bridge\n");
return PTR_ERR(pdata->next_bridge);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 88cd992df356..58c0283fb6b0 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -789,6 +789,8 @@ drm_atomic_private_obj_init(struct drm_device *dev,
obj->state = state;
obj->funcs = funcs;
list_add_tail(&obj->head, &dev->mode_config.privobj_list);
+
+ state->obj = obj;
}
EXPORT_SYMBOL(drm_atomic_private_obj_init);
@@ -1423,8 +1425,12 @@ EXPORT_SYMBOL(drm_atomic_check_only);
int drm_atomic_commit(struct drm_atomic_state *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
+ struct drm_printer p = drm_info_printer(state->dev->dev);
int ret;
+ if (drm_debug_enabled(DRM_UT_STATE))
+ drm_atomic_print_new_state(state, &p);
+
ret = drm_atomic_check_only(state);
if (ret)
return ret;
@@ -1632,6 +1638,15 @@ commit:
}
EXPORT_SYMBOL(__drm_atomic_helper_set_config);
+static void drm_atomic_private_obj_print_state(struct drm_printer *p,
+ const struct drm_private_state *state)
+{
+ struct drm_private_obj *obj = state->obj;
+
+ if (obj->funcs->atomic_print_state)
+ obj->funcs->atomic_print_state(p, state);
+}
+
/**
* drm_atomic_print_new_state - prints drm atomic state
* @state: atomic configuration to check
@@ -1652,6 +1667,8 @@ void drm_atomic_print_new_state(const struct drm_atomic_state *state,
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_connector_state *connector_state;
+ struct drm_private_obj *obj;
+ struct drm_private_state *obj_state;
int i;
if (!p) {
@@ -1669,6 +1686,9 @@ void drm_atomic_print_new_state(const struct drm_atomic_state *state,
for_each_new_connector_in_state(state, connector, connector_state, i)
drm_atomic_connector_print_state(p, connector_state);
+
+ for_each_new_private_obj_in_state(state, obj, obj_state, i)
+ drm_atomic_private_obj_print_state(p, obj_state);
}
EXPORT_SYMBOL(drm_atomic_print_new_state);
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 54d62fdb4ef9..c6394ba13b24 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1328,7 +1328,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
struct drm_out_fence_state *fence_state;
int ret = 0;
unsigned int i, j, num_fences;
- struct drm_printer p = drm_info_printer(dev->dev);
/* disallow for drivers not supporting atomic: */
if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1460,9 +1459,6 @@ retry:
} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
ret = drm_atomic_nonblocking_commit(state);
} else {
- if (drm_debug_enabled(DRM_UT_STATE))
- drm_atomic_print_new_state(state, &p);
-
ret = drm_atomic_commit(state);
}
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index ec37cbfabb50..46ee5d5df6b4 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -317,7 +317,7 @@ EXPORT_SYMBOL(drm_plane_create_rotation_property);
* DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
* DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_Y);
*
- * to eliminate the DRM_MODE_ROTATE_X flag. Depending on what kind of
+ * to eliminate the DRM_MODE_REFLECT_X flag. Depending on what kind of
* transforms the hardware supports, this function may not
* be able to produce a supported transform, so the caller should
* check the result afterwards.
diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
index 60923cdfe8e1..6b3dad03d77d 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -384,8 +384,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector_type, ddc);
drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
- if (bridge_connector->bridge_hpd)
+ if (bridge_connector->bridge_hpd) {
connector->polled = DRM_CONNECTOR_POLL_HPD;
+ drm_bridge_connector_enable_hpd(connector);
+ }
else if (bridge_connector->bridge_detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cc7bd58369df..04e818ecd662 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -97,7 +97,7 @@ static int oui(u8 first, u8 second, u8 third)
struct detailed_mode_closure {
struct drm_connector *connector;
- struct edid *edid;
+ const struct edid *edid;
bool preferred;
u32 quirks;
int modes;
@@ -1572,6 +1572,11 @@ static const u8 edid_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
+static void edid_header_fix(void *edid)
+{
+ memcpy(edid, edid_header, sizeof(edid_header));
+}
+
/**
* drm_edid_header_is_valid - sanity check the header of the base EDID block
* @raw_edid: pointer to raw base EDID block
@@ -1580,13 +1585,15 @@ static const u8 edid_header[] = {
*
* Return: 8 if the header is perfect, down to 0 if it's totally wrong.
*/
-int drm_edid_header_is_valid(const u8 *raw_edid)
+int drm_edid_header_is_valid(const void *_edid)
{
+ const struct edid *edid = _edid;
int i, score = 0;
- for (i = 0; i < sizeof(edid_header); i++)
- if (raw_edid[i] == edid_header[i])
+ for (i = 0; i < sizeof(edid_header); i++) {
+ if (edid->header[i] == edid_header[i])
score++;
+ }
return score;
}
@@ -1597,33 +1604,37 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
MODULE_PARM_DESC(edid_fixup,
"Minimum number of valid EDID header bytes (0-8, default 6)");
-static int drm_edid_block_checksum(const u8 *raw_edid)
+static int edid_block_compute_checksum(const void *_block)
{
+ const u8 *block = _block;
int i;
u8 csum = 0, crc = 0;
for (i = 0; i < EDID_LENGTH - 1; i++)
- csum += raw_edid[i];
+ csum += block[i];
crc = 0x100 - csum;
return crc;
}
-static bool drm_edid_block_checksum_diff(const u8 *raw_edid, u8 real_checksum)
+static int edid_block_get_checksum(const void *_block)
{
- if (raw_edid[EDID_LENGTH - 1] != real_checksum)
- return true;
- else
- return false;
+ const struct edid *block = _block;
+
+ return block->checksum;
}
-static bool drm_edid_is_zero(const u8 *in_edid, int length)
+static int edid_block_tag(const void *_block)
{
- if (memchr_inv(in_edid, 0, length))
- return false;
+ const u8 *block = _block;
- return true;
+ return block[0];
+}
+
+static bool edid_is_zero(const void *edid, int length)
+{
+ return !memchr_inv(edid, 0, length);
}
/**
@@ -1657,10 +1668,62 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2)
}
EXPORT_SYMBOL(drm_edid_are_equal);
+enum edid_block_status {
+ EDID_BLOCK_OK = 0,
+ EDID_BLOCK_NULL,
+ EDID_BLOCK_HEADER_CORRUPT,
+ EDID_BLOCK_HEADER_REPAIR,
+ EDID_BLOCK_HEADER_FIXED,
+ EDID_BLOCK_CHECKSUM,
+ EDID_BLOCK_VERSION,
+};
+
+static enum edid_block_status edid_block_check(const void *_block,
+ bool is_base_block)
+{
+ const struct edid *block = _block;
+
+ if (!block)
+ return EDID_BLOCK_NULL;
+
+ if (is_base_block) {
+ int score = drm_edid_header_is_valid(block);
+
+ if (score < clamp(edid_fixup, 0, 8))
+ return EDID_BLOCK_HEADER_CORRUPT;
+
+ if (score < 8)
+ return EDID_BLOCK_HEADER_REPAIR;
+ }
+
+ if (edid_block_compute_checksum(block) != edid_block_get_checksum(block))
+ return EDID_BLOCK_CHECKSUM;
+
+ if (is_base_block) {
+ if (block->version != 1)
+ return EDID_BLOCK_VERSION;
+ }
+
+ return EDID_BLOCK_OK;
+}
+
+static bool edid_block_status_valid(enum edid_block_status status, int tag)
+{
+ return status == EDID_BLOCK_OK ||
+ status == EDID_BLOCK_HEADER_FIXED ||
+ (status == EDID_BLOCK_CHECKSUM && tag == CEA_EXT);
+}
+
+static bool edid_block_valid(const void *block, bool base)
+{
+ return edid_block_status_valid(edid_block_check(block, base),
+ edid_block_tag(block));
+}
+
/**
* drm_edid_block_valid - Sanity check the EDID block (base or extension)
* @raw_edid: pointer to raw EDID block
- * @block: type of block to validate (0 for base, extension otherwise)
+ * @block_num: type of block to validate (0 for base, extension otherwise)
* @print_bad_edid: if true, dump bad EDID blocks to the console
* @edid_corrupt: if true, the header or checksum is invalid
*
@@ -1669,88 +1732,70 @@ EXPORT_SYMBOL(drm_edid_are_equal);
*
* Return: True if the block is valid, false otherwise.
*/
-bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
+bool drm_edid_block_valid(u8 *_block, int block_num, bool print_bad_edid,
bool *edid_corrupt)
{
- u8 csum;
- struct edid *edid = (struct edid *)raw_edid;
+ struct edid *block = (struct edid *)_block;
+ enum edid_block_status status;
+ bool is_base_block = block_num == 0;
+ bool valid;
- if (WARN_ON(!raw_edid))
+ if (WARN_ON(!block))
return false;
- if (edid_fixup > 8 || edid_fixup < 0)
- edid_fixup = 6;
+ status = edid_block_check(block, is_base_block);
+ if (status == EDID_BLOCK_HEADER_REPAIR) {
+ DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
+ edid_header_fix(block);
- if (block == 0) {
- int score = drm_edid_header_is_valid(raw_edid);
-
- if (score == 8) {
- if (edid_corrupt)
- *edid_corrupt = false;
- } else if (score >= edid_fixup) {
- /* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6
- * The corrupt flag needs to be set here otherwise, the
- * fix-up code here will correct the problem, the
- * checksum is correct and the test fails
- */
- if (edid_corrupt)
- *edid_corrupt = true;
- DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
- memcpy(raw_edid, edid_header, sizeof(edid_header));
- } else {
- if (edid_corrupt)
- *edid_corrupt = true;
- goto bad;
- }
+ /* Retry with fixed header, update status if that worked. */
+ status = edid_block_check(block, is_base_block);
+ if (status == EDID_BLOCK_OK)
+ status = EDID_BLOCK_HEADER_FIXED;
}
- csum = drm_edid_block_checksum(raw_edid);
- if (drm_edid_block_checksum_diff(raw_edid, csum)) {
- if (edid_corrupt)
+ if (edid_corrupt) {
+ /*
+ * Unknown major version isn't corrupt but we can't use it. Only
+ * the base block can reset edid_corrupt to false.
+ */
+ if (is_base_block &&
+ (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION))
+ *edid_corrupt = false;
+ else if (status != EDID_BLOCK_OK)
*edid_corrupt = true;
-
- /* allow CEA to slide through, switches mangle this */
- if (raw_edid[0] == CEA_EXT) {
- DRM_DEBUG("EDID checksum is invalid, remainder is %d\n", csum);
- DRM_DEBUG("Assuming a KVM switch modified the CEA block but left the original checksum\n");
- } else {
- if (print_bad_edid)
- DRM_NOTE("EDID checksum is invalid, remainder is %d\n", csum);
-
- goto bad;
- }
}
- /* per-block-type checks */
- switch (raw_edid[0]) {
- case 0: /* base */
- if (edid->version != 1) {
- DRM_NOTE("EDID has major version %d, instead of 1\n", edid->version);
- goto bad;
+ /* Determine whether we can use this block with this status. */
+ valid = edid_block_status_valid(status, edid_block_tag(block));
+
+ /* Some fairly random status printouts. */
+ if (status == EDID_BLOCK_CHECKSUM) {
+ if (valid) {
+ DRM_DEBUG("EDID block checksum is invalid, remainder is %d\n",
+ edid_block_compute_checksum(block));
+ DRM_DEBUG("Assuming a KVM switch modified the block but left the original checksum\n");
+ } else if (print_bad_edid) {
+ DRM_NOTE("EDID block checksum is invalid, remainder is %d\n",
+ edid_block_compute_checksum(block));
}
-
- if (edid->revision > 4)
- DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
- break;
-
- default:
- break;
+ } else if (status == EDID_BLOCK_VERSION) {
+ DRM_NOTE("EDID has major version %d, instead of 1\n",
+ block->version);
}
- return true;
-
-bad:
- if (print_bad_edid) {
- if (drm_edid_is_zero(raw_edid, EDID_LENGTH)) {
+ if (!valid && print_bad_edid) {
+ if (edid_is_zero(block, EDID_LENGTH)) {
pr_notice("EDID block is all zeroes\n");
} else {
pr_notice("Raw EDID:\n");
print_hex_dump(KERN_NOTICE,
" \t", DUMP_PREFIX_NONE, 16, 1,
- raw_edid, EDID_LENGTH, false);
+ block, EDID_LENGTH, false);
}
}
- return false;
+
+ return valid;
}
EXPORT_SYMBOL(drm_edid_block_valid);
@@ -1778,6 +1823,34 @@ bool drm_edid_is_valid(struct edid *edid)
}
EXPORT_SYMBOL(drm_edid_is_valid);
+static struct edid *edid_filter_invalid_blocks(const struct edid *edid,
+ int invalid_blocks)
+{
+ struct edid *new, *dest_block;
+ int valid_extensions = edid->extensions - invalid_blocks;
+ int i;
+
+ new = kmalloc_array(valid_extensions + 1, EDID_LENGTH, GFP_KERNEL);
+ if (!new)
+ goto out;
+
+ dest_block = new;
+ for (i = 0; i <= edid->extensions; i++) {
+ const void *block = edid + i;
+
+ if (edid_block_valid(block, i == 0))
+ memcpy(dest_block++, block, EDID_LENGTH);
+ }
+
+ new->extensions = valid_extensions;
+ new->checksum = edid_block_compute_checksum(new);
+
+out:
+ kfree(edid);
+
+ return new;
+}
+
#define DDC_SEGMENT_ADDR 0x30
/**
* drm_do_probe_ddc_edid() - get EDID information via I2C
@@ -1859,7 +1932,7 @@ static void connector_bad_edid(struct drm_connector *connector,
/* Calculate real checksum for the last edid extension block data */
if (last_block < num_blocks)
connector->real_edid_checksum =
- drm_edid_block_checksum(edid + last_block * EDID_LENGTH);
+ edid_block_compute_checksum(edid + last_block * EDID_LENGTH);
if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS))
return;
@@ -1869,7 +1942,7 @@ static void connector_bad_edid(struct drm_connector *connector,
u8 *block = edid + i * EDID_LENGTH;
char prefix[20];
- if (drm_edid_is_zero(block, EDID_LENGTH))
+ if (edid_is_zero(block, EDID_LENGTH))
sprintf(prefix, "\t[%02x] ZERO ", i);
else if (!drm_edid_block_valid(block, i, false, NULL))
sprintf(prefix, "\t[%02x] BAD ", i);
@@ -1934,25 +2007,25 @@ static struct edid *drm_do_get_edid_base_block(struct drm_connector *connector,
int *null_edid_counter = connector ? &connector->null_edid_counter : NULL;
bool *edid_corrupt = connector ? &connector->edid_corrupt : NULL;
void *edid;
- int i;
+ int try;
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (edid == NULL)
return NULL;
/* base block fetch */
- for (i = 0; i < 4; i++) {
+ for (try = 0; try < 4; try++) {
if (get_edid_block(data, edid, 0, EDID_LENGTH))
goto out;
if (drm_edid_block_valid(edid, 0, false, edid_corrupt))
break;
- if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
+ if (try == 0 && edid_is_zero(edid, EDID_LENGTH)) {
if (null_edid_counter)
(*null_edid_counter)++;
goto carp;
}
}
- if (i == 4)
+ if (try == 4)
goto carp;
return edid;
@@ -1990,71 +2063,47 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
size_t len),
void *data)
{
- int i, j = 0, valid_extensions = 0;
- u8 *edid, *new;
- struct edid *override;
+ int j, invalid_blocks = 0;
+ struct edid *edid, *new, *override;
override = drm_get_override_edid(connector);
if (override)
return override;
- edid = (u8 *)drm_do_get_edid_base_block(connector, get_edid_block, data);
+ edid = drm_do_get_edid_base_block(connector, get_edid_block, data);
if (!edid)
return NULL;
- /* if there's no extensions or no connector, we're done */
- valid_extensions = edid[0x7e];
- if (valid_extensions == 0)
- return (struct edid *)edid;
+ if (edid->extensions == 0)
+ return edid;
- new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+ new = krealloc(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new)
goto out;
edid = new;
- for (j = 1; j <= edid[0x7e]; j++) {
- u8 *block = edid + j * EDID_LENGTH;
+ for (j = 1; j <= edid->extensions; j++) {
+ void *block = edid + j;
+ int try;
- for (i = 0; i < 4; i++) {
+ for (try = 0; try < 4; try++) {
if (get_edid_block(data, block, j, EDID_LENGTH))
goto out;
if (drm_edid_block_valid(block, j, false, NULL))
break;
}
- if (i == 4)
- valid_extensions--;
+ if (try == 4)
+ invalid_blocks++;
}
- if (valid_extensions != edid[0x7e]) {
- u8 *base;
+ if (invalid_blocks) {
+ connector_bad_edid(connector, (u8 *)edid, edid->extensions + 1);
- connector_bad_edid(connector, edid, edid[0x7e] + 1);
-
- edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
- edid[0x7e] = valid_extensions;
-
- new = kmalloc_array(valid_extensions + 1, EDID_LENGTH,
- GFP_KERNEL);
- if (!new)
- goto out;
-
- base = new;
- for (i = 0; i <= edid[0x7e]; i++) {
- u8 *block = edid + i * EDID_LENGTH;
-
- if (!drm_edid_block_valid(block, i, false, NULL))
- continue;
-
- memcpy(base, block, EDID_LENGTH);
- base += EDID_LENGTH;
- }
-
- kfree(edid);
- edid = new;
+ edid = edid_filter_invalid_blocks(edid, invalid_blocks);
}
- return (struct edid *)edid;
+ return edid;
out:
kfree(edid);
@@ -2150,7 +2199,7 @@ static u32 edid_extract_panel_id(const struct edid *edid)
u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
{
- struct edid *edid;
+ const struct edid *edid;
u32 panel_id;
edid = drm_do_get_edid_base_block(NULL, drm_do_probe_ddc_edid, adapter);
@@ -2331,52 +2380,58 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_mode_find_dmt);
-static bool is_display_descriptor(const u8 d[18], u8 tag)
+static bool is_display_descriptor(const struct detailed_timing *descriptor, u8 type)
{
- return d[0] == 0x00 && d[1] == 0x00 &&
- d[2] == 0x00 && d[3] == tag;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), pixel_clock) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.pad1) != 2);
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.type) != 3);
+
+ return descriptor->pixel_clock == 0 &&
+ descriptor->data.other_data.pad1 == 0 &&
+ descriptor->data.other_data.type == type;
}
-static bool is_detailed_timing_descriptor(const u8 d[18])
+static bool is_detailed_timing_descriptor(const struct detailed_timing *descriptor)
{
- return d[0] != 0x00 || d[1] != 0x00;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), pixel_clock) != 0);
+
+ return descriptor->pixel_clock != 0;
}
-typedef void detailed_cb(struct detailed_timing *timing, void *closure);
+typedef void detailed_cb(const struct detailed_timing *timing, void *closure);
static void
-cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+cea_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure)
{
int i, n;
u8 d = ext[0x02];
- u8 *det_base = ext + d;
+ const u8 *det_base = ext + d;
if (d < 4 || d > 127)
return;
n = (127 - d) / 18;
for (i = 0; i < n; i++)
- cb((struct detailed_timing *)(det_base + 18 * i), closure);
+ cb((const struct detailed_timing *)(det_base + 18 * i), closure);
}
static void
-vtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+vtb_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure)
{
unsigned int i, n = min((int)ext[0x02], 6);
- u8 *det_base = ext + 5;
+ const u8 *det_base = ext + 5;
if (ext[0x01] != 1)
return; /* unknown version */
for (i = 0; i < n; i++)
- cb((struct detailed_timing *)(det_base + 18 * i), closure);
+ cb((const struct detailed_timing *)(det_base + 18 * i), closure);
}
static void
-drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
+drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *closure)
{
int i;
- struct edid *edid = (struct edid *)raw_edid;
if (edid == NULL)
return;
@@ -2384,8 +2439,8 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
cb(&(edid->detailed_timings[i]), closure);
- for (i = 1; i <= raw_edid[0x7e]; i++) {
- u8 *ext = raw_edid + (i * EDID_LENGTH);
+ for (i = 1; i <= edid->extensions; i++) {
+ const u8 *ext = (const u8 *)edid + (i * EDID_LENGTH);
switch (*ext) {
case CEA_EXT:
@@ -2401,25 +2456,29 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
}
static void
-is_rb(struct detailed_timing *t, void *data)
+is_rb(const struct detailed_timing *descriptor, void *data)
{
- u8 *r = (u8 *)t;
+ bool *res = data;
- if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
+ if (!is_display_descriptor(descriptor, EDID_DETAIL_MONITOR_RANGE))
return;
- if (r[15] & 0x10)
- *(bool *)data = true;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10);
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.cvt.flags) != 15);
+
+ if (descriptor->data.other_data.data.range.flags == DRM_EDID_CVT_SUPPORT_FLAG &&
+ descriptor->data.other_data.data.range.formula.cvt.flags & 0x10)
+ *res = true;
}
/* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */
static bool
-drm_monitor_supports_rb(struct edid *edid)
+drm_monitor_supports_rb(const struct edid *edid)
{
if (edid->revision >= 4) {
bool ret = false;
- drm_for_each_detailed_block((u8 *)edid, is_rb, &ret);
+ drm_for_each_detailed_block(edid, is_rb, &ret);
return ret;
}
@@ -2427,68 +2486,85 @@ drm_monitor_supports_rb(struct edid *edid)
}
static void
-find_gtf2(struct detailed_timing *t, void *data)
+find_gtf2(const struct detailed_timing *descriptor, void *data)
{
- u8 *r = (u8 *)t;
+ const struct detailed_timing **res = data;
- if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
+ if (!is_display_descriptor(descriptor, EDID_DETAIL_MONITOR_RANGE))
return;
- if (r[10] == 0x02)
- *(u8 **)data = r;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10);
+
+ if (descriptor->data.other_data.data.range.flags == 0x02)
+ *res = descriptor;
}
/* Secondary GTF curve kicks in above some break frequency */
static int
-drm_gtf2_hbreak(struct edid *edid)
+drm_gtf2_hbreak(const struct edid *edid)
{
- u8 *r = NULL;
+ const struct detailed_timing *descriptor = NULL;
+
+ drm_for_each_detailed_block(edid, find_gtf2, &descriptor);
- drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
- return r ? (r[12] * 2) : 0;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.hfreq_start_khz) != 12);
+
+ return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.hfreq_start_khz * 2 : 0;
}
static int
-drm_gtf2_2c(struct edid *edid)
+drm_gtf2_2c(const struct edid *edid)
{
- u8 *r = NULL;
+ const struct detailed_timing *descriptor = NULL;
+
+ drm_for_each_detailed_block(edid, find_gtf2, &descriptor);
- drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
- return r ? r[13] : 0;
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.c) != 13);
+
+ return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.c : 0;
}
static int
-drm_gtf2_m(struct edid *edid)
+drm_gtf2_m(const struct edid *edid)
{
- u8 *r = NULL;
+ const struct detailed_timing *descriptor = NULL;
+
+ drm_for_each_detailed_block(edid, find_gtf2, &descriptor);
+
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.m) != 14);
- drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
- return r ? (r[15] << 8) + r[14] : 0;
+ return descriptor ? le16_to_cpu(descriptor->data.other_data.data.range.formula.gtf2.m) : 0;
}
static int
-drm_gtf2_k(struct edid *edid)
+drm_gtf2_k(const struct edid *edid)
{
- u8 *r = NULL;
+ const struct detailed_timing *descriptor = NULL;
+
+ drm_for_each_detailed_block(edid, find_gtf2, &descriptor);
+
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.k) != 16);
- drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
- return r ? r[16] : 0;
+ return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.k : 0;
}
static int
-drm_gtf2_2j(struct edid *edid)
+drm_gtf2_2j(const struct edid *edid)
{
- u8 *r = NULL;
+ const struct detailed_timing *descriptor = NULL;
- drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
- return r ? r[17] : 0;
+ drm_for_each_detailed_block(edid, find_gtf2, &descriptor);
+
+ BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.j) != 17);
+
+ return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0;
}
/**
* standard_timing_level - get std. timing level(CVT/GTF/DMT)
* @edid: EDID block to scan
*/
-static int standard_timing_level(struct edid *edid)
+static int standard_timing_level(const struct edid *edid)
{
if (edid->revision >= 2) {
if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
@@ -2531,8 +2607,8 @@ static int drm_mode_hsync(const struct drm_display_mode *mode)
* and convert them into a real mode using CVT/GTF/DMT.
*/
static struct drm_display_mode *
-drm_mode_std(struct drm_connector *connector, struct edid *edid,
- struct std_timing *t)
+drm_mode_std(struct drm_connector *connector, const struct edid *edid,
+ const struct std_timing *t)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *m, *mode = NULL;
@@ -2650,7 +2726,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
*/
static void
drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
- struct detailed_pixel_timing *pt)
+ const struct detailed_pixel_timing *pt)
{
int i;
static const struct {
@@ -2693,12 +2769,12 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
* return a new struct drm_display_mode.
*/
static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
- struct edid *edid,
- struct detailed_timing *timing,
+ const struct edid *edid,
+ const struct detailed_timing *timing,
u32 quirks)
{
struct drm_display_mode *mode;
- struct detailed_pixel_timing *pt = &timing->data.pixel_data;
+ const struct detailed_pixel_timing *pt = &timing->data.pixel_data;
unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo;
@@ -2740,9 +2816,9 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
return NULL;
if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
- timing->pixel_clock = cpu_to_le16(1088);
-
- mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
+ mode->clock = 1088 * 10;
+ else
+ mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
mode->hdisplay = hactive;
mode->hsync_start = mode->hdisplay + hsync_offset;
@@ -2763,14 +2839,14 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
drm_mode_do_interlace_quirk(mode, pt);
if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
- pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
+ mode->flags |= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
+ } else {
+ mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
+ DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
+ mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
+ DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
}
- mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
- DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
- mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
- DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
-
set_size:
mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
@@ -2793,7 +2869,7 @@ set_size:
static bool
mode_in_hsync_range(const struct drm_display_mode *mode,
- struct edid *edid, u8 *t)
+ const struct edid *edid, const u8 *t)
{
int hsync, hmin, hmax;
@@ -2810,7 +2886,7 @@ mode_in_hsync_range(const struct drm_display_mode *mode,
static bool
mode_in_vsync_range(const struct drm_display_mode *mode,
- struct edid *edid, u8 *t)
+ const struct edid *edid, const u8 *t)
{
int vsync, vmin, vmax;
@@ -2826,7 +2902,7 @@ mode_in_vsync_range(const struct drm_display_mode *mode,
}
static u32
-range_pixel_clock(struct edid *edid, u8 *t)
+range_pixel_clock(const struct edid *edid, const u8 *t)
{
/* unspecified */
if (t[9] == 0 || t[9] == 255)
@@ -2841,11 +2917,11 @@ range_pixel_clock(struct edid *edid, u8 *t)
}
static bool
-mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
- struct detailed_timing *timing)
+mode_in_range(const struct drm_display_mode *mode, const struct edid *edid,
+ const struct detailed_timing *timing)
{
u32 max_clock;
- u8 *t = (u8 *)timing;
+ const u8 *t = (const u8 *)timing;
if (!mode_in_hsync_range(mode, edid, t))
return false;
@@ -2887,8 +2963,8 @@ static bool valid_inferred_mode(const struct drm_connector *connector,
}
static int
-drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
- struct detailed_timing *timing)
+drm_dmt_modes_for_range(struct drm_connector *connector, const struct edid *edid,
+ const struct detailed_timing *timing)
{
int i, modes = 0;
struct drm_display_mode *newmode;
@@ -2922,8 +2998,8 @@ void drm_mode_fixup_1366x768(struct drm_display_mode *mode)
}
static int
-drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
- struct detailed_timing *timing)
+drm_gtf_modes_for_range(struct drm_connector *connector, const struct edid *edid,
+ const struct detailed_timing *timing)
{
int i, modes = 0;
struct drm_display_mode *newmode;
@@ -2951,8 +3027,8 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
}
static int
-drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
- struct detailed_timing *timing)
+drm_cvt_modes_for_range(struct drm_connector *connector, const struct edid *edid,
+ const struct detailed_timing *timing)
{
int i, modes = 0;
struct drm_display_mode *newmode;
@@ -2981,13 +3057,13 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
}
static void
-do_inferred_modes(struct detailed_timing *timing, void *c)
+do_inferred_modes(const struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
- struct detailed_non_pixel *data = &timing->data.other_data;
- struct detailed_data_monitor_range *range = &data->data.range;
+ const struct detailed_non_pixel *data = &timing->data.other_data;
+ const struct detailed_data_monitor_range *range = &data->data.range;
- if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_MONITOR_RANGE))
+ if (!is_display_descriptor(timing, EDID_DETAIL_MONITOR_RANGE))
return;
closure->modes += drm_dmt_modes_for_range(closure->connector,
@@ -3019,7 +3095,7 @@ do_inferred_modes(struct detailed_timing *timing, void *c)
}
static int
-add_inferred_modes(struct drm_connector *connector, struct edid *edid)
+add_inferred_modes(struct drm_connector *connector, const struct edid *edid)
{
struct detailed_mode_closure closure = {
.connector = connector,
@@ -3027,18 +3103,17 @@ add_inferred_modes(struct drm_connector *connector, struct edid *edid)
};
if (version_greater(edid, 1, 0))
- drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
- &closure);
+ drm_for_each_detailed_block(edid, do_inferred_modes, &closure);
return closure.modes;
}
static int
-drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
+drm_est3_modes(struct drm_connector *connector, const struct detailed_timing *timing)
{
int i, j, m, modes = 0;
struct drm_display_mode *mode;
- u8 *est = ((u8 *)timing) + 6;
+ const u8 *est = ((const u8 *)timing) + 6;
for (i = 0; i < 6; i++) {
for (j = 7; j >= 0; j--) {
@@ -3063,11 +3138,11 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
}
static void
-do_established_modes(struct detailed_timing *timing, void *c)
+do_established_modes(const struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
- if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_EST_TIMINGS))
+ if (!is_display_descriptor(timing, EDID_DETAIL_EST_TIMINGS))
return;
closure->modes += drm_est3_modes(closure->connector, timing);
@@ -3082,7 +3157,7 @@ do_established_modes(struct detailed_timing *timing, void *c)
* (defined above). Tease them out and add them to the global modes list.
*/
static int
-add_established_modes(struct drm_connector *connector, struct edid *edid)
+add_established_modes(struct drm_connector *connector, const struct edid *edid)
{
struct drm_device *dev = connector->dev;
unsigned long est_bits = edid->established_timings.t1 |
@@ -3107,26 +3182,26 @@ add_established_modes(struct drm_connector *connector, struct edid *edid)
}
if (version_greater(edid, 1, 0))
- drm_for_each_detailed_block((u8 *)edid,
- do_established_modes, &closure);
+ drm_for_each_detailed_block(edid, do_established_modes,
+ &closure);
return modes + closure.modes;
}
static void
-do_standard_modes(struct detailed_timing *timing, void *c)
+do_standard_modes(const struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
- struct detailed_non_pixel *data = &timing->data.other_data;
+ const struct detailed_non_pixel *data = &timing->data.other_data;
struct drm_connector *connector = closure->connector;
- struct edid *edid = closure->edid;
+ const struct edid *edid = closure->edid;
int i;
- if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_STD_MODES))
+ if (!is_display_descriptor(timing, EDID_DETAIL_STD_MODES))
return;
for (i = 0; i < 6; i++) {
- struct std_timing *std = &data->data.timings[i];
+ const struct std_timing *std = &data->data.timings[i];
struct drm_display_mode *newmode;
newmode = drm_mode_std(connector, edid, std);
@@ -3146,7 +3221,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
* GTF or CVT. Grab them from @edid and add them to the list.
*/
static int
-add_standard_modes(struct drm_connector *connector, struct edid *edid)
+add_standard_modes(struct drm_connector *connector, const struct edid *edid)
{
int i, modes = 0;
struct detailed_mode_closure closure = {
@@ -3166,7 +3241,7 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
}
if (version_greater(edid, 1, 0))
- drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
+ drm_for_each_detailed_block(edid, do_standard_modes,
&closure);
/* XXX should also look for standard codes in VTB blocks */
@@ -3175,12 +3250,12 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
}
static int drm_cvt_modes(struct drm_connector *connector,
- struct detailed_timing *timing)
+ const struct detailed_timing *timing)
{
int i, j, modes = 0;
struct drm_display_mode *newmode;
struct drm_device *dev = connector->dev;
- struct cvt_timing *cvt;
+ const struct cvt_timing *cvt;
const int rates[] = { 60, 85, 75, 60, 50 };
const u8 empty[3] = { 0, 0, 0 };
@@ -3227,18 +3302,18 @@ static int drm_cvt_modes(struct drm_connector *connector,
}
static void
-do_cvt_mode(struct detailed_timing *timing, void *c)
+do_cvt_mode(const struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
- if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_CVT_3BYTE))
+ if (!is_display_descriptor(timing, EDID_DETAIL_CVT_3BYTE))
return;
closure->modes += drm_cvt_modes(closure->connector, timing);
}
static int
-add_cvt_modes(struct drm_connector *connector, struct edid *edid)
+add_cvt_modes(struct drm_connector *connector, const struct edid *edid)
{
struct detailed_mode_closure closure = {
.connector = connector,
@@ -3246,7 +3321,7 @@ add_cvt_modes(struct drm_connector *connector, struct edid *edid)
};
if (version_greater(edid, 1, 2))
- drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
+ drm_for_each_detailed_block(edid, do_cvt_mode, &closure);
/* XXX should also look for CVT codes in VTB blocks */
@@ -3256,12 +3331,12 @@ add_cvt_modes(struct drm_connector *connector, struct edid *edid)
static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode);
static void
-do_detailed_mode(struct detailed_timing *timing, void *c)
+do_detailed_mode(const struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
struct drm_display_mode *newmode;
- if (!is_detailed_timing_descriptor((const u8 *)timing))
+ if (!is_detailed_timing_descriptor(timing))
return;
newmode = drm_mode_detailed(closure->connector->dev,
@@ -3292,7 +3367,7 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
* @quirks: quirks to apply
*/
static int
-add_detailed_modes(struct drm_connector *connector, struct edid *edid,
+add_detailed_modes(struct drm_connector *connector, const struct edid *edid,
u32 quirks)
{
struct detailed_mode_closure closure = {
@@ -3306,7 +3381,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
closure.preferred =
(edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
- drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
+ drm_for_each_detailed_block(edid, do_detailed_mode, &closure);
return closure.modes;
}
@@ -3341,7 +3416,7 @@ const u8 *drm_find_edid_extension(const struct edid *edid,
/* Find CEA extension */
for (i = *ext_index; i < edid->extensions; i++) {
edid_ext = (const u8 *)edid + EDID_LENGTH * (i + 1);
- if (edid_ext[0] == ext_id)
+ if (edid_block_tag(edid_ext) == ext_id)
break;
}
@@ -3638,7 +3713,7 @@ static bool drm_valid_hdmi_vic(u8 vic)
}
static int
-add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
+add_alternate_cea_modes(struct drm_connector *connector, const struct edid *edid)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *tmp;
@@ -4319,7 +4394,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
}
static int
-add_cea_modes(struct drm_connector *connector, struct edid *edid)
+add_cea_modes(struct drm_connector *connector, const struct edid *edid)
{
const u8 *cea = drm_find_cea_extension(edid);
const u8 *db, *hdmi = NULL, *video = NULL;
@@ -4489,23 +4564,25 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
}
static void
-monitor_name(struct detailed_timing *t, void *data)
+monitor_name(const struct detailed_timing *timing, void *data)
{
- if (!is_display_descriptor((const u8 *)t, EDID_DETAIL_MONITOR_NAME))
+ const char **res = data;
+
+ if (!is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME))
return;
- *(u8 **)data = t->data.other_data.data.str.str;
+ *res = timing->data.other_data.data.str.str;
}
-static int get_monitor_name(struct edid *edid, char name[13])
+static int get_monitor_name(const struct edid *edid, char name[13])
{
- char *edid_name = NULL;
+ const char *edid_name = NULL;
int mnl;
if (!edid || !name)
return 0;
- drm_for_each_detailed_block((u8 *)edid, monitor_name, &edid_name);
+ drm_for_each_detailed_block(edid, monitor_name, &edid_name);
for (mnl = 0; edid_name && mnl < 13; mnl++) {
if (edid_name[mnl] == 0x0a)
break;
@@ -4523,7 +4600,7 @@ static int get_monitor_name(struct edid *edid, char name[13])
* @bufsize: The size of the name buffer (should be at least 14 chars.)
*
*/
-void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize)
+void drm_edid_get_monitor_name(const struct edid *edid, char *name, int bufsize)
{
int name_length;
char buf[13];
@@ -4557,7 +4634,8 @@ static void clear_eld(struct drm_connector *connector)
* Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The
* HDCP and Port_ID ELD fields are left for the graphics driver to fill in.
*/
-static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
+static void drm_edid_to_eld(struct drm_connector *connector,
+ const struct edid *edid)
{
uint8_t *eld = connector->eld;
const u8 *cea;
@@ -4653,7 +4731,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
*
* Return: The number of found SADs or negative number on error.
*/
-int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
+int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads)
{
int count = 0;
int i, start, end, dbl;
@@ -4715,7 +4793,7 @@ EXPORT_SYMBOL(drm_edid_to_sad);
* Return: The number of found Speaker Allocation Blocks or negative number on
* error.
*/
-int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
+int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb)
{
int count = 0;
int i, start, end, dbl;
@@ -4810,7 +4888,7 @@ EXPORT_SYMBOL(drm_av_sync_delay);
*
* Return: True if the monitor is HDMI, false if not or unknown.
*/
-bool drm_detect_hdmi_monitor(struct edid *edid)
+bool drm_detect_hdmi_monitor(const struct edid *edid)
{
const u8 *edid_ext;
int i;
@@ -4848,7 +4926,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor);
*
* Return: True if the monitor supports audio, false otherwise.
*/
-bool drm_detect_monitor_audio(struct edid *edid)
+bool drm_detect_monitor_audio(const struct edid *edid)
{
const u8 *edid_ext;
int i, j;
@@ -5219,14 +5297,14 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
}
static
-void get_monitor_range(struct detailed_timing *timing,
+void get_monitor_range(const struct detailed_timing *timing,
void *info_monitor_range)
{
struct drm_monitor_range_info *monitor_range = info_monitor_range;
const struct detailed_non_pixel *data = &timing->data.other_data;
const struct detailed_data_monitor_range *range = &data->data.range;
- if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_MONITOR_RANGE))
+ if (!is_display_descriptor(timing, EDID_DETAIL_MONITOR_RANGE))
return;
/*
@@ -5251,7 +5329,7 @@ void drm_get_monitor_range(struct drm_connector *connector,
if (!version_greater(edid, 1, 1))
return;
- drm_for_each_detailed_block((u8 *)edid, get_monitor_range,
+ drm_for_each_detailed_block(edid, get_monitor_range,
&info->monitor_range);
DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n",
@@ -5515,7 +5593,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector,
}
static int add_displayid_detailed_modes(struct drm_connector *connector,
- struct edid *edid)
+ const struct edid *edid)
{
const struct displayid_block *block;
struct displayid_iter iter;
@@ -5532,18 +5610,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
return num_modes;
}
-/**
- * drm_add_edid_modes - add modes from EDID data, if available
- * @connector: connector we're probing
- * @edid: EDID data
- *
- * Add the specified modes to the connector's mode list. Also fills out the
- * &drm_display_info structure and ELD in @connector with any information which
- * can be derived from the edid.
- *
- * Return: The number of modes added or 0 if we couldn't find any.
- */
-int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
+static int drm_edid_connector_update(struct drm_connector *connector,
+ const struct edid *edid)
{
int num_modes = 0;
u32 quirks;
@@ -5552,12 +5620,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
clear_eld(connector);
return 0;
}
- if (!drm_edid_is_valid(edid)) {
- clear_eld(connector);
- drm_warn(connector->dev, "%s: EDID invalid.\n",
- connector->name);
- return 0;
- }
drm_edid_to_eld(connector, edid);
@@ -5609,6 +5671,28 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
return num_modes;
}
+
+/**
+ * drm_add_edid_modes - add modes from EDID data, if available
+ * @connector: connector we're probing
+ * @edid: EDID data
+ *
+ * Add the specified modes to the connector's mode list. Also fills out the
+ * &drm_display_info structure and ELD in @connector with any information which
+ * can be derived from the edid.
+ *
+ * Return: The number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
+{
+ if (edid && !drm_edid_is_valid(edid)) {
+ drm_warn(connector->dev, "%s: EDID invalid.\n",
+ connector->name);
+ edid = NULL;
+ }
+
+ return drm_edid_connector_update(connector, edid);
+}
EXPORT_SYMBOL(drm_add_edid_modes);
/**
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index bc0f49773868..0e7135114728 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -594,37 +594,26 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
}
EXPORT_SYMBOL(drm_fb_blit_toio);
-static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels,
- unsigned int start_offset, unsigned int end_len)
-{
- unsigned int xb, i;
-
- for (xb = 0; xb < pixels; xb++) {
- unsigned int start = 0, end = 8;
- u8 byte = 0x00;
-
- if (xb == 0 && start_offset)
- start = start_offset;
-
- if (xb == pixels - 1 && end_len)
- end = end_len;
- for (i = start; i < end; i++) {
- unsigned int x = xb * 8 + i;
+static void drm_fb_gray8_to_mono_line(u8 *dst, const u8 *src, unsigned int pixels)
+{
+ while (pixels) {
+ unsigned int i, bits = min(pixels, 8U);
+ u8 byte = 0;
- byte >>= 1;
- if (src[x] >> 7)
- byte |= BIT(7);
+ for (i = 0; i < bits; i++, pixels--) {
+ if (*src++ >= 128)
+ byte |= BIT(i);
}
*dst++ = byte;
}
}
/**
- * drm_fb_xrgb8888_to_mono_reversed - Convert XRGB8888 to reversed monochrome
- * @dst: reversed monochrome destination buffer
+ * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome
+ * @dst: monochrome destination buffer (0=black, 1=white)
* @dst_pitch: Number of bytes between two consecutive scanlines within dst
- * @src: XRGB8888 source buffer
+ * @vaddr: XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
@@ -633,17 +622,23 @@ static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned
* and use this function to convert to the native format.
*
* This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
- * then the result is converted from grayscale to reversed monohrome.
+ * then the result is converted from grayscale to monochrome.
+ *
+ * The first pixel (upper left corner of the clip rectangle) will be converted
+ * and copied to the first bit (LSB) in the first byte of the monochrome
+ * destination buffer.
+ * If the caller requires that the first pixel in a byte must be located at an
+ * x-coordinate that is a multiple of 8, then the caller must take care itself
+ * of supplying a suitable clip rectangle.
*/
-void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr,
- const struct drm_framebuffer *fb, const struct drm_rect *clip)
+void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *vaddr,
+ const struct drm_framebuffer *fb, const struct drm_rect *clip)
{
unsigned int linepixels = drm_rect_width(clip);
- unsigned int lines = clip->y2 - clip->y1;
+ unsigned int lines = drm_rect_height(clip);
unsigned int cpp = fb->format->cpp[0];
unsigned int len_src32 = linepixels * cpp;
struct drm_device *dev = fb->dev;
- unsigned int start_offset, end_len;
unsigned int y;
u8 *mono = dst, *gray8;
u32 *src32;
@@ -652,21 +647,18 @@ void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const v
return;
/*
- * The reversed mono destination buffer contains 1 bit per pixel
- * and destination scanlines have to be in multiple of 8 pixels.
+ * The mono destination buffer contains 1 bit per pixel
*/
if (!dst_pitch)
dst_pitch = DIV_ROUND_UP(linepixels, 8);
- drm_WARN_ONCE(dev, dst_pitch % 8 != 0, "dst_pitch is not a multiple of 8\n");
-
/*
* The cma memory is write-combined so reads are uncached.
* Speed up by fetching one line at a time.
*
- * Also, format conversion from XR24 to reversed monochrome
- * are done line-by-line but are converted to 8-bit grayscale
- * as an intermediate step.
+ * Also, format conversion from XR24 to monochrome are done
+ * line-by-line but are converted to 8-bit grayscale as an
+ * intermediate step.
*
* Allocate a buffer to be used for both copying from the cma
* memory and to store the intermediate grayscale line pixels.
@@ -677,27 +669,15 @@ void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const v
gray8 = (u8 *)src32 + len_src32;
- /*
- * For damage handling, it is possible that only parts of the source
- * buffer is copied and this could lead to start and end pixels that
- * are not aligned to multiple of 8.
- *
- * Calculate if the start and end pixels are not aligned and set the
- * offsets for the reversed mono line conversion function to adjust.
- */
- start_offset = clip->x1 % 8;
- end_len = clip->x2 % 8;
-
vaddr += clip_offset(clip, fb->pitches[0], cpp);
for (y = 0; y < lines; y++) {
src32 = memcpy(src32, vaddr, len_src32);
drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
- drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch,
- start_offset, end_len);
+ drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
vaddr += fb->pitches[0];
mono += dst_pitch;
}
kfree(src32);
}
-EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono_reversed);
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 56fb87885146..133dfae06fab 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1273,83 +1273,3 @@ drm_gem_unlock_reservations(struct drm_gem_object **objs, int count,
ww_acquire_fini(acquire_ctx);
}
EXPORT_SYMBOL(drm_gem_unlock_reservations);
-
-/**
- * drm_gem_fence_array_add - Adds the fence to an array of fences to be
- * waited on, deduplicating fences from the same context.
- *
- * @fence_array: array of dma_fence * for the job to block on.
- * @fence: the dma_fence to add to the list of dependencies.
- *
- * This functions consumes the reference for @fence both on success and error
- * cases.
- *
- * Returns:
- * 0 on success, or an error on failing to expand the array.
- */
-int drm_gem_fence_array_add(struct xarray *fence_array,
- struct dma_fence *fence)
-{
- struct dma_fence *entry;
- unsigned long index;
- u32 id = 0;
- int ret;
-
- if (!fence)
- return 0;
-
- /* Deduplicate if we already depend on a fence from the same context.
- * This lets the size of the array of deps scale with the number of
- * engines involved, rather than the number of BOs.
- */
- xa_for_each(fence_array, index, entry) {
- if (entry->context != fence->context)
- continue;
-
- if (dma_fence_is_later(fence, entry)) {
- dma_fence_put(entry);
- xa_store(fence_array, index, fence, GFP_KERNEL);
- } else {
- dma_fence_put(fence);
- }
- return 0;
- }
-
- ret = xa_alloc(fence_array, &id, fence, xa_limit_32b, GFP_KERNEL);
- if (ret != 0)
- dma_fence_put(fence);
-
- return ret;
-}
-EXPORT_SYMBOL(drm_gem_fence_array_add);
-
-/**
- * drm_gem_fence_array_add_implicit - Adds the implicit dependencies tracked
- * in the GEM object's reservation object to an array of dma_fences for use in
- * scheduling a rendering job.
- *
- * This should be called after drm_gem_lock_reservations() on your array of
- * GEM objects used in the job but before updating the reservations with your
- * own fences.
- *
- * @fence_array: array of dma_fence * for the job to block on.
- * @obj: the gem object to add new dependencies from.
- * @write: whether the job might write the object (so we need to depend on
- * shared fences in the reservation object).
- */
-int drm_gem_fence_array_add_implicit(struct xarray *fence_array,
- struct drm_gem_object *obj,
- bool write)
-{
- struct dma_resv_iter cursor;
- struct dma_fence *fence;
- int ret = 0;
-
- dma_resv_for_each_fence(&cursor, obj->resv, write, fence) {
- ret = drm_gem_fence_array_add(fence_array, fence);
- if (ret)
- break;
- }
- return ret;
-}
-EXPORT_SYMBOL(drm_gem_fence_array_add_implicit);
diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c
index c3189afe10cb..9338ddb7edff 100644
--- a/drivers/gpu/drm/drm_gem_atomic_helper.c
+++ b/drivers/gpu/drm/drm_gem_atomic_helper.c
@@ -143,25 +143,21 @@
*/
int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
{
- struct dma_resv_iter cursor;
struct drm_gem_object *obj;
struct dma_fence *fence;
+ int ret;
if (!state->fb)
return 0;
obj = drm_gem_fb_get_obj(state->fb, 0);
- dma_resv_iter_begin(&cursor, obj->resv, false);
- dma_resv_for_each_fence_unlocked(&cursor, fence) {
- /* TODO: Currently there should be only one write fence, so this
- * here works fine. But drm_atomic_set_fence_for_plane() should
- * be changed to be able to handle more fences in general for
- * multiple BOs per fb anyway. */
- dma_fence_get(fence);
- break;
- }
- dma_resv_iter_end(&cursor);
+ ret = dma_resv_get_singleton(obj->resv, false, &fence);
+ if (ret)
+ return ret;
+ /* TODO: drm_atomic_set_fence_for_plane() should be changed to be able
+ * to handle more fences in general for multiple BOs per fb.
+ */
drm_atomic_set_fence_for_plane(state, fence);
return 0;
}
diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c
index dc7f938bfff2..123045b58fec 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -867,7 +867,7 @@ static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,
if (!tt)
return NULL;
- ret = ttm_tt_init(tt, bo, page_flags, ttm_cached);
+ ret = ttm_tt_init(tt, bo, page_flags, ttm_cached, 0);
if (ret < 0)
goto err_ttm_tt_init;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 3f819c7a021b..6e7e10f16ec0 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -942,6 +942,23 @@ void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *
EXPORT_SYMBOL(drm_mode_copy);
/**
+ * drm_mode_init - initialize the mode from another mode
+ * @dst: mode to overwrite
+ * @src: mode to copy
+ *
+ * Copy an existing mode into another mode, zeroing the
+ * list head of the destination mode. Typically used
+ * to guarantee the list head is not left with stack
+ * garbage in on-stack modes.
+ */
+void drm_mode_init(struct drm_display_mode *dst, const struct drm_display_mode *src)
+{
+ memset(dst, 0, sizeof(*dst));
+ drm_mode_copy(dst, src);
+}
+EXPORT_SYMBOL(drm_mode_init);
+
+/**
* drm_mode_duplicate - allocate and duplicate an existing mode
* @dev: drm_device to allocate the duplicated mode for
* @mode: mode to duplicate
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index 98e60df882b6..63688e6e4580 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -80,9 +80,6 @@ struct etnaviv_gem_submit_bo {
u64 va;
struct etnaviv_gem_object *obj;
struct etnaviv_vram_mapping *mapping;
- struct dma_fence *excl;
- unsigned int nr_shared;
- struct dma_fence **shared;
};
/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
@@ -95,7 +92,7 @@ struct etnaviv_gem_submit {
struct etnaviv_file_private *ctx;
struct etnaviv_gpu *gpu;
struct etnaviv_iommu_context *mmu_context, *prev_mmu_context;
- struct dma_fence *out_fence, *in_fence;
+ struct dma_fence *out_fence;
int out_fence_id;
struct list_head node; /* GPU active submit list */
struct etnaviv_cmdbuf cmdbuf;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 4eb00a0cb650..53f7c78628a4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -179,24 +179,18 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
struct etnaviv_gem_submit_bo *bo = &submit->bos[i];
struct dma_resv *robj = bo->obj->base.resv;
- if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) {
- ret = dma_resv_reserve_shared(robj, 1);
- if (ret)
- return ret;
- }
+ ret = dma_resv_reserve_fences(robj, 1);
+ if (ret)
+ return ret;
if (submit->flags & ETNA_SUBMIT_NO_IMPLICIT)
continue;
- if (bo->flags & ETNA_SUBMIT_BO_WRITE) {
- ret = dma_resv_get_fences(robj, true, &bo->nr_shared,
- &bo->shared);
- if (ret)
- return ret;
- } else {
- bo->excl = dma_fence_get(dma_resv_excl_fence(robj));
- }
-
+ ret = drm_sched_job_add_implicit_dependencies(&submit->sched_job,
+ &bo->obj->base,
+ bo->flags & ETNA_SUBMIT_BO_WRITE);
+ if (ret)
+ return ret;
}
return ret;
@@ -402,8 +396,6 @@ static void submit_cleanup(struct kref *kref)
wake_up_all(&submit->gpu->fence_event);
- if (submit->in_fence)
- dma_fence_put(submit->in_fence);
if (submit->out_fence) {
/* first remove from IDR, so fence can not be found anymore */
mutex_lock(&submit->gpu->fence_lock);
@@ -534,58 +526,69 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &submit->cmdbuf,
ALIGN(args->stream_size, 8) + 8);
if (ret)
- goto err_submit_objects;
+ goto err_submit_put;
submit->ctx = file->driver_priv;
submit->mmu_context = etnaviv_iommu_context_get(submit->ctx->mmu);
submit->exec_state = args->exec_state;
submit->flags = args->flags;
+ ret = drm_sched_job_init(&submit->sched_job,
+ &ctx->sched_entity[args->pipe],
+ submit->ctx);
+ if (ret)
+ goto err_submit_put;
+
ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
if ((priv->mmu_global->version != ETNAVIV_IOMMU_V2) &&
!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4,
relocs, args->nr_relocs)) {
ret = -EINVAL;
- goto err_submit_objects;
+ goto err_submit_job;
}
if (args->flags & ETNA_SUBMIT_FENCE_FD_IN) {
- submit->in_fence = sync_file_get_fence(args->fence_fd);
- if (!submit->in_fence) {
+ struct dma_fence *in_fence = sync_file_get_fence(args->fence_fd);
+ if (!in_fence) {
ret = -EINVAL;
- goto err_submit_objects;
+ goto err_submit_job;
}
+
+ ret = drm_sched_job_add_dependency(&submit->sched_job,
+ in_fence);
+ if (ret)
+ goto err_submit_job;
}
ret = submit_pin_objects(submit);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
ret = submit_reloc(submit, stream, args->stream_size / 4,
relocs, args->nr_relocs);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
ret = submit_perfmon_validate(submit, args->exec_state, pmrs);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
memcpy(submit->cmdbuf.vaddr, stream, args->stream_size);
ret = submit_lock_objects(submit, &ticket);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
ret = submit_fence_sync(submit);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
- ret = etnaviv_sched_push_job(&ctx->sched_entity[args->pipe], submit);
+ ret = etnaviv_sched_push_job(submit);
if (ret)
- goto err_submit_objects;
+ goto err_submit_job;
submit_attach_object_fences(submit);
@@ -599,7 +602,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
sync_file = sync_file_create(submit->out_fence);
if (!sync_file) {
ret = -ENOMEM;
- goto err_submit_objects;
+ goto err_submit_job;
}
fd_install(out_fence_fd, sync_file->file);
}
@@ -607,7 +610,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
args->fence_fd = out_fence_fd;
args->fence = submit->out_fence_id;
-err_submit_objects:
+err_submit_job:
+ drm_sched_job_cleanup(&submit->sched_job);
+err_submit_put:
etnaviv_submit_put(submit);
err_submit_ww_acquire:
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index 35e5ef7dbdcc..72e2553fbc98 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -17,58 +17,6 @@ module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444);
static int etnaviv_hw_jobs_limit = 4;
module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444);
-static struct dma_fence *
-etnaviv_sched_dependency(struct drm_sched_job *sched_job,
- struct drm_sched_entity *entity)
-{
- struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
- struct dma_fence *fence;
- int i;
-
- if (unlikely(submit->in_fence)) {
- fence = submit->in_fence;
- submit->in_fence = NULL;
-
- if (!dma_fence_is_signaled(fence))
- return fence;
-
- dma_fence_put(fence);
- }
-
- for (i = 0; i < submit->nr_bos; i++) {
- struct etnaviv_gem_submit_bo *bo = &submit->bos[i];
- int j;
-
- if (bo->excl) {
- fence = bo->excl;
- bo->excl = NULL;
-
- if (!dma_fence_is_signaled(fence))
- return fence;
-
- dma_fence_put(fence);
- }
-
- for (j = 0; j < bo->nr_shared; j++) {
- if (!bo->shared[j])
- continue;
-
- fence = bo->shared[j];
- bo->shared[j] = NULL;
-
- if (!dma_fence_is_signaled(fence))
- return fence;
-
- dma_fence_put(fence);
- }
- kfree(bo->shared);
- bo->nr_shared = 0;
- bo->shared = NULL;
- }
-
- return NULL;
-}
-
static struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job)
{
struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
@@ -142,29 +90,22 @@ static void etnaviv_sched_free_job(struct drm_sched_job *sched_job)
}
static const struct drm_sched_backend_ops etnaviv_sched_ops = {
- .dependency = etnaviv_sched_dependency,
.run_job = etnaviv_sched_run_job,
.timedout_job = etnaviv_sched_timedout_job,
.free_job = etnaviv_sched_free_job,
};
-int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
- struct etnaviv_gem_submit *submit)
+int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)
{
int ret = 0;
/*
* Hold the fence lock across the whole operation to avoid jobs being
* pushed out of order with regard to their sched fence seqnos as
- * allocated in drm_sched_job_init.
+ * allocated in drm_sched_job_arm.
*/
mutex_lock(&submit->gpu->fence_lock);
- ret = drm_sched_job_init(&submit->sched_job, sched_entity,
- submit->ctx);
- if (ret)
- goto out_unlock;
-
drm_sched_job_arm(&submit->sched_job);
submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.h b/drivers/gpu/drm/etnaviv/etnaviv_sched.h
index c0a6796e22c9..baebfa069afc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.h
@@ -18,7 +18,6 @@ struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job)
int etnaviv_sched_init(struct etnaviv_gpu *gpu);
void etnaviv_sched_fini(struct etnaviv_gpu *gpu);
-int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
- struct etnaviv_gem_submit *submit);
+int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit);
#endif /* __ETNAVIV_SCHED_H__ */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 334862d422e2..f067c86b0b12 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -24,9 +24,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -253,9 +251,7 @@ struct exynos_dsi_driver_data {
struct exynos_dsi {
struct drm_encoder encoder;
struct mipi_dsi_host dsi_host;
- struct drm_connector connector;
- struct drm_panel *panel;
- struct list_head bridge_chain;
+ struct drm_bridge bridge;
struct drm_bridge *out_bridge;
struct device *dev;
struct drm_display_mode mode;
@@ -285,11 +281,10 @@ struct exynos_dsi {
};
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
-#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
-static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
+static inline struct exynos_dsi *bridge_to_dsi(struct drm_bridge *b)
{
- return container_of(e, struct exynos_dsi, encoder);
+ return container_of(b, struct exynos_dsi, bridge);
}
enum reg_idx {
@@ -1365,10 +1360,10 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
}
}
-static void exynos_dsi_enable(struct drm_encoder *encoder)
+static void exynos_dsi_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
- struct drm_bridge *iter;
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
int ret;
if (dsi->state & DSIM_STATE_ENABLED)
@@ -1381,151 +1376,70 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
}
dsi->state |= DSIM_STATE_ENABLED;
+}
- if (dsi->panel) {
- ret = drm_panel_prepare(dsi->panel);
- if (ret < 0)
- goto err_put_sync;
- } else {
- list_for_each_entry_reverse(iter, &dsi->bridge_chain,
- chain_node) {
- if (iter->funcs->pre_enable)
- iter->funcs->pre_enable(iter);
- }
- }
+static void exynos_dsi_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
exynos_dsi_set_display_mode(dsi);
exynos_dsi_set_display_enable(dsi, true);
- if (dsi->panel) {
- ret = drm_panel_enable(dsi->panel);
- if (ret < 0)
- goto err_display_disable;
- } else {
- list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->enable)
- iter->funcs->enable(iter);
- }
- }
-
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
- return;
-
-err_display_disable:
- exynos_dsi_set_display_enable(dsi, false);
- drm_panel_unprepare(dsi->panel);
-err_put_sync:
- dsi->state &= ~DSIM_STATE_ENABLED;
- pm_runtime_put(dsi->dev);
+ return;
}
-static void exynos_dsi_disable(struct drm_encoder *encoder)
+static void exynos_dsi_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
- struct drm_bridge *iter;
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
if (!(dsi->state & DSIM_STATE_ENABLED))
return;
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
+}
- drm_panel_disable(dsi->panel);
-
- list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->disable)
- iter->funcs->disable(iter);
- }
+static void exynos_dsi_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
exynos_dsi_set_display_enable(dsi, false);
- drm_panel_unprepare(dsi->panel);
-
- list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->post_disable)
- iter->funcs->post_disable(iter);
- }
dsi->state &= ~DSIM_STATE_ENABLED;
pm_runtime_put_sync(dsi->dev);
}
-static void exynos_dsi_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static void exynos_dsi_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
drm_mode_copy(&dsi->mode, adjusted_mode);
}
-static enum drm_connector_status
-exynos_dsi_detect(struct drm_connector *connector, bool force)
-{
- return connector->status;
-}
-
-static void exynos_dsi_connector_destroy(struct drm_connector *connector)
-{
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- connector->dev = NULL;
-}
-
-static const struct drm_connector_funcs exynos_dsi_connector_funcs = {
- .detect = exynos_dsi_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = exynos_dsi_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static int exynos_dsi_get_modes(struct drm_connector *connector)
+static int exynos_dsi_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
- struct exynos_dsi *dsi = connector_to_dsi(connector);
-
- if (dsi->panel)
- return drm_panel_get_modes(dsi->panel, connector);
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
- return 0;
+ return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, flags);
}
-static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
- .get_modes = exynos_dsi_get_modes,
-};
-
-static int exynos_dsi_create_connector(struct drm_encoder *encoder)
-{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
- struct drm_connector *connector = &dsi->connector;
- struct drm_device *drm = encoder->dev;
- int ret;
-
- connector->polled = DRM_CONNECTOR_POLL_HPD;
-
- ret = drm_connector_init(drm, connector, &exynos_dsi_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
- if (ret) {
- DRM_DEV_ERROR(dsi->dev,
- "Failed to initialize connector with drm\n");
- return ret;
- }
-
- connector->status = connector_status_disconnected;
- drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
- drm_connector_attach_encoder(connector, encoder);
- if (!drm->registered)
- return 0;
-
- connector->funcs->reset(connector);
- drm_connector_register(connector);
- return 0;
-}
-
-static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
- .enable = exynos_dsi_enable,
- .disable = exynos_dsi_disable,
- .mode_set = exynos_dsi_mode_set,
+static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_pre_enable = exynos_dsi_atomic_pre_enable,
+ .atomic_enable = exynos_dsi_atomic_enable,
+ .atomic_disable = exynos_dsi_atomic_disable,
+ .atomic_post_disable = exynos_dsi_atomic_post_disable,
+ .mode_set = exynos_dsi_mode_set,
+ .attach = exynos_dsi_attach,
};
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
@@ -1534,33 +1448,24 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
+ struct device *dev = dsi->dev;
struct drm_encoder *encoder = &dsi->encoder;
struct drm_device *drm = encoder->dev;
- struct drm_bridge *out_bridge;
-
- out_bridge = of_drm_find_bridge(device->dev.of_node);
- if (out_bridge) {
- drm_bridge_attach(encoder, out_bridge, NULL, 0);
- dsi->out_bridge = out_bridge;
- list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
- } else {
- int ret = exynos_dsi_create_connector(encoder);
-
- if (ret) {
- DRM_DEV_ERROR(dsi->dev,
- "failed to create connector ret = %d\n",
- ret);
- drm_encoder_cleanup(encoder);
- return ret;
- }
+ int ret;
- dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (IS_ERR(dsi->panel))
- dsi->panel = NULL;
- else
- dsi->connector.status = connector_status_connected;
+ dsi->out_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(dsi->out_bridge)) {
+ ret = PTR_ERR(dsi->out_bridge);
+ DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret);
+ return ret;
}
+ DRM_DEV_INFO(dev, "Attached %s device\n", device->name);
+
+ drm_bridge_add(&dsi->bridge);
+
+ drm_bridge_attach(encoder, &dsi->bridge, NULL, 0);
+
/*
* This is a temporary solution and should be made by more generic way.
*
@@ -1568,7 +1473,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
* TE interrupt handler.
*/
if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) {
- int ret = exynos_dsi_register_te_irq(dsi, &device->dev);
+ ret = exynos_dsi_register_te_irq(dsi, &device->dev);
if (ret)
return ret;
}
@@ -1595,24 +1500,17 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
struct exynos_dsi *dsi = host_to_dsi(host);
struct drm_device *drm = dsi->encoder.dev;
- if (dsi->panel) {
- mutex_lock(&drm->mode_config.mutex);
- exynos_dsi_disable(&dsi->encoder);
- dsi->panel = NULL;
- dsi->connector.status = connector_status_disconnected;
- mutex_unlock(&drm->mode_config.mutex);
- } else {
- if (dsi->out_bridge->funcs->detach)
- dsi->out_bridge->funcs->detach(dsi->out_bridge);
- dsi->out_bridge = NULL;
- INIT_LIST_HEAD(&dsi->bridge_chain);
- }
+ if (dsi->out_bridge->funcs->detach)
+ dsi->out_bridge->funcs->detach(dsi->out_bridge);
+ dsi->out_bridge = NULL;
if (drm->mode_config.poll_enabled)
drm_kms_helper_hotplug_event(drm);
exynos_dsi_unregister_te_irq(dsi);
+ drm_bridge_remove(&dsi->bridge);
+
return 0;
}
@@ -1662,11 +1560,6 @@ static int exynos_dsi_of_read_u32(const struct device_node *np,
return ret;
}
-enum {
- DSI_PORT_IN,
- DSI_PORT_OUT
-};
-
static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
{
struct device *dev = dsi->dev;
@@ -1697,26 +1590,14 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
struct exynos_dsi *dsi = dev_get_drvdata(dev);
struct drm_encoder *encoder = &dsi->encoder;
struct drm_device *drm_dev = data;
- struct device_node *in_bridge_node;
- struct drm_bridge *in_bridge;
int ret;
drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
-
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
- in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0);
- if (in_bridge_node) {
- in_bridge = of_drm_find_bridge(in_bridge_node);
- if (in_bridge)
- drm_bridge_attach(encoder, in_bridge, NULL, 0);
- of_node_put(in_bridge_node);
- }
-
return mipi_dsi_host_register(&dsi->dsi_host);
}
@@ -1724,9 +1605,8 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
void *data)
{
struct exynos_dsi *dsi = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &dsi->encoder;
- exynos_dsi_disable(encoder);
+ exynos_dsi_atomic_disable(&dsi->bridge, NULL);
mipi_dsi_host_unregister(&dsi->dsi_host);
}
@@ -1749,7 +1629,6 @@ static int exynos_dsi_probe(struct platform_device *pdev)
init_completion(&dsi->completed);
spin_lock_init(&dsi->transfer_lock);
INIT_LIST_HEAD(&dsi->transfer_list);
- INIT_LIST_HEAD(&dsi->bridge_chain);
dsi->dsi_host.ops = &exynos_dsi_ops;
dsi->dsi_host.dev = dev;
@@ -1817,6 +1696,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
+ dsi->bridge.funcs = &exynos_dsi_bridge_funcs;
+ dsi->bridge.of_node = dev->of_node;
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
ret = component_add(dev, &exynos_dsi_component_ops);
if (ret)
goto err_disable_runtime;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 32672bf8ae4a..9e06f8e2a863 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -102,6 +102,7 @@ struct exynos_mic {
struct videomode vm;
struct drm_encoder *encoder;
struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
bool enabled;
};
@@ -298,12 +299,22 @@ unlock:
static void mic_enable(struct drm_bridge *bridge) { }
+static int mic_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct exynos_mic *mic = bridge->driver_private;
+
+ return drm_bridge_attach(bridge->encoder, mic->next_bridge,
+ &mic->bridge, flags);
+}
+
static const struct drm_bridge_funcs mic_bridge_funcs = {
.disable = mic_disable,
.post_disable = mic_post_disable,
.mode_set = mic_mode_set,
.pre_enable = mic_pre_enable,
.enable = mic_enable,
+ .attach = mic_attach,
};
static int exynos_mic_bind(struct device *dev, struct device *master,
@@ -377,6 +388,7 @@ static int exynos_mic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct exynos_mic *mic;
+ struct device_node *remote;
struct resource res;
int ret, i;
@@ -420,6 +432,16 @@ static int exynos_mic_probe(struct platform_device *pdev)
}
}
+ remote = of_graph_get_remote_node(dev->of_node, 1, 0);
+ mic->next_bridge = of_drm_find_bridge(remote);
+ if (IS_ERR(mic->next_bridge)) {
+ DRM_DEV_ERROR(dev, "mic: Failed to find next bridge\n");
+ ret = PTR_ERR(mic->next_bridge);
+ goto err;
+ }
+
+ of_node_put(remote);
+
platform_set_drvdata(pdev, mic);
mic->bridge.funcs = &mic_bridge_funcs;
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index d7c6cca23e94..dd32b484dd82 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -262,6 +262,7 @@ static int cdv_save_display_registers(struct drm_device *dev)
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
struct psb_save_area *regs = &dev_priv->regs;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
dev_dbg(dev->dev, "Saving GPU registers.\n");
@@ -298,8 +299,10 @@ static int cdv_save_display_registers(struct drm_device *dev)
regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter)
connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+ drm_connector_list_iter_end(&conn_iter);
return 0;
}
@@ -317,6 +320,7 @@ static int cdv_restore_display_registers(struct drm_device *dev)
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
struct psb_save_area *regs = &dev_priv->regs;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
u32 temp;
@@ -373,8 +377,10 @@ static int cdv_restore_display_registers(struct drm_device *dev)
drm_mode_config_reset(dev);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter)
connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
+ drm_connector_list_iter_end(&conn_iter);
/* Resume the modeset for every activated CRTC */
drm_helper_resume_force_mode(dev);
@@ -603,7 +609,6 @@ const struct psb_ops cdv_chip_ops = {
.errata = cdv_errata,
.crtc_helper = &cdv_intel_helper_funcs,
- .crtc_funcs = &gma_intel_crtc_funcs,
.clock_funcs = &cdv_clock_funcs,
.output_init = cdv_output_init,
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index 4a9bb4994a26..6bcd18c63c31 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -191,12 +191,12 @@ static enum drm_connector_status cdv_intel_crt_detect(
static void cdv_intel_crt_destroy(struct drm_connector *connector)
{
+ struct gma_connector *gma_connector = to_gma_connector(connector);
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
psb_intel_i2c_destroy(gma_encoder->ddc_bus);
- drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
static int cdv_intel_crt_get_modes(struct drm_connector *connector)
@@ -281,8 +281,6 @@ void cdv_intel_crt_init(struct drm_device *dev,
drm_connector_helper_add(connector,
&cdv_intel_crt_connector_helper_funcs);
- drm_connector_register(connector);
-
return;
failed_ddc:
drm_encoder_cleanup(&gma_encoder->base);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 94ebc48a4349..0c3ddcdc29dc 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -584,13 +584,14 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
bool ok;
bool is_lvds = false;
bool is_dp = false;
- struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
const struct gma_limit_t *limit;
u32 ddi_select = 0;
bool is_edp = false;
- list_for_each_entry(connector, &mode_config->connector_list, head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
struct gma_encoder *gma_encoder =
gma_attached_encoder(connector);
@@ -613,10 +614,14 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
is_edp = true;
break;
default:
+ drm_connector_list_iter_end(&conn_iter);
DRM_ERROR("invalid output type.\n");
return 0;
}
+
+ break;
}
+ drm_connector_list_iter_end(&conn_iter);
if (dev_priv->dplla_96mhz)
/* low-end sku, 96/100 mhz */
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index f562e91337c7..72b1b2fc3c27 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -1857,6 +1857,7 @@ done:
static void
cdv_intel_dp_destroy(struct drm_connector *connector)
{
+ struct gma_connector *gma_connector = to_gma_connector(connector);
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
struct cdv_intel_dp *intel_dp = gma_encoder->dev_priv;
@@ -1866,9 +1867,8 @@ cdv_intel_dp_destroy(struct drm_connector *connector)
intel_dp->panel_fixed_mode = NULL;
}
i2c_del_adapter(&intel_dp->adapter);
- drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
static const struct drm_encoder_helper_funcs cdv_intel_dp_helper_funcs = {
@@ -1990,8 +1990,6 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- drm_connector_register(connector);
-
/* Set up the DDC bus. */
switch (output_reg) {
case DP_B:
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index e525689f84f0..8987e555e113 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -242,12 +242,12 @@ static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector,
static void cdv_hdmi_destroy(struct drm_connector *connector)
{
+ struct gma_connector *gma_connector = to_gma_connector(connector);
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
psb_intel_i2c_destroy(gma_encoder->i2c_bus);
- drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
@@ -352,7 +352,6 @@ void cdv_hdmi_init(struct drm_device *dev,
hdmi_priv->hdmi_i2c_adapter = &(gma_encoder->i2c_bus->adapter);
hdmi_priv->dev = dev;
- drm_connector_register(connector);
return;
failed_ddc:
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 9e1cdb11023c..98d9f5483a7c 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -326,12 +326,12 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector)
*/
static void cdv_intel_lvds_destroy(struct drm_connector *connector)
{
+ struct gma_connector *gma_connector = to_gma_connector(connector);
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
psb_intel_i2c_destroy(gma_encoder->i2c_bus);
- drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
static int cdv_intel_lvds_set_property(struct drm_connector *connector,
@@ -647,7 +647,6 @@ void cdv_intel_lvds_init(struct drm_device *dev,
out:
mutex_unlock(&dev->mode_config.mutex);
- drm_connector_register(connector);
return;
failed_find:
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 45df9de22007..0ac6ea5fd3a1 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -451,6 +451,7 @@ static const struct drm_mode_config_funcs psb_mode_funcs = {
static void psb_setup_outputs(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
drm_mode_create_scaling_mode_property(dev);
@@ -461,8 +462,8 @@ static void psb_setup_outputs(struct drm_device *dev)
"backlight", 0, 100);
dev_priv->ops->output_init(dev);
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
struct drm_encoder *encoder = &gma_encoder->base;
int crtc_mask = 0, clone_mask = 0;
@@ -505,6 +506,7 @@ static void psb_setup_outputs(struct drm_device *dev)
encoder->possible_clones =
gma_connector_clones(dev, clone_mask);
}
+ drm_connector_list_iter_end(&conn_iter);
}
void psb_modeset_init(struct drm_device *dev)
@@ -514,7 +516,8 @@ void psb_modeset_init(struct drm_device *dev)
struct pci_dev *pdev = to_pci_dev(dev->dev);
int i;
- drm_mode_config_init(dev);
+ if (drmm_mode_config_init(dev))
+ return;
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -546,6 +549,5 @@ void psb_modeset_cleanup(struct drm_device *dev)
if (dev_priv->modeset) {
drm_kms_helper_poll_fini(dev);
psb_fbdev_fini(dev);
- drm_mode_config_cleanup(dev);
}
}
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c
index 8d65af80bb08..dffe37490206 100644
--- a/drivers/gpu/drm/gma500/gem.c
+++ b/drivers/gpu/drm/gma500/gem.c
@@ -21,6 +21,10 @@
#include "gem.h"
#include "psb_drv.h"
+/*
+ * PSB GEM object
+ */
+
int psb_gem_pin(struct psb_gem_object *pobj)
{
struct drm_gem_object *obj = &pobj->base;
@@ -31,7 +35,9 @@ int psb_gem_pin(struct psb_gem_object *pobj)
unsigned int npages;
int ret;
- mutex_lock(&dev_priv->gtt_mutex);
+ ret = dma_resv_lock(obj->resv, NULL);
+ if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret))
+ return ret;
if (pobj->in_gart || pobj->stolen)
goto out; /* already mapped */
@@ -39,7 +45,7 @@ int psb_gem_pin(struct psb_gem_object *pobj)
pages = drm_gem_get_pages(obj);
if (IS_ERR(pages)) {
ret = PTR_ERR(pages);
- goto err_mutex_unlock;
+ goto err_dma_resv_unlock;
}
npages = obj->size / PAGE_SIZE;
@@ -51,17 +57,16 @@ int psb_gem_pin(struct psb_gem_object *pobj)
(gpu_base + pobj->offset), npages, 0, 0,
PSB_MMU_CACHED_MEMORY);
- pobj->npage = npages;
pobj->pages = pages;
out:
++pobj->in_gart;
- mutex_unlock(&dev_priv->gtt_mutex);
+ dma_resv_unlock(obj->resv);
return 0;
-err_mutex_unlock:
- mutex_unlock(&dev_priv->gtt_mutex);
+err_dma_resv_unlock:
+ dma_resv_unlock(obj->resv);
return ret;
}
@@ -71,8 +76,12 @@ void psb_gem_unpin(struct psb_gem_object *pobj)
struct drm_device *dev = obj->dev;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
u32 gpu_base = dev_priv->gtt.gatt_start;
+ unsigned long npages;
+ int ret;
- mutex_lock(&dev_priv->gtt_mutex);
+ ret = dma_resv_lock(obj->resv, NULL);
+ if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret))
+ return;
WARN_ON(!pobj->in_gart);
@@ -81,19 +90,20 @@ void psb_gem_unpin(struct psb_gem_object *pobj)
if (pobj->in_gart || pobj->stolen)
goto out;
+ npages = obj->size / PAGE_SIZE;
+
psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu),
- (gpu_base + pobj->offset), pobj->npage, 0, 0);
+ (gpu_base + pobj->offset), npages, 0, 0);
psb_gtt_remove_pages(dev_priv, &pobj->resource);
/* Reset caching flags */
- set_pages_array_wb(pobj->pages, pobj->npage);
+ set_pages_array_wb(pobj->pages, npages);
drm_gem_put_pages(obj, pobj->pages, true, false);
pobj->pages = NULL;
- pobj->npage = 0;
out:
- mutex_unlock(&dev_priv->gtt_mutex);
+ dma_resv_unlock(obj->resv);
}
static vm_fault_t psb_gem_fault(struct vm_fault *vmf);
@@ -290,3 +300,132 @@ fail:
return ret;
}
+
+/*
+ * Memory management
+ */
+
+/* Insert vram stolen pages into the GTT. */
+static void psb_gem_mm_populate_stolen(struct drm_psb_private *pdev)
+{
+ struct drm_device *dev = &pdev->dev;
+ unsigned int pfn_base;
+ unsigned int i, num_pages;
+ uint32_t pte;
+
+ pfn_base = pdev->stolen_base >> PAGE_SHIFT;
+ num_pages = pdev->vram_stolen_size >> PAGE_SHIFT;
+
+ drm_dbg(dev, "Set up %u stolen pages starting at 0x%08x, GTT offset %dK\n",
+ num_pages, pfn_base << PAGE_SHIFT, 0);
+
+ for (i = 0; i < num_pages; ++i) {
+ pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY);
+ iowrite32(pte, pdev->gtt_map + i);
+ }
+
+ (void)ioread32(pdev->gtt_map + i - 1);
+}
+
+int psb_gem_mm_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ unsigned long stolen_size, vram_stolen_size;
+ struct psb_gtt *pg;
+ int ret;
+
+ mutex_init(&dev_priv->mmap_mutex);
+
+ pg = &dev_priv->gtt;
+
+ pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base);
+ vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE;
+
+ stolen_size = vram_stolen_size;
+
+ dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n",
+ dev_priv->stolen_base, vram_stolen_size / 1024);
+
+ pg->stolen_size = stolen_size;
+ dev_priv->vram_stolen_size = vram_stolen_size;
+
+ dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size);
+ if (!dev_priv->vram_addr) {
+ dev_err(dev->dev, "Failure to map stolen base.\n");
+ ret = -ENOMEM;
+ goto err_mutex_destroy;
+ }
+
+ psb_gem_mm_populate_stolen(dev_priv);
+
+ return 0;
+
+err_mutex_destroy:
+ mutex_destroy(&dev_priv->mmap_mutex);
+ return ret;
+}
+
+void psb_gem_mm_fini(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+
+ iounmap(dev_priv->vram_addr);
+
+ mutex_destroy(&dev_priv->mmap_mutex);
+}
+
+/* Re-insert all pinned GEM objects into GTT. */
+static void psb_gem_mm_populate_resources(struct drm_psb_private *pdev)
+{
+ unsigned int restored = 0, total = 0, size = 0;
+ struct resource *r = pdev->gtt_mem->child;
+ struct drm_device *dev = &pdev->dev;
+ struct psb_gem_object *pobj;
+
+ while (r) {
+ /*
+ * TODO: GTT restoration needs a refactoring, so that we don't have to touch
+ * struct psb_gem_object here. The type represents a GEM object and is
+ * not related to the GTT itself.
+ */
+ pobj = container_of(r, struct psb_gem_object, resource);
+ if (pobj->pages) {
+ psb_gtt_insert_pages(pdev, &pobj->resource, pobj->pages);
+ size += resource_size(&pobj->resource);
+ ++restored;
+ }
+ r = r->sibling;
+ ++total;
+ }
+
+ drm_dbg(dev, "Restored %u of %u gtt ranges (%u KB)", restored, total, (size / 1024));
+}
+
+int psb_gem_mm_resume(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ unsigned long stolen_size, vram_stolen_size;
+ struct psb_gtt *pg;
+
+ pg = &dev_priv->gtt;
+
+ pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base);
+ vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE;
+
+ stolen_size = vram_stolen_size;
+
+ dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", dev_priv->stolen_base,
+ vram_stolen_size / 1024);
+
+ if (stolen_size != pg->stolen_size) {
+ dev_err(dev->dev, "GTT resume error.\n");
+ return -EINVAL;
+ }
+
+ psb_gem_mm_populate_stolen(dev_priv);
+ psb_gem_mm_populate_resources(dev_priv);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h
index 79cced40c87f..27df6ff4ed37 100644
--- a/drivers/gpu/drm/gma500/gem.h
+++ b/drivers/gpu/drm/gma500/gem.h
@@ -14,6 +14,10 @@
struct drm_device;
+/*
+ * PSB GEM object
+ */
+
struct psb_gem_object {
struct drm_gem_object base;
@@ -23,7 +27,6 @@ struct psb_gem_object {
bool stolen; /* Backed from stolen RAM */
bool mmapping; /* Is mmappable */
struct page **pages; /* Backing pages if present */
- int npage; /* Number of backing pages */
};
static inline struct psb_gem_object *to_psb_gem_object(struct drm_gem_object *obj)
@@ -37,4 +40,12 @@ psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen,
int psb_gem_pin(struct psb_gem_object *pobj);
void psb_gem_unpin(struct psb_gem_object *pobj);
+/*
+ * Memory management
+ */
+
+int psb_gem_mm_init(struct drm_device *dev);
+void psb_gem_mm_fini(struct drm_device *dev);
+int psb_gem_mm_resume(struct drm_device *dev);
+
#endif
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
index 60ba7de59139..34ec3fca09ba 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -17,7 +17,7 @@
#include "framebuffer.h"
#include "gem.h"
#include "gma_display.h"
-#include "psb_drv.h"
+#include "psb_irq.h"
#include "psb_intel_drv.h"
#include "psb_intel_reg.h"
@@ -27,17 +27,21 @@
bool gma_pipe_has_type(struct drm_crtc *crtc, int type)
{
struct drm_device *dev = crtc->dev;
- struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_connector *l_entry;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
- list_for_each_entry(l_entry, &mode_config->connector_list, head) {
- if (l_entry->encoder && l_entry->encoder->crtc == crtc) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (connector->encoder && connector->encoder->crtc == crtc) {
struct gma_encoder *gma_encoder =
- gma_attached_encoder(l_entry);
- if (gma_encoder->type == type)
+ gma_attached_encoder(connector);
+ if (gma_encoder->type == type) {
+ drm_connector_list_iter_end(&conn_iter);
return true;
+ }
}
}
+ drm_connector_list_iter_end(&conn_iter);
return false;
}
@@ -172,9 +176,9 @@ void gma_crtc_load_lut(struct drm_crtc *crtc)
}
}
-int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue,
- u32 size,
- struct drm_modeset_acquire_ctx *ctx)
+static int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, u32 size,
+ struct drm_modeset_acquire_ctx *ctx)
{
gma_crtc_load_lut(crtc);
@@ -319,10 +323,9 @@ void gma_crtc_dpms(struct drm_crtc *crtc, int mode)
REG_WRITE(DSPARB, 0x3F3E);
}
-int gma_crtc_cursor_set(struct drm_crtc *crtc,
- struct drm_file *file_priv,
- uint32_t handle,
- uint32_t width, uint32_t height)
+static int gma_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv, uint32_t handle,
+ uint32_t width, uint32_t height)
{
struct drm_device *dev = crtc->dev;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
@@ -391,11 +394,9 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
goto unref_cursor;
}
- /* Prevent overflow */
- if (pobj->npage > 4)
- cursor_pages = 4;
- else
- cursor_pages = pobj->npage;
+ cursor_pages = obj->size / PAGE_SIZE;
+ if (cursor_pages > 4)
+ cursor_pages = 4; /* Prevent overflow */
/* Copy the cursor to cursor mem */
tmp_dst = dev_priv->vram_addr + cursor_pobj->offset;
@@ -437,7 +438,7 @@ unref_cursor:
return ret;
}
-int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+static int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
struct drm_device *dev = crtc->dev;
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
@@ -567,6 +568,18 @@ int gma_crtc_set_config(struct drm_mode_set *set,
return ret;
}
+const struct drm_crtc_funcs gma_crtc_funcs = {
+ .cursor_set = gma_crtc_cursor_set,
+ .cursor_move = gma_crtc_cursor_move,
+ .gamma_set = gma_crtc_gamma_set,
+ .set_config = gma_crtc_set_config,
+ .destroy = gma_crtc_destroy,
+ .page_flip = gma_crtc_page_flip,
+ .enable_vblank = gma_crtc_enable_vblank,
+ .disable_vblank = gma_crtc_disable_vblank,
+ .get_vblank_counter = gma_crtc_get_vblank_counter,
+};
+
/*
* Save HW states of given crtc
*/
diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h
index 7bd6c1ee8b21..113cf048105e 100644
--- a/drivers/gpu/drm/gma500/gma_display.h
+++ b/drivers/gpu/drm/gma500/gma_display.h
@@ -58,15 +58,7 @@ extern bool gma_pipe_has_type(struct drm_crtc *crtc, int type);
extern void gma_wait_for_vblank(struct drm_device *dev);
extern int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
-extern int gma_crtc_cursor_set(struct drm_crtc *crtc,
- struct drm_file *file_priv,
- uint32_t handle,
- uint32_t width, uint32_t height);
-extern int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
extern void gma_crtc_load_lut(struct drm_crtc *crtc);
-extern int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, u32 size,
- struct drm_modeset_acquire_ctx *ctx);
extern void gma_crtc_dpms(struct drm_crtc *crtc, int mode);
extern void gma_crtc_prepare(struct drm_crtc *crtc);
extern void gma_crtc_commit(struct drm_crtc *crtc);
@@ -83,6 +75,8 @@ extern int gma_crtc_set_config(struct drm_mode_set *set,
extern void gma_crtc_save(struct drm_crtc *crtc);
extern void gma_crtc_restore(struct drm_crtc *crtc);
+extern const struct drm_crtc_funcs gma_crtc_funcs;
+
extern void gma_encoder_prepare(struct drm_encoder *encoder);
extern void gma_encoder_commit(struct drm_encoder *encoder);
extern void gma_encoder_destroy(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index 309ffe921bfd..379bc218aa6b 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -49,7 +49,7 @@ int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res
*
* Set the GTT entry for the appropriate memory type.
*/
-static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
+uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
{
uint32_t mask = PSB_PTE_VALID;
@@ -74,11 +74,7 @@ static u32 __iomem *psb_gtt_entry(struct drm_psb_private *pdev, const struct res
return pdev->gtt_map + (offset >> PAGE_SHIFT);
}
-/*
- * Take our preallocated GTT range and insert the GEM object into
- * the GTT. This is protected via the gtt mutex which the caller
- * must hold.
- */
+/* Acquires GTT mutex internally. */
void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res,
struct page **pages)
{
@@ -86,6 +82,8 @@ void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *r
u32 __iomem *gtt_slot;
u32 pte;
+ mutex_lock(&pdev->gtt_mutex);
+
/* Write our page entries into the GTT itself */
npages = resource_size(res) >> PAGE_SHIFT;
@@ -98,19 +96,19 @@ void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *r
/* Make sure all the entries are set before we return */
ioread32(gtt_slot - 1);
+
+ mutex_unlock(&pdev->gtt_mutex);
}
-/*
- * Remove a preallocated GTT range from the GTT. Overwrite all the
- * page table entries with the dummy page. This is protected via the gtt
- * mutex which the caller must hold.
- */
+/* Acquires GTT mutex internally. */
void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res)
{
resource_size_t npages, i;
u32 __iomem *gtt_slot;
u32 pte;
+ mutex_lock(&pdev->gtt_mutex);
+
/* Install scratch page for the resource */
pte = psb_gtt_mask_pte(page_to_pfn(pdev->scratch_page), PSB_MMU_CACHED_MEMORY);
@@ -123,211 +121,192 @@ void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *r
/* Make sure all the entries are set before we return */
ioread32(gtt_slot - 1);
+
+ mutex_unlock(&pdev->gtt_mutex);
}
-static void psb_gtt_alloc(struct drm_device *dev)
+static int psb_gtt_enable(struct drm_psb_private *dev_priv)
{
- struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
- init_rwsem(&dev_priv->gtt.sem);
+ struct drm_device *dev = &dev_priv->dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ int ret;
+
+ ret = pci_read_config_word(pdev, PSB_GMCH_CTRL, &dev_priv->gmch_ctrl);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+ ret = pci_write_config_word(pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL);
+ PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
+
+ (void)PSB_RVDC32(PSB_PGETBL_CTL);
+
+ return 0;
}
-void psb_gtt_takedown(struct drm_device *dev)
+static void psb_gtt_disable(struct drm_psb_private *dev_priv)
{
- struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct drm_device *dev = &dev_priv->dev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
- if (dev_priv->gtt_map) {
- iounmap(dev_priv->gtt_map);
- dev_priv->gtt_map = NULL;
- }
- if (dev_priv->gtt_initialized) {
- pci_write_config_word(pdev, PSB_GMCH_CTRL,
- dev_priv->gmch_ctrl);
- PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL);
- (void) PSB_RVDC32(PSB_PGETBL_CTL);
- }
- if (dev_priv->vram_addr)
- iounmap(dev_priv->gtt_map);
+ pci_write_config_word(pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl);
+ PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL);
+
+ (void)PSB_RVDC32(PSB_PGETBL_CTL);
}
-int psb_gtt_init(struct drm_device *dev, int resume)
+void psb_gtt_fini(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- unsigned gtt_pages;
- unsigned long stolen_size, vram_stolen_size;
- unsigned i, num_pages;
- unsigned pfn_base;
- struct psb_gtt *pg;
- int ret = 0;
+ iounmap(dev_priv->gtt_map);
+ psb_gtt_disable(dev_priv);
+ mutex_destroy(&dev_priv->gtt_mutex);
+}
+
+/* Clear GTT. Use a scratch page to avoid accidents or scribbles. */
+static void psb_gtt_clear(struct drm_psb_private *pdev)
+{
+ resource_size_t pfn_base;
+ unsigned long i;
uint32_t pte;
- if (!resume) {
- mutex_init(&dev_priv->gtt_mutex);
- mutex_init(&dev_priv->mmap_mutex);
- psb_gtt_alloc(dev);
- }
+ pfn_base = page_to_pfn(pdev->scratch_page);
+ pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY);
- pg = &dev_priv->gtt;
+ for (i = 0; i < pdev->gtt.gtt_pages; ++i)
+ iowrite32(pte, pdev->gtt_map + i);
- /* Enable the GTT */
- pci_read_config_word(pdev, PSB_GMCH_CTRL, &dev_priv->gmch_ctrl);
- pci_write_config_word(pdev, PSB_GMCH_CTRL,
- dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
+ (void)ioread32(pdev->gtt_map + i - 1);
+}
- dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL);
- PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
- (void) PSB_RVDC32(PSB_PGETBL_CTL);
+static void psb_gtt_init_ranges(struct drm_psb_private *dev_priv)
+{
+ struct drm_device *dev = &dev_priv->dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ struct psb_gtt *pg = &dev_priv->gtt;
+ resource_size_t gtt_phys_start, mmu_gatt_start, gtt_start, gtt_pages,
+ gatt_start, gatt_pages;
+ struct resource *gtt_mem;
/* The root resource we allocate address space from */
- dev_priv->gtt_initialized = 1;
-
- pg->gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK;
+ gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK;
/*
- * The video mmu has a hw bug when accessing 0x0D0000000.
- * Make gatt start at 0x0e000,0000. This doesn't actually
- * matter for us but may do if the video acceleration ever
- * gets opened up.
+ * The video MMU has a HW bug when accessing 0x0d0000000. Make
+ * GATT start at 0x0e0000000. This doesn't actually matter for
+ * us now, but maybe will if the video acceleration ever gets
+ * opened up.
*/
- pg->mmu_gatt_start = 0xE0000000;
+ mmu_gatt_start = 0xe0000000;
+
+ gtt_start = pci_resource_start(pdev, PSB_GTT_RESOURCE);
+ gtt_pages = pci_resource_len(pdev, PSB_GTT_RESOURCE) >> PAGE_SHIFT;
- pg->gtt_start = pci_resource_start(pdev, PSB_GTT_RESOURCE);
- gtt_pages = pci_resource_len(pdev, PSB_GTT_RESOURCE)
- >> PAGE_SHIFT;
/* CDV doesn't report this. In which case the system has 64 gtt pages */
- if (pg->gtt_start == 0 || gtt_pages == 0) {
+ if (!gtt_start || !gtt_pages) {
dev_dbg(dev->dev, "GTT PCI BAR not initialized.\n");
gtt_pages = 64;
- pg->gtt_start = dev_priv->pge_ctl;
+ gtt_start = dev_priv->pge_ctl;
}
- pg->gatt_start = pci_resource_start(pdev, PSB_GATT_RESOURCE);
- pg->gatt_pages = pci_resource_len(pdev, PSB_GATT_RESOURCE)
- >> PAGE_SHIFT;
- dev_priv->gtt_mem = &pdev->resource[PSB_GATT_RESOURCE];
+ gatt_start = pci_resource_start(pdev, PSB_GATT_RESOURCE);
+ gatt_pages = pci_resource_len(pdev, PSB_GATT_RESOURCE) >> PAGE_SHIFT;
- if (pg->gatt_pages == 0 || pg->gatt_start == 0) {
+ if (!gatt_pages || !gatt_start) {
static struct resource fudge; /* Preferably peppermint */
- /* This can occur on CDV systems. Fudge it in this case.
- We really don't care what imaginary space is being allocated
- at this point */
+
+ /*
+ * This can occur on CDV systems. Fudge it in this case. We
+ * really don't care what imaginary space is being allocated
+ * at this point.
+ */
dev_dbg(dev->dev, "GATT PCI BAR not initialized.\n");
- pg->gatt_start = 0x40000000;
- pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT;
- /* This is a little confusing but in fact the GTT is providing
- a view from the GPU into memory and not vice versa. As such
- this is really allocating space that is not the same as the
- CPU address space on CDV */
+ gatt_start = 0x40000000;
+ gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT;
+
+ /*
+ * This is a little confusing but in fact the GTT is providing
+ * a view from the GPU into memory and not vice versa. As such
+ * this is really allocating space that is not the same as the
+ * CPU address space on CDV.
+ */
fudge.start = 0x40000000;
fudge.end = 0x40000000 + 128 * 1024 * 1024 - 1;
fudge.name = "fudge";
fudge.flags = IORESOURCE_MEM;
- dev_priv->gtt_mem = &fudge;
+
+ gtt_mem = &fudge;
+ } else {
+ gtt_mem = &pdev->resource[PSB_GATT_RESOURCE];
}
- pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base);
- vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base
- - PAGE_SIZE;
+ pg->gtt_phys_start = gtt_phys_start;
+ pg->mmu_gatt_start = mmu_gatt_start;
+ pg->gtt_start = gtt_start;
+ pg->gtt_pages = gtt_pages;
+ pg->gatt_start = gatt_start;
+ pg->gatt_pages = gatt_pages;
+ dev_priv->gtt_mem = gtt_mem;
+}
- stolen_size = vram_stolen_size;
+int psb_gtt_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct psb_gtt *pg = &dev_priv->gtt;
+ int ret;
- dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n",
- dev_priv->stolen_base, vram_stolen_size / 1024);
+ mutex_init(&dev_priv->gtt_mutex);
- if (resume && (gtt_pages != pg->gtt_pages) &&
- (stolen_size != pg->stolen_size)) {
- dev_err(dev->dev, "GTT resume error.\n");
- ret = -EINVAL;
- goto out_err;
- }
+ ret = psb_gtt_enable(dev_priv);
+ if (ret)
+ goto err_mutex_destroy;
- pg->gtt_pages = gtt_pages;
- pg->stolen_size = stolen_size;
- dev_priv->vram_stolen_size = vram_stolen_size;
+ psb_gtt_init_ranges(dev_priv);
- /*
- * Map the GTT and the stolen memory area
- */
- if (!resume)
- dev_priv->gtt_map = ioremap(pg->gtt_phys_start,
- gtt_pages << PAGE_SHIFT);
+ dev_priv->gtt_map = ioremap(pg->gtt_phys_start, pg->gtt_pages << PAGE_SHIFT);
if (!dev_priv->gtt_map) {
dev_err(dev->dev, "Failure to map gtt.\n");
ret = -ENOMEM;
- goto out_err;
- }
-
- if (!resume)
- dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base,
- stolen_size);
-
- if (!dev_priv->vram_addr) {
- dev_err(dev->dev, "Failure to map stolen base.\n");
- ret = -ENOMEM;
- goto out_err;
+ goto err_psb_gtt_disable;
}
- /*
- * Insert vram stolen pages into the GTT
- */
-
- pfn_base = dev_priv->stolen_base >> PAGE_SHIFT;
- num_pages = vram_stolen_size >> PAGE_SHIFT;
- dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",
- num_pages, pfn_base << PAGE_SHIFT, 0);
- for (i = 0; i < num_pages; ++i) {
- pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY);
- iowrite32(pte, dev_priv->gtt_map + i);
- }
-
- /*
- * Init rest of GTT to the scratch page to avoid accidents or scribbles
- */
+ psb_gtt_clear(dev_priv);
- pfn_base = page_to_pfn(dev_priv->scratch_page);
- pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY);
- for (; i < gtt_pages; ++i)
- iowrite32(pte, dev_priv->gtt_map + i);
-
- (void) ioread32(dev_priv->gtt_map + i - 1);
return 0;
-out_err:
- psb_gtt_takedown(dev);
+err_psb_gtt_disable:
+ psb_gtt_disable(dev_priv);
+err_mutex_destroy:
+ mutex_destroy(&dev_priv->gtt_mutex);
return ret;
}
-int psb_gtt_restore(struct drm_device *dev)
+int psb_gtt_resume(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
- struct resource *r = dev_priv->gtt_mem->child;
- struct psb_gem_object *pobj;
- unsigned int restored = 0, total = 0, size = 0;
+ struct psb_gtt *pg = &dev_priv->gtt;
+ unsigned int old_gtt_pages = pg->gtt_pages;
+ int ret;
- /* On resume, the gtt_mutex is already initialized */
- mutex_lock(&dev_priv->gtt_mutex);
- psb_gtt_init(dev, 1);
+ /* Enable the GTT */
+ ret = psb_gtt_enable(dev_priv);
+ if (ret)
+ return ret;
- while (r != NULL) {
- /*
- * TODO: GTT restoration needs a refactoring, so that we don't have to touch
- * struct psb_gem_object here. The type represents a GEM object and is
- * not related to the GTT itself.
- */
- pobj = container_of(r, struct psb_gem_object, resource);
- if (pobj->pages) {
- psb_gtt_insert_pages(dev_priv, &pobj->resource, pobj->pages);
- size += pobj->resource.end - pobj->resource.start;
- restored++;
- }
- r = r->sibling;
- total++;
+ psb_gtt_init_ranges(dev_priv);
+
+ if (old_gtt_pages != pg->gtt_pages) {
+ dev_err(dev->dev, "GTT resume error.\n");
+ ret = -ENODEV;
+ goto err_psb_gtt_disable;
}
- mutex_unlock(&dev_priv->gtt_mutex);
- DRM_DEBUG_DRIVER("Restored %u of %u gtt ranges (%u KB)", restored,
- total, (size / 1024));
- return 0;
+ psb_gtt_clear(dev_priv);
+
+err_psb_gtt_disable:
+ psb_gtt_disable(dev_priv);
+ return ret;
}
diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h
index ff1dcdd1ff52..d5a5fd4466c1 100644
--- a/drivers/gpu/drm/gma500/gtt.h
+++ b/drivers/gpu/drm/gma500/gtt.h
@@ -22,18 +22,18 @@ struct psb_gtt {
unsigned gatt_pages;
unsigned long stolen_size;
unsigned long vram_stolen_size;
- struct rw_semaphore sem;
};
/* Exported functions */
-extern int psb_gtt_init(struct drm_device *dev, int resume);
-extern void psb_gtt_takedown(struct drm_device *dev);
-extern int psb_gtt_restore(struct drm_device *dev);
+int psb_gtt_init(struct drm_device *dev);
+void psb_gtt_fini(struct drm_device *dev);
+int psb_gtt_resume(struct drm_device *dev);
int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res,
const char *name, resource_size_t size, resource_size_t align,
bool stolen, u32 *offset);
+uint32_t psb_gtt_mask_pte(uint32_t pfn, int type);
void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res,
struct page **pages);
void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res);
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 36c7c2686c90..22398d34853a 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -372,9 +372,9 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
bool ok, is_sdvo = false;
bool is_lvds = false;
bool is_mipi = false;
- struct drm_mode_config *mode_config = &dev->mode_config;
struct gma_encoder *gma_encoder = NULL;
uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
int i;
int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0;
@@ -385,14 +385,11 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
if (!gma_power_begin(dev, true))
return 0;
- memcpy(&gma_crtc->saved_mode,
- mode,
- sizeof(struct drm_display_mode));
- memcpy(&gma_crtc->saved_adjusted_mode,
- adjusted_mode,
- sizeof(struct drm_display_mode));
+ drm_mode_copy(&gma_crtc->saved_mode, mode);
+ drm_mode_copy(&gma_crtc->saved_adjusted_mode, adjusted_mode);
- list_for_each_entry(connector, &mode_config->connector_list, head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
if (!connector->encoder || connector->encoder->crtc != crtc)
continue;
@@ -409,8 +406,16 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
is_mipi = true;
break;
}
+
+ break;
}
+ if (gma_encoder)
+ drm_object_property_get_value(&connector->base,
+ dev->mode_config.scaling_mode_property, &scalingType);
+
+ drm_connector_list_iter_end(&conn_iter);
+
/* Disable the VGA plane that we never use */
for (i = 0; i <= need_aux; i++)
REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i);
@@ -424,10 +429,6 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
(mode->crtc_vdisplay - 1), i);
}
- if (gma_encoder)
- drm_object_property_get_value(&connector->base,
- dev->mode_config.scaling_mode_property, &scalingType);
-
if (scalingType == DRM_MODE_SCALE_NO_SCALE) {
/* Moorestown doesn't have register support for centering so
* we need to mess with the h/vblank and h/vsync start and
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 5c75eae630b5..5923a9c89312 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -545,7 +545,6 @@ const struct psb_ops oaktrail_chip_ops = {
.chip_setup = oaktrail_chip_setup,
.chip_teardown = oaktrail_teardown,
.crtc_helper = &oaktrail_helper_funcs,
- .crtc_funcs = &gma_intel_crtc_funcs,
.output_init = oaktrail_output_init,
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 6eef60a5ac27..b5946a1cdcd5 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -654,7 +654,6 @@ void oaktrail_hdmi_init(struct drm_device *dev,
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- drm_connector_register(connector);
dev_info(dev->dev, "HDMI initialised.\n");
return;
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 28b995ef2844..aed5de8f8245 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -85,7 +85,7 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
- struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector = NULL;
struct drm_crtc *crtc = encoder->crtc;
u32 lvds_port;
@@ -112,21 +112,22 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder,
REG_WRITE(LVDS, lvds_port);
/* Find the connector we're trying to set up */
- list_for_each_entry(connector, &mode_config->connector_list, head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->encoder && connector->encoder->crtc == crtc)
break;
}
- if (list_entry_is_head(connector, &mode_config->connector_list, head)) {
+ if (!connector) {
+ drm_connector_list_iter_end(&conn_iter);
DRM_ERROR("Couldn't find connector when setting mode");
gma_power_end(dev);
return;
}
- drm_object_property_get_value(
- &connector->base,
- dev->mode_config.scaling_mode_property,
- &v);
+ drm_object_property_get_value( &connector->base,
+ dev->mode_config.scaling_mode_property, &v);
+ drm_connector_list_iter_end(&conn_iter);
if (v == DRM_MODE_SCALE_NO_SCALE)
REG_WRITE(PFIT_CONTROL, 0);
@@ -400,7 +401,6 @@ void oaktrail_lvds_init(struct drm_device *dev,
out:
mutex_unlock(&dev->mode_config.mutex);
- drm_connector_register(connector);
return;
failed_find:
diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c
index fef04ff8c3a9..dc494df71a48 100644
--- a/drivers/gpu/drm/gma500/opregion.c
+++ b/drivers/gpu/drm/gma500/opregion.c
@@ -23,6 +23,7 @@
*/
#include <linux/acpi.h>
#include "psb_drv.h"
+#include "psb_irq.h"
#include "psb_intel_reg.h"
#define PCI_ASLE 0xe4
@@ -217,8 +218,8 @@ void psb_intel_opregion_enable_asle(struct drm_device *dev)
if (asle && system_opregion ) {
/* Don't do this on Medfield or other non PC like devices, they
use the bit for something different altogether */
- psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
- psb_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+ gma_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
+ gma_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN
| ASLE_PFMB_EN;
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
index d2a46d96e746..b91de6d36e41 100644
--- a/drivers/gpu/drm/gma500/power.c
+++ b/drivers/gpu/drm/gma500/power.c
@@ -28,6 +28,7 @@
* Alan Cox <alan@linux.intel.com>
*/
+#include "gem.h"
#include "power.h"
#include "psb_drv.h"
#include "psb_reg.h"
@@ -112,7 +113,9 @@ static void gma_resume_display(struct pci_dev *pdev)
pci_write_config_word(pdev, PSB_GMCH_CTRL,
dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
- psb_gtt_restore(dev); /* Rebuild our GTT mappings */
+ /* Rebuild our GTT mappings */
+ psb_gtt_resume(dev);
+ psb_gem_mm_resume(dev);
dev_priv->ops->restore_regs(dev);
}
@@ -198,7 +201,7 @@ int gma_power_suspend(struct device *_dev)
dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
return -EBUSY;
}
- psb_irq_uninstall(dev);
+ gma_irq_uninstall(dev);
gma_suspend_display(dev);
gma_suspend_pci(pdev);
}
@@ -220,8 +223,8 @@ int gma_power_resume(struct device *_dev)
mutex_lock(&power_mutex);
gma_resume_pci(pdev);
gma_resume_display(pdev);
- psb_irq_preinstall(dev);
- psb_irq_postinstall(dev);
+ gma_irq_preinstall(dev);
+ gma_irq_postinstall(dev);
mutex_unlock(&power_mutex);
return 0;
}
@@ -267,8 +270,8 @@ bool gma_power_begin(struct drm_device *dev, bool force_on)
/* Ok power up needed */
ret = gma_resume_pci(pdev);
if (ret == 0) {
- psb_irq_preinstall(dev);
- psb_irq_postinstall(dev);
+ gma_irq_preinstall(dev);
+ gma_irq_postinstall(dev);
pm_runtime_get(dev->dev);
dev_priv->display_count++;
spin_unlock_irqrestore(&power_ctrl_lock, flags);
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index 3030f18ba022..71534f4ca834 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -168,8 +168,10 @@ static void psb_init_pm(struct drm_device *dev)
static int psb_save_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct gma_connector *gma_connector;
struct drm_crtc *crtc;
- struct gma_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration control + watermarks */
@@ -189,9 +191,13 @@ static int psb_save_display_registers(struct drm_device *dev)
dev_priv->ops->save_crtc(crtc);
}
- list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
- if (connector->save)
- connector->save(&connector->base);
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ gma_connector = to_gma_connector(connector);
+ if (gma_connector->save)
+ gma_connector->save(connector);
+ }
+ drm_connector_list_iter_end(&conn_iter);
drm_modeset_unlock_all(dev);
return 0;
@@ -206,8 +212,10 @@ static int psb_save_display_registers(struct drm_device *dev)
static int psb_restore_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct gma_connector *gma_connector;
struct drm_crtc *crtc;
- struct gma_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration + watermarks */
@@ -228,9 +236,13 @@ static int psb_restore_display_registers(struct drm_device *dev)
if (drm_helper_crtc_in_use(crtc))
dev_priv->ops->restore_crtc(crtc);
- list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
- if (connector->restore)
- connector->restore(&connector->base);
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ gma_connector = to_gma_connector(connector);
+ if (gma_connector->restore)
+ gma_connector->restore(connector);
+ }
+ drm_connector_list_iter_end(&conn_iter);
drm_modeset_unlock_all(dev);
return 0;
@@ -329,7 +341,6 @@ const struct psb_ops psb_chip_ops = {
.chip_teardown = psb_chip_teardown,
.crtc_helper = &psb_intel_helper_funcs,
- .crtc_funcs = &gma_intel_crtc_funcs,
.clock_funcs = &psb_clock_funcs,
.output_init = psb_output_init,
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index eeb681be9c95..2aff54d505e2 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -28,6 +28,7 @@
#include <drm/drm_vblank.h>
#include "framebuffer.h"
+#include "gem.h"
#include "intel_bios.h"
#include "mid_bios.h"
#include "power.h"
@@ -99,7 +100,7 @@ static const struct drm_ioctl_desc psb_ioctls[] = {
*
* Soft reset the graphics engine and then reload the necessary registers.
*/
-void psb_spank(struct drm_psb_private *dev_priv)
+static void psb_spank(struct drm_psb_private *dev_priv)
{
PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET |
_PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET |
@@ -172,6 +173,8 @@ static void psb_driver_unload(struct drm_device *dev)
gma_backlight_exit(dev);
psb_modeset_cleanup(dev);
+ gma_irq_uninstall(dev);
+
if (dev_priv->ops->chip_teardown)
dev_priv->ops->chip_teardown(dev);
@@ -184,17 +187,16 @@ static void psb_driver_unload(struct drm_device *dev)
if (dev_priv->mmu) {
struct psb_gtt *pg = &dev_priv->gtt;
- down_read(&pg->sem);
psb_mmu_remove_pfn_sequence(
psb_mmu_get_default_pd
(dev_priv->mmu),
pg->mmu_gatt_start,
dev_priv->vram_stolen_size >> PAGE_SHIFT);
- up_read(&pg->sem);
psb_mmu_driver_takedown(dev_priv->mmu);
dev_priv->mmu = NULL;
}
- psb_gtt_takedown(dev);
+ psb_gem_mm_fini(dev);
+ psb_gtt_fini(dev);
if (dev_priv->scratch_page) {
set_pages_wb(dev_priv->scratch_page, 1);
__free_page(dev_priv->scratch_page);
@@ -234,10 +236,11 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
unsigned long resource_start, resource_len;
unsigned long irqflags;
- int ret = -ENOMEM;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
struct gma_encoder *gma_encoder;
struct psb_gtt *pg;
+ int ret = -ENOMEM;
/* initializing driver private data */
@@ -326,7 +329,10 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
set_pages_uc(dev_priv->scratch_page, 1);
- ret = psb_gtt_init(dev, 0);
+ ret = psb_gtt_init(dev);
+ if (ret)
+ goto out_err;
+ ret = psb_gem_mm_init(dev);
if (ret)
goto out_err;
@@ -345,12 +351,10 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
return ret;
/* Add stolen memory to SGX MMU */
- down_read(&pg->sem);
ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd(dev_priv->mmu),
dev_priv->stolen_base >> PAGE_SHIFT,
pg->gatt_start,
pg->stolen_size >> PAGE_SHIFT, 0);
- up_read(&pg->sem);
psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0);
psb_mmu_set_pd_context(dev_priv->pf_pd, 1);
@@ -379,7 +383,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
- psb_irq_install(dev, pdev->irq);
+ gma_irq_install(dev, pdev->irq);
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
@@ -387,9 +391,9 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
psb_fbdev_init(dev);
drm_kms_helper_poll_init(dev);
- /* Only add backlight support if we have LVDS output */
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
+ /* Only add backlight support if we have LVDS or MIPI output */
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
gma_encoder = gma_attached_encoder(connector);
switch (gma_encoder->type) {
@@ -399,6 +403,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
break;
}
}
+ drm_connector_list_iter_end(&conn_iter);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 0439b10d3db5..0ddfec1a0851 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -13,7 +13,6 @@
#include <drm/drm_device.h>
-#include "gma_display.h"
#include "gtt.h"
#include "intel_bios.h"
#include "mmu.h"
@@ -36,12 +35,6 @@
/* Append new drm mode definition here, align with libdrm definition */
#define DRM_MODE_SCALE_NO_SCALE 2
-enum {
- CHIP_PSB_8108 = 0, /* Poulsbo */
- CHIP_PSB_8109 = 1, /* Poulsbo */
- CHIP_MRST_4100 = 2, /* Moorestown/Oaktrail */
-};
-
#define IS_PSB(drm) ((to_pci_dev((drm)->dev)->device & 0xfffe) == 0x8108)
#define IS_MRST(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x4100)
#define IS_CDV(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x0be0)
@@ -408,7 +401,6 @@ struct drm_psb_private {
uint32_t stolen_base;
u8 __iomem *vram_addr;
unsigned long vram_stolen_size;
- int gtt_initialized;
u16 gmch_ctrl; /* Saved GTT setup */
u32 pge_ctl;
@@ -586,7 +578,6 @@ struct psb_ops {
/* Sub functions */
struct drm_crtc_helper_funcs const *crtc_helper;
- struct drm_crtc_funcs const *crtc_funcs;
const struct gma_clock_funcs *clock_funcs;
/* Setup hooks */
@@ -618,36 +609,9 @@ struct psb_ops {
int i2c_bus; /* I2C bus identifier for Moorestown */
};
-
-
-extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int);
-extern int drm_pick_crtcs(struct drm_device *dev);
-
-/* psb_irq.c */
-extern void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands);
-extern int psb_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
-extern int psb_vblank_wait(struct drm_device *dev, unsigned int *sequence);
-extern int psb_enable_vblank(struct drm_crtc *crtc);
-extern void psb_disable_vblank(struct drm_crtc *crtc);
-void
-psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
-
-void
-psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
-
-extern u32 psb_get_vblank_counter(struct drm_crtc *crtc);
-
-/* framebuffer.c */
-extern int psbfb_probed(struct drm_device *dev);
-extern int psbfb_remove(struct drm_device *dev,
- struct drm_framebuffer *fb);
-/* psb_drv.c */
-extern void psb_spank(struct drm_psb_private *dev_priv);
-
-/* psb_reset.c */
+/* psb_lid.c */
extern void psb_lid_timer_init(struct drm_psb_private *dev_priv);
extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv);
-extern void psb_print_pagefault(struct drm_psb_private *dev_priv);
/* modesetting */
extern void psb_modeset_init(struct drm_device *dev);
@@ -670,7 +634,6 @@ extern void oaktrail_lvds_init(struct drm_device *dev,
/* psb_intel_display.c */
extern const struct drm_crtc_helper_funcs psb_intel_helper_funcs;
-extern const struct drm_crtc_funcs gma_intel_crtc_funcs;
/* psb_intel_lvds.c */
extern const struct drm_connector_helper_funcs
@@ -690,43 +653,7 @@ extern const struct psb_ops oaktrail_chip_ops;
/* cdv_device.c */
extern const struct psb_ops cdv_chip_ops;
-/* Debug print bits setting */
-#define PSB_D_GENERAL (1 << 0)
-#define PSB_D_INIT (1 << 1)
-#define PSB_D_IRQ (1 << 2)
-#define PSB_D_ENTRY (1 << 3)
-/* debug the get H/V BP/FP count */
-#define PSB_D_HV (1 << 4)
-#define PSB_D_DBI_BF (1 << 5)
-#define PSB_D_PM (1 << 6)
-#define PSB_D_RENDER (1 << 7)
-#define PSB_D_REG (1 << 8)
-#define PSB_D_MSVDX (1 << 9)
-#define PSB_D_TOPAZ (1 << 10)
-
-extern int drm_idle_check_interval;
-
/* Utilities */
-static inline u32 MRST_MSG_READ32(int domain, uint port, uint offset)
-{
- int mcr = (0xD0<<24) | (port << 16) | (offset << 8);
- uint32_t ret_val = 0;
- struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0);
- pci_write_config_dword(pci_root, 0xD0, mcr);
- pci_read_config_dword(pci_root, 0xD4, &ret_val);
- pci_dev_put(pci_root);
- return ret_val;
-}
-static inline void MRST_MSG_WRITE32(int domain, uint port, uint offset,
- u32 value)
-{
- int mcr = (0xE0<<24) | (port << 16) | (offset << 8) | 0xF0;
- struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0);
- pci_write_config_dword(pci_root, 0xD4, value);
- pci_write_config_dword(pci_root, 0xD0, mcr);
- pci_dev_put(pci_root);
-}
-
static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
@@ -807,24 +734,9 @@ static inline void REGISTER_WRITE8(struct drm_device *dev,
#define PSB_WVDC32(_val, _offs) iowrite32(_val, dev_priv->vdc_reg + (_offs))
#define PSB_RVDC32(_offs) ioread32(dev_priv->vdc_reg + (_offs))
-/* #define TRAP_SGX_PM_FAULT 1 */
-#ifdef TRAP_SGX_PM_FAULT
-#define PSB_RSGX32(_offs) \
-({ \
- if (inl(dev_priv->apm_base + PSB_APM_STS) & 0x3) { \
- pr_err("access sgx when it's off!! (READ) %s, %d\n", \
- __FILE__, __LINE__); \
- melay(1000); \
- } \
- ioread32(dev_priv->sgx_reg + (_offs)); \
-})
-#else
#define PSB_RSGX32(_offs) ioread32(dev_priv->sgx_reg + (_offs))
-#endif
#define PSB_WSGX32(_val, _offs) iowrite32(_val, dev_priv->sgx_reg + (_offs))
-#define MSVDX_REG_DUMP 0
-
#define PSB_WMSVDX32(_val, _offs) iowrite32(_val, dev_priv->msvdx_reg + (_offs))
#define PSB_RMSVDX32(_offs) ioread32(dev_priv->msvdx_reg + (_offs))
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index d5f95212934e..9a5ea06a1a8e 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -106,7 +106,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
bool ok, is_sdvo = false;
bool is_lvds = false, is_tv = false;
- struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
const struct gma_limit_t *limit;
@@ -116,7 +116,8 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
return 0;
}
- list_for_each_entry(connector, &mode_config->connector_list, head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
if (!connector->encoder
@@ -134,7 +135,10 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
is_tv = true;
break;
}
+
+ break;
}
+ drm_connector_list_iter_end(&conn_iter);
refclk = 96000;
@@ -427,18 +431,6 @@ const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
.disable = gma_crtc_disable,
};
-const struct drm_crtc_funcs gma_intel_crtc_funcs = {
- .cursor_set = gma_crtc_cursor_set,
- .cursor_move = gma_crtc_cursor_move,
- .gamma_set = gma_crtc_gamma_set,
- .set_config = gma_crtc_set_config,
- .destroy = gma_crtc_destroy,
- .page_flip = gma_crtc_page_flip,
- .enable_vblank = psb_enable_vblank,
- .disable_vblank = psb_disable_vblank,
- .get_vblank_counter = psb_get_vblank_counter,
-};
-
const struct gma_clock_funcs psb_clock_funcs = {
.clock = psb_intel_clock,
.limit = psb_intel_limit,
@@ -500,8 +492,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
return;
}
- /* Set the CRTC operations from the chip specific data */
- drm_crtc_init(dev, &gma_crtc->base, dev_priv->ops->crtc_funcs);
+ drm_crtc_init(dev, &gma_crtc->base, &gma_crtc_funcs);
/* Set the CRTC clock functions from chip specific data */
gma_crtc->clock_funcs = dev_priv->ops->clock_funcs;
@@ -535,28 +526,32 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
{
- struct drm_crtc *crtc = NULL;
+ struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
+
if (gma_crtc->pipe == pipe)
- break;
+ return crtc;
}
- return crtc;
+ return NULL;
}
int gma_connector_clones(struct drm_device *dev, int type_mask)
{
- int index_mask = 0;
+ struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
+ int index_mask = 0;
int entry = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
if (type_mask & (1 << gma_encoder->type))
index_mask |= (1 << entry);
entry++;
}
+ drm_connector_list_iter_end(&conn_iter);
+
return index_mask;
}
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index ac97e0d3c7dd..cad00380b386 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -521,13 +521,13 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector)
*/
void psb_intel_lvds_destroy(struct drm_connector *connector)
{
+ struct gma_connector *gma_connector = to_gma_connector(connector);
struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv;
psb_intel_i2c_destroy(lvds_priv->ddc_bus);
- drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
int psb_intel_lvds_set_property(struct drm_connector *connector,
@@ -782,7 +782,6 @@ void psb_intel_lvds_init(struct drm_device *dev,
*/
out:
mutex_unlock(&dev->mode_config.mutex);
- drm_connector_register(connector);
return;
failed_find:
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 042c4392e676..a85aace25548 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1542,9 +1542,10 @@ static int psb_intel_sdvo_get_modes(struct drm_connector *connector)
static void psb_intel_sdvo_destroy(struct drm_connector *connector)
{
- drm_connector_unregister(connector);
+ struct gma_connector *gma_connector = to_gma_connector(connector);
+
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(gma_connector);
}
static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
@@ -1932,7 +1933,6 @@ psb_intel_sdvo_connector_init(struct psb_intel_sdvo_connector *connector,
connector->base.restore = psb_intel_sdvo_restore;
gma_connector_attach_encoder(&connector->base, &encoder->base);
- drm_connector_register(&connector->base.base);
}
static void
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index ccf402007beb..e6e6d61bbeab 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -21,8 +21,7 @@
* inline functions
*/
-static inline u32
-psb_pipestat(int pipe)
+static inline u32 gma_pipestat(int pipe)
{
if (pipe == 0)
return PIPEASTAT;
@@ -33,8 +32,7 @@ psb_pipestat(int pipe)
BUG();
}
-static inline u32
-mid_pipe_event(int pipe)
+static inline u32 gma_pipe_event(int pipe)
{
if (pipe == 0)
return _PSB_PIPEA_EVENT_FLAG;
@@ -45,20 +43,7 @@ mid_pipe_event(int pipe)
BUG();
}
-static inline u32
-mid_pipe_vsync(int pipe)
-{
- if (pipe == 0)
- return _PSB_VSYNC_PIPEA_FLAG;
- if (pipe == 1)
- return _PSB_VSYNC_PIPEB_FLAG;
- if (pipe == 2)
- return _MDFLD_PIPEC_VBLANK_FLAG;
- BUG();
-}
-
-static inline u32
-mid_pipeconf(int pipe)
+static inline u32 gma_pipeconf(int pipe)
{
if (pipe == 0)
return PIPEACONF;
@@ -69,11 +54,10 @@ mid_pipeconf(int pipe)
BUG();
}
-void
-psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
+void gma_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
{
if ((dev_priv->pipestat[pipe] & mask) != mask) {
- u32 reg = psb_pipestat(pipe);
+ u32 reg = gma_pipestat(pipe);
dev_priv->pipestat[pipe] |= mask;
/* Enable the interrupt, clear any pending status */
if (gma_power_begin(&dev_priv->dev, false)) {
@@ -86,11 +70,10 @@ psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
}
}
-void
-psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
+void gma_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
{
if ((dev_priv->pipestat[pipe] & mask) != 0) {
- u32 reg = psb_pipestat(pipe);
+ u32 reg = gma_pipestat(pipe);
dev_priv->pipestat[pipe] &= ~mask;
if (gma_power_begin(&dev_priv->dev, false)) {
u32 writeVal = PSB_RVDC32(reg);
@@ -105,12 +88,12 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
/*
* Display controller interrupt handler for pipe event.
*/
-static void mid_pipe_event_handler(struct drm_device *dev, int pipe)
+static void gma_pipe_event_handler(struct drm_device *dev, int pipe)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
uint32_t pipe_stat_val = 0;
- uint32_t pipe_stat_reg = psb_pipestat(pipe);
+ uint32_t pipe_stat_reg = gma_pipestat(pipe);
uint32_t pipe_enable = dev_priv->pipestat[pipe];
uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16;
uint32_t pipe_clear;
@@ -160,22 +143,22 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe)
/*
* Display controller interrupt handler.
*/
-static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
+static void gma_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
{
if (vdc_stat & _PSB_IRQ_ASLE)
psb_intel_opregion_asle_intr(dev);
if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG)
- mid_pipe_event_handler(dev, 0);
+ gma_pipe_event_handler(dev, 0);
if (vdc_stat & _PSB_VSYNC_PIPEB_FLAG)
- mid_pipe_event_handler(dev, 1);
+ gma_pipe_event_handler(dev, 1);
}
/*
* SGX interrupt handler
*/
-static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2)
+static void gma_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
u32 val, addr;
@@ -222,7 +205,7 @@ static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2)
PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2);
}
-static irqreturn_t psb_irq_handler(int irq, void *arg)
+static irqreturn_t gma_irq_handler(int irq, void *arg)
{
struct drm_device *dev = arg;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
@@ -246,14 +229,14 @@ static irqreturn_t psb_irq_handler(int irq, void *arg)
spin_unlock(&dev_priv->irqmask_lock);
if (dsp_int && gma_power_is_on(dev)) {
- psb_vdc_interrupt(dev, vdc_stat);
+ gma_vdc_interrupt(dev, vdc_stat);
handled = 1;
}
if (sgx_int) {
sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS);
sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2);
- psb_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2);
+ gma_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2);
handled = 1;
}
@@ -274,7 +257,7 @@ static irqreturn_t psb_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-void psb_irq_preinstall(struct drm_device *dev)
+void gma_irq_preinstall(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
unsigned long irqflags;
@@ -303,7 +286,7 @@ void psb_irq_preinstall(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}
-void psb_irq_postinstall(struct drm_device *dev)
+void gma_irq_postinstall(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
unsigned long irqflags;
@@ -322,9 +305,9 @@ void psb_irq_postinstall(struct drm_device *dev)
for (i = 0; i < dev->num_crtcs; ++i) {
if (dev->vblank[i].enabled)
- psb_enable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+ gma_enable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
else
- psb_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+ gma_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
}
if (dev_priv->ops->hotplug_enable)
@@ -333,26 +316,26 @@ void psb_irq_postinstall(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}
-int psb_irq_install(struct drm_device *dev, unsigned int irq)
+int gma_irq_install(struct drm_device *dev, unsigned int irq)
{
int ret;
if (irq == IRQ_NOTCONNECTED)
return -ENOTCONN;
- psb_irq_preinstall(dev);
+ gma_irq_preinstall(dev);
/* PCI devices require shared interrupts. */
- ret = request_irq(irq, psb_irq_handler, IRQF_SHARED, dev->driver->name, dev);
+ ret = request_irq(irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
if (ret)
return ret;
- psb_irq_postinstall(dev);
+ gma_irq_postinstall(dev);
return 0;
}
-void psb_irq_uninstall(struct drm_device *dev)
+void gma_irq_uninstall(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
@@ -368,7 +351,7 @@ void psb_irq_uninstall(struct drm_device *dev)
for (i = 0; i < dev->num_crtcs; ++i) {
if (dev->vblank[i].enabled)
- psb_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
+ gma_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
}
dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG |
@@ -388,17 +371,14 @@ void psb_irq_uninstall(struct drm_device *dev)
free_irq(pdev->irq, dev);
}
-/*
- * It is used to enable VBLANK interrupt
- */
-int psb_enable_vblank(struct drm_crtc *crtc)
+int gma_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
unsigned int pipe = crtc->index;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
unsigned long irqflags;
uint32_t reg_val = 0;
- uint32_t pipeconf_reg = mid_pipeconf(pipe);
+ uint32_t pipeconf_reg = gma_pipeconf(pipe);
if (gma_power_begin(dev, false)) {
reg_val = REG_READ(pipeconf_reg);
@@ -417,17 +397,14 @@ int psb_enable_vblank(struct drm_crtc *crtc)
PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
- psb_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);
+ gma_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
return 0;
}
-/*
- * It is used to disable VBLANK interrupt
- */
-void psb_disable_vblank(struct drm_crtc *crtc)
+void gma_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
unsigned int pipe = crtc->index;
@@ -443,7 +420,7 @@ void psb_disable_vblank(struct drm_crtc *crtc)
PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
- psb_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);
+ gma_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}
@@ -451,7 +428,7 @@ void psb_disable_vblank(struct drm_crtc *crtc)
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
-u32 psb_get_vblank_counter(struct drm_crtc *crtc)
+u32 gma_crtc_get_vblank_counter(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
unsigned int pipe = crtc->index;
@@ -486,8 +463,8 @@ u32 psb_get_vblank_counter(struct drm_crtc *crtc)
if (!(reg_val & PIPEACONF_ENABLE)) {
dev_err(dev->dev, "trying to get vblank count for disabled pipe %u\n",
- pipe);
- goto psb_get_vblank_counter_exit;
+ pipe);
+ goto err_gma_power_end;
}
/*
@@ -506,8 +483,7 @@ u32 psb_get_vblank_counter(struct drm_crtc *crtc)
count = (high1 << 8) | low;
-psb_get_vblank_counter_exit:
-
+err_gma_power_end:
gma_power_end(dev);
return count;
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h
index a97cb49393d8..b51e395194ff 100644
--- a/drivers/gpu/drm/gma500/psb_irq.h
+++ b/drivers/gpu/drm/gma500/psb_irq.h
@@ -15,16 +15,15 @@
struct drm_crtc;
struct drm_device;
-bool sysirq_init(struct drm_device *dev);
-void sysirq_uninit(struct drm_device *dev);
+void gma_irq_preinstall(struct drm_device *dev);
+void gma_irq_postinstall(struct drm_device *dev);
+int gma_irq_install(struct drm_device *dev, unsigned int irq);
+void gma_irq_uninstall(struct drm_device *dev);
-void psb_irq_preinstall(struct drm_device *dev);
-void psb_irq_postinstall(struct drm_device *dev);
-int psb_irq_install(struct drm_device *dev, unsigned int irq);
-void psb_irq_uninstall(struct drm_device *dev);
-
-int psb_enable_vblank(struct drm_crtc *crtc);
-void psb_disable_vblank(struct drm_crtc *crtc);
-u32 psb_get_vblank_counter(struct drm_crtc *crtc);
+int gma_crtc_enable_vblank(struct drm_crtc *crtc);
+void gma_crtc_disable_vblank(struct drm_crtc *crtc);
+u32 gma_crtc_get_vblank_counter(struct drm_crtc *crtc);
+void gma_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
+void gma_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
#endif /* _PSB_IRQ_H_ */
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
index ce91b23385cf..1fd0cc9ca213 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
@@ -108,7 +108,8 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj,
trace_i915_gem_object_clflush(obj);
clflush = NULL;
- if (!(flags & I915_CLFLUSH_SYNC))
+ if (!(flags & I915_CLFLUSH_SYNC) &&
+ dma_resv_reserve_fences(obj->base.resv, 1) == 0)
clflush = clflush_work_create(obj);
if (clflush) {
i915_sw_fence_await_reservation(&clflush->base.chain,
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index d42f437149c9..78f8797853ce 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -998,11 +998,9 @@ static int eb_validate_vmas(struct i915_execbuffer *eb)
}
}
- if (!(ev->flags & EXEC_OBJECT_WRITE)) {
- err = dma_resv_reserve_shared(vma->obj->base.resv, 1);
- if (err)
- return err;
- }
+ err = dma_resv_reserve_fences(vma->obj->base.resv, 1);
+ if (err)
+ return err;
GEM_BUG_ON(drm_mm_node_allocated(&vma->node) &&
eb_vma_misplaced(&eb->exec[i], vma, ev->flags));
@@ -2303,7 +2301,7 @@ static int eb_parse(struct i915_execbuffer *eb)
if (IS_ERR(batch))
return PTR_ERR(batch);
- err = dma_resv_reserve_shared(shadow->obj->base.resv, 1);
+ err = dma_resv_reserve_fences(shadow->obj->base.resv, 1);
if (err)
return err;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index 45cc5837ce00..b9ae6b02f304 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -283,7 +283,7 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
i915_tt->is_shmem = true;
}
- ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, caching);
+ ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, caching, 0);
if (ret)
goto err_free;
@@ -936,7 +936,7 @@ void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
bo->priority = I915_TTM_PRIO_HAS_PAGES;
}
- ttm_bo_move_to_lru_tail(bo, bo->resource, NULL);
+ ttm_bo_move_to_lru_tail(bo);
spin_unlock(&bo->bdev->lru_lock);
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
index 1ebe6e4086a1..432ac74ff225 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
@@ -611,7 +611,11 @@ int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst,
assert_object_held(src);
i915_deps_init(&deps, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
- ret = dma_resv_reserve_shared(src_bo->base.resv, 1);
+ ret = dma_resv_reserve_fences(src_bo->base.resv, 1);
+ if (ret)
+ return ret;
+
+ ret = dma_resv_reserve_fences(dst_bo->base.resv, 1);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_migrate.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_migrate.c
index d534141b2cf7..0e52eb87cd55 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_migrate.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_migrate.c
@@ -216,7 +216,10 @@ static int __igt_lmem_pages_migrate(struct intel_gt *gt,
i915_gem_object_is_lmem(obj),
0xdeadbeaf, &rq);
if (rq) {
- dma_resv_add_excl_fence(obj->base.resv, &rq->fence);
+ err = dma_resv_reserve_fences(obj->base.resv, 1);
+ if (!err)
+ dma_resv_add_excl_fence(obj->base.resv,
+ &rq->fence);
i915_gem_object_set_moving_fence(obj, &rq->fence);
i915_request_put(rq);
}
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 94fcdb7bd21d..bae3423f58e8 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -1819,6 +1819,12 @@ int _i915_vma_move_to_active(struct i915_vma *vma,
intel_frontbuffer_put(front);
}
+ if (!(flags & __EXEC_OBJECT_NO_RESERVE)) {
+ err = dma_resv_reserve_fences(vma->obj->base.resv, 1);
+ if (unlikely(err))
+ return err;
+ }
+
if (fence) {
dma_resv_add_excl_fence(vma->obj->base.resv, fence);
obj->write_domain = I915_GEM_DOMAIN_RENDER;
@@ -1826,7 +1832,7 @@ int _i915_vma_move_to_active(struct i915_vma *vma,
}
} else {
if (!(flags & __EXEC_OBJECT_NO_RESERVE)) {
- err = dma_resv_reserve_shared(vma->obj->base.resv, 1);
+ err = dma_resv_reserve_fences(vma->obj->base.resv, 1);
if (unlikely(err))
return err;
}
@@ -2044,7 +2050,7 @@ int i915_vma_unbind_async(struct i915_vma *vma, bool trylock_vm)
if (!obj->mm.rsgt)
return -EBUSY;
- err = dma_resv_reserve_shared(obj->base.resv, 1);
+ err = dma_resv_reserve_fences(obj->base.resv, 1);
if (err)
return -EBUSY;
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index ba32893e0873..6114e013092b 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -1043,6 +1043,13 @@ static int igt_lmem_write_cpu(void *arg)
}
i915_gem_object_lock(obj, NULL);
+
+ err = dma_resv_reserve_fences(obj->base.resv, 1);
+ if (err) {
+ i915_gem_object_unlock(obj);
+ goto out_put;
+ }
+
/* Put the pages into a known state -- from the gpu for added fun */
intel_engine_pm_get(engine);
err = intel_context_migrate_clear(engine->gt->migrate.context, NULL,
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index fb0e951248f6..14a058a42854 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -150,10 +150,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
if (imx_ldb_ch->mode_valid) {
struct drm_display_mode *mode;
- mode = drm_mode_create(connector->dev);
+ mode = drm_mode_duplicate(connector->dev, &imx_ldb_ch->mode);
if (!mode)
return -EINVAL;
- drm_mode_copy(mode, &imx_ldb_ch->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
num_modes++;
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index ac52b49bf901..a4f5a323f490 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -226,6 +226,18 @@ static int ingenic_drm_update_pixclk(struct notifier_block *nb,
}
}
+static void ingenic_drm_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct ingenic_drm *priv = drm_device_get_priv(bridge->dev);
+
+ regmap_write(priv->map, JZ_REG_LCD_STATE, 0);
+
+ regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
+ JZ_LCD_CTRL_ENABLE | JZ_LCD_CTRL_DISABLE,
+ JZ_LCD_CTRL_ENABLE);
+}
+
static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
@@ -237,28 +249,20 @@ static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
if (WARN_ON(IS_ERR(priv_state)))
return;
- regmap_write(priv->map, JZ_REG_LCD_STATE, 0);
-
/* Set addresses of our DMA descriptor chains */
next_id = priv_state->use_palette ? HWDESC_PALETTE : 0;
regmap_write(priv->map, JZ_REG_LCD_DA0, dma_hwdesc_addr(priv, next_id));
regmap_write(priv->map, JZ_REG_LCD_DA1, dma_hwdesc_addr(priv, 1));
- regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
- JZ_LCD_CTRL_ENABLE | JZ_LCD_CTRL_DISABLE,
- JZ_LCD_CTRL_ENABLE);
-
drm_crtc_vblank_on(crtc);
}
-static void ingenic_drm_crtc_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void ingenic_drm_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
+ struct ingenic_drm *priv = drm_device_get_priv(bridge->dev);
unsigned int var;
- drm_crtc_vblank_off(crtc);
-
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
JZ_LCD_CTRL_DISABLE, JZ_LCD_CTRL_DISABLE);
@@ -267,6 +271,12 @@ static void ingenic_drm_crtc_atomic_disable(struct drm_crtc *crtc,
1000, 0);
}
+static void ingenic_drm_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ drm_crtc_vblank_off(crtc);
+}
+
static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv,
struct drm_display_mode *mode)
{
@@ -968,6 +978,8 @@ static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs =
static const struct drm_bridge_funcs ingenic_drm_bridge_funcs = {
.attach = ingenic_drm_bridge_attach,
+ .atomic_enable = ingenic_drm_bridge_atomic_enable,
+ .atomic_disable = ingenic_drm_bridge_atomic_disable,
.atomic_check = ingenic_drm_bridge_atomic_check,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 55bb1ec3c4f7..e0a11ee0e86d 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -257,13 +257,11 @@ int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset)
static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo,
bool write, bool explicit)
{
- int err = 0;
+ int err;
- if (!write) {
- err = dma_resv_reserve_shared(lima_bo_resv(bo), 1);
- if (err)
- return err;
- }
+ err = dma_resv_reserve_fences(lima_bo_resv(bo), 1);
+ if (err)
+ return err;
/* explicit sync use user passed dep fence */
if (explicit)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 5651734ce977..960b49ea2ee5 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -19,7 +19,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -39,7 +38,6 @@ struct mcde_dsi {
struct device *dev;
struct mcde *mcde;
struct drm_bridge bridge;
- struct drm_panel *panel;
struct drm_bridge *bridge_out;
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *mdsi;
@@ -1073,9 +1071,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mcde *mcde = to_mcde(drm);
struct mcde_dsi *d = dev_get_drvdata(dev);
- struct device_node *child;
- struct drm_panel *panel = NULL;
- struct drm_bridge *bridge = NULL;
+ struct drm_bridge *bridge;
if (!of_get_available_child_count(dev->of_node)) {
dev_info(dev, "unused DSI interface\n");
@@ -1100,37 +1096,10 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
return PTR_ERR(d->lp_clk);
}
- /* Look for a panel as a child to this node */
- for_each_available_child_of_node(dev->of_node, child) {
- panel = of_drm_find_panel(child);
- if (IS_ERR(panel)) {
- dev_err(dev, "failed to find panel try bridge (%ld)\n",
- PTR_ERR(panel));
- panel = NULL;
-
- bridge = of_drm_find_bridge(child);
- if (!bridge) {
- dev_err(dev, "failed to find bridge\n");
- return -EINVAL;
- }
- }
- }
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- if (IS_ERR(bridge)) {
- dev_err(dev, "error adding panel bridge\n");
- return PTR_ERR(bridge);
- }
- dev_info(dev, "connected to panel\n");
- d->panel = panel;
- } else if (bridge) {
- /* TODO: AV8100 HDMI encoder goes here for example */
- dev_info(dev, "connected to non-panel bridge (unsupported)\n");
- return -ENODEV;
- } else {
- dev_err(dev, "no panel or bridge\n");
- return -ENODEV;
+ bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
+ if (IS_ERR(bridge)) {
+ dev_err(dev, "error to get bridge\n");
+ return PTR_ERR(bridge);
}
d->bridge_out = bridge;
@@ -1153,8 +1122,6 @@ static void mcde_dsi_unbind(struct device *dev, struct device *master,
{
struct mcde_dsi *d = dev_get_drvdata(dev);
- if (d->panel)
- drm_panel_bridge_remove(d->bridge_out);
regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index ccb0511b9cd5..bd3f5b485085 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -500,6 +500,18 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
DRM_WARN("HFP + HBP less than d-phy, FPS will under 60Hz\n");
}
+ if ((dsi->mode_flags & MIPI_DSI_HS_PKT_END_ALIGNED) &&
+ (dsi->lanes == 4)) {
+ horizontal_sync_active_byte =
+ roundup(horizontal_sync_active_byte, dsi->lanes) - 2;
+ horizontal_frontporch_byte =
+ roundup(horizontal_frontporch_byte, dsi->lanes) - 2;
+ horizontal_backporch_byte =
+ roundup(horizontal_backporch_byte, dsi->lanes) - 2;
+ horizontal_backporch_byte -=
+ (vm->hactive * dsi_tmp_buf_bpp + 2) % dsi->lanes;
+ }
+
writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC);
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index edae79f41153..1b70938cfd2c 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -168,7 +168,7 @@ static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
},
.attrs = (const struct soc_device_attribute []) {
{ .soc_id = "GXL (S805*)", },
- { /* sentinel */ },
+ { /* sentinel */ }
}
},
};
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index c6d60c8d286d..3164db8be893 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -320,16 +320,14 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
struct drm_gem_object *obj = &submit->bos[i].obj->base;
bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE;
- if (!write) {
- /* NOTE: _reserve_shared() must happen before
- * _add_shared_fence(), which makes this a slightly
- * strange place to call it. OTOH this is a
- * convenient can-fail point to hook it in.
- */
- ret = dma_resv_reserve_shared(obj->resv, 1);
- if (ret)
- return ret;
- }
+ /* NOTE: _reserve_shared() must happen before
+ * _add_shared_fence(), which makes this a slightly
+ * strange place to call it. OTOH this is a
+ * convenient can-fail point to hook it in.
+ */
+ ret = dma_resv_reserve_fences(obj->resv, 1);
+ if (ret)
+ return ret;
/* exclusive fences must be ordered */
if (no_implicit && !write)
diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h
index 3d82b3c67dec..93f8f4f64578 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -160,14 +160,14 @@ nv50_head_atom_get(struct drm_atomic_state *state, struct drm_crtc *crtc)
static inline struct drm_encoder *
nv50_head_atom_get_encoder(struct nv50_head_atom *atom)
{
- struct drm_encoder *encoder = NULL;
+ struct drm_encoder *encoder;
/* We only ever have a single encoder */
drm_for_each_encoder_mask(encoder, atom->state.crtc->dev,
atom->state.encoder_mask)
- break;
+ return encoder;
- return encoder;
+ return NULL;
}
#define nv50_wndw_atom(p) container_of((p), struct nv50_wndw_atom, state)
diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c
index 29428e770f14..b834e8a9ae77 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/crc.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c
@@ -390,9 +390,18 @@ void nv50_crc_atomic_check_outp(struct nv50_atom *atom)
struct nv50_head_atom *armh = nv50_head_atom(old_crtc_state);
struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);
struct nv50_outp_atom *outp_atom;
- struct nouveau_encoder *outp =
- nv50_real_outp(nv50_head_atom_get_encoder(armh));
- struct drm_encoder *encoder = &outp->base.base;
+ struct nouveau_encoder *outp;
+ struct drm_encoder *encoder, *enc;
+
+ enc = nv50_head_atom_get_encoder(armh);
+ if (!enc)
+ continue;
+
+ outp = nv50_real_outp(enc);
+ if (!outp)
+ continue;
+
+ encoder = &outp->base.base;
if (!asyh->clr.crc)
continue;
@@ -443,8 +452,16 @@ void nv50_crc_atomic_set(struct nv50_head *head,
struct drm_device *dev = crtc->dev;
struct nv50_crc *crc = &head->crc;
const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc;
- struct nouveau_encoder *outp =
- nv50_real_outp(nv50_head_atom_get_encoder(asyh));
+ struct nouveau_encoder *outp;
+ struct drm_encoder *encoder;
+
+ encoder = nv50_head_atom_get_encoder(asyh);
+ if (!encoder)
+ return;
+
+ outp = nv50_real_outp(encoder);
+ if (!outp)
+ return;
func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src),
&crc->ctx[crc->ctx_idx]);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 0c1a2ea0ed04..e2faf92e4831 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -536,8 +536,6 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
struct nouveau_bo *nvbo;
struct nv50_head_atom *asyh;
struct nv50_wndw_ctxdma *ctxdma;
- struct dma_resv_iter cursor;
- struct dma_fence *fence;
int ret;
NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, fb);
@@ -560,13 +558,11 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
asyw->image.handle[0] = ctxdma->object.handle;
}
- dma_resv_iter_begin(&cursor, nvbo->bo.base.resv, false);
- dma_resv_for_each_fence_unlocked(&cursor, fence) {
- /* TODO: We only use the first writer here */
- asyw->state.fence = dma_fence_get(fence);
- break;
- }
- dma_resv_iter_end(&cursor);
+ ret = dma_resv_get_singleton(nvbo->bo.base.resv, false,
+ &asyw->state.fence);
+ if (ret)
+ return ret;
+
asyw->image.offset[0] = nvbo->offset;
if (wndw->func->prepare) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index fa73fe57f97b..74f8652d2bd3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -959,7 +959,14 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct drm_device *dev = drm->dev;
- struct dma_fence *fence = dma_resv_excl_fence(bo->base.resv);
+ struct dma_fence *fence;
+ int ret;
+
+ /* TODO: This is actually a memory management dependency */
+ ret = dma_resv_get_singleton(bo->base.resv, false, &fence);
+ if (ret)
+ dma_resv_wait_timeout(bo->base.resv, false, false,
+ MAX_SCHEDULE_TIMEOUT);
nv10_bo_put_tile_region(dev, *old_tile, fence);
*old_tile = new_tile;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index a3a04e0d76ec..0268259e97eb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -346,11 +346,9 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
struct dma_resv *resv = nvbo->bo.base.resv;
int i, ret;
- if (!exclusive) {
- ret = dma_resv_reserve_shared(resv, 1);
- if (ret)
- return ret;
- }
+ ret = dma_resv_reserve_fences(resv, 1);
+ if (ret)
+ return ret;
/* Waiting for the exclusive fence first causes performance regressions
* under some circumstances. So manually wait for the shared ones first.
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index 88d262ba648c..62efbd0f3846 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -2935,7 +2935,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
/* switch mmio to cpu's native endianness */
if (!nvkm_device_endianness(device)) {
nvdev_error(device,
- "Couldn't switch GPU to CPUs endianess\n");
+ "Couldn't switch GPU to CPUs endianness\n");
ret = -ENOSYS;
goto done;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
index 57199be082fd..c2b5cc5f97ed 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -135,10 +135,10 @@ nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
list_for_each_entry_from_reverse(cstate, &pstate->list, head) {
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp))
- break;
+ return cstate;
}
- return cstate;
+ return NULL;
}
static struct nvkm_cstate *
@@ -169,6 +169,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
if (!list_empty(&pstate->list)) {
cstate = nvkm_cstate_get(clk, pstate, cstatei);
cstate = nvkm_cstate_find_best(clk, pstate, cstate);
+ if (!cstate)
+ return -EINVAL;
} else {
cstate = &pstate->base;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
index 96aca0edfa3c..c51bac76174c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
@@ -313,7 +313,7 @@ nv50_instobj_dtor(struct nvkm_memory *memory)
struct nv50_instobj *iobj = nv50_instobj(memory);
struct nvkm_instmem *imem = &iobj->imem->base;
struct nvkm_vma *bar;
- void *map = map;
+ void *map;
mutex_lock(&imem->mutex);
if (likely(iobj->lru.next))
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index b0fa17409b66..cf571796fd26 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -38,7 +38,7 @@ struct omap_gem_object {
/** roll applied when mapping to DMM */
u32 roll;
- /** protects dma_addr_cnt, block, pages, dma_addrs and vaddr */
+ /** protects pin_cnt, block, pages, dma_addrs and vaddr */
struct mutex lock;
/**
@@ -50,24 +50,24 @@ struct omap_gem_object {
* - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set)
* if they are physically contiguous (when sgt->orig_nents == 1)
*
- * - buffers mapped through the TILER when dma_addr_cnt is not zero, in
- * which case the DMA address points to the TILER aperture
+ * - buffers mapped through the TILER when pin_cnt is not zero, in which
+ * case the DMA address points to the TILER aperture
*
* Physically contiguous buffers have their DMA address equal to the
* physical address as we don't remap those buffers through the TILER.
*
* Buffers mapped to the TILER have their DMA address pointing to the
- * TILER aperture. As TILER mappings are refcounted (through
- * dma_addr_cnt) the DMA address must be accessed through omap_gem_pin()
- * to ensure that the mapping won't disappear unexpectedly. References
- * must be released with omap_gem_unpin().
+ * TILER aperture. As TILER mappings are refcounted (through pin_cnt)
+ * the DMA address must be accessed through omap_gem_pin() to ensure
+ * that the mapping won't disappear unexpectedly. References must be
+ * released with omap_gem_unpin().
*/
dma_addr_t dma_addr;
/**
- * # of users of dma_addr
+ * # of users
*/
- refcount_t dma_addr_cnt;
+ refcount_t pin_cnt;
/**
* If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag
@@ -750,6 +750,46 @@ void omap_gem_dma_sync_buffer(struct drm_gem_object *obj,
}
}
+static int omap_gem_pin_tiler(struct drm_gem_object *obj)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ u32 npages = obj->size >> PAGE_SHIFT;
+ enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
+ struct tiler_block *block;
+ int ret;
+
+ BUG_ON(omap_obj->block);
+
+ if (omap_obj->flags & OMAP_BO_TILED_MASK) {
+ block = tiler_reserve_2d(fmt, omap_obj->width, omap_obj->height,
+ PAGE_SIZE);
+ } else {
+ block = tiler_reserve_1d(obj->size);
+ }
+
+ if (IS_ERR(block)) {
+ ret = PTR_ERR(block);
+ dev_err(obj->dev->dev, "could not remap: %d (%d)\n", ret, fmt);
+ goto fail;
+ }
+
+ /* TODO: enable async refill.. */
+ ret = tiler_pin(block, omap_obj->pages, npages, omap_obj->roll, true);
+ if (ret) {
+ tiler_release(block);
+ dev_err(obj->dev->dev, "could not pin: %d\n", ret);
+ goto fail;
+ }
+
+ omap_obj->dma_addr = tiler_ssptr(block);
+ omap_obj->block = block;
+
+ DBG("got dma address: %pad", &omap_obj->dma_addr);
+
+fail:
+ return ret;
+}
+
/**
* omap_gem_pin() - Pin a GEM object in memory
* @obj: the GEM object
@@ -772,63 +812,30 @@ 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 (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);
+ if (!omap_gem_is_contiguous(omap_obj)) {
+ if (refcount_read(&omap_obj->pin_cnt) == 0) {
- refcount_set(&omap_obj->dma_addr_cnt, 1);
+ refcount_set(&omap_obj->pin_cnt, 1);
ret = omap_gem_attach_pages(obj);
if (ret)
goto fail;
- if (omap_obj->flags & OMAP_BO_TILED_MASK) {
- block = tiler_reserve_2d(fmt,
- omap_obj->width,
- omap_obj->height, PAGE_SIZE);
- } else {
- block = tiler_reserve_1d(obj->size);
- }
-
- if (IS_ERR(block)) {
- ret = PTR_ERR(block);
- dev_err(obj->dev->dev,
- "could not remap: %d (%d)\n", ret, fmt);
- goto fail;
- }
-
- /* TODO: enable async refill.. */
- ret = tiler_pin(block, omap_obj->pages, npages,
- omap_obj->roll, true);
- if (ret) {
- tiler_release(block);
- dev_err(obj->dev->dev,
- "could not pin: %d\n", ret);
- goto fail;
+ if (omap_obj->flags & OMAP_BO_SCANOUT) {
+ if (priv->has_dmm) {
+ ret = omap_gem_pin_tiler(obj);
+ if (ret)
+ goto fail;
+ }
}
-
- omap_obj->dma_addr = tiler_ssptr(block);
- omap_obj->block = block;
-
- DBG("got dma address: %pad", &omap_obj->dma_addr);
} else {
- refcount_inc(&omap_obj->dma_addr_cnt);
+ refcount_inc(&omap_obj->pin_cnt);
}
-
- if (dma_addr)
- *dma_addr = omap_obj->dma_addr;
- } else if (omap_gem_is_contiguous(omap_obj)) {
- if (dma_addr)
- *dma_addr = omap_obj->dma_addr;
- } else {
- ret = -EINVAL;
- goto fail;
}
+ if (dma_addr)
+ *dma_addr = omap_obj->dma_addr;
+
fail:
mutex_unlock(&omap_obj->lock);
@@ -847,27 +854,31 @@ static void omap_gem_unpin_locked(struct drm_gem_object *obj)
struct omap_gem_object *omap_obj = to_omap_bo(obj);
int ret;
- if (omap_gem_is_contiguous(omap_obj) || !priv->has_dmm)
+ if (omap_gem_is_contiguous(omap_obj))
return;
- if (refcount_dec_and_test(&omap_obj->dma_addr_cnt)) {
+ if (refcount_dec_and_test(&omap_obj->pin_cnt)) {
if (omap_obj->sgt) {
sg_free_table(omap_obj->sgt);
kfree(omap_obj->sgt);
omap_obj->sgt = NULL;
}
- 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);
+ if (!(omap_obj->flags & OMAP_BO_SCANOUT))
+ return;
+ if (priv->has_dmm) {
+ 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_obj->dma_addr = 0;
- omap_obj->block = NULL;
}
}
@@ -900,7 +911,7 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient,
mutex_lock(&omap_obj->lock);
- if ((refcount_read(&omap_obj->dma_addr_cnt) > 0) && omap_obj->block &&
+ if ((refcount_read(&omap_obj->pin_cnt) > 0) && omap_obj->block &&
(omap_obj->flags & OMAP_BO_TILED_MASK)) {
*dma_addr = tiler_tsptr(omap_obj->block, orient, x, y);
ret = 0;
@@ -968,7 +979,8 @@ int omap_gem_put_pages(struct drm_gem_object *obj)
return 0;
}
-struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj)
+struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj,
+ enum dma_data_direction dir)
{
struct omap_gem_object *omap_obj = to_omap_bo(obj);
dma_addr_t addr;
@@ -993,28 +1005,44 @@ struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj)
goto err_unpin;
}
- if (omap_obj->flags & OMAP_BO_TILED_MASK) {
- enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
+ if (addr) {
+ if (omap_obj->flags & OMAP_BO_TILED_MASK) {
+ enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
- len = omap_obj->width << (int)fmt;
- count = omap_obj->height;
- stride = tiler_stride(fmt, 0);
+ len = omap_obj->width << (int)fmt;
+ count = omap_obj->height;
+ stride = tiler_stride(fmt, 0);
+ } else {
+ len = obj->size;
+ count = 1;
+ stride = 0;
+ }
} else {
- len = obj->size;
- count = 1;
- stride = 0;
+ count = obj->size >> PAGE_SHIFT;
}
ret = sg_alloc_table(sgt, count, GFP_KERNEL);
if (ret)
goto err_free;
- for_each_sg(sgt->sgl, sg, count, i) {
- sg_set_page(sg, phys_to_page(addr), len, offset_in_page(addr));
- sg_dma_address(sg) = addr;
- sg_dma_len(sg) = len;
+ /* this must be after omap_gem_pin() to ensure we have pages attached */
+ omap_gem_dma_sync_buffer(obj, dir);
- addr += stride;
+ if (addr) {
+ for_each_sg(sgt->sgl, sg, count, i) {
+ sg_set_page(sg, phys_to_page(addr), len,
+ offset_in_page(addr));
+ sg_dma_address(sg) = addr;
+ sg_dma_len(sg) = len;
+
+ addr += stride;
+ }
+ } else {
+ for_each_sg(sgt->sgl, sg, count, i) {
+ sg_set_page(sg, omap_obj->pages[i], PAGE_SIZE, 0);
+ sg_dma_address(sg) = omap_obj->dma_addrs[i];
+ sg_dma_len(sg) = PAGE_SIZE;
+ }
}
omap_obj->sgt = sgt;
@@ -1124,7 +1152,7 @@ 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,
- refcount_read(&omap_obj->dma_addr_cnt),
+ refcount_read(&omap_obj->pin_cnt),
omap_obj->vaddr, omap_obj->roll);
if (omap_obj->flags & OMAP_BO_TILED_MASK) {
@@ -1187,7 +1215,7 @@ static void omap_gem_free_object(struct drm_gem_object *obj)
mutex_lock(&omap_obj->lock);
/* The object should not be pinned. */
- WARN_ON(refcount_read(&omap_obj->dma_addr_cnt) > 0);
+ WARN_ON(refcount_read(&omap_obj->pin_cnt) > 0);
if (omap_obj->pages) {
if (omap_obj->flags & OMAP_BO_MEM_DMABUF)
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h
index 19209e319663..4d4488939f6b 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.h
+++ b/drivers/gpu/drm/omapdrm/omap_gem.h
@@ -82,7 +82,8 @@ u32 omap_gem_flags(struct drm_gem_object *obj);
int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient,
int x, int y, dma_addr_t *dma_addr);
int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient);
-struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj);
+struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj,
+ enum dma_data_direction dir);
void omap_gem_put_sg(struct drm_gem_object *obj, struct sg_table *sgt);
#endif /* __OMAPDRM_GEM_H__ */
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
index ab3fc86e7256..393f82e26927 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
@@ -23,13 +23,10 @@ static struct sg_table *omap_gem_map_dma_buf(
{
struct drm_gem_object *obj = attachment->dmabuf->priv;
struct sg_table *sg;
- sg = omap_gem_get_sg(obj);
+ sg = omap_gem_get_sg(obj, dir);
if (IS_ERR(sg))
return sg;
- /* this must be after omap_gem_pin() to ensure we have pages attached */
- omap_gem_dma_sync_buffer(obj, dir);
-
return sg;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c
index 10730c9b2752..b0bc9ad2ef73 100644
--- a/drivers/gpu/drm/omapdrm/omap_overlay.c
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.c
@@ -86,7 +86,7 @@ int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
caps, fourcc);
if (!r_ovl) {
- overlay_map[r_ovl->idx] = NULL;
+ overlay_map[ovl->idx] = NULL;
*overlay = NULL;
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index ddf5f38e8731..cc51ddeb54fd 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -284,6 +284,15 @@ config DRM_PANEL_NEC_NL8048HL11
panel (found on the Zoom2/3/3630 SDP boards). To compile this driver
as a module, choose M here.
+config DRM_PANEL_NEWVISION_NV3052C
+ tristate "NewVision NV3052C RGB/SPI panel"
+ depends on OF && SPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_MIPI_DBI
+ help
+ Say Y here if you want to enable support for the panels built
+ around the NewVision NV3052C display controller.
+
config DRM_PANEL_NOVATEK_NT35510
tristate "Novatek NT35510 RGB panel driver"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 5740911f637c..42a7ab54234b 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
+obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o
diff --git a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c
index ed626fdc08e8..1cc0f1d09684 100644
--- a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c
+++ b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c
@@ -140,7 +140,7 @@ static const struct reg_sequence y030xx067a_init_sequence[] = {
{ 0x03, REG03_VPOSITION(0x0a) },
{ 0x04, REG04_HPOSITION1(0xd2) },
{ 0x05, REG05_CLIP | REG05_NVM_VREFRESH | REG05_SLBRCHARGE(0x2) },
- { 0x06, REG06_XPSAVE | REG06_NT },
+ { 0x06, REG06_NT },
{ 0x07, 0 },
{ 0x08, REG08_PANEL(0x1) | REG08_CLOCK_DIV(0x2) },
{ 0x09, REG09_SUB_BRIGHT_R(0x20) },
@@ -183,8 +183,6 @@ static int y030xx067a_prepare(struct drm_panel *panel)
goto err_disable_regulator;
}
- msleep(120);
-
return 0;
err_disable_regulator:
@@ -202,6 +200,29 @@ static int y030xx067a_unprepare(struct drm_panel *panel)
return 0;
}
+static int y030xx067a_enable(struct drm_panel *panel)
+{
+ struct y030xx067a *priv = to_y030xx067a(panel);
+
+ regmap_set_bits(priv->map, 0x06, REG06_XPSAVE);
+
+ if (panel->backlight) {
+ /* Wait for the picture to be ready before enabling backlight */
+ msleep(120);
+ }
+
+ return 0;
+}
+
+static int y030xx067a_disable(struct drm_panel *panel)
+{
+ struct y030xx067a *priv = to_y030xx067a(panel);
+
+ regmap_clear_bits(priv->map, 0x06, REG06_XPSAVE);
+
+ return 0;
+}
+
static int y030xx067a_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
@@ -239,6 +260,8 @@ static int y030xx067a_get_modes(struct drm_panel *panel,
static const struct drm_panel_funcs y030xx067a_funcs = {
.prepare = y030xx067a_prepare,
.unprepare = y030xx067a_unprepare,
+ .enable = y030xx067a_enable,
+ .disable = y030xx067a_disable,
.get_modes = y030xx067a_get_modes,
};
@@ -246,6 +269,7 @@ static const struct regmap_config y030xx067a_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x15,
+ .cache_type = REGCACHE_FLAT,
};
static int y030xx067a_probe(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index f7bfcf63d48e..1732b4f56e38 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1847,6 +1847,7 @@ static const struct panel_delay delay_100_500_e200 = {
static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"),
+ EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"),
@@ -1859,6 +1860,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"),
+ EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"),
diff --git a/drivers/gpu/drm/panel/panel-innolux-ej030na.c b/drivers/gpu/drm/panel/panel-innolux-ej030na.c
index e3b1daa0cb72..b2b0ebc9e943 100644
--- a/drivers/gpu/drm/panel/panel-innolux-ej030na.c
+++ b/drivers/gpu/drm/panel/panel-innolux-ej030na.c
@@ -80,8 +80,6 @@ static const struct reg_sequence ej030na_init_sequence[] = {
{ 0x47, 0x08 },
{ 0x48, 0x0f },
{ 0x49, 0x0f },
-
- { 0x2b, 0x01 },
};
static int ej030na_prepare(struct drm_panel *panel)
@@ -109,8 +107,6 @@ static int ej030na_prepare(struct drm_panel *panel)
goto err_disable_regulator;
}
- msleep(120);
-
return 0;
err_disable_regulator:
@@ -128,6 +124,31 @@ static int ej030na_unprepare(struct drm_panel *panel)
return 0;
}
+static int ej030na_enable(struct drm_panel *panel)
+{
+ struct ej030na *priv = to_ej030na(panel);
+
+ /* standby off */
+ regmap_write(priv->map, 0x2b, 0x01);
+
+ if (panel->backlight) {
+ /* Wait for the picture to be ready before enabling backlight */
+ msleep(120);
+ }
+
+ return 0;
+}
+
+static int ej030na_disable(struct drm_panel *panel)
+{
+ struct ej030na *priv = to_ej030na(panel);
+
+ /* standby on */
+ regmap_write(priv->map, 0x2b, 0x00);
+
+ return 0;
+}
+
static int ej030na_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
@@ -165,6 +186,8 @@ static int ej030na_get_modes(struct drm_panel *panel,
static const struct drm_panel_funcs ej030na_funcs = {
.prepare = ej030na_prepare,
.unprepare = ej030na_unprepare,
+ .enable = ej030na_enable,
+ .disable = ej030na_disable,
.get_modes = ej030na_get_modes,
};
diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
new file mode 100644
index 000000000000..cf078f0d3cd3
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NewVision NV3052C IPS LCD panel driver
+ *
+ * Copyright (C) 2020, Paul Cercueil <paul@crapouillou.net>
+ * Copyright (C) 2022, Christophe Branchereau <cbranchereau@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <video/mipi_display.h>
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct nv3052c_panel_info {
+ const struct drm_display_mode *display_modes;
+ unsigned int num_modes;
+ u16 width_mm, height_mm;
+ u32 bus_format, bus_flags;
+};
+
+struct nv3052c {
+ struct device *dev;
+ struct drm_panel panel;
+ struct mipi_dbi dbi;
+ const struct nv3052c_panel_info *panel_info;
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+};
+
+struct nv3052c_reg {
+ u8 cmd;
+ u8 val;
+};
+
+static const struct nv3052c_reg nv3052c_panel_regs[] = {
+ { 0xff, 0x30 },
+ { 0xff, 0x52 },
+ { 0xff, 0x01 },
+ { 0xe3, 0x00 },
+ { 0x40, 0x00 },
+ { 0x03, 0x40 },
+ { 0x04, 0x00 },
+ { 0x05, 0x03 },
+ { 0x08, 0x00 },
+ { 0x09, 0x07 },
+ { 0x0a, 0x01 },
+ { 0x0b, 0x32 },
+ { 0x0c, 0x32 },
+ { 0x0d, 0x0b },
+ { 0x0e, 0x00 },
+ { 0x23, 0xa0 },
+ { 0x24, 0x0c },
+ { 0x25, 0x06 },
+ { 0x26, 0x14 },
+ { 0x27, 0x14 },
+ { 0x38, 0xcc },
+ { 0x39, 0xd7 },
+ { 0x3a, 0x4a },
+ { 0x28, 0x40 },
+ { 0x29, 0x01 },
+ { 0x2a, 0xdf },
+ { 0x49, 0x3c },
+ { 0x91, 0x77 },
+ { 0x92, 0x77 },
+ { 0xa0, 0x55 },
+ { 0xa1, 0x50 },
+ { 0xa4, 0x9c },
+ { 0xa7, 0x02 },
+ { 0xa8, 0x01 },
+ { 0xa9, 0x01 },
+ { 0xaa, 0xfc },
+ { 0xab, 0x28 },
+ { 0xac, 0x06 },
+ { 0xad, 0x06 },
+ { 0xae, 0x06 },
+ { 0xaf, 0x03 },
+ { 0xb0, 0x08 },
+ { 0xb1, 0x26 },
+ { 0xb2, 0x28 },
+ { 0xb3, 0x28 },
+ { 0xb4, 0x33 },
+ { 0xb5, 0x08 },
+ { 0xb6, 0x26 },
+ { 0xb7, 0x08 },
+ { 0xb8, 0x26 },
+ { 0xf0, 0x00 },
+ { 0xf6, 0xc0 },
+ { 0xff, 0x30 },
+ { 0xff, 0x52 },
+ { 0xff, 0x02 },
+ { 0xb0, 0x0b },
+ { 0xb1, 0x16 },
+ { 0xb2, 0x17 },
+ { 0xb3, 0x2c },
+ { 0xb4, 0x32 },
+ { 0xb5, 0x3b },
+ { 0xb6, 0x29 },
+ { 0xb7, 0x40 },
+ { 0xb8, 0x0d },
+ { 0xb9, 0x05 },
+ { 0xba, 0x12 },
+ { 0xbb, 0x10 },
+ { 0xbc, 0x12 },
+ { 0xbd, 0x15 },
+ { 0xbe, 0x19 },
+ { 0xbf, 0x0e },
+ { 0xc0, 0x16 },
+ { 0xc1, 0x0a },
+ { 0xd0, 0x0c },
+ { 0xd1, 0x17 },
+ { 0xd2, 0x14 },
+ { 0xd3, 0x2e },
+ { 0xd4, 0x32 },
+ { 0xd5, 0x3c },
+ { 0xd6, 0x22 },
+ { 0xd7, 0x3d },
+ { 0xd8, 0x0d },
+ { 0xd9, 0x07 },
+ { 0xda, 0x13 },
+ { 0xdb, 0x13 },
+ { 0xdc, 0x11 },
+ { 0xdd, 0x15 },
+ { 0xde, 0x19 },
+ { 0xdf, 0x10 },
+ { 0xe0, 0x17 },
+ { 0xe1, 0x0a },
+ { 0xff, 0x30 },
+ { 0xff, 0x52 },
+ { 0xff, 0x03 },
+ { 0x00, 0x2a },
+ { 0x01, 0x2a },
+ { 0x02, 0x2a },
+ { 0x03, 0x2a },
+ { 0x04, 0x61 },
+ { 0x05, 0x80 },
+ { 0x06, 0xc7 },
+ { 0x07, 0x01 },
+ { 0x08, 0x03 },
+ { 0x09, 0x04 },
+ { 0x70, 0x22 },
+ { 0x71, 0x80 },
+ { 0x30, 0x2a },
+ { 0x31, 0x2a },
+ { 0x32, 0x2a },
+ { 0x33, 0x2a },
+ { 0x34, 0x61 },
+ { 0x35, 0xc5 },
+ { 0x36, 0x80 },
+ { 0x37, 0x23 },
+ { 0x40, 0x03 },
+ { 0x41, 0x04 },
+ { 0x42, 0x05 },
+ { 0x43, 0x06 },
+ { 0x44, 0x11 },
+ { 0x45, 0xe8 },
+ { 0x46, 0xe9 },
+ { 0x47, 0x11 },
+ { 0x48, 0xea },
+ { 0x49, 0xeb },
+ { 0x50, 0x07 },
+ { 0x51, 0x08 },
+ { 0x52, 0x09 },
+ { 0x53, 0x0a },
+ { 0x54, 0x11 },
+ { 0x55, 0xec },
+ { 0x56, 0xed },
+ { 0x57, 0x11 },
+ { 0x58, 0xef },
+ { 0x59, 0xf0 },
+ { 0xb1, 0x01 },
+ { 0xb4, 0x15 },
+ { 0xb5, 0x16 },
+ { 0xb6, 0x09 },
+ { 0xb7, 0x0f },
+ { 0xb8, 0x0d },
+ { 0xb9, 0x0b },
+ { 0xba, 0x00 },
+ { 0xc7, 0x02 },
+ { 0xca, 0x17 },
+ { 0xcb, 0x18 },
+ { 0xcc, 0x0a },
+ { 0xcd, 0x10 },
+ { 0xce, 0x0e },
+ { 0xcf, 0x0c },
+ { 0xd0, 0x00 },
+ { 0x81, 0x00 },
+ { 0x84, 0x15 },
+ { 0x85, 0x16 },
+ { 0x86, 0x10 },
+ { 0x87, 0x0a },
+ { 0x88, 0x0c },
+ { 0x89, 0x0e },
+ { 0x8a, 0x02 },
+ { 0x97, 0x00 },
+ { 0x9a, 0x17 },
+ { 0x9b, 0x18 },
+ { 0x9c, 0x0f },
+ { 0x9d, 0x09 },
+ { 0x9e, 0x0b },
+ { 0x9f, 0x0d },
+ { 0xa0, 0x01 },
+ { 0xff, 0x30 },
+ { 0xff, 0x52 },
+ { 0xff, 0x02 },
+ { 0x01, 0x01 },
+ { 0x02, 0xda },
+ { 0x03, 0xba },
+ { 0x04, 0xa8 },
+ { 0x05, 0x9a },
+ { 0x06, 0x70 },
+ { 0x07, 0xff },
+ { 0x08, 0x91 },
+ { 0x09, 0x90 },
+ { 0x0a, 0xff },
+ { 0x0b, 0x8f },
+ { 0x0c, 0x60 },
+ { 0x0d, 0x58 },
+ { 0x0e, 0x48 },
+ { 0x0f, 0x38 },
+ { 0x10, 0x2b },
+ { 0xff, 0x30 },
+ { 0xff, 0x52 },
+ { 0xff, 0x00 },
+ { 0x36, 0x0a },
+};
+
+static inline struct nv3052c *to_nv3052c(struct drm_panel *panel)
+{
+ return container_of(panel, struct nv3052c, panel);
+}
+
+static int nv3052c_prepare(struct drm_panel *panel)
+{
+ struct nv3052c *priv = to_nv3052c(panel);
+ struct mipi_dbi *dbi = &priv->dbi;
+ unsigned int i;
+ int err;
+
+ err = regulator_enable(priv->supply);
+ if (err) {
+ dev_err(priv->dev, "Failed to enable power supply: %d\n", err);
+ return err;
+ }
+
+ /* Reset the chip */
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ usleep_range(10, 1000);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+ usleep_range(5000, 20000);
+
+ for (i = 0; i < ARRAY_SIZE(nv3052c_panel_regs); i++) {
+ err = mipi_dbi_command(dbi, nv3052c_panel_regs[i].cmd,
+ nv3052c_panel_regs[i].val);
+
+ if (err) {
+ dev_err(priv->dev, "Unable to set register: %d\n", err);
+ goto err_disable_regulator;
+ }
+ }
+
+ err = mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+ if (err) {
+ dev_err(priv->dev, "Unable to exit sleep mode: %d\n", err);
+ goto err_disable_regulator;
+ }
+
+ return 0;
+
+err_disable_regulator:
+ regulator_disable(priv->supply);
+ return err;
+}
+
+static int nv3052c_unprepare(struct drm_panel *panel)
+{
+ struct nv3052c *priv = to_nv3052c(panel);
+ struct mipi_dbi *dbi = &priv->dbi;
+ int err;
+
+ err = mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
+ if (err)
+ dev_err(priv->dev, "Unable to enter sleep mode: %d\n", err);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_disable(priv->supply);
+
+ return 0;
+}
+
+static int nv3052c_enable(struct drm_panel *panel)
+{
+ struct nv3052c *priv = to_nv3052c(panel);
+ struct mipi_dbi *dbi = &priv->dbi;
+ int err;
+
+ err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
+ if (err) {
+ dev_err(priv->dev, "Unable to enable display: %d\n", err);
+ return err;
+ }
+
+ if (panel->backlight) {
+ /* Wait for the picture to be ready before enabling backlight */
+ msleep(120);
+ }
+
+ return 0;
+}
+
+static int nv3052c_disable(struct drm_panel *panel)
+{
+ struct nv3052c *priv = to_nv3052c(panel);
+ struct mipi_dbi *dbi = &priv->dbi;
+ int err;
+
+ err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
+ if (err) {
+ dev_err(priv->dev, "Unable to disable display: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int nv3052c_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct nv3052c *priv = to_nv3052c(panel);
+ const struct nv3052c_panel_info *panel_info = priv->panel_info;
+ struct drm_display_mode *mode;
+ unsigned int i;
+
+ for (i = 0; i < panel_info->num_modes; i++) {
+ mode = drm_mode_duplicate(connector->dev,
+ &panel_info->display_modes[i]);
+ if (!mode)
+ return -ENOMEM;
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (panel_info->num_modes == 1)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.bpc = 8;
+ connector->display_info.width_mm = panel_info->width_mm;
+ connector->display_info.height_mm = panel_info->height_mm;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &panel_info->bus_format, 1);
+ connector->display_info.bus_flags = panel_info->bus_flags;
+
+ return panel_info->num_modes;
+}
+
+static const struct drm_panel_funcs nv3052c_funcs = {
+ .prepare = nv3052c_prepare,
+ .unprepare = nv3052c_unprepare,
+ .enable = nv3052c_enable,
+ .disable = nv3052c_disable,
+ .get_modes = nv3052c_get_modes,
+};
+
+static int nv3052c_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct nv3052c *priv;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ priv->panel_info = of_device_get_match_data(dev);
+ if (!priv->panel_info)
+ return -EINVAL;
+
+ priv->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(priv->supply))
+ return dev_err_probe(dev, PTR_ERR(priv->supply), "Failed to get power supply\n");
+
+ priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n");
+
+ err = mipi_dbi_spi_init(spi, &priv->dbi, NULL);
+ if (err)
+ return dev_err_probe(dev, err, "MIPI DBI init failed\n");
+
+ priv->dbi.read_commands = NULL;
+
+ spi_set_drvdata(spi, priv);
+
+ drm_panel_init(&priv->panel, dev, &nv3052c_funcs,
+ DRM_MODE_CONNECTOR_DPI);
+
+ err = drm_panel_of_backlight(&priv->panel);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to attach backlight\n");
+
+ drm_panel_add(&priv->panel);
+
+ return 0;
+}
+
+static void nv3052c_remove(struct spi_device *spi)
+{
+ struct nv3052c *priv = spi_get_drvdata(spi);
+
+ drm_panel_remove(&priv->panel);
+ drm_panel_disable(&priv->panel);
+ drm_panel_unprepare(&priv->panel);
+}
+
+static const struct drm_display_mode ltk035c5444t_modes[] = {
+ { /* 60 Hz */
+ .clock = 24000,
+ .hdisplay = 640,
+ .hsync_start = 640 + 96,
+ .hsync_end = 640 + 96 + 16,
+ .htotal = 640 + 96 + 16 + 48,
+ .vdisplay = 480,
+ .vsync_start = 480 + 5,
+ .vsync_end = 480 + 5 + 2,
+ .vtotal = 480 + 5 + 2 + 13,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+ { /* 50 Hz */
+ .clock = 18000,
+ .hdisplay = 640,
+ .hsync_start = 640 + 39,
+ .hsync_end = 640 + 39 + 2,
+ .htotal = 640 + 39 + 2 + 39,
+ .vdisplay = 480,
+ .vsync_start = 480 + 5,
+ .vsync_end = 480 + 5 + 2,
+ .vtotal = 480 + 5 + 2 + 13,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+};
+
+static const struct nv3052c_panel_info ltk035c5444t_panel_info = {
+ .display_modes = ltk035c5444t_modes,
+ .num_modes = ARRAY_SIZE(ltk035c5444t_modes),
+ .width_mm = 77,
+ .height_mm = 64,
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+};
+
+static const struct of_device_id nv3052c_of_match[] = {
+ { .compatible = "leadtek,ltk035c5444t", .data = &ltk035c5444t_panel_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nv3052c_of_match);
+
+static struct spi_driver nv3052c_driver = {
+ .driver = {
+ .name = "nv3052c",
+ .of_match_table = nv3052c_of_match,
+ },
+ .probe = nv3052c_probe,
+ .remove = nv3052c_remove,
+};
+module_spi_driver(nv3052c_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c
index b24b92d93ea5..9ca5c7ff41d6 100644
--- a/drivers/gpu/drm/panel/panel-truly-nt35597.c
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -446,7 +446,7 @@ static int truly_nt35597_get_modes(struct drm_panel *panel,
const struct nt35597_config *config;
config = ctx->config;
- mode = drm_mode_create(connector->dev);
+ mode = drm_mode_duplicate(connector->dev, config->dm);
if (!mode) {
dev_err(ctx->dev, "failed to create a new display mode\n");
return 0;
@@ -454,7 +454,6 @@ static int truly_nt35597_get_modes(struct drm_panel *panel,
connector->display_info.width_mm = config->width_mm;
connector->display_info.height_mm = config->height_mm;
- drm_mode_copy(mode, config->dm);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c
index eb43503ec97b..db2443ac81d3 100644
--- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c
+++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c
@@ -168,7 +168,8 @@ static int visionox_rm69299_get_modes(struct drm_panel *panel,
struct visionox_rm69299 *ctx = panel_to_ctx(panel);
struct drm_display_mode *mode;
- mode = drm_mode_create(connector->dev);
+ mode = drm_mode_duplicate(connector->dev,
+ &visionox_rm69299_1080x2248_60hz);
if (!mode) {
dev_err(ctx->panel.dev, "failed to create a new display mode\n");
return 0;
@@ -176,7 +177,6 @@ static int visionox_rm69299_get_modes(struct drm_panel *panel,
connector->display_info.width_mm = 74;
connector->display_info.height_mm = 131;
- drm_mode_copy(mode, &visionox_rm69299_1080x2248_60hz);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index a6925dbb6224..c34114560e49 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -247,6 +247,10 @@ static int panfrost_acquire_object_fences(struct drm_gem_object **bos,
int i, ret;
for (i = 0; i < bo_count; i++) {
+ ret = dma_resv_reserve_fences(bos[i]->resv, 1);
+ if (ret)
+ return ret;
+
/* panfrost always uses write mode in its current uapi */
ret = drm_sched_job_add_implicit_dependencies(job, bos[i],
true);
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index 4dc5ad13f12c..a054e4a00fe8 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -165,7 +165,7 @@ int qxl_device_init(struct qxl_device *qdev,
(int)qdev->surfaceram_size / 1024,
(sb == 4) ? "64bit" : "32bit");
- qdev->rom = ioremap(qdev->rom_base, qdev->rom_size);
+ qdev->rom = ioremap_wc(qdev->rom_base, qdev->rom_size);
if (!qdev->rom) {
pr_err("Unable to ioremap ROM\n");
r = -ENOMEM;
@@ -183,7 +183,7 @@ int qxl_device_init(struct qxl_device *qdev,
goto rom_unmap;
}
- qdev->ram_header = ioremap(qdev->vram_base +
+ qdev->ram_header = ioremap_wc(qdev->vram_base +
qdev->rom->ram_header_offset,
sizeof(*qdev->ram_header));
if (!qdev->ram_header) {
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index 469979cd0341..cde1e8ddaeaa 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -200,7 +200,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
return ret;
}
- ret = dma_resv_reserve_shared(bo->tbo.base.resv, 1);
+ ret = dma_resv_reserve_fences(bo->tbo.base.resv, 1);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index b2e33d5ba5d0..9ba871bd19b1 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -82,13 +82,13 @@ int qxl_ttm_io_mem_reserve(struct ttm_device *bdev,
case TTM_PL_VRAM:
mem->bus.is_iomem = true;
mem->bus.offset = (mem->start << PAGE_SHIFT) + qdev->vram_base;
- mem->bus.caching = ttm_cached;
+ mem->bus.caching = ttm_write_combined;
break;
case TTM_PL_PRIV:
mem->bus.is_iomem = true;
mem->bus.offset = (mem->start << PAGE_SHIFT) +
qdev->surfaceram_base;
- mem->bus.caching = ttm_cached;
+ mem->bus.caching = ttm_write_combined;
break;
default:
return -EINVAL;
@@ -113,7 +113,7 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
ttm = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
if (ttm == NULL)
return NULL;
- if (ttm_tt_init(ttm, bo, page_flags, ttm_cached)) {
+ if (ttm_tt_init(ttm, bo, page_flags, ttm_cached, 0)) {
kfree(ttm);
return NULL;
}
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 9ed2b2700e0a..446f7bae54c4 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -535,6 +535,10 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
return r;
radeon_sync_fence(&p->ib.sync, bo_va->last_pt_update);
+
+ r = dma_resv_reserve_fences(bo->tbo.base.resv, 1);
+ if (r)
+ return r;
}
return radeon_vm_clear_invalids(rdev, vm);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index b9a07677a71e..f60e826cd292 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -533,7 +533,12 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
DRM_ERROR("failed to pin new rbo buffer before flip\n");
goto cleanup;
}
- work->fence = dma_fence_get(dma_resv_excl_fence(new_rbo->tbo.base.resv));
+ r = dma_resv_get_singleton(new_rbo->tbo.base.resv, false, &work->fence);
+ if (r) {
+ radeon_bo_unreserve(new_rbo);
+ DRM_ERROR("failed to get new rbo buffer fences\n");
+ goto cleanup;
+ }
radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL);
radeon_bo_unreserve(new_rbo);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 91a72cd14304..7ffd2e90f325 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -782,6 +782,14 @@ void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
bool shared)
{
struct dma_resv *resv = bo->tbo.base.resv;
+ int r;
+
+ r = dma_resv_reserve_fences(resv, 1);
+ if (r) {
+ /* As last resort on OOM we block for the fence */
+ dma_fence_wait(&fence->base, false);
+ return;
+ }
if (shared)
dma_resv_add_shared_fence(resv, &fence->base);
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index bb53016f3138..987cabbf1318 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -831,7 +831,7 @@ static int radeon_vm_update_ptes(struct radeon_device *rdev,
int r;
radeon_sync_resv(rdev, &ib->sync, pt->tbo.base.resv, true);
- r = dma_resv_reserve_shared(pt->tbo.base.resv, 1);
+ r = dma_resv_reserve_fences(pt->tbo.base.resv, 1);
if (r)
return r;
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index b81fceb0b8a2..c5660b066554 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -703,6 +703,8 @@ int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
struct dma_fence *fence;
int ret;
+ dma_resv_assert_held(obj->resv);
+
dma_resv_for_each_fence(&cursor, obj->resv, write, fence) {
/* Make sure to grab an additional ref on the added fence */
dma_fence_get(fence);
diff --git a/drivers/gpu/drm/selftests/test-drm_buddy.c b/drivers/gpu/drm/selftests/test-drm_buddy.c
index fa997f89522b..aca0c491040f 100644
--- a/drivers/gpu/drm/selftests/test-drm_buddy.c
+++ b/drivers/gpu/drm/selftests/test-drm_buddy.c
@@ -488,8 +488,10 @@ static int igt_buddy_alloc_smoke(void *arg)
}
order = drm_random_order(mm.max_order + 1, &prng);
- if (!order)
+ if (!order) {
+ err = -ENOMEM;
goto out_fini;
+ }
for (i = 0; i <= mm.max_order; ++i) {
struct drm_buddy_block *block;
@@ -902,14 +904,13 @@ err_fini:
static int igt_buddy_alloc_limit(void *arg)
{
- u64 end, size = U64_MAX, start = 0;
+ u64 size = U64_MAX, start = 0;
struct drm_buddy_block *block;
unsigned long flags = 0;
LIST_HEAD(allocated);
struct drm_buddy mm;
int err;
- size = end = round_down(size, 4096);
err = drm_buddy_init(&mm, size, PAGE_SIZE);
if (err)
return err;
@@ -921,7 +922,8 @@ static int igt_buddy_alloc_limit(void *arg)
goto out_fini;
}
- err = drm_buddy_alloc_blocks(&mm, start, end, size,
+ size = mm.chunk_size << mm.max_order;
+ err = drm_buddy_alloc_blocks(&mm, start, size, size,
PAGE_SIZE, &allocated, flags);
if (unlikely(err))
diff --git a/drivers/gpu/drm/solomon/Kconfig b/drivers/gpu/drm/solomon/Kconfig
index 5861c3ab7c45..6230369505c9 100644
--- a/drivers/gpu/drm/solomon/Kconfig
+++ b/drivers/gpu/drm/solomon/Kconfig
@@ -1,6 +1,6 @@
config DRM_SSD130X
tristate "DRM support for Solomon SSD130x OLED displays"
- depends on DRM
+ depends on DRM && MMU
select BACKLIGHT_CLASS_DEVICE
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index ce4dc20412e0..38b6c2c14f53 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -48,7 +48,7 @@
#define SSD130X_CONTRAST 0x81
#define SSD130X_SET_LOOKUP_TABLE 0x91
#define SSD130X_CHARGE_PUMP 0x8d
-#define SSD130X_SEG_REMAP_ON 0xa1
+#define SSD130X_SET_SEG_REMAP 0xa0
#define SSD130X_DISPLAY_OFF 0xae
#define SSD130X_SET_MULTIPLEX_RATIO 0xa8
#define SSD130X_DISPLAY_ON 0xaf
@@ -61,7 +61,9 @@
#define SSD130X_SET_COM_PINS_CONFIG 0xda
#define SSD130X_SET_VCOMH 0xdb
-#define SSD130X_SET_COM_SCAN_DIR_MASK GENMASK(3, 2)
+#define SSD130X_SET_SEG_REMAP_MASK GENMASK(0, 0)
+#define SSD130X_SET_SEG_REMAP_SET(val) FIELD_PREP(SSD130X_SET_SEG_REMAP_MASK, (val))
+#define SSD130X_SET_COM_SCAN_DIR_MASK GENMASK(3, 3)
#define SSD130X_SET_COM_SCAN_DIR_SET(val) FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))
#define SSD130X_SET_CLOCK_DIV_MASK GENMASK(3, 0)
#define SSD130X_SET_CLOCK_DIV_SET(val) FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))
@@ -235,7 +237,7 @@ static void ssd130x_power_off(struct ssd130x_device *ssd130x)
static int ssd130x_init(struct ssd130x_device *ssd130x)
{
- u32 precharge, dclk, com_invdir, compins, chargepump;
+ u32 precharge, dclk, com_invdir, compins, chargepump, seg_remap;
int ret;
/* Set initial contrast */
@@ -244,11 +246,11 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
return ret;
/* Set segment re-map */
- if (ssd130x->seg_remap) {
- ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SEG_REMAP_ON);
- if (ret < 0)
- return ret;
- }
+ seg_remap = (SSD130X_SET_SEG_REMAP |
+ SSD130X_SET_SEG_REMAP_SET(ssd130x->seg_remap));
+ ret = ssd130x_write_cmd(ssd130x, 1, seg_remap);
+ if (ret < 0)
+ return ret;
/* Set COM direction */
com_invdir = (SSD130X_SET_COM_SCAN_DIR |
@@ -353,11 +355,14 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
unsigned int width = drm_rect_width(rect);
unsigned int height = drm_rect_height(rect);
unsigned int line_length = DIV_ROUND_UP(width, 8);
- unsigned int pages = DIV_ROUND_UP(y % 8 + height, 8);
+ unsigned int pages = DIV_ROUND_UP(height, 8);
+ struct drm_device *drm = &ssd130x->drm;
u32 array_idx = 0;
int ret, i, j, k;
u8 *data_array = NULL;
+ drm_WARN_ONCE(drm, y % 8 != 0, "y must be aligned to screen page\n");
+
data_array = kcalloc(width, pages, GFP_KERNEL);
if (!data_array)
return -ENOMEM;
@@ -399,13 +404,13 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
if (ret < 0)
goto out_free;
- for (i = y / 8; i < y / 8 + pages; i++) {
+ for (i = 0; i < pages; i++) {
int m = 8;
/* Last page may be partial */
- if (8 * (i + 1) > ssd130x->height)
+ if (8 * (y / 8 + i + 1) > ssd130x->height)
m = ssd130x->height % 8;
- for (j = x; j < x + width; j++) {
+ for (j = 0; j < width; j++) {
u8 data = 0;
for (k = 0; k < m; k++) {
@@ -435,7 +440,8 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
.y2 = ssd130x->height,
};
- buf = kcalloc(ssd130x->width, ssd130x->height, GFP_KERNEL);
+ buf = kcalloc(DIV_ROUND_UP(ssd130x->width, 8), ssd130x->height,
+ GFP_KERNEL);
if (!buf)
return;
@@ -449,14 +455,20 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_m
{
struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
+ unsigned int dst_pitch;
int ret = 0;
u8 *buf = NULL;
- buf = kcalloc(fb->width, fb->height, GFP_KERNEL);
+ /* Align y to display page boundaries */
+ rect->y1 = round_down(rect->y1, 8);
+ rect->y2 = min_t(unsigned int, round_up(rect->y2, 8), ssd130x->height);
+
+ dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
+ buf = kcalloc(dst_pitch, drm_rect_height(rect), GFP_KERNEL);
if (!buf)
return -ENOMEM;
- drm_fb_xrgb8888_to_mono_reversed(buf, 0, vmap, fb, rect);
+ drm_fb_xrgb8888_to_mono(buf, dst_pitch, vmap, fb, rect);
ssd130x_update_rect(ssd130x, buf, rect);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 29890d704cb4..853c6b443fff 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -433,7 +433,7 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
set_scanout(crtc, fb);
- crtc->hwmode = crtc->state->adjusted_mode;
+ drm_mode_copy(&crtc->hwmode, &crtc->state->adjusted_mode);
tilcdc_crtc->hvtotal_us =
tilcdc_mode_hvtotal(&crtc->hwmode);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 7594cf6e186e..3b86d002ef62 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -60,11 +60,13 @@ struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
int tilcdc_add_component_encoder(struct drm_device *ddev)
{
struct tilcdc_drm_private *priv = ddev->dev_private;
- struct drm_encoder *encoder;
+ struct drm_encoder *encoder = NULL, *iter;
- list_for_each_entry(encoder, &ddev->mode_config.encoder_list, head)
- if (encoder->possible_crtcs & (1 << priv->crtc->index))
+ list_for_each_entry(iter, &ddev->mode_config.encoder_list, head)
+ if (iter->possible_crtcs & (1 << priv->crtc->index)) {
+ encoder = iter;
break;
+ }
if (!encoder) {
dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__);
diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c
index 37b6bb90e46e..a096fb8b83e9 100644
--- a/drivers/gpu/drm/tiny/repaper.c
+++ b/drivers/gpu/drm/tiny/repaper.c
@@ -540,7 +540,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
if (ret)
goto out_free;
- drm_fb_xrgb8888_to_mono_reversed(buf, 0, cma_obj->vaddr, fb, &clip);
+ drm_fb_xrgb8888_to_mono(buf, 0, cma_obj->vaddr, fb, &clip);
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 6ddc16f0fe2b..d27691f2e451 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -134,7 +134,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo,
agp_be->mem = NULL;
agp_be->bridge = bridge;
- if (ttm_tt_init(&agp_be->ttm, bo, page_flags, ttm_write_combined)) {
+ if (ttm_tt_init(&agp_be->ttm, bo, page_flags, ttm_write_combined, 0)) {
kfree(agp_be);
return NULL;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index db3dc7ef5382..c49996cf25d0 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -69,107 +69,54 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
}
}
-static inline void ttm_bo_move_to_pinned(struct ttm_buffer_object *bo)
-{
- struct ttm_device *bdev = bo->bdev;
-
- list_move_tail(&bo->lru, &bdev->pinned);
-
- if (bdev->funcs->del_from_lru_notify)
- bdev->funcs->del_from_lru_notify(bo);
-}
-
-static inline void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
-{
- struct ttm_device *bdev = bo->bdev;
-
- list_del_init(&bo->lru);
-
- if (bdev->funcs->del_from_lru_notify)
- bdev->funcs->del_from_lru_notify(bo);
-}
-
-static void ttm_bo_bulk_move_set_pos(struct ttm_lru_bulk_move_pos *pos,
- struct ttm_buffer_object *bo)
-{
- if (!pos->first)
- pos->first = bo;
- pos->last = bo;
-}
-
-void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo,
- struct ttm_resource *mem,
- struct ttm_lru_bulk_move *bulk)
+/**
+ * ttm_bo_move_to_lru_tail
+ *
+ * @bo: The buffer object.
+ *
+ * Move this BO to the tail of all lru lists used to lookup and reserve an
+ * object. This function must be called with struct ttm_global::lru_lock
+ * held, and is used to make a BO less likely to be considered for eviction.
+ */
+void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
{
- struct ttm_device *bdev = bo->bdev;
- struct ttm_resource_manager *man;
-
- if (!bo->deleted)
- dma_resv_assert_held(bo->base.resv);
-
- if (bo->pin_count) {
- ttm_bo_move_to_pinned(bo);
- return;
- }
-
- if (!mem)
- return;
-
- man = ttm_manager_type(bdev, mem->mem_type);
- list_move_tail(&bo->lru, &man->lru[bo->priority]);
-
- if (bdev->funcs->del_from_lru_notify)
- bdev->funcs->del_from_lru_notify(bo);
-
- if (bulk && !bo->pin_count) {
- switch (bo->resource->mem_type) {
- case TTM_PL_TT:
- ttm_bo_bulk_move_set_pos(&bulk->tt[bo->priority], bo);
- break;
+ dma_resv_assert_held(bo->base.resv);
- case TTM_PL_VRAM:
- ttm_bo_bulk_move_set_pos(&bulk->vram[bo->priority], bo);
- break;
- }
- }
+ if (bo->resource)
+ ttm_resource_move_to_lru_tail(bo->resource);
}
EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
-void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
+/**
+ * ttm_bo_set_bulk_move - update BOs bulk move object
+ *
+ * @bo: The buffer object.
+ *
+ * Update the BOs bulk move object, making sure that resources are added/removed
+ * as well. A bulk move allows to move many resource on the LRU at once,
+ * resulting in much less overhead of maintaining the LRU.
+ * The only requirement is that the resources stay together on the LRU and are
+ * never separated. This is enforces by setting the bulk_move structure on a BO.
+ * ttm_lru_bulk_move_tail() should be used to move all resources to the tail of
+ * their LRU list.
+ */
+void ttm_bo_set_bulk_move(struct ttm_buffer_object *bo,
+ struct ttm_lru_bulk_move *bulk)
{
- unsigned i;
-
- for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
- struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i];
- struct ttm_resource_manager *man;
-
- if (!pos->first)
- continue;
-
- dma_resv_assert_held(pos->first->base.resv);
- dma_resv_assert_held(pos->last->base.resv);
-
- man = ttm_manager_type(pos->first->bdev, TTM_PL_TT);
- list_bulk_move_tail(&man->lru[i], &pos->first->lru,
- &pos->last->lru);
- }
-
- for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
- struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i];
- struct ttm_resource_manager *man;
-
- if (!pos->first)
- continue;
+ dma_resv_assert_held(bo->base.resv);
- dma_resv_assert_held(pos->first->base.resv);
- dma_resv_assert_held(pos->last->base.resv);
+ if (bo->bulk_move == bulk)
+ return;
- man = ttm_manager_type(pos->first->bdev, TTM_PL_VRAM);
- list_bulk_move_tail(&man->lru[i], &pos->first->lru,
- &pos->last->lru);
- }
+ spin_lock(&bo->bdev->lru_lock);
+ if (bo->bulk_move && bo->resource)
+ ttm_lru_bulk_move_del(bo->bulk_move, bo->resource);
+ bo->bulk_move = bulk;
+ if (bo->bulk_move && bo->resource)
+ ttm_lru_bulk_move_add(bo->bulk_move, bo->resource);
+ spin_unlock(&bo->bdev->lru_lock);
}
-EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail);
+EXPORT_SYMBOL(ttm_bo_set_bulk_move);
static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
struct ttm_resource *mem, bool evict,
@@ -204,6 +151,10 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
}
}
+ ret = dma_resv_reserve_fences(bo->base.resv, 1);
+ if (ret)
+ goto out_err;
+
ret = bdev->funcs->move(bo, evict, ctx, mem, hop);
if (ret) {
if (ret == -EMULTIHOP)
@@ -344,7 +295,6 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
return ret;
}
- ttm_bo_move_to_pinned(bo);
list_del_init(&bo->ddestroy);
spin_unlock(&bo->bdev->lru_lock);
ttm_bo_cleanup_memtype_use(bo);
@@ -409,6 +359,7 @@ static void ttm_bo_release(struct kref *kref)
int ret;
WARN_ON_ONCE(bo->pin_count);
+ WARN_ON_ONCE(bo->bulk_move);
if (!bo->deleted) {
ret = ttm_bo_individualize_resv(bo);
@@ -445,7 +396,7 @@ static void ttm_bo_release(struct kref *kref)
*/
if (bo->pin_count) {
bo->pin_count = 0;
- ttm_bo_move_to_lru_tail(bo, bo->resource, NULL);
+ ttm_resource_move_to_lru_tail(bo->resource);
}
kref_init(&bo->kref);
@@ -458,7 +409,6 @@ static void ttm_bo_release(struct kref *kref)
}
spin_lock(&bo->bdev->lru_lock);
- ttm_bo_del_from_lru(bo);
list_del(&bo->ddestroy);
spin_unlock(&bo->bdev->lru_lock);
@@ -673,36 +623,29 @@ int ttm_mem_evict_first(struct ttm_device *bdev,
struct ww_acquire_ctx *ticket)
{
struct ttm_buffer_object *bo = NULL, *busy_bo = NULL;
+ struct ttm_resource_cursor cursor;
+ struct ttm_resource *res;
bool locked = false;
- unsigned i;
int ret;
spin_lock(&bdev->lru_lock);
- for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
- list_for_each_entry(bo, &man->lru[i], lru) {
- bool busy;
-
- if (!ttm_bo_evict_swapout_allowable(bo, ctx, place,
- &locked, &busy)) {
- if (busy && !busy_bo && ticket !=
- dma_resv_locking_ctx(bo->base.resv))
- busy_bo = bo;
- continue;
- }
-
- if (!ttm_bo_get_unless_zero(bo)) {
- if (locked)
- dma_resv_unlock(bo->base.resv);
- continue;
- }
- break;
+ ttm_resource_manager_for_each_res(man, &cursor, res) {
+ bool busy;
+
+ if (!ttm_bo_evict_swapout_allowable(res->bo, ctx, place,
+ &locked, &busy)) {
+ if (busy && !busy_bo && ticket !=
+ dma_resv_locking_ctx(res->bo->base.resv))
+ busy_bo = res->bo;
+ continue;
}
- /* If the inner loop terminated early, we have our candidate */
- if (&bo->lru != &man->lru[i])
+ if (ttm_bo_get_unless_zero(res->bo)) {
+ bo = res->bo;
break;
-
- bo = NULL;
+ }
+ if (locked)
+ dma_resv_unlock(res->bo->base.resv);
}
if (!bo) {
@@ -734,6 +677,40 @@ int ttm_mem_evict_first(struct ttm_device *bdev,
return ret;
}
+/**
+ * ttm_bo_pin - Pin the buffer object.
+ * @bo: The buffer object to pin
+ *
+ * Make sure the buffer is not evicted any more during memory pressure.
+ * @bo must be unpinned again by calling ttm_bo_unpin().
+ */
+void ttm_bo_pin(struct ttm_buffer_object *bo)
+{
+ dma_resv_assert_held(bo->base.resv);
+ WARN_ON_ONCE(!kref_read(&bo->kref));
+ if (!(bo->pin_count++) && bo->bulk_move && bo->resource)
+ ttm_lru_bulk_move_del(bo->bulk_move, bo->resource);
+}
+EXPORT_SYMBOL(ttm_bo_pin);
+
+/**
+ * ttm_bo_unpin - Unpin the buffer object.
+ * @bo: The buffer object to unpin
+ *
+ * Allows the buffer object to be evicted again during memory pressure.
+ */
+void ttm_bo_unpin(struct ttm_buffer_object *bo)
+{
+ dma_resv_assert_held(bo->base.resv);
+ WARN_ON_ONCE(!kref_read(&bo->kref));
+ if (WARN_ON_ONCE(!bo->pin_count))
+ return;
+
+ if (!(--bo->pin_count) && bo->bulk_move && bo->resource)
+ ttm_lru_bulk_move_add(bo->bulk_move, bo->resource);
+}
+EXPORT_SYMBOL(ttm_bo_unpin);
+
/*
* Add the last move fence to the BO and reserve a new shared slot. We only use
* a shared slot to avoid unecessary sync and rely on the subsequent bo move to
@@ -762,7 +739,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
dma_resv_add_shared_fence(bo->base.resv, fence);
- ret = dma_resv_reserve_shared(bo->base.resv, 1);
+ ret = dma_resv_reserve_fences(bo->base.resv, 1);
if (unlikely(ret)) {
dma_fence_put(fence);
return ret;
@@ -821,7 +798,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
bool type_found = false;
int i, ret;
- ret = dma_resv_reserve_shared(bo->base.resv, 1);
+ ret = dma_resv_reserve_fences(bo->base.resv, 1);
if (unlikely(ret))
return ret;
@@ -875,9 +852,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
}
error:
- if (bo->resource->mem_type == TTM_PL_SYSTEM && !bo->pin_count)
- ttm_bo_move_to_lru_tail_unlocked(bo);
-
return ret;
}
EXPORT_SYMBOL(ttm_bo_mem_space);
@@ -971,7 +945,6 @@ int ttm_bo_init_reserved(struct ttm_device *bdev,
bo->destroy = destroy ? destroy : ttm_bo_default_destroy;
kref_init(&bo->kref);
- INIT_LIST_HEAD(&bo->lru);
INIT_LIST_HEAD(&bo->ddestroy);
bo->bdev = bdev;
bo->type = type;
@@ -979,6 +952,7 @@ int ttm_bo_init_reserved(struct ttm_device *bdev,
bo->moving = NULL;
bo->pin_count = 0;
bo->sg = sg;
+ bo->bulk_move = NULL;
if (resv) {
bo->base.resv = resv;
dma_resv_assert_held(bo->base.resv);
@@ -1021,8 +995,6 @@ int ttm_bo_init_reserved(struct ttm_device *bdev,
return ret;
}
- ttm_bo_move_to_lru_tail_unlocked(bo);
-
return ret;
}
EXPORT_SYMBOL(ttm_bo_init_reserved);
@@ -1123,7 +1095,6 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
return ret == -EBUSY ? -ENOSPC : ret;
}
- ttm_bo_move_to_pinned(bo);
/* TODO: Cleanup the locking */
spin_unlock(&bo->bdev->lru_lock);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 2b8caa1efaa3..1b96b91bf81b 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -221,9 +221,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
fbo->base = *bo;
- ttm_bo_get(bo);
- fbo->bo = bo;
-
/**
* Fix up members that we shouldn't copy directly:
* TODO: Explicit member copy would probably be better here.
@@ -231,7 +228,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
atomic_inc(&ttm_glob.bo_count);
INIT_LIST_HEAD(&fbo->base.ddestroy);
- INIT_LIST_HEAD(&fbo->base.lru);
fbo->base.moving = NULL;
drm_vma_node_reset(&fbo->base.base.vma_node);
@@ -251,6 +247,15 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
ret = dma_resv_trylock(&fbo->base.base._resv);
WARN_ON(!ret);
+ ret = dma_resv_reserve_fences(&fbo->base.base._resv, 1);
+ if (ret) {
+ kfree(fbo);
+ return ret;
+ }
+
+ ttm_bo_get(bo);
+ fbo->bo = bo;
+
ttm_bo_move_to_lru_tail_unlocked(&fbo->base);
*new_obj = &fbo->base;
diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c
index be24bb6cefd0..a0562ab386f5 100644
--- a/drivers/gpu/drm/ttm/ttm_device.c
+++ b/drivers/gpu/drm/ttm/ttm_device.c
@@ -142,9 +142,10 @@ EXPORT_SYMBOL(ttm_global_swapout);
int ttm_device_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx,
gfp_t gfp_flags)
{
+ struct ttm_resource_cursor cursor;
struct ttm_resource_manager *man;
- struct ttm_buffer_object *bo;
- unsigned i, j;
+ struct ttm_resource *res;
+ unsigned i;
int ret;
spin_lock(&bdev->lru_lock);
@@ -153,17 +154,16 @@ int ttm_device_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx,
if (!man || !man->use_tt)
continue;
- for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) {
- list_for_each_entry(bo, &man->lru[j], lru) {
- uint32_t num_pages = PFN_UP(bo->base.size);
-
- ret = ttm_bo_swapout(bo, ctx, gfp_flags);
- /* ttm_bo_swapout has dropped the lru_lock */
- if (!ret)
- return num_pages;
- if (ret != -EBUSY)
- return ret;
- }
+ ttm_resource_manager_for_each_res(man, &cursor, res) {
+ struct ttm_buffer_object *bo = res->bo;
+ uint32_t num_pages = PFN_UP(bo->base.size);
+
+ ret = ttm_bo_swapout(bo, ctx, gfp_flags);
+ /* ttm_bo_swapout has dropped the lru_lock */
+ if (!ret)
+ return num_pages;
+ if (ret != -EBUSY)
+ return ret;
}
}
spin_unlock(&bdev->lru_lock);
@@ -259,49 +259,45 @@ void ttm_device_fini(struct ttm_device *bdev)
}
EXPORT_SYMBOL(ttm_device_fini);
-void ttm_device_clear_dma_mappings(struct ttm_device *bdev)
+static void ttm_device_clear_lru_dma_mappings(struct ttm_device *bdev,
+ struct list_head *list)
{
- struct ttm_resource_manager *man;
- struct ttm_buffer_object *bo;
- unsigned int i, j;
+ struct ttm_resource *res;
spin_lock(&bdev->lru_lock);
- while (!list_empty(&bdev->pinned)) {
- bo = list_first_entry(&bdev->pinned, struct ttm_buffer_object, lru);
+ while ((res = list_first_entry_or_null(list, typeof(*res), lru))) {
+ struct ttm_buffer_object *bo = res->bo;
+
/* Take ref against racing releases once lru_lock is unlocked */
- if (ttm_bo_get_unless_zero(bo)) {
- list_del_init(&bo->lru);
- spin_unlock(&bdev->lru_lock);
+ if (!ttm_bo_get_unless_zero(bo))
+ continue;
- if (bo->ttm)
- ttm_tt_unpopulate(bo->bdev, bo->ttm);
+ list_del_init(&res->lru);
+ spin_unlock(&bdev->lru_lock);
- ttm_bo_put(bo);
- spin_lock(&bdev->lru_lock);
- }
+ if (bo->ttm)
+ ttm_tt_unpopulate(bo->bdev, bo->ttm);
+
+ ttm_bo_put(bo);
+ spin_lock(&bdev->lru_lock);
}
+ spin_unlock(&bdev->lru_lock);
+}
+
+void ttm_device_clear_dma_mappings(struct ttm_device *bdev)
+{
+ struct ttm_resource_manager *man;
+ unsigned int i, j;
+
+ ttm_device_clear_lru_dma_mappings(bdev, &bdev->pinned);
for (i = TTM_PL_SYSTEM; i < TTM_NUM_MEM_TYPES; ++i) {
man = ttm_manager_type(bdev, i);
if (!man || !man->use_tt)
continue;
- for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) {
- while (!list_empty(&man->lru[j])) {
- bo = list_first_entry(&man->lru[j], struct ttm_buffer_object, lru);
- if (ttm_bo_get_unless_zero(bo)) {
- list_del_init(&bo->lru);
- spin_unlock(&bdev->lru_lock);
-
- if (bo->ttm)
- ttm_tt_unpopulate(bo->bdev, bo->ttm);
-
- ttm_bo_put(bo);
- spin_lock(&bdev->lru_lock);
- }
- }
- }
+ for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j)
+ ttm_device_clear_lru_dma_mappings(bdev, &man->lru[j]);
}
- spin_unlock(&bdev->lru_lock);
}
EXPORT_SYMBOL(ttm_device_clear_dma_mappings);
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index 071c48d672c6..789c645f004e 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -90,6 +90,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
list_for_each_entry(entry, list, head) {
struct ttm_buffer_object *bo = entry->bo;
+ unsigned int num_fences;
ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
if (ret == -EALREADY && dups) {
@@ -100,12 +101,10 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
continue;
}
+ num_fences = min(entry->num_shared, 1u);
if (!ret) {
- if (!entry->num_shared)
- continue;
-
- ret = dma_resv_reserve_shared(bo->base.resv,
- entry->num_shared);
+ ret = dma_resv_reserve_fences(bo->base.resv,
+ num_fences);
if (!ret)
continue;
}
@@ -120,9 +119,9 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
ret = ttm_bo_reserve_slowpath(bo, intr, ticket);
}
- if (!ret && entry->num_shared)
- ret = dma_resv_reserve_shared(bo->base.resv,
- entry->num_shared);
+ if (!ret)
+ ret = dma_resv_reserve_fences(bo->base.resv,
+ num_fences);
if (unlikely(ret != 0)) {
if (ticket) {
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 9a477f0fddee..7d5a438180e9 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -30,12 +30,129 @@
#include <drm/ttm/ttm_bo_driver.h>
/**
+ * ttm_lru_bulk_move_init - initialize a bulk move structure
+ * @bulk: the structure to init
+ *
+ * For now just memset the structure to zero.
+ */
+void ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk)
+{
+ memset(bulk, 0, sizeof(*bulk));
+}
+EXPORT_SYMBOL(ttm_lru_bulk_move_init);
+
+/**
+ * ttm_lru_bulk_move_tail - bulk move range of resources to the LRU tail.
+ *
+ * @bulk: bulk move structure
+ *
+ * Bulk move BOs to the LRU tail, only valid to use when driver makes sure that
+ * resource order never changes. Should be called with &ttm_device.lru_lock held.
+ */
+void ttm_lru_bulk_move_tail(struct ttm_lru_bulk_move *bulk)
+{
+ unsigned i, j;
+
+ for (i = 0; i < TTM_NUM_MEM_TYPES; ++i) {
+ for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) {
+ struct ttm_lru_bulk_move_pos *pos = &bulk->pos[i][j];
+ struct ttm_resource_manager *man;
+
+ if (!pos->first)
+ continue;
+
+ lockdep_assert_held(&pos->first->bo->bdev->lru_lock);
+ dma_resv_assert_held(pos->first->bo->base.resv);
+ dma_resv_assert_held(pos->last->bo->base.resv);
+
+ man = ttm_manager_type(pos->first->bo->bdev, i);
+ list_bulk_move_tail(&man->lru[j], &pos->first->lru,
+ &pos->last->lru);
+ }
+ }
+}
+EXPORT_SYMBOL(ttm_lru_bulk_move_tail);
+
+/* Return the bulk move pos object for this resource */
+static struct ttm_lru_bulk_move_pos *
+ttm_lru_bulk_move_pos(struct ttm_lru_bulk_move *bulk, struct ttm_resource *res)
+{
+ return &bulk->pos[res->mem_type][res->bo->priority];
+}
+
+/* Move the resource to the tail of the bulk move range */
+static void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos,
+ struct ttm_resource *res)
+{
+ if (pos->last != res) {
+ list_move(&res->lru, &pos->last->lru);
+ pos->last = res;
+ }
+}
+
+/* Add the resource to a bulk_move cursor */
+void ttm_lru_bulk_move_add(struct ttm_lru_bulk_move *bulk,
+ struct ttm_resource *res)
+{
+ struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
+
+ if (!pos->first) {
+ pos->first = res;
+ pos->last = res;
+ } else {
+ ttm_lru_bulk_move_pos_tail(pos, res);
+ }
+}
+
+/* Remove the resource from a bulk_move range */
+void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk,
+ struct ttm_resource *res)
+{
+ struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
+
+ if (unlikely(pos->first == res && pos->last == res)) {
+ pos->first = NULL;
+ pos->last = NULL;
+ } else if (pos->first == res) {
+ pos->first = list_next_entry(res, lru);
+ } else if (pos->last == res) {
+ pos->last = list_prev_entry(res, lru);
+ } else {
+ list_move(&res->lru, &pos->last->lru);
+ }
+}
+
+/* Move a resource to the LRU or bulk tail */
+void ttm_resource_move_to_lru_tail(struct ttm_resource *res)
+{
+ struct ttm_buffer_object *bo = res->bo;
+ struct ttm_device *bdev = bo->bdev;
+
+ lockdep_assert_held(&bo->bdev->lru_lock);
+
+ if (bo->pin_count) {
+ list_move_tail(&res->lru, &bdev->pinned);
+
+ } else if (bo->bulk_move) {
+ struct ttm_lru_bulk_move_pos *pos =
+ ttm_lru_bulk_move_pos(bo->bulk_move, res);
+
+ ttm_lru_bulk_move_pos_tail(pos, res);
+ } else {
+ struct ttm_resource_manager *man;
+
+ man = ttm_manager_type(bdev, res->mem_type);
+ list_move_tail(&res->lru, &man->lru[bo->priority]);
+ }
+}
+
+/**
* ttm_resource_init - resource object constructure
* @bo: buffer object this resources is allocated for
* @place: placement of the resource
* @res: the resource object to inistilize
*
- * Initialize a new resource object. Counterpart of &ttm_resource_fini.
+ * Initialize a new resource object. Counterpart of ttm_resource_fini().
*/
void ttm_resource_init(struct ttm_buffer_object *bo,
const struct ttm_place *place,
@@ -52,10 +169,15 @@ void ttm_resource_init(struct ttm_buffer_object *bo,
res->bus.is_iomem = false;
res->bus.caching = ttm_cached;
res->bo = bo;
+ INIT_LIST_HEAD(&res->lru);
man = ttm_manager_type(bo->bdev, place->mem_type);
spin_lock(&bo->bdev->lru_lock);
- man->usage += bo->base.size;
+ man->usage += res->num_pages << PAGE_SHIFT;
+ if (bo->bulk_move)
+ ttm_lru_bulk_move_add(bo->bulk_move, res);
+ else
+ ttm_resource_move_to_lru_tail(res);
spin_unlock(&bo->bdev->lru_lock);
}
EXPORT_SYMBOL(ttm_resource_init);
@@ -66,15 +188,19 @@ EXPORT_SYMBOL(ttm_resource_init);
* @res: the resource to clean up
*
* Should be used by resource manager backends to clean up the TTM resource
- * objects before freeing the underlying structure. Counterpart of
- * &ttm_resource_init
+ * objects before freeing the underlying structure. Makes sure the resource is
+ * removed from the LRU before destruction.
+ * Counterpart of ttm_resource_init().
*/
void ttm_resource_fini(struct ttm_resource_manager *man,
struct ttm_resource *res)
{
- spin_lock(&man->bdev->lru_lock);
- man->usage -= res->bo->base.size;
- spin_unlock(&man->bdev->lru_lock);
+ struct ttm_device *bdev = man->bdev;
+
+ spin_lock(&bdev->lru_lock);
+ list_del_init(&res->lru);
+ man->usage -= res->num_pages << PAGE_SHIFT;
+ spin_unlock(&bdev->lru_lock);
}
EXPORT_SYMBOL(ttm_resource_fini);
@@ -95,6 +221,12 @@ void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)
if (!*res)
return;
+ if (bo->bulk_move) {
+ spin_lock(&bo->bdev->lru_lock);
+ ttm_lru_bulk_move_del(bo->bulk_move, *res);
+ spin_unlock(&bo->bdev->lru_lock);
+ }
+
man = ttm_manager_type(bo->bdev, (*res)->mem_type);
man->func->free(man, *res);
*res = NULL;
@@ -273,6 +405,57 @@ void ttm_resource_manager_debug(struct ttm_resource_manager *man,
}
EXPORT_SYMBOL(ttm_resource_manager_debug);
+/**
+ * ttm_resource_manager_first
+ *
+ * @man: resource manager to iterate over
+ * @cursor: cursor to record the position
+ *
+ * Returns the first resource from the resource manager.
+ */
+struct ttm_resource *
+ttm_resource_manager_first(struct ttm_resource_manager *man,
+ struct ttm_resource_cursor *cursor)
+{
+ struct ttm_resource *res;
+
+ lockdep_assert_held(&man->bdev->lru_lock);
+
+ for (cursor->priority = 0; cursor->priority < TTM_MAX_BO_PRIORITY;
+ ++cursor->priority)
+ list_for_each_entry(res, &man->lru[cursor->priority], lru)
+ return res;
+
+ return NULL;
+}
+
+/**
+ * ttm_resource_manager_next
+ *
+ * @man: resource manager to iterate over
+ * @cursor: cursor to record the position
+ * @res: the current resource pointer
+ *
+ * Returns the next resource from the resource manager.
+ */
+struct ttm_resource *
+ttm_resource_manager_next(struct ttm_resource_manager *man,
+ struct ttm_resource_cursor *cursor,
+ struct ttm_resource *res)
+{
+ lockdep_assert_held(&man->bdev->lru_lock);
+
+ list_for_each_entry_continue(res, &man->lru[cursor->priority], lru)
+ return res;
+
+ for (++cursor->priority; cursor->priority < TTM_MAX_BO_PRIORITY;
+ ++cursor->priority)
+ list_for_each_entry(res, &man->lru[cursor->priority], lru)
+ return res;
+
+ return NULL;
+}
+
static void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter *iter,
struct iosys_map *dmap,
pgoff_t i)
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index d234aab800a0..1a66d9fc589a 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -134,9 +134,10 @@ void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
static void ttm_tt_init_fields(struct ttm_tt *ttm,
struct ttm_buffer_object *bo,
uint32_t page_flags,
- enum ttm_caching caching)
+ enum ttm_caching caching,
+ unsigned long extra_pages)
{
- ttm->num_pages = PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT;
+ ttm->num_pages = (PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT) + extra_pages;
ttm->caching = ttm_cached;
ttm->page_flags = page_flags;
ttm->dma_address = NULL;
@@ -146,9 +147,10 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm,
}
int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
- uint32_t page_flags, enum ttm_caching caching)
+ uint32_t page_flags, enum ttm_caching caching,
+ unsigned long extra_pages)
{
- ttm_tt_init_fields(ttm, bo, page_flags, caching);
+ ttm_tt_init_fields(ttm, bo, page_flags, caching, extra_pages);
if (ttm_tt_alloc_page_directory(ttm)) {
pr_err("Failed allocating page table\n");
@@ -180,7 +182,7 @@ int ttm_sg_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
{
int ret;
- ttm_tt_init_fields(ttm, bo, page_flags, caching);
+ ttm_tt_init_fields(ttm, bo, page_flags, caching, 0);
if (page_flags & TTM_TT_FLAG_EXTERNAL)
ret = ttm_sg_tt_alloc_page_directory(ttm);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 92bc0faee84f..961812d33827 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -259,16 +259,21 @@ v3d_lock_bo_reservations(struct v3d_job *job,
return ret;
for (i = 0; i < job->bo_count; i++) {
+ ret = dma_resv_reserve_fences(job->bo[i]->resv, 1);
+ if (ret)
+ goto fail;
+
ret = drm_sched_job_add_implicit_dependencies(&job->base,
job->bo[i], true);
- if (ret) {
- drm_gem_unlock_reservations(job->bo, job->bo_count,
- acquire_ctx);
- return ret;
- }
+ if (ret)
+ goto fail;
}
return 0;
+
+fail:
+ drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx);
+ return ret;
}
/**
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 783890e8d43a..59b20c8f132b 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -70,6 +70,7 @@ static const struct debugfs_reg32 crtc_regs[] = {
static unsigned int
vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
{
+ struct vc4_hvs *hvs = vc4->hvs;
u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
/* Top/base are supposed to be 4-pixel aligned, but the
* Raspberry Pi firmware fills the low bits (which are
@@ -89,6 +90,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
unsigned int cob_size;
@@ -123,7 +125,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
*vpos /= 2;
/* Use hpos to correct for field offset in interlaced mode. */
- if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
+ if (vc4_hvs_get_fifo_frame_count(hvs, vc4_crtc_state->assigned_channel) % 2)
*hpos += mode->crtc_htotal / 2;
}
@@ -413,6 +415,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
static void require_hvs_enabled(struct drm_device *dev)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) !=
SCALER_DISPCTRL_ENABLE);
@@ -426,6 +429,7 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
int ret;
CRTC_WRITE(PV_V_CONTROL,
@@ -455,7 +459,7 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
vc4_encoder->post_crtc_disable(encoder, state);
vc4_crtc_pixelvalve_reset(crtc);
- vc4_hvs_stop_channel(dev, channel);
+ vc4_hvs_stop_channel(vc4->hvs, channel);
if (vc4_encoder && vc4_encoder->post_crtc_powerdown)
vc4_encoder->post_crtc_powerdown(encoder, state);
@@ -481,6 +485,7 @@ static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
{
struct drm_device *drm = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
enum vc4_encoder_type encoder_type;
const struct vc4_pv_data *pv_data;
@@ -502,7 +507,7 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
if (!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN))
return 0;
- channel = vc4_hvs_get_fifo_from_output(drm, vc4_crtc->data->hvs_output);
+ channel = vc4_hvs_get_fifo_from_output(vc4->hvs, vc4_crtc->data->hvs_output);
if (channel < 0)
return 0;
@@ -717,6 +722,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
struct drm_crtc *crtc = &vc4_crtc->base;
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
u32 chan = vc4_crtc->current_hvs_channel;
unsigned long flags;
@@ -735,7 +741,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
* the CRTC and encoder already reconfigured, leading to
* underruns. This can be seen when reconfiguring the CRTC.
*/
- vc4_hvs_unmask_underrun(dev, chan);
+ vc4_hvs_unmask_underrun(hvs, chan);
}
spin_unlock(&vc4_crtc->irq_lock);
spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 4329e09d357c..15e0c2ac3940 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -574,8 +574,8 @@ to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
-#define HVS_READ(offset) readl(vc4->hvs->regs + offset)
-#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
+#define HVS_READ(offset) readl(hvs->regs + offset)
+#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
#define VC4_REG32(reg) { .name = #reg, .offset = reg }
@@ -933,16 +933,17 @@ void vc4_irq_reset(struct drm_device *dev);
/* vc4_hvs.c */
extern struct platform_driver vc4_hvs_driver;
-void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
-int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
+void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
+int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
+u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
-void vc4_hvs_dump_state(struct drm_device *dev);
-void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel);
-void vc4_hvs_mask_underrun(struct drm_device *dev, int channel);
+void vc4_hvs_dump_state(struct vc4_hvs *hvs);
+void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel);
+void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel);
/* vc4_kms.c */
int vc4_kms_load(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 445d3bab89e0..594bd6bb00d2 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -485,6 +485,8 @@ again:
* immediately move it to the to-be-rendered queue.
*/
if (exec->ct0ca != exec->ct0ea) {
+ trace_vc4_submit_cl(dev, false, exec->seqno, exec->ct0ca,
+ exec->ct0ea);
submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
} else {
struct vc4_exec_info *next;
@@ -519,6 +521,7 @@ vc4_submit_next_render_job(struct drm_device *dev)
*/
vc4_flush_texture_caches(dev);
+ trace_vc4_submit_cl(dev, true, exec->seqno, exec->ct1ca, exec->ct1ea);
submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
}
@@ -641,7 +644,7 @@ retry:
for (i = 0; i < exec->bo_count; i++) {
bo = &exec->bo[i]->base;
- ret = dma_resv_reserve_shared(bo->resv, 1);
+ ret = dma_resv_reserve_fences(bo->resv, 1);
if (ret) {
vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
return ret;
@@ -1135,6 +1138,10 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
struct dma_fence *in_fence;
int ret = 0;
+ trace_vc4_submit_cl_ioctl(dev, args->bin_cl_size,
+ args->shader_rec_size,
+ args->bo_handle_count);
+
if (!vc4->v3d) {
DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n");
return -ENODEV;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 6c58b0fd13fb..e601b29e632b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -99,9 +99,32 @@
#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
-static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode)
+static const char * const output_format_str[] = {
+ [VC4_HDMI_OUTPUT_RGB] = "RGB",
+ [VC4_HDMI_OUTPUT_YUV420] = "YUV 4:2:0",
+ [VC4_HDMI_OUTPUT_YUV422] = "YUV 4:2:2",
+ [VC4_HDMI_OUTPUT_YUV444] = "YUV 4:4:4",
+};
+
+static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt)
{
- return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK;
+ if (fmt >= ARRAY_SIZE(output_format_str))
+ return "invalid";
+
+ return output_format_str[fmt];
+}
+
+static unsigned long long
+vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
+ unsigned int bpc, enum vc4_hdmi_output_format fmt);
+
+static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
+ unsigned int bpc,
+ enum vc4_hdmi_output_format fmt)
+{
+ unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
+
+ return clock > HDMI_14_MAX_TMDS_CLK;
}
static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
@@ -266,7 +289,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode)) {
+ if (vc4_hdmi_mode_needs_scrambling(mode, 8, VC4_HDMI_OUTPUT_RGB)) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
@@ -323,6 +346,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
new_state->base.max_bpc = 8;
new_state->base.max_requested_bpc = 8;
+ new_state->output_format = VC4_HDMI_OUTPUT_RGB;
drm_atomic_helper_connector_tv_reset(connector);
}
@@ -337,7 +361,9 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
if (!new_state)
return NULL;
- new_state->pixel_rate = vc4_state->pixel_rate;
+ new_state->tmds_char_rate = vc4_state->tmds_char_rate;
+ new_state->output_bpc = vc4_state->output_bpc;
+ new_state->output_format = vc4_state->output_format;
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
return &new_state->base;
@@ -481,11 +507,38 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
}
+static void vc4_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame,
+ enum vc4_hdmi_output_format fmt)
+{
+ switch (fmt) {
+ case VC4_HDMI_OUTPUT_RGB:
+ frame->colorspace = HDMI_COLORSPACE_RGB;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV420:
+ frame->colorspace = HDMI_COLORSPACE_YUV420;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV422:
+ frame->colorspace = HDMI_COLORSPACE_YUV422;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV444:
+ frame->colorspace = HDMI_COLORSPACE_YUV444;
+ break;
+
+ default:
+ break;
+ }
+}
+
static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_connector_state *cstate = connector->state;
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(cstate);
const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
union hdmi_infoframe frame;
int ret;
@@ -505,6 +558,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
HDMI_QUANTIZATION_RANGE_FULL :
HDMI_QUANTIZATION_RANGE_LIMITED);
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
+ vc4_hdmi_avi_infoframe_colorspace(&frame.avi, vc4_state->output_format);
drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
vc4_hdmi_write_infoframe(encoder, &frame);
@@ -607,7 +661,9 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
if (!vc4_hdmi_supports_scrambling(encoder, mode))
return;
- if (!vc4_hdmi_mode_needs_scrambling(mode))
+ if (!vc4_hdmi_mode_needs_scrambling(mode,
+ vc4_hdmi->output_bpc,
+ vc4_hdmi->output_format))
return;
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
@@ -802,6 +858,39 @@ static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
{ 0x0000, 0x0000, 0x1b80, 0x0400 },
};
+/*
+ * Conversion between Full Range RGB and Full Range YUV422 using the
+ * BT.709 Colorspace
+ *
+ *
+ * [ 0.181906 0.611804 0.061758 16 ]
+ * [ -0.100268 -0.337232 0.437500 128 ]
+ * [ 0.437500 -0.397386 -0.040114 128 ]
+ *
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+ */
+static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709[3][4] = {
+ { 0x05d2, 0x1394, 0x01fa, 0x0400 },
+ { 0xfccc, 0xf536, 0x0e00, 0x2000 },
+ { 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
+};
+
+/*
+ * Conversion between Full Range RGB and Full Range YUV444 using the
+ * BT.709 Colorspace
+ *
+ * [ -0.100268 -0.337232 0.437500 128 ]
+ * [ 0.437500 -0.397386 -0.040114 128 ]
+ * [ 0.181906 0.611804 0.061758 16 ]
+ *
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+ */
+static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709[3][4] = {
+ { 0xfccc, 0xf536, 0x0e00, 0x2000 },
+ { 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
+ { 0x05d2, 0x1394, 0x01fa, 0x0400 },
+};
+
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
const u16 coeffs[3][4])
{
@@ -819,19 +908,53 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
struct drm_connector_state *state,
const struct drm_display_mode *mode)
{
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
unsigned long flags;
+ u32 if_cfg = 0;
+ u32 if_xbar = 0x543210;
+ u32 csc_chan_ctl = 0;
u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
VC5_MT_CP_CSC_CTL_MODE);
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
- HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
+ switch (vc4_state->output_format) {
+ case VC4_HDMI_OUTPUT_YUV444:
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709);
+ break;
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
- else
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
+ case VC4_HDMI_OUTPUT_YUV422:
+ csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
+ VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
+ VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
+ VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
+
+ csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
+ VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
+
+ if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
+ VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
+
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709);
+ break;
+
+ case VC4_HDMI_OUTPUT_RGB:
+ if_xbar = 0x354021;
+ if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
+ else
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
+ break;
+
+ default:
+ break;
+ }
+
+ HDMI_WRITE(HDMI_VEC_INTERFACE_CFG, if_cfg);
+ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, if_xbar);
+ HDMI_WRITE(HDMI_CSC_CHANNEL_CTL, csc_chan_ctl);
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
@@ -892,6 +1015,8 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
struct drm_connector_state *state,
struct drm_display_mode *mode)
{
+ const struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -939,7 +1064,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
HDMI_WRITE(HDMI_VERTB0, vertb_even);
HDMI_WRITE(HDMI_VERTB1, vertb);
- switch (state->max_bpc) {
+ switch (vc4_state->output_bpc) {
case 12:
gcp = 6;
gcp_en = true;
@@ -955,6 +1080,15 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
break;
}
+ /*
+ * YCC422 is always 36-bit and not considered deep colour so
+ * doesn't signal in GCP.
+ */
+ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) {
+ gcp = 4;
+ gcp_en = false;
+ }
+
reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
@@ -1022,7 +1156,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
struct vc4_hdmi_connector_state *vc4_conn_state =
conn_state_to_vc4_hdmi_conn_state(conn_state);
struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
- unsigned long pixel_rate = vc4_conn_state->pixel_rate;
+ unsigned long tmds_char_rate = vc4_conn_state->tmds_char_rate;
unsigned long bvb_rate, hsm_rate;
unsigned long flags;
int ret;
@@ -1045,7 +1179,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
* Additionally, the AXI clock needs to be at least 25% of
* pixel clock, but HSM ends up being the limiting factor.
*/
- hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
+ hsm_rate = max_t(unsigned long, 120000000, (tmds_char_rate / 100) * 101);
ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
if (ret) {
DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
@@ -1058,7 +1192,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
goto out;
}
- ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
+ ret = clk_set_rate(vc4_hdmi->pixel_clock, tmds_char_rate);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
goto err_put_runtime_pm;
@@ -1073,9 +1207,9 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
- if (pixel_rate > 297000000)
+ if (tmds_char_rate > 297000000)
bvb_rate = 300000000;
- else if (pixel_rate > 148500000)
+ else if (tmds_char_rate > 148500000)
bvb_rate = 150000000;
else
bvb_rate = 75000000;
@@ -1232,13 +1366,234 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(conn_state);
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
+ vc4_hdmi->output_bpc = vc4_state->output_bpc;
+ vc4_hdmi->output_format = vc4_state->output_format;
mutex_unlock(&vc4_hdmi->mutex);
}
+static bool
+vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode,
+ unsigned int format, unsigned int bpc)
+{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
+ u8 vic = drm_match_cea_mode(mode);
+
+ if (vic == 1 && bpc != 8) {
+ drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
+ return false;
+ }
+
+ if (!info->is_hdmi &&
+ (format != VC4_HDMI_OUTPUT_RGB || bpc != 8)) {
+ drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n");
+ return false;
+ }
+
+ switch (format) {
+ case VC4_HDMI_OUTPUT_RGB:
+ drm_dbg(dev, "RGB Format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
+ return false;
+
+ if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
+ return false;
+ }
+
+ if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) {
+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "RGB format supported in that configuration.\n");
+
+ return true;
+
+ case VC4_HDMI_OUTPUT_YUV422:
+ drm_dbg(dev, "YUV422 format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
+ drm_dbg(dev, "Sink doesn't support YUV422.\n");
+ return false;
+ }
+
+ if (bpc != 12) {
+ drm_dbg(dev, "YUV422 only supports 12 bpc.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "YUV422 format supported in that configuration.\n");
+
+ return true;
+
+ case VC4_HDMI_OUTPUT_YUV444:
+ drm_dbg(dev, "YUV444 format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) {
+ drm_dbg(dev, "Sink doesn't support YUV444.\n");
+ return false;
+ }
+
+ if (bpc == 10 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)) {
+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
+ return false;
+ }
+
+ if (bpc == 12 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36)) {
+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "YUV444 format supported in that configuration.\n");
+
+ return true;
+ }
+
+ return false;
+}
+
+static enum drm_mode_status
+vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi,
+ unsigned long long clock)
+{
+ const struct drm_connector *connector = &vc4_hdmi->connector;
+ const struct drm_display_info *info = &connector->display_info;
+
+ if (clock > vc4_hdmi->variant->max_pixel_clock)
+ return MODE_CLOCK_HIGH;
+
+ if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK)
+ return MODE_CLOCK_HIGH;
+
+ if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000))
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static unsigned long long
+vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
+ unsigned int bpc,
+ enum vc4_hdmi_output_format fmt)
+{
+ unsigned long long clock = mode->clock * 1000;
+
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ clock = clock * 2;
+
+ if (fmt == VC4_HDMI_OUTPUT_YUV422)
+ bpc = 8;
+
+ clock = clock * bpc;
+ do_div(clock, 8);
+
+ return clock;
+}
+
+static int
+vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode,
+ unsigned int bpc, unsigned int fmt)
+{
+ unsigned long long clock;
+
+ clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
+ if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK)
+ return -EINVAL;
+
+ vc4_state->tmds_char_rate = clock;
+
+ return 0;
+}
+
+static int
+vc4_hdmi_encoder_compute_format(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode,
+ unsigned int bpc)
+{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
+ const struct drm_connector *connector = &vc4_hdmi->connector;
+ const struct drm_display_info *info = &connector->display_info;
+ unsigned int format;
+
+ drm_dbg(dev, "Trying with an RGB output\n");
+
+ format = VC4_HDMI_OUTPUT_RGB;
+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) {
+ int ret;
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc, format);
+ if (!ret) {
+ vc4_state->output_format = format;
+ return 0;
+ }
+ }
+
+ drm_dbg(dev, "Failed, Trying with an YUV422 output\n");
+
+ format = VC4_HDMI_OUTPUT_YUV422;
+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) {
+ int ret;
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc, format);
+ if (!ret) {
+ vc4_state->output_format = format;
+ return 0;
+ }
+ }
+
+ drm_dbg(dev, "Failed. No Format Supported for that bpc count.\n");
+
+ return -EINVAL;
+}
+
+static int
+vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode)
+{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
+ struct drm_connector_state *conn_state = &vc4_state->base;
+ unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12);
+ unsigned int bpc;
+ int ret;
+
+ for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
+ drm_dbg(dev, "Trying with a %d bpc output\n", bpc);
+
+ ret = vc4_hdmi_encoder_compute_format(vc4_hdmi, vc4_state,
+ mode, bpc);
+ if (ret)
+ continue;
+
+ vc4_state->output_bpc = bpc;
+
+ drm_dbg(dev,
+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n",
+ mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
+ vc4_state->output_bpc,
+ vc4_hdmi_output_fmt_str(vc4_state->output_format),
+ vc4_state->tmds_char_rate);
+
+ break;
+ }
+
+ return ret;
+}
+
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
@@ -1249,8 +1604,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state);
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- unsigned long long pixel_rate = mode->clock * 1000;
- unsigned long long tmds_rate;
+ unsigned long long tmds_char_rate = mode->clock * 1000;
+ unsigned long long tmds_bit_rate;
+ int ret;
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
!(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
@@ -1264,32 +1620,17 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
* bandwidth). Slightly lower the frequency to bring it out of
* the WiFi range.
*/
- tmds_rate = pixel_rate * 10;
+ tmds_bit_rate = tmds_char_rate * 10;
if (vc4_hdmi->disable_wifi_frequencies &&
- (tmds_rate >= WIFI_2_4GHz_CH1_MIN_FREQ &&
- tmds_rate <= WIFI_2_4GHz_CH1_MAX_FREQ)) {
+ (tmds_bit_rate >= WIFI_2_4GHz_CH1_MIN_FREQ &&
+ tmds_bit_rate <= WIFI_2_4GHz_CH1_MAX_FREQ)) {
mode->clock = 238560;
- pixel_rate = mode->clock * 1000;
+ tmds_char_rate = mode->clock * 1000;
}
- if (conn_state->max_bpc == 12) {
- pixel_rate = pixel_rate * 150;
- do_div(pixel_rate, 100);
- } else if (conn_state->max_bpc == 10) {
- pixel_rate = pixel_rate * 125;
- do_div(pixel_rate, 100);
- }
-
- if (mode->flags & DRM_MODE_FLAG_DBLCLK)
- pixel_rate = pixel_rate * 2;
-
- if (pixel_rate > vc4_hdmi->variant->max_pixel_clock)
- return -EINVAL;
-
- if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK))
- return -EINVAL;
-
- vc4_state->pixel_rate = pixel_rate;
+ ret = vc4_hdmi_encoder_compute_config(vc4_hdmi, vc4_state, mode);
+ if (ret)
+ return ret;
return 0;
}
@@ -1306,13 +1647,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
(mode->hsync_end % 2) || (mode->htotal % 2)))
return MODE_H_ILLEGAL;
- if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
- return MODE_CLOCK_HIGH;
-
- if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode))
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
+ return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000);
}
static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
@@ -2568,19 +2903,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
}
/*
- * If we boot without any cable connected to the HDMI connector,
- * the firmware will skip the HSM initialization and leave it
- * with a rate of 0, resulting in a bus lockup when we're
- * accessing the registers even if it's enabled.
- *
- * Let's put a sensible default at runtime_resume so that we
- * don't end up in this situation.
- */
- ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
- if (ret)
- goto err_put_ddc;
-
- /*
* We need to have the device powered up at this point to call
* our reset hook and for the CEC init.
*/
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 1076faeab616..015a4b7955a0 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -121,6 +121,13 @@ struct vc4_hdmi_audio {
bool streaming;
};
+enum vc4_hdmi_output_format {
+ VC4_HDMI_OUTPUT_RGB,
+ VC4_HDMI_OUTPUT_YUV422,
+ VC4_HDMI_OUTPUT_YUV444,
+ VC4_HDMI_OUTPUT_YUV420,
+};
+
/* General HDMI hardware state. */
struct vc4_hdmi {
struct vc4_hdmi_audio audio;
@@ -220,6 +227,18 @@ struct vc4_hdmi {
* the scrambler on? Protected by @mutex.
*/
bool scdc_enabled;
+
+ /**
+ * @output_bpc: Copy of @vc4_connector_state.output_bpc for use
+ * outside of KMS hooks. Protected by @mutex.
+ */
+ unsigned int output_bpc;
+
+ /**
+ * @output_format: Copy of @vc4_connector_state.output_format
+ * for use outside of KMS hooks. Protected by @mutex.
+ */
+ enum vc4_hdmi_output_format output_format;
};
static inline struct vc4_hdmi *
@@ -238,7 +257,9 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder)
struct vc4_hdmi_connector_state {
struct drm_connector_state base;
- unsigned long long pixel_rate;
+ unsigned long long tmds_char_rate;
+ unsigned int output_bpc;
+ enum vc4_hdmi_output_format output_format;
};
static inline struct vc4_hdmi_connector_state *
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
index 62148f0dc284..ec24999bf96d 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
@@ -365,7 +365,7 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
{
const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings;
const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
- unsigned long long pixel_freq = conn_state->pixel_rate;
+ unsigned long long pixel_freq = conn_state->tmds_char_rate;
unsigned long long vco_freq;
unsigned char word_sel;
unsigned long flags;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
index fc971506bd4f..a040356b6bdc 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
@@ -54,6 +54,7 @@ enum vc4_hdmi_field {
HDMI_CSC_24_23,
HDMI_CSC_32_31,
HDMI_CSC_34_33,
+ HDMI_CSC_CHANNEL_CTL,
HDMI_CSC_CTL,
/*
@@ -119,6 +120,7 @@ enum vc4_hdmi_field {
HDMI_TX_PHY_POWERDOWN_CTL,
HDMI_TX_PHY_RESET_CTL,
HDMI_TX_PHY_TMDS_CLK_WORD_SEL,
+ HDMI_VEC_INTERFACE_CFG,
HDMI_VEC_INTERFACE_XBAR,
HDMI_VERTA0,
HDMI_VERTA1,
@@ -244,6 +246,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = {
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -289,6 +292,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = {
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
};
static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
@@ -324,6 +328,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -369,6 +374,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
};
static inline
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index 604933e20e6a..9194cb52e706 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -64,22 +64,21 @@ static const struct debugfs_reg32 hvs_regs[] = {
VC4_REG32(SCALER_OLEDCOEF2),
};
-void vc4_hvs_dump_state(struct drm_device *dev)
+void vc4_hvs_dump_state(struct vc4_hvs *hvs)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct drm_printer p = drm_info_printer(&vc4->hvs->pdev->dev);
+ struct drm_printer p = drm_info_printer(&hvs->pdev->dev);
int i;
- drm_print_regset32(&p, &vc4->hvs->regset);
+ drm_print_regset32(&p, &hvs->regset);
DRM_INFO("HVS ctx:\n");
for (i = 0; i < 64; i += 4) {
DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n",
i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D",
- readl((u32 __iomem *)vc4->hvs->dlist + i + 0),
- readl((u32 __iomem *)vc4->hvs->dlist + i + 1),
- readl((u32 __iomem *)vc4->hvs->dlist + i + 2),
- readl((u32 __iomem *)vc4->hvs->dlist + i + 3));
+ readl((u32 __iomem *)hvs->dlist + i + 0),
+ readl((u32 __iomem *)hvs->dlist + i + 1),
+ readl((u32 __iomem *)hvs->dlist + i + 2),
+ readl((u32 __iomem *)hvs->dlist + i + 3));
}
}
@@ -157,11 +156,10 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
return 0;
}
-static void vc4_hvs_lut_load(struct drm_crtc *crtc)
+static void vc4_hvs_lut_load(struct vc4_hvs *hvs,
+ struct vc4_crtc *vc4_crtc)
{
- struct drm_device *dev = crtc->dev;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_crtc *crtc = &vc4_crtc->base;
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
u32 i;
@@ -181,11 +179,12 @@ static void vc4_hvs_lut_load(struct drm_crtc *crtc)
HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]);
}
-static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
+static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs,
+ struct vc4_crtc *vc4_crtc)
{
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- struct drm_color_lut *lut = crtc->state->gamma_lut->data;
- u32 length = drm_color_lut_size(crtc->state->gamma_lut);
+ struct drm_crtc_state *crtc_state = vc4_crtc->base.state;
+ struct drm_color_lut *lut = crtc_state->gamma_lut->data;
+ u32 length = drm_color_lut_size(crtc_state->gamma_lut);
u32 i;
for (i = 0; i < length; i++) {
@@ -194,16 +193,37 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
vc4_crtc->lut_b[i] = drm_color_lut_extract(lut[i].blue, 8);
}
- vc4_hvs_lut_load(crtc);
+ vc4_hvs_lut_load(hvs, vc4_crtc);
}
-int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
+u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo)
+{
+ u8 field = 0;
+
+ switch (fifo) {
+ case 0:
+ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
+ SCALER_DISPSTAT1_FRCNT0);
+ break;
+ case 1:
+ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
+ SCALER_DISPSTAT1_FRCNT1);
+ break;
+ case 2:
+ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
+ SCALER_DISPSTAT2_FRCNT2);
+ break;
+ }
+
+ return field;
+}
+
+int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
u32 reg;
int ret;
- if (!vc4->hvs->hvs5)
+ if (!hvs->hvs5)
return output;
switch (output) {
@@ -250,9 +270,10 @@ int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
}
}
-static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
+static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc,
struct drm_display_mode *mode, bool oneshot)
{
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
unsigned int chan = vc4_crtc_state->assigned_channel;
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -270,7 +291,7 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
*/
dispctrl = SCALER_DISPCTRLX_ENABLE;
- if (!vc4->hvs->hvs5)
+ if (!hvs->hvs5)
dispctrl |= VC4_SET_FIELD(mode->hdisplay,
SCALER_DISPCTRLX_WIDTH) |
VC4_SET_FIELD(mode->vdisplay,
@@ -291,21 +312,19 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
SCALER_DISPBKGND_AUTOHS |
- ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
+ ((!hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
/* Reload the LUT, since the SRAMs would have been disabled if
* all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
*/
- vc4_hvs_lut_load(crtc);
+ vc4_hvs_lut_load(hvs, vc4_crtc);
return 0;
}
-void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan)
+void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)
return;
@@ -359,10 +378,20 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
return 0;
}
-static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
+static void vc4_hvs_install_dlist(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+
+ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
+ vc4_state->mm.start);
+}
+
+static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
unsigned long flags;
@@ -379,13 +408,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
crtc->state->event = NULL;
}
- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
- vc4_state->mm.start);
-
spin_unlock_irqrestore(&dev->event_lock, flags);
- } else {
- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
- vc4_state->mm.start);
}
spin_lock_irqsave(&vc4_crtc->irq_lock, flags);
@@ -414,19 +437,21 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
bool oneshot = vc4_crtc->feeds_txp;
+ vc4_hvs_install_dlist(crtc);
vc4_hvs_update_dlist(crtc);
- vc4_hvs_init_channel(vc4, crtc, mode, oneshot);
+ vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
}
void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state);
unsigned int chan = vc4_state->assigned_channel;
- vc4_hvs_stop_channel(dev, chan);
+ vc4_hvs_stop_channel(vc4->hvs, chan);
}
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
@@ -436,7 +461,10 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
crtc);
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+ unsigned int channel = vc4_state->assigned_channel;
struct drm_plane *plane;
struct vc4_plane_state *vc4_plane_state;
bool debug_dump_regs = false;
@@ -446,7 +474,7 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
if (debug_dump_regs) {
DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
- vc4_hvs_dump_state(dev);
+ vc4_hvs_dump_state(hvs);
}
/* Copy all the active planes' dlist contents to the hardware dlist. */
@@ -477,8 +505,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
/* This sets a black background color fill, as is the case
* with other DRM drivers.
*/
- HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
- HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) |
+ HVS_WRITE(SCALER_DISPBKGNDX(channel),
+ HVS_READ(SCALER_DISPBKGNDX(channel)) |
SCALER_DISPBKGND_FILL);
/* Only update DISPLIST if the CRTC was already running and is not
@@ -488,14 +516,16 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
* If the CRTC is being disabled, there's no point in updating this
* information.
*/
- if (crtc->state->active && old_state->active)
+ if (crtc->state->active && old_state->active) {
+ vc4_hvs_install_dlist(crtc);
vc4_hvs_update_dlist(crtc);
+ }
if (crtc->state->color_mgmt_changed) {
- u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
+ u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel));
if (crtc->state->gamma_lut) {
- vc4_hvs_update_gamma_lut(crtc);
+ vc4_hvs_update_gamma_lut(hvs, vc4_crtc);
dispbkgndx |= SCALER_DISPBKGND_GAMMA;
} else {
/* Unsetting DISPBKGND_GAMMA skips the gamma lut step
@@ -504,18 +534,17 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
*/
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
}
- HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
+ HVS_WRITE(SCALER_DISPBKGNDX(channel), dispbkgndx);
}
if (debug_dump_regs) {
DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
- vc4_hvs_dump_state(dev);
+ vc4_hvs_dump_state(hvs);
}
}
-void vc4_hvs_mask_underrun(struct drm_device *dev, int channel)
+void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
u32 dispctrl = HVS_READ(SCALER_DISPCTRL);
dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel);
@@ -523,9 +552,8 @@ void vc4_hvs_mask_underrun(struct drm_device *dev, int channel)
HVS_WRITE(SCALER_DISPCTRL, dispctrl);
}
-void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel)
+void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel)
{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
u32 dispctrl = HVS_READ(SCALER_DISPCTRL);
dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel);
@@ -547,6 +575,7 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
{
struct drm_device *dev = data;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
irqreturn_t irqret = IRQ_NONE;
int channel;
u32 control;
@@ -559,7 +588,7 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
/* Interrupt masking is not always honored, so check it here. */
if (status & SCALER_DISPSTAT_EUFLOW(channel) &&
control & SCALER_DISPCTRL_DSPEISLUR(channel)) {
- vc4_hvs_mask_underrun(dev, channel);
+ vc4_hvs_mask_underrun(hvs, channel);
vc4_hvs_report_underrun(dev);
irqret = IRQ_HANDLED;
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 20fa8e34c20b..4342fb43e8c1 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -51,6 +51,7 @@
#include "vc4_drv.h"
#include "vc4_regs.h"
+#include "vc4_trace.h"
#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
V3D_INT_FLDONE | \
@@ -123,6 +124,8 @@ vc4_irq_finish_bin_job(struct drm_device *dev)
if (!exec)
return;
+ trace_vc4_bcl_end_irq(dev, exec->seqno);
+
vc4_move_job_to_render(dev, exec);
next = vc4_first_bin_job(vc4);
@@ -161,6 +164,8 @@ vc4_irq_finish_render_job(struct drm_device *dev)
if (!exec)
return;
+ trace_vc4_rcl_end_irq(dev, exec->seqno);
+
vc4->finished_seqno++;
list_move_tail(&exec->head, &vc4->job_done_list);
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 24de29bc1cda..747a2d199eca 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -32,7 +32,8 @@ struct vc4_ctm_state {
int fifo;
};
-static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
+static struct vc4_ctm_state *
+to_vc4_ctm_state(const struct drm_private_state *priv)
{
return container_of(priv, struct vc4_ctm_state, base);
}
@@ -49,7 +50,7 @@ struct vc4_hvs_state {
};
static struct vc4_hvs_state *
-to_vc4_hvs_state(struct drm_private_state *priv)
+to_vc4_hvs_state(const struct drm_private_state *priv)
{
return container_of(priv, struct vc4_hvs_state, base);
}
@@ -61,7 +62,7 @@ struct vc4_load_tracker_state {
};
static struct vc4_load_tracker_state *
-to_vc4_load_tracker_state(struct drm_private_state *priv)
+to_vc4_load_tracker_state(const struct drm_private_state *priv)
{
return container_of(priv, struct vc4_load_tracker_state, base);
}
@@ -157,6 +158,7 @@ static u16 vc4_ctm_s31_32_to_s0_9(u64 in)
static void
vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
{
+ struct vc4_hvs *hvs = vc4->hvs;
struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
struct drm_color_ctm *ctm = ctm_state->ctm;
@@ -230,6 +232,7 @@ vc4_hvs_get_global_state(struct drm_atomic_state *state)
static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
struct drm_atomic_state *state)
{
+ struct vc4_hvs *hvs = vc4->hvs;
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
unsigned int i;
@@ -270,6 +273,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,
struct drm_atomic_state *state)
{
+ struct vc4_hvs *hvs = vc4->hvs;
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
unsigned char mux;
@@ -362,7 +366,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
continue;
vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
- vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
+ vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel);
}
for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
@@ -385,12 +389,20 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
}
if (vc4->hvs->hvs5) {
+ unsigned long state_rate = max(old_hvs_state->core_clock_rate,
+ new_hvs_state->core_clock_rate);
unsigned long core_rate = max_t(unsigned long,
- 500000000,
- new_hvs_state->core_clock_rate);
+ 500000000, state_rate);
+ drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate);
+
+ /*
+ * Do a temporary request on the core clock during the
+ * modeset.
+ */
clk_set_min_rate(hvs->core_clk, core_rate);
}
+
drm_atomic_helper_commit_modeset_disables(dev, state);
vc4_ctm_commit(vc4, state);
@@ -400,7 +412,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
else
vc4_hvs_pv_muxing_commit(vc4, state);
- drm_atomic_helper_commit_planes(dev, state, 0);
+ drm_atomic_helper_commit_planes(dev, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
drm_atomic_helper_commit_modeset_enables(dev, state);
@@ -416,6 +429,10 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
drm_dbg(dev, "Running the core clock at %lu Hz\n",
new_hvs_state->core_clock_rate);
+ /*
+ * Request a clock rate based on the current HVS
+ * requirements.
+ */
clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate);
}
}
@@ -700,9 +717,26 @@ static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj,
kfree(hvs_state);
}
+static void vc4_hvs_channels_print_state(struct drm_printer *p,
+ const struct drm_private_state *state)
+{
+ struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state);
+ unsigned int i;
+
+ drm_printf(p, "HVS State\n");
+ drm_printf(p, "\tCore Clock Rate: %lu\n", hvs_state->core_clock_rate);
+
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+ drm_printf(p, "\tChannel %d\n", i);
+ drm_printf(p, "\t\tin use=%d\n", hvs_state->fifo_state[i].in_use);
+ drm_printf(p, "\t\tload=%lu\n", hvs_state->fifo_state[i].fifo_load);
+ }
+}
+
static const struct drm_private_state_funcs vc4_hvs_state_funcs = {
.atomic_duplicate_state = vc4_hvs_channels_duplicate_state,
.atomic_destroy_state = vc4_hvs_channels_destroy_state,
+ .atomic_print_state = vc4_hvs_channels_print_state,
};
static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused)
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 33410718089e..a2b5cbbbc1b0 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -379,8 +379,6 @@
# define SCALER_DISPSTATX_MODE_EOF 3
# define SCALER_DISPSTATX_FULL BIT(29)
# define SCALER_DISPSTATX_EMPTY BIT(28)
-# define SCALER_DISPSTATX_FRAME_COUNT_MASK VC4_MASK(17, 12)
-# define SCALER_DISPSTATX_FRAME_COUNT_SHIFT 12
# define SCALER_DISPSTATX_LINE_MASK VC4_MASK(11, 0)
# define SCALER_DISPSTATX_LINE_SHIFT 0
@@ -403,9 +401,15 @@
(x) * (SCALER_DISPBKGND1 - \
SCALER_DISPBKGND0))
#define SCALER_DISPSTAT1 0x00000058
+# define SCALER_DISPSTAT1_FRCNT0_MASK VC4_MASK(23, 18)
+# define SCALER_DISPSTAT1_FRCNT0_SHIFT 18
+# define SCALER_DISPSTAT1_FRCNT1_MASK VC4_MASK(17, 12)
+# define SCALER_DISPSTAT1_FRCNT1_SHIFT 12
+
#define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \
(x) * (SCALER_DISPSTAT1 - \
SCALER_DISPSTAT0))
+
#define SCALER_DISPBASE1 0x0000005c
#define SCALER_DISPBASEX(x) (SCALER_DISPBASE0 + \
(x) * (SCALER_DISPBASE1 - \
@@ -415,7 +419,11 @@
(x) * (SCALER_DISPCTRL1 - \
SCALER_DISPCTRL0))
#define SCALER_DISPBKGND2 0x00000064
+
#define SCALER_DISPSTAT2 0x00000068
+# define SCALER_DISPSTAT2_FRCNT2_MASK VC4_MASK(17, 12)
+# define SCALER_DISPSTAT2_FRCNT2_SHIFT 12
+
#define SCALER_DISPBASE2 0x0000006c
#define SCALER_DISPALPHA2 0x00000070
#define SCALER_GAMADDR 0x00000078
@@ -774,11 +782,27 @@ enum {
# define VC4_HD_CSC_CTL_RGB2YCC BIT(1)
# define VC4_HD_CSC_CTL_ENABLE BIT(0)
+# define VC5_MT_CP_CSC_CTL_USE_444_TO_422 BIT(6)
+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_MASK \
+ VC4_MASK(5, 4)
+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD \
+ 3
+# define VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION BIT(3)
# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2)
# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0)
+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_MASK \
+ VC4_MASK(7, 6)
+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE \
+ 2
+
# define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1)
+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_MASK \
+ VC4_MASK(3, 2)
+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY \
+ 2
+
/* HVS display list information. */
#define HVS_BOOTLOADER_DLIST_END 32
diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h
index 1cccde0b09a7..7f4c49e7e011 100644
--- a/drivers/gpu/drm/vc4/vc4_trace.h
+++ b/drivers/gpu/drm/vc4/vc4_trace.h
@@ -52,6 +52,101 @@ TRACE_EVENT(vc4_wait_for_seqno_end,
__entry->dev, __entry->seqno)
);
+TRACE_EVENT(vc4_submit_cl_ioctl,
+ TP_PROTO(struct drm_device *dev, u32 bin_cl_size, u32 shader_rec_size, u32 bo_count),
+ TP_ARGS(dev, bin_cl_size, shader_rec_size, bo_count),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(u32, bin_cl_size)
+ __field(u32, shader_rec_size)
+ __field(u32, bo_count)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->bin_cl_size = bin_cl_size;
+ __entry->shader_rec_size = shader_rec_size;
+ __entry->bo_count = bo_count;
+ ),
+
+ TP_printk("dev=%u, bin_cl_size=%u, shader_rec_size=%u, bo_count=%u",
+ __entry->dev,
+ __entry->bin_cl_size,
+ __entry->shader_rec_size,
+ __entry->bo_count)
+);
+
+TRACE_EVENT(vc4_submit_cl,
+ TP_PROTO(struct drm_device *dev, bool is_render,
+ uint64_t seqno,
+ u32 ctnqba, u32 ctnqea),
+ TP_ARGS(dev, is_render, seqno, ctnqba, ctnqea),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(bool, is_render)
+ __field(u64, seqno)
+ __field(u32, ctnqba)
+ __field(u32, ctnqea)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->is_render = is_render;
+ __entry->seqno = seqno;
+ __entry->ctnqba = ctnqba;
+ __entry->ctnqea = ctnqea;
+ ),
+
+ TP_printk("dev=%u, %s, seqno=%llu, 0x%08x..0x%08x",
+ __entry->dev,
+ __entry->is_render ? "RCL" : "BCL",
+ __entry->seqno,
+ __entry->ctnqba,
+ __entry->ctnqea)
+);
+
+TRACE_EVENT(vc4_bcl_end_irq,
+ TP_PROTO(struct drm_device *dev,
+ uint64_t seqno),
+ TP_ARGS(dev, seqno),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(u64, seqno)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->seqno = seqno;
+ ),
+
+ TP_printk("dev=%u, seqno=%llu",
+ __entry->dev,
+ __entry->seqno)
+);
+
+TRACE_EVENT(vc4_rcl_end_irq,
+ TP_PROTO(struct drm_device *dev,
+ uint64_t seqno),
+ TP_ARGS(dev, seqno),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(u64, seqno)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->seqno = seqno;
+ ),
+
+ TP_printk("dev=%u, seqno=%llu",
+ __entry->dev,
+ __entry->seqno)
+);
+
#endif /* _VC4_TRACE_H_ */
/* This part must be outside protection */
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index bd6f75285fd9..2ddbebca87d9 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -157,12 +157,14 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
}
/* Expose the fence via the dma-buf */
- ret = 0;
dma_resv_lock(resv, NULL);
- if (arg->flags & VGEM_FENCE_WRITE)
- dma_resv_add_excl_fence(resv, fence);
- else if ((ret = dma_resv_reserve_shared(resv, 1)) == 0)
- dma_resv_add_shared_fence(resv, fence);
+ ret = dma_resv_reserve_fences(resv, 1);
+ if (!ret) {
+ if (arg->flags & VGEM_FENCE_WRITE)
+ dma_resv_add_excl_fence(resv, fence);
+ else
+ dma_resv_add_shared_fence(resv, fence);
+ }
dma_resv_unlock(resv);
/* Record the fence in our idr for later signaling */
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 5b00310ac4cd..f73352e7b832 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -179,6 +179,8 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
DRM_DEBUG("add mode: %dx%d\n", width, height);
mode = drm_cvt_mode(connector->dev, width, height, 60,
false, false, false);
+ if (!mode)
+ return count;
mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
count++;
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 48d3c9955f0d..1820ca6cf673 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -214,6 +214,7 @@ void virtio_gpu_array_add_obj(struct virtio_gpu_object_array *objs,
int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs)
{
+ unsigned int i;
int ret;
if (objs->nents == 1) {
@@ -222,6 +223,14 @@ int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs)
ret = drm_gem_lock_reservations(objs->objs, objs->nents,
&objs->ticket);
}
+ if (ret)
+ return ret;
+
+ for (i = 0; i < objs->nents; ++i) {
+ ret = dma_resv_reserve_fences(objs->objs[i]->resv, 1);
+ if (ret)
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index c708bab555c6..77743fd2c61a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -609,8 +609,7 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
if (!vgdev->has_resource_blob)
return -EINVAL;
- if ((rc_blob->blob_flags & ~VIRTGPU_BLOB_FLAG_USE_MASK) ||
- !rc_blob->blob_flags)
+ if (rc_blob->blob_flags & ~VIRTGPU_BLOB_FLAG_USE_MASK)
return -EINVAL;
if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 31aecc46624b..fe13aa8b4a64 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -747,16 +747,22 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
struct vmw_fence_obj *fence)
{
struct ttm_device *bdev = bo->bdev;
-
struct vmw_private *dev_priv =
container_of(bdev, struct vmw_private, bdev);
+ int ret;
- if (fence == NULL) {
+ if (fence == NULL)
vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
+ else
+ dma_fence_get(&fence->base);
+
+ ret = dma_resv_reserve_fences(bo->base.resv, 1);
+ if (!ret)
dma_resv_add_excl_fence(bo->base.resv, &fence->base);
- dma_fence_put(&fence->base);
- } else
- dma_resv_add_excl_fence(bo->base.resv, &fence->base);
+ else
+ /* Last resort fallback when we are OOM */
+ dma_fence_wait(&fence->base, false);
+ dma_fence_put(&fence->base);
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
index a3bfbb6c3e14..162dfeb1cc5a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
@@ -528,7 +528,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
*seqno = atomic_add_return(1, &dev_priv->marker_seq);
} while (*seqno == 0);
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) {
+ if (!vmw_has_fences(dev_priv)) {
/*
* Don't request hardware to send a fence. The
@@ -675,11 +675,14 @@ int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv,
*/
bool vmw_cmd_supported(struct vmw_private *vmw)
{
- if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
- SVGA_CAP_CMD_BUFFERS_2)) != 0)
- return true;
+ bool has_cmdbufs =
+ (vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
+ SVGA_CAP_CMD_BUFFERS_2)) != 0;
+ if (vmw_is_svga_v3(vmw))
+ return (has_cmdbufs &&
+ (vmw->capabilities & SVGA_CAP_GBOBJECTS) != 0);
/*
* We have FIFO cmd's
*/
- return vmw->fifo_mem != NULL;
+ return has_cmdbufs || vmw->fifo_mem != NULL;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 26eb5478394a..791f9a5f3868 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2016 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -848,12 +848,16 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
-
+ vmw_print_bitmap(&dev_priv->drm, "Capabilities",
+ dev_priv->capabilities,
+ cap1_names, ARRAY_SIZE(cap1_names));
if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) {
dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2);
+ vmw_print_bitmap(&dev_priv->drm, "Capabilities2",
+ dev_priv->capabilities2,
+ cap2_names, ARRAY_SIZE(cap2_names));
}
-
ret = vmw_dma_select_mode(dev_priv);
if (unlikely(ret != 0)) {
drm_info(&dev_priv->drm,
@@ -939,14 +943,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
"MOB limits: max mob size = %u kB, max mob pages = %u\n",
dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages);
- vmw_print_bitmap(&dev_priv->drm, "Capabilities",
- dev_priv->capabilities,
- cap1_names, ARRAY_SIZE(cap1_names));
- if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER)
- vmw_print_bitmap(&dev_priv->drm, "Capabilities2",
- dev_priv->capabilities2,
- cap2_names, ARRAY_SIZE(cap2_names));
-
ret = vmw_dma_masks(dev_priv);
if (unlikely(ret != 0))
goto out_err0;
@@ -984,7 +980,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
}
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
- ret = vmw_irq_install(&dev_priv->drm, pdev->irq);
+ ret = vmw_irq_install(dev_priv);
if (ret != 0) {
drm_err(&dev_priv->drm,
"Failed installing irq: %d\n", ret);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index ea3ecdda561d..be19aa6e1f13 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright 2009-2021 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -66,6 +66,11 @@
#define VMWGFX_PCI_ID_SVGA3 0x0406
/*
+ * This has to match get_count_order(SVGA_IRQFLAG_MAX)
+ */
+#define VMWGFX_MAX_NUM_IRQS 6
+
+/*
* Perhaps we should have sysfs entries for these.
*/
#define VMWGFX_NUM_GB_CONTEXT 256
@@ -101,6 +106,7 @@ struct vmw_fpriv {
* struct vmw_buffer_object - TTM buffer object with vmwgfx additions
* @base: The TTM buffer object
* @res_tree: RB tree of resources using this buffer object as a backing MOB
+ * @base_mapped_count: ttm BO mapping count; used by KMS atomic helpers.
* @cpu_writers: Number of synccpu write grabs. Protected by reservation when
* increased. May be decreased without reservation.
* @dx_query_ctx: DX context if this buffer object is used as a DX query MOB
@@ -111,6 +117,9 @@ struct vmw_fpriv {
struct vmw_buffer_object {
struct ttm_buffer_object base;
struct rb_root res_tree;
+ /* For KMS atomic helpers: ttm bo mapping count */
+ atomic_t base_mapped_count;
+
atomic_t cpu_writers;
/* Not ref-counted. Protected by binding_mutex */
struct vmw_resource *dx_query_ctx;
@@ -528,6 +537,8 @@ struct vmw_private {
bool has_mob;
spinlock_t hw_lock;
bool assume_16bpp;
+ u32 irqs[VMWGFX_MAX_NUM_IRQS];
+ u32 num_irq_vectors;
enum vmw_sm_type sm_type;
@@ -1154,7 +1165,7 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
* IRQs and wating - vmwgfx_irq.c
*/
-extern int vmw_irq_install(struct drm_device *dev, int irq);
+extern int vmw_irq_install(struct vmw_private *dev_priv);
extern void vmw_irq_uninstall(struct drm_device *dev);
extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
uint32_t seqno);
@@ -1679,4 +1690,12 @@ static inline void vmw_irq_status_write(struct vmw_private *vmw,
outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT);
}
+static inline bool vmw_has_fences(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
+ SVGA_CAP_CMD_BUFFERS_2)) != 0)
+ return true;
+ return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0;
+}
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 8ee34576c7d0..adf17c740656 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -483,7 +483,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
static int vmw_fb_kms_framebuffer(struct fb_info *info)
{
- struct drm_mode_fb_cmd2 mode_cmd;
+ struct drm_mode_fb_cmd2 mode_cmd = {0};
struct vmw_fb_par *par = info->par;
struct fb_var_screeninfo *var = &info->var;
struct drm_framebuffer *cur_fb;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 59d6a2dd4c2e..66cc35dc223e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -82,6 +82,22 @@ fman_from_fence(struct vmw_fence_obj *fence)
return container_of(fence->base.lock, struct vmw_fence_manager, lock);
}
+static u32 vmw_fence_goal_read(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ return vmw_read(vmw, SVGA_REG_FENCE_GOAL);
+ else
+ return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL);
+}
+
+static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ vmw_write(vmw, SVGA_REG_FENCE_GOAL, value);
+ else
+ vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value);
+}
+
/*
* Note on fencing subsystem usage of irqs:
* Typically the vmw_fences_update function is called
@@ -392,7 +408,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
if (likely(!fman->seqno_valid))
return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
+ goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
return false;
@@ -400,9 +416,8 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
list_for_each_entry(fence, &fman->fence_list, head) {
if (!list_empty(&fence->seq_passed_actions)) {
fman->seqno_valid = true;
- vmw_fifo_mem_write(fman->dev_priv,
- SVGA_FIFO_FENCE_GOAL,
- fence->base.seqno);
+ vmw_fence_goal_write(fman->dev_priv,
+ fence->base.seqno);
break;
}
}
@@ -434,13 +449,12 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
if (dma_fence_is_signaled_locked(&fence->base))
return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
+ goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(fman->seqno_valid &&
goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
return false;
- vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL,
- fence->base.seqno);
+ vmw_fence_goal_write(fman->dev_priv, fence->base.seqno);
fman->seqno_valid = true;
return true;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 471da2b4c177..a1da5678c731 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -27,9 +27,11 @@
#include "vmwgfx_drv.h"
#include "vmwgfx_devcaps.h"
-#include <drm/vmwgfx_drm.h>
#include "vmwgfx_kms.h"
+#include <drm/vmwgfx_drm.h>
+#include <linux/pci.h>
+
int vmw_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -62,17 +64,15 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
break;
case DRM_VMW_PARAM_FIFO_HW_VERSION:
{
- if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) {
+ if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
param->value = SVGA3D_HWVERSION_WS8_B1;
- break;
- }
-
- param->value =
- vmw_fifo_mem_read(dev_priv,
- ((vmw_fifo_caps(dev_priv) &
- SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
- SVGA_FIFO_3D_HWVERSION_REVISED :
- SVGA_FIFO_3D_HWVERSION));
+ else
+ param->value = vmw_fifo_mem_read(
+ dev_priv,
+ ((vmw_fifo_caps(dev_priv) &
+ SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
+ SVGA_FIFO_3D_HWVERSION_REVISED :
+ SVGA_FIFO_3D_HWVERSION));
break;
}
case DRM_VMW_PARAM_MAX_SURF_MEMORY:
@@ -108,6 +108,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
case DRM_VMW_PARAM_GL43:
param->value = has_gl43_context(dev_priv);
break;
+ case DRM_VMW_PARAM_DEVICE_ID:
+ param->value = to_pci_dev(dev_priv->drm.dev)->device;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index c5191de365ca..086e69a130d4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -32,6 +32,14 @@
#define VMW_FENCE_WRAP (1 << 24)
+static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ return SVGA_IRQFLAG_REG_FENCE_GOAL;
+ else
+ return SVGA_IRQFLAG_FENCE_GOAL;
+}
+
/**
* vmw_thread_fn - Deferred (process context) irq handler
*
@@ -96,7 +104,7 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg)
wake_up_all(&dev_priv->fifo_queue);
if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE |
- SVGA_IRQFLAG_FENCE_GOAL)) &&
+ vmw_irqflag_fence_goal(dev_priv))) &&
!test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending))
ret = IRQ_WAKE_THREAD;
@@ -137,8 +145,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv,
if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
return true;
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) &&
- vmw_fifo_idle(dev_priv, seqno))
+ if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno))
return true;
/**
@@ -160,6 +167,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
unsigned long timeout)
{
struct vmw_fifo_state *fifo_state = dev_priv->fifo;
+ bool fifo_down = false;
uint32_t count = 0;
uint32_t signal_seq;
@@ -176,12 +184,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
*/
if (fifo_idle) {
- down_read(&fifo_state->rwsem);
if (dev_priv->cman) {
ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible,
10*HZ);
if (ret)
goto out_err;
+ } else if (fifo_state) {
+ down_read(&fifo_state->rwsem);
+ fifo_down = true;
}
}
@@ -218,12 +228,12 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
}
}
finish_wait(&dev_priv->fence_queue, &__wait);
- if (ret == 0 && fifo_idle)
+ if (ret == 0 && fifo_idle && fifo_state)
vmw_fence_write(dev_priv, signal_seq);
wake_up_all(&dev_priv->fence_queue);
out_err:
- if (fifo_idle)
+ if (fifo_down)
up_read(&fifo_state->rwsem);
return ret;
@@ -266,13 +276,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
void vmw_goal_waiter_add(struct vmw_private *dev_priv)
{
- vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+ vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}
void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
{
- vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+ vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}
@@ -290,6 +300,7 @@ void vmw_irq_uninstall(struct drm_device *dev)
struct vmw_private *dev_priv = vmw_priv(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
uint32_t status;
+ u32 i;
if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
return;
@@ -299,20 +310,62 @@ void vmw_irq_uninstall(struct drm_device *dev)
status = vmw_irq_status_read(dev_priv);
vmw_irq_status_write(dev_priv, status);
- free_irq(pdev->irq, dev);
+ for (i = 0; i < dev_priv->num_irq_vectors; ++i)
+ free_irq(dev_priv->irqs[i], dev);
+
+ pci_free_irq_vectors(pdev);
+ dev_priv->num_irq_vectors = 0;
}
/**
* vmw_irq_install - Install the irq handlers
*
- * @dev: Pointer to the drm device.
- * @irq: The irq number.
+ * @dev_priv: Pointer to the vmw_private device.
* Return: Zero if successful. Negative number otherwise.
*/
-int vmw_irq_install(struct drm_device *dev, int irq)
+int vmw_irq_install(struct vmw_private *dev_priv)
{
+ struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+ struct drm_device *dev = &dev_priv->drm;
+ int ret;
+ int nvec;
+ int i = 0;
+
+ BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1);
+ BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX));
+
+ nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS,
+ PCI_IRQ_ALL_TYPES);
+
+ if (nvec <= 0) {
+ drm_err(&dev_priv->drm,
+ "IRQ's are unavailable, nvec: %d\n", nvec);
+ ret = nvec;
+ goto done;
+ }
+
vmw_irq_preinstall(dev);
- return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn,
- IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+ for (i = 0; i < nvec; ++i) {
+ ret = pci_irq_vector(pdev, i);
+ if (ret < 0) {
+ drm_err(&dev_priv->drm,
+ "failed getting irq vector: %d\n", ret);
+ goto done;
+ }
+ dev_priv->irqs[i] = ret;
+
+ ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn,
+ IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+ if (ret != 0) {
+ drm_err(&dev_priv->drm,
+ "Failed installing irq(%d): %d\n",
+ dev_priv->irqs[i], ret);
+ goto done;
+ }
+ }
+
+done:
+ dev_priv->num_irq_vectors = i;
+ return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index bbd2f4ec08ec..693028c31b6b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -41,7 +41,7 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
struct vmw_private *dev_priv = vmw_priv(du->primary.dev);
drm_plane_cleanup(&du->primary);
if (vmw_cmd_supported(dev_priv))
- drm_plane_cleanup(&du->cursor);
+ drm_plane_cleanup(&du->cursor.base);
drm_connector_unregister(&du->connector);
drm_crtc_cleanup(&du->crtc);
@@ -53,23 +53,43 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
* Display Unit Cursor functions
*/
-static int vmw_cursor_update_image(struct vmw_private *dev_priv,
- u32 *image, u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
+static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *bo,
+ struct ttm_bo_kmap_obj *map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY);
+
+struct vmw_svga_fifo_cmd_define_cursor {
+ u32 cmd;
+ SVGAFifoCmdDefineAlphaCursor cursor;
+};
+
+static void vmw_cursor_update_image(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *cm_bo,
+ struct ttm_bo_kmap_obj *cm_map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
{
- struct {
- u32 cmd;
- SVGAFifoCmdDefineAlphaCursor cursor;
- } *cmd;
- u32 image_size = width * height * 4;
- u32 cmd_size = sizeof(*cmd) + image_size;
+ struct vmw_svga_fifo_cmd_define_cursor *cmd;
+ const u32 image_size = width * height * sizeof(*image);
+ const u32 cmd_size = sizeof(*cmd) + image_size;
- if (!image)
- return -EINVAL;
+ if (cm_bo != NULL) {
+ vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image,
+ width, height,
+ hotspotX, hotspotY);
+ return;
+ }
+ /* Try to reserve fifocmd space and swallow any failures;
+ such reservations cannot be left unconsumed for long
+ under the risk of clogging other fifocmd users, so
+ we treat reservations separtely from the way we treat
+ other fallible KMS-atomic resources at prepare_fb */
cmd = VMW_CMD_RESERVE(dev_priv, cmd_size);
+
if (unlikely(cmd == NULL))
- return -ENOMEM;
+ return;
memset(cmd, 0, sizeof(*cmd));
@@ -83,55 +103,158 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv,
cmd->cursor.hotspotY = hotspotY;
vmw_cmd_commit_flush(dev_priv, cmd_size);
-
- return 0;
}
-static int vmw_cursor_update_bo(struct vmw_private *dev_priv,
- struct vmw_buffer_object *bo,
- u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
-{
- struct ttm_bo_kmap_obj map;
- unsigned long kmap_offset;
- unsigned long kmap_num;
- void *virtual;
+/**
+ * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism
+ *
+ * @dev_priv: device to work with
+ * @bo: BO for the MOB
+ * @map: kmap obj for the BO
+ * @image: cursor source data to fill the MOB with
+ * @width: source data width
+ * @height: source data height
+ * @hotspotX: cursor hotspot x
+ * @hotspotY: cursor hotspot Y
+ */
+static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *bo,
+ struct ttm_bo_kmap_obj *map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
+{
+ SVGAGBCursorHeader *header;
+ SVGAGBAlphaCursorHeader *alpha_header;
+ const u32 image_size = width * height * sizeof(*image);
bool dummy;
- int ret;
- kmap_offset = 0;
- kmap_num = PFN_UP(width*height*4);
+ BUG_ON(!image);
- ret = ttm_bo_reserve(&bo->base, true, false, NULL);
- if (unlikely(ret != 0)) {
- DRM_ERROR("reserve failed\n");
- return -EINVAL;
+ header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy);
+ alpha_header = &header->header.alphaHeader;
+
+ header->type = SVGA_ALPHA_CURSOR;
+ header->sizeInBytes = image_size;
+
+ alpha_header->hotspotX = hotspotX;
+ alpha_header->hotspotY = hotspotY;
+ alpha_header->width = width;
+ alpha_header->height = height;
+
+ memcpy(header + 1, image, image_size);
+
+ vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start);
+}
+
+void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) {
+ if (vcp->cursor_mob[i] != NULL) {
+ ttm_bo_unpin(vcp->cursor_mob[i]);
+ ttm_bo_put(vcp->cursor_mob[i]);
+ kfree(vcp->cursor_mob[i]);
+ vcp->cursor_mob[i] = NULL;
+ }
}
+}
- ret = ttm_bo_kmap(&bo->base, kmap_offset, kmap_num, &map);
- if (unlikely(ret != 0))
- goto err_unreserve;
+#define CURSOR_MOB_SIZE(dimension) \
+ ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader))
- virtual = ttm_kmap_obj_virtual(&map, &dummy);
- ret = vmw_cursor_update_image(dev_priv, virtual, width, height,
- hotspotX, hotspotY);
+int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor)
+{
+ struct vmw_private *dev_priv = cursor->base.dev->dev_private;
+ uint32_t cursor_max_dim, mob_max_size;
+ int ret = 0;
+ size_t i;
- ttm_bo_kunmap(&map);
-err_unreserve:
- ttm_bo_unreserve(&bo->base);
+ if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
+ return -ENOSYS;
+
+ mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
+ cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
+
+ if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size)
+ cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */
+
+ for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) {
+ struct ttm_buffer_object **const bo = &cursor->cursor_mob[i];
+
+ ret = vmw_bo_create_kernel(dev_priv,
+ CURSOR_MOB_SIZE(cursor_max_dim),
+ &vmw_mob_placement, bo);
+
+ if (ret != 0)
+ goto teardown;
+
+ if ((*bo)->resource->mem_type != VMW_PL_MOB) {
+ DRM_ERROR("Obtained buffer object is not a MOB.\n");
+ ret = -ENOSYS;
+ goto teardown;
+ }
+
+ /* Fence the mob creation so we are guarateed to have the mob */
+ ret = ttm_bo_reserve(*bo, false, false, NULL);
+
+ if (ret != 0)
+ goto teardown;
+
+ vmw_bo_fence_single(*bo, NULL);
+
+ ttm_bo_unreserve(*bo);
+
+ drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n",
+ (*bo)->resource->start, cursor_max_dim);
+ }
+
+ return 0;
+
+teardown:
+ vmw_du_destroy_cursor_mob_array(cursor);
return ret;
}
+#undef CURSOR_MOB_SIZE
+
+static void vmw_cursor_update_bo(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *cm_bo,
+ struct ttm_bo_kmap_obj *cm_map,
+ struct vmw_buffer_object *bo,
+ u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
+{
+ void *virtual;
+ bool dummy;
+
+ virtual = ttm_kmap_obj_virtual(&bo->map, &dummy);
+ if (virtual) {
+ vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual,
+ width, height,
+ hotspotX, hotspotY);
+ atomic_dec(&bo->base_mapped_count);
+ }
+}
+
static void vmw_cursor_update_position(struct vmw_private *dev_priv,
bool show, int x, int y)
{
+ const uint32_t svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW
+ : SVGA_CURSOR_ON_HIDE;
uint32_t count;
spin_lock(&dev_priv->cursor_lock);
- if (vmw_is_cursor_bypass3_enabled(dev_priv)) {
- vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, show ? 1 : 0);
+ if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) {
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_SCREEN_ID, SVGA3D_INVALID_ID);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, TRUE);
+ } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) {
+ vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on);
vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x);
vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y);
count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT);
@@ -139,7 +262,7 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv,
} else {
vmw_write(dev_priv, SVGA_REG_CURSOR_X, x);
vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y);
- vmw_write(dev_priv, SVGA_REG_CURSOR_ON, show ? 1 : 0);
+ vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on);
}
spin_unlock(&dev_priv->cursor_lock);
}
@@ -269,7 +392,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
continue;
du->cursor_age = du->cursor_surface->snooper.age;
- vmw_cursor_update_image(dev_priv,
+ vmw_cursor_update_image(dev_priv, NULL, NULL,
du->cursor_surface->snooper.image,
64, 64,
du->hotspot_x + du->core_hotspot_x,
@@ -283,7 +406,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
{
vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
-
+ vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane));
drm_plane_cleanup(plane);
}
@@ -321,7 +444,7 @@ void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
/**
- * vmw_du_plane_cleanup_fb - Unpins the cursor
+ * vmw_du_plane_cleanup_fb - Unpins the plane surface
*
* @plane: display plane
* @old_state: Contains the FB to clean up
@@ -341,6 +464,55 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane,
/**
+ * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface
+ *
+ * @plane: cursor plane
+ * @old_state: contains the state to clean up
+ *
+ * Unmaps all cursor bo mappings and unpins the cursor surface
+ *
+ * Returns 0 on success
+ */
+void
+vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
+ bool dummy;
+
+ if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+
+ if (likely(ret == 0)) {
+ if (atomic_read(&vps->bo->base_mapped_count) == 0)
+ ttm_bo_kunmap(&vps->bo->map);
+ ttm_bo_unreserve(&vps->bo->base);
+ }
+ }
+
+ if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL);
+
+ if (likely(ret == 0)) {
+ ttm_bo_kunmap(&vps->cm_map);
+ ttm_bo_unreserve(vps->cm_bo);
+ }
+ }
+
+ vmw_du_plane_unpin_surf(vps, false);
+
+ if (vps->surf) {
+ vmw_surface_unreference(&vps->surf);
+ vps->surf = NULL;
+ }
+
+ if (vps->bo) {
+ vmw_bo_unreference(&vps->bo);
+ vps->bo = NULL;
+ }
+}
+
+/**
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
*
* @plane: display plane
@@ -353,14 +525,21 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
struct drm_framebuffer *fb = new_state->fb;
+ struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
+ struct ttm_buffer_object *cm_bo = NULL;
+ bool dummy;
+ int ret = 0;
-
- if (vps->surf)
+ if (vps->surf) {
vmw_surface_unreference(&vps->surf);
+ vps->surf = NULL;
+ }
- if (vps->bo)
+ if (vps->bo) {
vmw_bo_unreference(&vps->bo);
+ vps->bo = NULL;
+ }
if (fb) {
if (vmw_framebuffer_to_vfb(fb)->bo) {
@@ -372,7 +551,90 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
}
}
+ vps->cm_bo = NULL;
+
+ if (vps->surf == NULL && vps->bo != NULL) {
+ const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
+
+ /* Not using vmw_bo_map_and_cache() helper here as we need to reserve
+ the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */
+ ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+
+ ret = ttm_bo_kmap(&vps->bo->base, 0, PFN_UP(size), &vps->bo->map);
+
+ if (likely(ret == 0))
+ atomic_inc(&vps->bo->base_mapped_count);
+
+ ttm_bo_unreserve(&vps->bo->base);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+ }
+
+ if (vps->surf || vps->bo) {
+ unsigned cursor_mob_idx = vps->cursor_mob_idx;
+
+ /* Lazily set up cursor MOBs just once -- no reattempts. */
+ if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL)
+ if (vmw_du_create_cursor_mob_array(vcp) != 0)
+ vps->cursor_mob_idx = cursor_mob_idx = -1U;
+
+ if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) {
+ const u32 size = sizeof(SVGAGBCursorHeader) +
+ new_state->crtc_w * new_state->crtc_h * sizeof(u32);
+
+ cm_bo = vcp->cursor_mob[cursor_mob_idx];
+
+ if (cm_bo->resource->num_pages * PAGE_SIZE < size) {
+ ret = -EINVAL;
+ goto error_bo_unmap;
+ }
+
+ ret = ttm_bo_reserve(cm_bo, false, false, NULL);
+
+ if (unlikely(ret != 0)) {
+ ret = -ENOMEM;
+ goto error_bo_unmap;
+ }
+
+ ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map);
+
+ /*
+ * We just want to try to get mob bind to finish
+ * so that the first write to SVGA_REG_CURSOR_MOBID
+ * is done with a buffer that the device has already
+ * seen
+ */
+ (void) ttm_bo_wait(cm_bo, false, false);
+
+ ttm_bo_unreserve(cm_bo);
+
+ if (unlikely(ret != 0)) {
+ ret = -ENOMEM;
+ goto error_bo_unmap;
+ }
+
+ vps->cursor_mob_idx = cursor_mob_idx ^ 1;
+ vps->cm_bo = cm_bo;
+ }
+ }
+
return 0;
+
+error_bo_unmap:
+ if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+ if (likely(ret == 0)) {
+ atomic_dec(&vps->bo->base_mapped_count);
+ ttm_bo_kunmap(&vps->bo->map);
+ ttm_bo_unreserve(&vps->bo->base);
+ }
+ }
+
+ return ret;
}
@@ -389,8 +651,6 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
s32 hotspot_x, hotspot_y;
- int ret = 0;
-
hotspot_x = du->hotspot_x;
hotspot_y = du->hotspot_y;
@@ -406,33 +666,31 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
if (vps->surf) {
du->cursor_age = du->cursor_surface->snooper.age;
- ret = vmw_cursor_update_image(dev_priv,
- vps->surf->snooper.image,
- 64, 64, hotspot_x,
- hotspot_y);
+ vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map,
+ vps->surf->snooper.image,
+ new_state->crtc_w,
+ new_state->crtc_h,
+ hotspot_x, hotspot_y);
} else if (vps->bo) {
- ret = vmw_cursor_update_bo(dev_priv, vps->bo,
- new_state->crtc_w,
- new_state->crtc_h,
- hotspot_x, hotspot_y);
+ vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map,
+ vps->bo,
+ new_state->crtc_w,
+ new_state->crtc_h,
+ hotspot_x, hotspot_y);
} else {
vmw_cursor_update_position(dev_priv, false, 0, 0);
return;
}
- if (!ret) {
- du->cursor_x = new_state->crtc_x + du->set_gui_x;
- du->cursor_y = new_state->crtc_y + du->set_gui_y;
+ du->cursor_x = new_state->crtc_x + du->set_gui_x;
+ du->cursor_y = new_state->crtc_y + du->set_gui_y;
- vmw_cursor_update_position(dev_priv, true,
- du->cursor_x + hotspot_x,
- du->cursor_y + hotspot_y);
+ vmw_cursor_update_position(dev_priv, true,
+ du->cursor_x + hotspot_x,
+ du->cursor_y + hotspot_y);
- du->core_hotspot_x = hotspot_x - du->hotspot_x;
- du->core_hotspot_y = hotspot_y - du->hotspot_y;
- } else {
- DRM_ERROR("Failed to update cursor image\n");
- }
+ du->core_hotspot_x = hotspot_x - du->hotspot_x;
+ du->core_hotspot_y = hotspot_y - du->hotspot_y;
}
@@ -518,7 +776,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
DRM_ERROR("Invalid cursor dimensions (%d, %d)\n",
new_state->crtc_w, new_state->crtc_h);
- ret = -EINVAL;
+ return -EINVAL;
}
if (!vmw_framebuffer_to_vfb(fb)->bo)
@@ -526,10 +784,10 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
if (surface && !surface->snooper.image) {
DRM_ERROR("surface not suitable for cursor\n");
- ret = -EINVAL;
+ return -EINVAL;
}
- return ret;
+ return 0;
}
@@ -712,7 +970,6 @@ void vmw_du_plane_reset(struct drm_plane *plane)
{
struct vmw_plane_state *vps;
-
if (plane->state)
vmw_du_plane_destroy_state(plane, plane->state);
@@ -914,6 +1171,15 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
* Sanity checks.
*/
+ if (!drm_any_plane_has_format(&dev_priv->drm,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0])) {
+ drm_dbg(&dev_priv->drm,
+ "unsupported pixel format %p4cc / modifier 0x%llx\n",
+ &mode_cmd->pixel_format, mode_cmd->modifier[0]);
+ return -EINVAL;
+ }
+
/* Surface must be marked as a scanout. */
if (unlikely(!surface->metadata.scanout))
return -EINVAL;
@@ -1236,20 +1502,13 @@ static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv,
return -EINVAL;
}
- /* Limited framebuffer color depth support for screen objects */
- if (dev_priv->active_display_unit == vmw_du_screen_object) {
- switch (mode_cmd->pixel_format) {
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
- break;
- case DRM_FORMAT_XRGB1555:
- case DRM_FORMAT_RGB565:
- break;
- default:
- DRM_ERROR("Invalid pixel format: %p4cc\n",
- &mode_cmd->pixel_format);
- return -EINVAL;
- }
+ if (!drm_any_plane_has_format(&dev_priv->drm,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0])) {
+ drm_dbg(&dev_priv->drm,
+ "unsupported pixel format %p4cc / modifier 0x%llx\n",
+ &mode_cmd->pixel_format, mode_cmd->modifier[0]);
+ return -EINVAL;
}
vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
@@ -1344,7 +1603,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_bo_proxy);
-
/*
* vmw_create_bo_proxy() adds a reference that is no longer
* needed
@@ -1385,13 +1643,16 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
ret = vmw_user_lookup_handle(dev_priv, file_priv,
mode_cmd->handles[0],
&surface, &bo);
- if (ret)
+ if (ret) {
+ DRM_ERROR("Invalid buffer object handle %u (0x%x).\n",
+ mode_cmd->handles[0], mode_cmd->handles[0]);
goto err_out;
+ }
if (!bo &&
!vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
- DRM_ERROR("Surface size cannot exceed %dx%d",
+ DRM_ERROR("Surface size cannot exceed %dx%d\n",
dev_priv->texture_max_width,
dev_priv->texture_max_height);
goto err_out;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 4d36e8507380..1d1c8b82c898 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -247,7 +247,6 @@ struct vmw_framebuffer_bo {
static const uint32_t __maybe_unused vmw_primary_plane_formats[] = {
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
};
@@ -261,6 +260,7 @@ static const uint32_t __maybe_unused vmw_cursor_plane_formats[] = {
#define vmw_plane_state_to_vps(x) container_of(x, struct vmw_plane_state, base)
#define vmw_connector_state_to_vcs(x) \
container_of(x, struct vmw_connector_state, base)
+#define vmw_plane_to_vcp(x) container_of(x, struct vmw_cursor_plane, base)
/**
* Derived class for crtc state object
@@ -293,6 +293,14 @@ struct vmw_plane_state {
/* For CPU Blit */
unsigned int cpp;
+
+ /* CursorMob flipping index; -1 if cursor mobs not used */
+ unsigned int cursor_mob_idx;
+ /* Currently-active CursorMob */
+ struct ttm_buffer_object *cm_bo;
+ /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update
+ IFF currently-active CursorMob above is valid */
+ struct ttm_bo_kmap_obj cm_map;
};
@@ -326,6 +334,17 @@ struct vmw_connector_state {
};
/**
+ * Derived class for cursor plane object
+ *
+ * @base DRM plane object
+ * @cursor_mob array of two MOBs for CursorMob flipping
+ */
+struct vmw_cursor_plane {
+ struct drm_plane base;
+ struct ttm_buffer_object *cursor_mob[2];
+};
+
+/**
* Base class display unit.
*
* Since the SVGA hw doesn't have a concept of a crtc, encoder or connector
@@ -337,7 +356,7 @@ struct vmw_display_unit {
struct drm_encoder encoder;
struct drm_connector connector;
struct drm_plane primary;
- struct drm_plane cursor;
+ struct vmw_cursor_plane cursor;
struct vmw_surface *cursor_surface;
struct vmw_buffer_object *cursor_bo;
@@ -452,6 +471,8 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
/* Universal Plane Helpers */
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
+int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp);
+void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
/* Atomic Helpers */
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
@@ -462,6 +483,8 @@ void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *state);
int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state);
+void vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state);
void vmw_du_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state);
void vmw_du_plane_reset(struct drm_plane *plane);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index fb58a71c458f..e4347faccee0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -338,7 +338,7 @@ drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -363,7 +363,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
@@ -392,7 +393,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
ldu->base.is_implicit = true;
/* Initialize primary plane */
- ret = drm_universal_plane_init(dev, &ldu->base.primary,
+ ret = drm_universal_plane_init(dev, primary,
0, &vmw_ldu_plane_funcs,
vmw_primary_plane_formats,
ARRAY_SIZE(vmw_primary_plane_formats),
@@ -409,7 +410,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
*/
if (vmw_cmd_supported(dev_priv)) {
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, &ldu->base.cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_ldu_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -420,7 +421,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_ldu_cursor_plane_helper_funcs);
}
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
@@ -450,9 +451,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(
- dev, crtc, &ldu->base.primary,
- vmw_cmd_supported(dev_priv) ? &ldu->base.cursor : NULL,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ vmw_cmd_supported(dev_priv) ? &cursor->base : NULL,
&vmw_legacy_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
@@ -492,6 +492,8 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
int i, ret;
+ int num_display_units = (dev_priv->capabilities & SVGA_CAP_MULTIMON) ?
+ VMWGFX_NUM_DISPLAY_UNITS : 1;
if (unlikely(dev_priv->ldu_priv)) {
return -EINVAL;
@@ -506,21 +508,17 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL;
- /* for old hardware without multimon only enable one display */
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
- ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
- else
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev, num_display_units);
if (ret != 0)
goto err_free;
vmw_kms_create_implicit_placement_property(dev_priv);
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
- for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
- vmw_ldu_init(dev_priv, i);
- else
- vmw_ldu_init(dev_priv, 0);
+ for (i = 0; i < num_display_units; ++i) {
+ ret = vmw_ldu_init(dev_priv, i);
+ if (ret != 0)
+ goto err_free;
+ }
dev_priv->active_display_unit = vmw_du_legacy;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 708899ba2102..626067104751 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -859,22 +859,21 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo,
struct ttm_device *bdev = bo->bdev;
struct vmw_private *dev_priv;
-
dev_priv = container_of(bdev, struct vmw_private, bdev);
mutex_lock(&dev_priv->binding_mutex);
- dx_query_mob = container_of(bo, struct vmw_buffer_object, base);
- if (!dx_query_mob || !dx_query_mob->dx_query_ctx) {
- mutex_unlock(&dev_priv->binding_mutex);
- return;
- }
-
/* If BO is being moved from MOB to system memory */
if (new_mem->mem_type == TTM_PL_SYSTEM &&
old_mem->mem_type == VMW_PL_MOB) {
struct vmw_fence_obj *fence;
+ dx_query_mob = container_of(bo, struct vmw_buffer_object, base);
+ if (!dx_query_mob || !dx_query_mob->dx_query_ctx) {
+ mutex_unlock(&dev_priv->binding_mutex);
+ return;
+ }
+
(void) vmw_query_readback_all(dx_query_mob);
mutex_unlock(&dev_priv->binding_mutex);
@@ -888,7 +887,6 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo,
(void) ttm_bo_wait(bo, false, false);
} else
mutex_unlock(&dev_priv->binding_mutex);
-
}
/**
@@ -1165,8 +1163,9 @@ int vmw_resources_clean(struct vmw_buffer_object *vbo, pgoff_t start,
vmw_bo_fence_single(bo, NULL);
if (bo->moving)
dma_fence_put(bo->moving);
- bo->moving = dma_fence_get
- (dma_resv_excl_fence(bo->base.resv));
+
+ return dma_resv_get_singleton(bo->base.resv, false,
+ &bo->moving);
}
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 3004c7a719e9..c89ad3a2d141 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2011-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -804,7 +804,7 @@ drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -832,7 +832,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
@@ -859,7 +860,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
sou->base.is_implicit = false;
/* Initialize primary plane */
- ret = drm_universal_plane_init(dev, &sou->base.primary,
+ ret = drm_universal_plane_init(dev, primary,
0, &vmw_sou_plane_funcs,
vmw_primary_plane_formats,
ARRAY_SIZE(vmw_primary_plane_formats),
@@ -873,7 +874,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, &sou->base.cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_sou_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -884,7 +885,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_sou_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
@@ -913,8 +914,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary,
- &sou->base.cursor,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ &cursor->base,
&vmw_screen_object_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index ae9a6044d448..eb014b97d156 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/******************************************************************************
*
- * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA
+ * COPYRIGHT (C) 2014-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -138,6 +138,11 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);
* Screen Target Display Unit CRTC Functions
*****************************************************************************/
+static bool vmw_stdu_use_cpu_blit(const struct vmw_private *vmw)
+{
+ return !(vmw->capabilities & SVGA_CAP_3D) || vmw->vram_size < (32 * 1024 * 1024);
+}
+
/**
* vmw_stdu_crtc_destroy - cleans up the STDU
@@ -689,7 +694,7 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
container_of(vfb, struct vmw_framebuffer_bo, base)->buffer;
struct vmw_stdu_dirty ddirty;
int ret;
- bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
+ bool cpu_blit = vmw_stdu_use_cpu_blit(dev_priv);
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
/*
@@ -1164,7 +1169,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
* so cache these mappings
*/
if (vps->content_fb_type == SEPARATE_BO &&
- !(dev_priv->capabilities & SVGA_CAP_3D))
+ vmw_stdu_use_cpu_blit(dev_priv))
vps->cpp = new_fb->pitches[0] / new_fb->width;
return 0;
@@ -1368,7 +1373,7 @@ static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
bo_update.base.vfb = vfb;
bo_update.base.out_fence = out_fence;
bo_update.base.mutex = NULL;
- bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
+ bo_update.base.cpu_blit = vmw_stdu_use_cpu_blit(dev_priv);
bo_update.base.intr = false;
/*
@@ -1685,7 +1690,7 @@ drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -1723,11 +1728,11 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
-
stdu = kzalloc(sizeof(*stdu), GFP_KERNEL);
if (!stdu)
return -ENOMEM;
@@ -1759,7 +1764,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_stdu_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -1770,7 +1775,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
@@ -1799,8 +1804,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary,
- &stdu->base.cursor,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ &cursor->base,
&vmw_stdu_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index b84ecc6d6611..4e3938e62c08 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -517,7 +517,7 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
ttm_cached);
else
ret = ttm_tt_init(&vmw_be->dma_ttm, bo, page_flags,
- ttm_cached);
+ ttm_cached, 0);
if (unlikely(ret != 0))
goto out_no_init;
diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
index f0760741f281..d32cd7538835 100644
--- a/drivers/infiniband/core/umem_dmabuf.c
+++ b/drivers/infiniband/core/umem_dmabuf.c
@@ -16,7 +16,6 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
{
struct sg_table *sgt;
struct scatterlist *sg;
- struct dma_fence *fence;
unsigned long start, end, cur = 0;
unsigned int nmap = 0;
int i;
@@ -68,11 +67,8 @@ wait_fence:
* may be not up-to-date. Wait for the exporter to finish
* the migration.
*/
- fence = dma_resv_excl_fence(umem_dmabuf->attach->dmabuf->resv);
- if (fence)
- return dma_fence_wait(fence, false);
-
- return 0;
+ return dma_resv_wait_timeout(umem_dmabuf->attach->dmabuf->resv, false,
+ false, MAX_SCHEDULE_TIMEOUT);
}
EXPORT_SYMBOL(ib_umem_dmabuf_map_pages);
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 93b8d84c34cf..f2a6b81e45c4 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -66,13 +66,6 @@ config FB_DDC
select I2C_ALGOBIT
select I2C
-config FB_BOOT_VESA_SUPPORT
- bool
- depends on FB
- help
- If true, at least one selected framebuffer driver can take advantage
- of VESA video modes set at an early boot stage via the vga= parameter.
-
config FB_CFB_FILLRECT
tristate
depends on FB
@@ -627,7 +620,7 @@ config FB_VESA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select FB_BOOT_VESA_SUPPORT
+ select SYSFB
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -641,6 +634,7 @@ config FB_EFI
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select SYSFB
help
This is the EFI frame buffer device driver. If the firmware on
your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
@@ -1051,7 +1045,7 @@ config FB_INTEL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select FB_BOOT_VESA_SUPPORT if FB_INTEL = y
+ select BOOT_VESA_SUPPORT if FB_INTEL = y
depends on !DRM_I915
help
This driver supports the on-board graphics built in to the Intel
@@ -1378,7 +1372,7 @@ config FB_SIS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select FB_BOOT_VESA_SUPPORT if FB_SIS = y
+ select BOOT_VESA_SUPPORT if FB_SIS = y
select FB_SIS_300 if !FB_SIS_315
help
This is the frame buffer device driver for the SiS 300, 315, 330
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index 842c66b3e33d..6aaf6d0abf39 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -59,7 +59,6 @@ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
printk(KERN_ERR "no mapping available\n");
BUG_ON(!page->mapping);
- INIT_LIST_HEAD(&page->lru);
page->index = vmf->pgoff;
vmf->page = page;
@@ -213,6 +212,8 @@ static void fb_deferred_io_work(struct work_struct *work)
void fb_deferred_io_init(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct page *page;
+ unsigned int i;
BUG_ON(!fbdefio);
mutex_init(&fbdefio->lock);
@@ -220,6 +221,12 @@ void fb_deferred_io_init(struct fb_info *info)
INIT_LIST_HEAD(&fbdefio->pagelist);
if (fbdefio->delay == 0) /* set a default of 1 s */
fbdefio->delay = HZ;
+
+ /* initialize all the page lists one time */
+ for (i = 0; i < info->fix.smem_len; i += PAGE_SIZE) {
+ page = fb_deferred_io_page(info, i);
+ INIT_LIST_HEAD(&page->lru);
+ }
}
EXPORT_SYMBOL_GPL(fb_deferred_io_init);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 1701c2128a5c..0777725085df 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -227,6 +227,18 @@ struct drm_private_state_funcs {
*/
void (*atomic_destroy_state)(struct drm_private_obj *obj,
struct drm_private_state *state);
+
+ /**
+ * @atomic_print_state:
+ *
+ * If driver subclasses &struct drm_private_state, it should implement
+ * this optional hook for printing additional driver specific state.
+ *
+ * Do not call this directly, use drm_atomic_private_obj_print_state()
+ * instead.
+ */
+ void (*atomic_print_state)(struct drm_printer *p,
+ const struct drm_private_state *state);
};
/**
@@ -311,14 +323,21 @@ struct drm_private_obj {
/**
* struct drm_private_state - base struct for driver private object state
- * @state: backpointer to global drm_atomic_state
*
- * Currently only contains a backpointer to the overall atomic update, but in
- * the future also might hold synchronization information similar to e.g.
- * &drm_crtc.commit.
+ * Currently only contains a backpointer to the overall atomic update,
+ * and the relevant private object but in the future also might hold
+ * synchronization information similar to e.g. &drm_crtc.commit.
*/
struct drm_private_state {
+ /**
+ * @state: backpointer to global drm_atomic_state
+ */
struct drm_atomic_state *state;
+
+ /**
+ * @obj: backpointer to the private object
+ */
+ struct drm_private_obj *obj;
};
struct __drm_private_objs_state {
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 144c495b99c4..b7e170584000 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -372,8 +372,8 @@ struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
-int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads);
-int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb);
+int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads);
+int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb);
int drm_av_sync_delay(struct drm_connector *connector,
const struct drm_display_mode *mode);
@@ -569,8 +569,8 @@ 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);
-bool drm_detect_hdmi_monitor(struct edid *edid);
-bool drm_detect_monitor_audio(struct edid *edid);
+bool drm_detect_hdmi_monitor(const struct edid *edid);
+bool drm_detect_monitor_audio(const struct edid *edid);
enum hdmi_quantization_range
drm_default_rgb_quant_range(const struct drm_display_mode *mode);
int drm_add_modes_noedid(struct drm_connector *connector,
@@ -578,11 +578,11 @@ int drm_add_modes_noedid(struct drm_connector *connector,
void drm_set_preferred_mode(struct drm_connector *connector,
int hpref, int vpref);
-int drm_edid_header_is_valid(const u8 *raw_edid);
+int drm_edid_header_is_valid(const void *edid);
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
bool *edid_corrupt);
bool drm_edid_is_valid(struct edid *edid);
-void drm_edid_get_monitor_name(struct edid *edid, char *name,
+void drm_edid_get_monitor_name(const struct edid *edid, char *name,
int buflen);
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
int hsize, int vsize, int fresh,
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index a3acb7ac3550..e0a73a1e2df7 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -248,7 +248,7 @@ struct drm_file {
*/
struct drm_master *master;
- /** @master_lock: Serializes @master. */
+ /** @master_lookup_lock: Serializes @master. */
spinlock_t master_lookup_lock;
/** @pid: Process that opened this file. */
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 0b0937c0b2f6..55145eca0782 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -43,8 +43,7 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for
const void *vmap, const struct drm_framebuffer *fb,
const struct drm_rect *rect);
-void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *src,
- const struct drm_framebuffer *fb,
- const struct drm_rect *clip);
+void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *src,
+ const struct drm_framebuffer *fb, const struct drm_rect *clip);
#endif /* __LINUX_DRM_FORMAT_HELPER_H */
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index e2941cee14b6..9d7c61a122dc 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -407,11 +407,6 @@ int drm_gem_lock_reservations(struct drm_gem_object **objs, int count,
struct ww_acquire_ctx *acquire_ctx);
void drm_gem_unlock_reservations(struct drm_gem_object **objs, int count,
struct ww_acquire_ctx *acquire_ctx);
-int drm_gem_fence_array_add(struct xarray *fence_array,
- struct dma_fence *fence);
-int drm_gem_fence_array_add_implicit(struct xarray *fence_array,
- struct drm_gem_object *obj,
- bool write);
int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
u32 handle, u64 *offset);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 147e51b6d241..51e09a1a106a 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -137,6 +137,8 @@ struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
/* transmit data in low power */
#define MIPI_DSI_MODE_LPM BIT(11)
+/* transmit data ending at the same time for all lanes within one hsync */
+#define MIPI_DSI_HS_PKT_END_ALIGNED BIT(12)
enum mipi_dsi_pixel_format {
MIPI_DSI_FMT_RGB888,
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 2fa6b2c33b3f..a80ae9639e96 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -492,6 +492,8 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p,
int adjust_flags);
void drm_mode_copy(struct drm_display_mode *dst,
const struct drm_display_mode *src);
+void drm_mode_init(struct drm_display_mode *dst,
+ const struct drm_display_mode *src);
struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
const struct drm_display_mode *mode);
bool drm_mode_match(const struct drm_display_mode *mode1,
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index fdfa9f37ce05..fafa70ac1337 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1384,7 +1384,7 @@ struct drm_mode_config_helper_funcs {
* starting to commit the update to the hardware.
*
* After the atomic update is committed to the hardware this hook needs
- * to call drm_atomic_helper_commit_hw_done(). Then wait for the upate
+ * to call drm_atomic_helper_commit_hw_done(). Then wait for the update
* to be executed by the hardware, for example using
* drm_atomic_helper_wait_for_vblanks() or
* drm_atomic_helper_wait_for_flip_done(), and then clean up the old
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 944f83ef9f2e..0fca8f38bee4 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -270,6 +270,7 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f);
* @sched: the scheduler instance on which this job is scheduled.
* @s_fence: contains the fences for the scheduling of job.
* @finish_cb: the callback for the finished fence.
+ * @work: Helper to reschdeule job kill to different context.
* @id: a unique id assigned to each job scheduled on the scheduler.
* @karma: increment on every hang caused by this job. If this exceeds the hang
* limit of the scheduler then the job is marked guilty and will not
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index 155b19ee12fb..c76932b68a33 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -55,8 +55,6 @@ struct ttm_placement;
struct ttm_place;
-struct ttm_lru_bulk_move;
-
/**
* enum ttm_bo_type
*
@@ -94,7 +92,6 @@ struct ttm_tt;
* @ttm: TTM structure holding system pages.
* @evicted: Whether the object was evicted without user-space knowing.
* @deleted: True if the object is only a zombie and already deleted.
- * @lru: List head for the lru list.
* @ddestroy: List head for the delayed destroy list.
* @swap: List head for swap LRU list.
* @moving: Fence set when BO is moving
@@ -138,12 +135,12 @@ struct ttm_buffer_object {
struct ttm_resource *resource;
struct ttm_tt *ttm;
bool deleted;
+ struct ttm_lru_bulk_move *bulk_move;
/**
* Members protected by the bdev::lru_lock.
*/
- struct list_head lru;
struct list_head ddestroy;
/**
@@ -291,30 +288,9 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
*/
void ttm_bo_put(struct ttm_buffer_object *bo);
-/**
- * ttm_bo_move_to_lru_tail
- *
- * @bo: The buffer object.
- * @mem: Resource object.
- * @bulk: optional bulk move structure to remember BO positions
- *
- * Move this BO to the tail of all lru lists used to lookup and reserve an
- * object. This function must be called with struct ttm_global::lru_lock
- * held, and is used to make a BO less likely to be considered for eviction.
- */
-void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo,
- struct ttm_resource *mem,
- struct ttm_lru_bulk_move *bulk);
-
-/**
- * ttm_bo_bulk_move_lru_tail
- *
- * @bulk: bulk move structure
- *
- * Bulk move BOs to the LRU tail, only valid to use when driver makes sure that
- * BO order never changes. Should be called with ttm_global::lru_lock held.
- */
-void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk);
+void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo);
+void ttm_bo_set_bulk_move(struct ttm_buffer_object *bo,
+ struct ttm_lru_bulk_move *bulk);
/**
* ttm_bo_lock_delayed_workqueue
@@ -540,34 +516,8 @@ ssize_t ttm_bo_io(struct ttm_device *bdev, struct file *filp,
int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
gfp_t gfp_flags);
-/**
- * ttm_bo_pin - Pin the buffer object.
- * @bo: The buffer object to pin
- *
- * Make sure the buffer is not evicted any more during memory pressure.
- */
-static inline void ttm_bo_pin(struct ttm_buffer_object *bo)
-{
- dma_resv_assert_held(bo->base.resv);
- WARN_ON_ONCE(!kref_read(&bo->kref));
- ++bo->pin_count;
-}
-
-/**
- * ttm_bo_unpin - Unpin the buffer object.
- * @bo: The buffer object to unpin
- *
- * Allows the buffer object to be evicted again during memory pressure.
- */
-static inline void ttm_bo_unpin(struct ttm_buffer_object *bo)
-{
- dma_resv_assert_held(bo->base.resv);
- WARN_ON_ONCE(!kref_read(&bo->kref));
- if (bo->pin_count)
- --bo->pin_count;
- else
- WARN_ON_ONCE(true);
-}
+void ttm_bo_pin(struct ttm_buffer_object *bo);
+void ttm_bo_unpin(struct ttm_buffer_object *bo);
int ttm_mem_evict_first(struct ttm_device *bdev,
struct ttm_resource_manager *man,
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index 5f087575194b..059a595e14e5 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -45,33 +45,6 @@
#include "ttm_tt.h"
#include "ttm_pool.h"
-/**
- * struct ttm_lru_bulk_move_pos
- *
- * @first: first BO in the bulk move range
- * @last: last BO in the bulk move range
- *
- * Positions for a lru bulk move.
- */
-struct ttm_lru_bulk_move_pos {
- struct ttm_buffer_object *first;
- struct ttm_buffer_object *last;
-};
-
-/**
- * struct ttm_lru_bulk_move
- *
- * @tt: first/last lru entry for BOs in the TT domain
- * @vram: first/last lru entry for BOs in the VRAM domain
- * @swap: first/last lru entry for BOs on the swap list
- *
- * Helper structure for bulk moves on the LRU list.
- */
-struct ttm_lru_bulk_move {
- struct ttm_lru_bulk_move_pos tt[TTM_MAX_BO_PRIORITY];
- struct ttm_lru_bulk_move_pos vram[TTM_MAX_BO_PRIORITY];
-};
-
/*
* ttm_bo.c
*/
@@ -182,7 +155,7 @@ static inline void
ttm_bo_move_to_lru_tail_unlocked(struct ttm_buffer_object *bo)
{
spin_lock(&bo->bdev->lru_lock);
- ttm_bo_move_to_lru_tail(bo, bo->resource, NULL);
+ ttm_bo_move_to_lru_tail(bo);
spin_unlock(&bo->bdev->lru_lock);
}
diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
index 0a4ddec78d8f..95b3c04b1ab9 100644
--- a/include/drm/ttm/ttm_device.h
+++ b/include/drm/ttm/ttm_device.h
@@ -30,8 +30,6 @@
#include <drm/ttm/ttm_resource.h>
#include <drm/ttm/ttm_pool.h>
-#define TTM_NUM_MEM_TYPES 8
-
struct ttm_device;
struct ttm_placement;
struct ttm_buffer_object;
@@ -201,15 +199,6 @@ struct ttm_device_funcs {
void *buf, int len, int write);
/**
- * struct ttm_bo_driver member del_from_lru_notify
- *
- * @bo: the buffer object deleted from lru
- *
- * notify driver that a BO was deleted from LRU.
- */
- void (*del_from_lru_notify)(struct ttm_buffer_object *bo);
-
- /**
* Notify the driver that we're about to release a BO
*
* @bo: BO that is about to be released
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
index 0f1d55262c68..314f73de4280 100644
--- a/include/drm/ttm/ttm_resource.h
+++ b/include/drm/ttm/ttm_resource.h
@@ -26,14 +26,17 @@
#define _TTM_RESOURCE_H_
#include <linux/types.h>
+#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/iosys-map.h>
#include <linux/dma-fence.h>
+
#include <drm/drm_print.h>
#include <drm/ttm/ttm_caching.h>
#include <drm/ttm/ttm_kmap_iter.h>
#define TTM_MAX_BO_PRIORITY 4U
+#define TTM_NUM_MEM_TYPES 8
struct ttm_device;
struct ttm_resource_manager;
@@ -178,6 +181,48 @@ struct ttm_resource {
uint32_t placement;
struct ttm_bus_placement bus;
struct ttm_buffer_object *bo;
+
+ /**
+ * @lru: Least recently used list, see &ttm_resource_manager.lru
+ */
+ struct list_head lru;
+};
+
+/**
+ * struct ttm_resource_cursor
+ *
+ * @priority: the current priority
+ *
+ * Cursor to iterate over the resources in a manager.
+ */
+struct ttm_resource_cursor {
+ unsigned int priority;
+};
+
+/**
+ * struct ttm_lru_bulk_move_pos
+ *
+ * @first: first res in the bulk move range
+ * @last: last res in the bulk move range
+ *
+ * Range of resources for a lru bulk move.
+ */
+struct ttm_lru_bulk_move_pos {
+ struct ttm_resource *first;
+ struct ttm_resource *last;
+};
+
+/**
+ * struct ttm_lru_bulk_move
+ *
+ * @tt: first/last lru entry for resources in the TT domain
+ * @vram: first/last lru entry for resources in the VRAM domain
+ *
+ * Container for the current bulk move state. Should be used with
+ * ttm_lru_bulk_move_init() and ttm_bo_set_bulk_move().
+ */
+struct ttm_lru_bulk_move {
+ struct ttm_lru_bulk_move_pos pos[TTM_NUM_MEM_TYPES][TTM_MAX_BO_PRIORITY];
};
/**
@@ -266,6 +311,15 @@ ttm_resource_manager_cleanup(struct ttm_resource_manager *man)
man->move = NULL;
}
+void ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk);
+void ttm_lru_bulk_move_add(struct ttm_lru_bulk_move *bulk,
+ struct ttm_resource *res);
+void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk,
+ struct ttm_resource *res);
+void ttm_lru_bulk_move_tail(struct ttm_lru_bulk_move *bulk);
+
+void ttm_resource_move_to_lru_tail(struct ttm_resource *res);
+
void ttm_resource_init(struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource *res);
@@ -292,6 +346,26 @@ uint64_t ttm_resource_manager_usage(struct ttm_resource_manager *man);
void ttm_resource_manager_debug(struct ttm_resource_manager *man,
struct drm_printer *p);
+struct ttm_resource *
+ttm_resource_manager_first(struct ttm_resource_manager *man,
+ struct ttm_resource_cursor *cursor);
+struct ttm_resource *
+ttm_resource_manager_next(struct ttm_resource_manager *man,
+ struct ttm_resource_cursor *cursor,
+ struct ttm_resource *res);
+
+/**
+ * ttm_resource_manager_for_each_res - iterate over all resources
+ * @man: the resource manager
+ * @cursor: struct ttm_resource_cursor for the current position
+ * @res: the current resource
+ *
+ * Iterate over all the evictable resources in a resource manager.
+ */
+#define ttm_resource_manager_for_each_res(man, cursor, res) \
+ for (res = ttm_resource_manager_first(man, cursor); res; \
+ res = ttm_resource_manager_next(man, cursor, res))
+
struct ttm_kmap_iter *
ttm_kmap_iter_iomap_init(struct ttm_kmap_iter_iomap *iter_io,
struct io_mapping *iomap,
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index f20832139815..17a0310e8aaa 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -140,6 +140,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc);
* @bo: The buffer object we create the ttm for.
* @page_flags: Page flags as identified by TTM_TT_FLAG_XX flags.
* @caching: the desired caching state of the pages
+ * @extra_pages: Extra pages needed for the driver.
*
* Create a struct ttm_tt to back data with system memory pages.
* No pages are actually allocated.
@@ -147,7 +148,8 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc);
* NULL: Out of memory.
*/
int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
- uint32_t page_flags, enum ttm_caching caching);
+ uint32_t page_flags, enum ttm_caching caching,
+ unsigned long extra_pages);
int ttm_sg_tt_init(struct ttm_tt *ttm_dma, struct ttm_buffer_object *bo,
uint32_t page_flags, enum ttm_caching caching);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index 2097760e8e95..6fb91956ab8d 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -424,9 +424,7 @@ struct dma_buf {
* IMPORTANT:
*
* All drivers must obey the struct dma_resv rules, specifically the
- * rules for updating fences, see &dma_resv.fence_excl and
- * &dma_resv.fence. If these dependency rules are broken access tracking
- * can be lost resulting in use after free issues.
+ * rules for updating and obeying fences.
*/
struct dma_resv *resv;
diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index afdfdfac729f..5fa04d0fccad 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -47,18 +47,7 @@
extern struct ww_class reservation_ww_class;
-/**
- * struct dma_resv_list - a list of shared fences
- * @rcu: for internal use
- * @shared_count: table of shared fences
- * @shared_max: for growing shared fence table
- * @shared: shared fence table
- */
-struct dma_resv_list {
- struct rcu_head rcu;
- u32 shared_count, shared_max;
- struct dma_fence __rcu *shared[];
-};
+struct dma_resv_list;
/**
* struct dma_resv - a reservation object manages fences for a buffer
@@ -104,23 +93,11 @@ struct dma_resv {
*
* The exclusive fence, if there is one currently.
*
- * There are two ways to update this fence:
- *
- * - First by calling dma_resv_add_excl_fence(), which replaces all
- * fences attached to the reservation object. To guarantee that no
- * fences are lost, this new fence must signal only after all previous
- * fences, both shared and exclusive, have signalled. In some cases it
- * is convenient to achieve that by attaching a struct dma_fence_array
- * with all the new and old fences.
- *
- * - Alternatively the fence can be set directly, which leaves the
- * shared fences unchanged. To guarantee that no fences are lost, this
- * new fence must signal only after the previous exclusive fence has
- * signalled. Since the shared fences are staying intact, it is not
- * necessary to maintain any ordering against those. If semantically
- * only a new access is added without actually treating the previous
- * one as a dependency the exclusive fences can be strung together
- * using struct dma_fence_chain.
+ * To guarantee that no fences are lost, this new fence must signal
+ * only after the previous exclusive fence has signalled. If
+ * semantically only a new access is added without actually treating the
+ * previous one as a dependency the exclusive fences can be strung
+ * together using struct dma_fence_chain.
*
* Note that actual semantics of what an exclusive or shared fence mean
* is defined by the user, for reservation objects shared across drivers
@@ -140,7 +117,7 @@ struct dma_resv {
* A new fence is added by calling dma_resv_add_shared_fence(). Since
* this often needs to be done past the point of no return in command
* submission it cannot fail, and therefore sufficient slots need to be
- * reserved by calling dma_resv_reserve_shared().
+ * reserved by calling dma_resv_reserve_fences().
*
* Note that actual semantics of what an exclusive or shared fence mean
* is defined by the user, for reservation objects shared across drivers
@@ -434,43 +411,17 @@ static inline void dma_resv_unlock(struct dma_resv *obj)
ww_mutex_unlock(&obj->lock);
}
-/**
- * dma_resv_excl_fence - return the object's exclusive fence
- * @obj: the reservation object
- *
- * Returns the exclusive fence (if any). Caller must either hold the objects
- * through dma_resv_lock() or the RCU read side lock through rcu_read_lock(),
- * or one of the variants of each
- *
- * RETURNS
- * The exclusive fence or NULL
- */
-static inline struct dma_fence *
-dma_resv_excl_fence(struct dma_resv *obj)
-{
- return rcu_dereference_check(obj->fence_excl, dma_resv_held(obj));
-}
-
-/**
- * dma_resv_shared_list - get the reservation object's shared fence list
- * @obj: the reservation object
- *
- * Returns the shared fence list. Caller must either hold the objects
- * through dma_resv_lock() or the RCU read side lock through rcu_read_lock(),
- * or one of the variants of each
- */
-static inline struct dma_resv_list *dma_resv_shared_list(struct dma_resv *obj)
-{
- return rcu_dereference_check(obj->fence, dma_resv_held(obj));
-}
-
void dma_resv_init(struct dma_resv *obj);
void dma_resv_fini(struct dma_resv *obj);
-int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences);
+int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences);
void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence);
+void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
+ struct dma_fence *fence);
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence);
int dma_resv_get_fences(struct dma_resv *obj, bool write,
unsigned int *num_fences, struct dma_fence ***fences);
+int dma_resv_get_singleton(struct dma_resv *obj, bool write,
+ struct dma_fence **fence);
int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src);
long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,
unsigned long timeout);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ccd4d3f91c98..0cbbc4103632 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1329,10 +1329,6 @@ static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
}
#endif
-#ifdef CONFIG_SYSFB
extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
-#else
-static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) { }
-#endif
#endif /* _LINUX_EFI_H */
diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h
index 8277644c1144..26549c86a91f 100644
--- a/include/uapi/drm/vmwgfx_drm.h
+++ b/include/uapi/drm/vmwgfx_drm.h
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -92,6 +92,12 @@ extern "C" {
*
* DRM_VMW_PARAM_SM5
* SM5 support is enabled.
+ *
+ * DRM_VMW_PARAM_GL43
+ * SM5.1+GL4.3 support is enabled.
+ *
+ * DRM_VMW_PARAM_DEVICE_ID
+ * PCI ID of the underlying SVGA device.
*/
#define DRM_VMW_PARAM_NUM_STREAMS 0
@@ -111,6 +117,7 @@ extern "C" {
#define DRM_VMW_PARAM_SM4_1 14
#define DRM_VMW_PARAM_SM5 15
#define DRM_VMW_PARAM_GL43 16
+#define DRM_VMW_PARAM_DEVICE_ID 17
/**
* enum drm_vmw_handle_type - handle type for ref ioctls