diff options
318 files changed, 7618 insertions, 5719 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index 50220190c203..60091db5dfa5 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -22,13 +22,11 @@ among others. Required properties: -- compatible: Must be one or more of the following - - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer - - "lvds-encoder" for a generic LVDS encoder device +- compatible: Must be "lvds-encoder" - When compatible with the generic version, nodes must list the - device-specific version corresponding to the device first - followed by the generic version. + Any encoder compatible with this generic binding, but with additional + properties not listed here, must list a device specific compatible first + followed by this generic compatible. Required nodes: @@ -44,8 +42,6 @@ Example lvds-encoder { compatible = "lvds-encoder"; - #address-cells = <1>; - #size-cells = <0>; ports { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt index ba5469dd09f3..27a054e1bb5f 100644 --- a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt +++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt @@ -8,6 +8,7 @@ Required properties: - compatible : Shall contain one of - "renesas,r8a7743-lvds" for R8A7743 (RZ/G1M) compatible LVDS encoders + - "renesas,r8a774c0-lvds" for R8A774C0 (RZ/G2E) compatible LVDS encoders - "renesas,r8a7790-lvds" for R8A7790 (R-Car H2) compatible LVDS encoders - "renesas,r8a7791-lvds" for R8A7791 (R-Car M2-W) compatible LVDS encoders - "renesas,r8a7793-lvds" for R8A7793 (R-Car M2-N) compatible LVDS encoders @@ -25,7 +26,7 @@ Required properties: - clock-names: Name of the clocks. This property is model-dependent. - The functional clock, which mandatory for all models, shall be listed first, and shall be named "fck". - - On R8A77990 and R8A77995, the LVDS encoder can use the EXTAL or + - On R8A77990, R8A77995 and R8A774C0, the LVDS encoder can use the EXTAL or DU_DOTCLKINx clocks. Those clocks are optional. When supplied they must be named "extal" and "dclkin.x" respectively, with "x" being the DU_DOTCLKIN numerical index. diff --git a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt b/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt index 527e236e9a2a..fee3c88e1a17 100644 --- a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt +++ b/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt @@ -10,7 +10,7 @@ Required properties: Optional properties: -- pwdn-gpios: Power down control GPIO +- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low). Required nodes: diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt b/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt new file mode 100644 index 000000000000..e575f996959a --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt @@ -0,0 +1,55 @@ +Texas Instruments FPD-Link (LVDS) Serializer +-------------------------------------------- + +The DS90C185 and DS90C187 are low-power serializers for portable +battery-powered applications that reduces the size of the RGB +interface between the host GPU and the display. + +Required properties: + +- compatible: Should be + "ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer + "ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer + +Optional properties: + +- powerdown-gpios: Power down control GPIO (the PDB pin, active-low) + +Required nodes: + +The devices have two video ports. Their connections are modeled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for parallel input +- Video port 1 for LVDS output + + +Example +------- + +lvds-encoder { + compatible = "ti,ds90c185", "lvds-encoder"; + + powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_enc_in: endpoint { + remote-endpoint = <&lcdc_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + + lvds_enc_out: endpoint { + remote-endpoint = <&lvds_panel_in>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 b/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt index bc6a0c858e23..bc6a0c858e23 100644 --- a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 +++ b/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index 3c855d9f2719..aedb22b4d161 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -7,6 +7,7 @@ Required Properties: - "renesas,du-r8a7744" for R8A7744 (RZ/G1N) compatible DU - "renesas,du-r8a7745" for R8A7745 (RZ/G1E) compatible DU - "renesas,du-r8a77470" for R8A77470 (RZ/G1C) compatible DU + - "renesas,du-r8a774c0" for R8A774C0 (RZ/G2E) compatible DU - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU - "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU @@ -57,6 +58,7 @@ corresponding to each DU output. R8A7744 (RZ/G1N) DPAD 0 LVDS 0 - - R8A7745 (RZ/G1E) DPAD 0 DPAD 1 - - R8A77470 (RZ/G1C) DPAD 0 DPAD 1 LVDS 0 - + R8A774C0 (RZ/G2E) DPAD 0 LVDS 0 LVDS 1 - R8A7779 (R-Car H1) DPAD 0 DPAD 1 - - R8A7790 (R-Car H2) DPAD 0 LVDS 0 LVDS 1 - R8A7791 (R-Car M2-W) DPAD 0 LVDS 0 - - diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index b79e5769f0ae..4f58c5a2d195 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -10,6 +10,7 @@ Required properties: "rockchip,rk3126-vop"; "rockchip,px30-vop-lit"; "rockchip,px30-vop-big"; + "rockchip,rk3066-vop"; "rockchip,rk3188-vop"; "rockchip,rk3288-vop"; "rockchip,rk3368-vop"; diff --git a/Documentation/gpu/dp-mst/topology-figure-1.dot b/Documentation/gpu/dp-mst/topology-figure-1.dot new file mode 100644 index 000000000000..157e17c7e0b0 --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-1.dot @@ -0,0 +1,52 @@ +digraph T { + /* Make sure our payloads are always drawn below the driver node */ + subgraph cluster_driver { + fillcolor = grey; + style = filled; + driver -> {payload1, payload2} [dir=none]; + } + + /* Driver malloc references */ + edge [style=dashed]; + driver -> port1; + driver -> port2; + driver -> port3:e; + driver -> port4; + + payload1:s -> port1:e; + payload2:s -> port3:e; + edge [style=""]; + + subgraph cluster_topology { + label="Topology Manager"; + labelloc=bottom; + + /* Topology references */ + mstb1 -> {port1, port2}; + port1 -> mstb2; + port2 -> mstb3 -> {port3, port4}; + port3 -> mstb4; + + /* Malloc references */ + edge [style=dashed;dir=back]; + mstb1 -> {port1, port2}; + port1 -> mstb2; + port2 -> mstb3 -> {port3, port4}; + port3 -> mstb4; + } + + driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; + + payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; + payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue]; + + mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen;shape=oval]; + mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen;shape=oval]; + mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;shape=oval]; + mstb4 [label="MSTB #4";style=filled;fillcolor=palegreen;shape=oval]; + + port1 [label="Port #1";shape=oval]; + port2 [label="Port #2";shape=oval]; + port3 [label="Port #3";shape=oval]; + port4 [label="Port #4";shape=oval]; +} diff --git a/Documentation/gpu/dp-mst/topology-figure-2.dot b/Documentation/gpu/dp-mst/topology-figure-2.dot new file mode 100644 index 000000000000..4243dd1737cb --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-2.dot @@ -0,0 +1,56 @@ +digraph T { + /* Make sure our payloads are always drawn below the driver node */ + subgraph cluster_driver { + fillcolor = grey; + style = filled; + driver -> {payload1, payload2} [dir=none]; + } + + /* Driver malloc references */ + edge [style=dashed]; + driver -> port1; + driver -> port2; + driver -> port3:e; + driver -> port4 [color=red]; + + payload1:s -> port1:e; + payload2:s -> port3:e; + edge [style=""]; + + subgraph cluster_topology { + label="Topology Manager"; + labelloc=bottom; + + /* Topology references */ + mstb1 -> {port1, port2}; + port1 -> mstb2; + edge [color=red]; + port2 -> mstb3 -> {port3, port4}; + port3 -> mstb4; + edge [color=""]; + + /* Malloc references */ + edge [style=dashed;dir=back]; + mstb1 -> {port1, port2}; + port1 -> mstb2; + port2 -> mstb3 -> port3; + edge [color=red]; + mstb3 -> port4; + port3 -> mstb4; + } + + mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen]; + mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen]; + mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen]; + mstb4 [label="MSTB #4";style=filled;fillcolor=grey]; + + port1 [label="Port #1"]; + port2 [label="Port #2"]; + port3 [label="Port #3"]; + port4 [label="Port #4";style=filled;fillcolor=grey]; + + driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; + + payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; + payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue]; +} diff --git a/Documentation/gpu/dp-mst/topology-figure-3.dot b/Documentation/gpu/dp-mst/topology-figure-3.dot new file mode 100644 index 000000000000..6cd78d06778b --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-3.dot @@ -0,0 +1,59 @@ +digraph T { + /* Make sure our payloads are always drawn below the driver node */ + subgraph cluster_driver { + fillcolor = grey; + style = filled; + edge [dir=none]; + driver -> payload1; + driver -> payload2 [penwidth=3]; + edge [dir=""]; + } + + /* Driver malloc references */ + edge [style=dashed]; + driver -> port1; + driver -> port2; + driver -> port3:e; + driver -> port4 [color=grey]; + payload1:s -> port1:e; + payload2:s -> port3:e [penwidth=3]; + edge [style=""]; + + subgraph cluster_topology { + label="Topology Manager"; + labelloc=bottom; + + /* Topology references */ + mstb1 -> {port1, port2}; + port1 -> mstb2; + edge [color=grey]; + port2 -> mstb3 -> {port3, port4}; + port3 -> mstb4; + edge [color=""]; + + /* Malloc references */ + edge [style=dashed;dir=back]; + mstb1 -> {port1, port2}; + port1 -> mstb2; + port2 -> mstb3 [penwidth=3]; + mstb3 -> port3 [penwidth=3]; + edge [color=grey]; + mstb3 -> port4; + port3 -> mstb4; + } + + mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen]; + mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen]; + mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;penwidth=3]; + mstb4 [label="MSTB #4";style=filled;fillcolor=grey]; + + port1 [label="Port #1"]; + port2 [label="Port #2";penwidth=5]; + port3 [label="Port #3";penwidth=3]; + port4 [label="Port #4";style=filled;fillcolor=grey]; + + driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; + + payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; + payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue;penwidth=3]; +} diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 5ee9674fb9e9..2caf21effd28 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -143,6 +143,9 @@ Device Instance and Driver Handling .. kernel-doc:: drivers/gpu/drm/drm_drv.c :doc: driver instance overview +.. kernel-doc:: include/drm/drm_device.h + :internal: + .. kernel-doc:: include/drm/drm_drv.h :internal: @@ -230,6 +233,15 @@ Printer .. kernel-doc:: drivers/gpu/drm/drm_print.c :export: +Utilities +--------- + +.. kernel-doc:: include/drm/drm_util.h + :doc: drm utils + +.. kernel-doc:: include/drm/drm_util.h + :internal: + Legacy Support Code =================== diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index b422eb8edf16..fbd11b2fe5b5 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -116,8 +116,6 @@ Framebuffer CMA Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c :export: -.. _drm_bridges: - Framebuffer GEM Helper Reference ================================ @@ -127,6 +125,8 @@ Framebuffer GEM Helper Reference .. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c :export: +.. _drm_bridges: + Bridges ======= @@ -208,18 +208,40 @@ Display Port Dual Mode Adaptor Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c :export: -Display Port MST Helper Functions Reference -=========================================== +Display Port MST Helpers +======================== + +Overview +-------- .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c :doc: dp mst helper +.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c + :doc: Branch device and port refcounting + +Functions Reference +------------------- + .. kernel-doc:: include/drm/drm_dp_mst_helper.h :internal: .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c :export: +Topology Lifetime Internals +--------------------------- + +These functions aren't exported to drivers, but are documented here to help make +the MST topology helpers easier to understand + +.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c + :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb + drm_dp_mst_topology_put_mstb + drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port + drm_dp_mst_topology_put_port + drm_dp_mst_get_mstb_malloc drm_dp_mst_put_mstb_malloc + MIPI DSI Helper Functions Reference =================================== diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 41da7b06195c..38360ede1221 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -82,30 +82,6 @@ events for atomic commits correctly. But fixing these bugs is good anyway. Contact: Daniel Vetter, respective driver maintainers -Better manual-upload support for atomic ---------------------------------------- - -This would be especially useful for tinydrm: - -- Add a struct drm_rect dirty_clip to drm_crtc_state. When duplicating the - crtc state, clear that to the max values, x/y = 0 and w/h = MAX_INT, in - __drm_atomic_helper_crtc_duplicate_state(). - -- Move tinydrm_merge_clips into drm_framebuffer.c, dropping the tinydrm\_ - prefix ofc and using drm_fb\_. drm_framebuffer.c makes sense since this - is a function useful to implement the fb->dirty function. - -- Create a new drm_fb_dirty function which does essentially what e.g. - mipi_dbi_fb_dirty does. You can use e.g. drm_atomic_helper_update_plane as the - template. But instead of doing a simple full-screen plane update, this new - helper also sets crtc_state->dirty_clip to the right coordinates. And of - course it needs to check whether the fb is actually active (and maybe where), - so there's some book-keeping involved. There's also some good fun involved in - scaling things appropriately. For that case we might simply give up and - declare the entire area covered by the plane as dirty. - -Contact: Noralf Trønnes, Daniel Vetter - Fallout from atomic KMS ----------------------- @@ -209,6 +185,36 @@ Would be great to refactor this all into a set of small common helpers. Contact: Daniel Vetter +Generic fbdev defio support +--------------------------- + +The defio support code in the fbdev core has some very specific requirements, +which means drivers need to have a special framebuffer for fbdev. Which prevents +us from using the generic fbdev emulation code everywhere. The main issue is +that it uses some fields in struct page itself, which breaks shmem gem objects +(and other things). + +Possible solution would be to write our own defio mmap code in the drm fbdev +emulation. It would need to fully wrap the existing mmap ops, forwarding +everything after it has done the write-protect/mkwrite trickery: + +- In the drm_fbdev_fb_mmap helper, if we need defio, change the + default page prots to write-protected with something like this:: + + vma->vm_page_prot = pgprot_wrprotect(vma->vm_page_prot); + +- Set the mkwrite and fsync callbacks with similar implementions to the core + fbdev defio stuff. These should all work on plain ptes, they don't actually + require a struct page. uff. These should all work on plain ptes, they don't + actually require a struct page. + +- Track the dirty pages in a separate structure (bitfield with one bit per page + should work) to avoid clobbering struct page. + +Might be good to also have some igt testcases for this. + +Contact: Daniel Vetter, Noralf Tronnes + Put a reservation_object into drm_gem_object -------------------------------------------- @@ -429,21 +435,10 @@ those drivers as simple as possible, so lots of room for refactoring: one of the ideas for having a shared dsi/dbi helper, abstracting away the transport details more. -- tinydrm_gem_cma_prime_import_sg_table should probably go into the cma - helpers, as a _vmapped variant (since not every driver needs the vmap). - And tinydrm_gem_cma_free_object could the be merged into - drm_gem_cma_free_object(). - -- tinydrm_fb_create we could move into drm_simple_pipe, only need to add - the fb_create hook to drm_simple_pipe_funcs, which would again simplify a - bunch of things (since it gives you a one-stop vfunc for simple drivers). - - Quick aside: The unregister devm stuff is kinda getting the lifetimes of a drm_device wrong. Doesn't matter, since everyone else gets it wrong too :-) -- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above. - Contact: Noralf Trønnes, Daniel Vetter AMD DC Display Driver diff --git a/MAINTAINERS b/MAINTAINERS index 6b510ef800f6..6e1cef2f21d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4910,6 +4910,13 @@ DRM DRIVER FOR TDFX VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/tdfx/ +DRM DRIVER FOR TPO TPG110 PANELS +M: Linus Walleij <linus.walleij@linaro.org> +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +F: drivers/gpu/drm/panel/panel-tpo-tpg110.c +F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt + DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS M: Dave Airlie <airlied@redhat.com> R: Sean Paul <sean@poorly.run> @@ -4918,6 +4925,16 @@ S: Odd Fixes F: drivers/gpu/drm/udl/ T: git git://anongit.freedesktop.org/drm/drm-misc +DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) +M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> +R: Haneen Mohammed <hamohammed.sa@gmail.com> +R: Daniel Vetter <daniel@ffwll.ch> +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +L: dri-devel@lists.freedesktop.org +F: drivers/gpu/drm/vkms/ +F: Documentation/gpu/vkms.rst + DRM DRIVER FOR VMWARE VIRTUAL GPU M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> M: Thomas Hellstrom <thellstrom@vmware.com> diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index ca18e0d23df9..c14cfaea92e2 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/acpi.h> +#include <linux/mfd/intel_soc_pmic.h> #include <linux/regmap.h> #include <acpi/acpi_lpat.h> #include "intel_pmic.h" @@ -36,6 +37,8 @@ struct intel_pmic_opregion { struct intel_pmic_regs_handler_ctx ctx; }; +static struct intel_pmic_opregion *intel_pmic_opregion; + static int pmic_get_reg_bit(int address, struct pmic_table *table, int count, int *reg, int *bit) { @@ -304,6 +307,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, } opregion->data = d; + intel_pmic_opregion = opregion; return 0; out_remove_thermal_handler: @@ -319,3 +323,60 @@ out_error: return ret; } EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); + +/** + * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence + * @i2c_address: I2C client address for the PMIC + * @reg_address: PMIC register address + * @value: New value for the register bits to change + * @mask: Mask indicating which register bits to change + * + * DSI LCD panels describe an initialization sequence in the i915 VBT (Video + * BIOS Tables) using so called MIPI sequences. One possible element in these + * sequences is a PMIC specific element of 15 bytes. + * + * This function executes these PMIC specific elements sending the embedded + * commands to the PMIC. + * + * Return 0 on success, < 0 on failure. + */ +int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, + u32 value, u32 mask) +{ + struct intel_pmic_opregion_data *d; + int ret; + + if (!intel_pmic_opregion) { + pr_warn("%s: No PMIC registered\n", __func__); + return -ENXIO; + } + + d = intel_pmic_opregion->data; + + mutex_lock(&intel_pmic_opregion->lock); + + if (d->exec_mipi_pmic_seq_element) { + ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap, + i2c_address, reg_address, + value, mask); + } else if (d->pmic_i2c_address) { + if (i2c_address == d->pmic_i2c_address) { + ret = regmap_update_bits(intel_pmic_opregion->regmap, + reg_address, mask, value); + } else { + pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n", + __func__, i2c_address, reg_address, value, mask); + ret = -ENXIO; + } + } else { + pr_warn("%s: Not implemented\n", __func__); + pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n", + __func__, i2c_address, reg_address, value, mask); + ret = -EOPNOTSUPP; + } + + mutex_unlock(&intel_pmic_opregion->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element); diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h index 095afc96952e..89379476a1df 100644 --- a/drivers/acpi/pmic/intel_pmic.h +++ b/drivers/acpi/pmic/intel_pmic.h @@ -15,10 +15,14 @@ struct intel_pmic_opregion_data { int (*update_aux)(struct regmap *r, int reg, int raw_temp); int (*get_policy)(struct regmap *r, int reg, int bit, u64 *value); int (*update_policy)(struct regmap *r, int reg, int bit, int enable); + int (*exec_mipi_pmic_seq_element)(struct regmap *r, u16 i2c_address, + u32 reg_address, u32 value, u32 mask); struct pmic_table *power_table; int power_table_count; struct pmic_table *thermal_table; int thermal_table_count; + /* For generic exec_mipi_pmic_seq_element handling */ + int pmic_i2c_address; }; int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d); diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 078b0448f30a..7ffd5624b8e1 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -231,6 +231,24 @@ static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0); } +static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap, + u16 i2c_client_address, + u32 reg_address, + u32 value, u32 mask) +{ + u32 address; + + if (i2c_client_address > 0xff || reg_address > 0xff) { + pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n", + __func__, i2c_client_address, reg_address); + return -ERANGE; + } + + address = (i2c_client_address << 8) | reg_address; + + return regmap_update_bits(regmap, address, mask, value); +} + /* * The thermal table and ops are empty, we do not support the Thermal opregion * (DPTF) due to lacking documentation. @@ -238,6 +256,7 @@ static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { .get_power = intel_cht_wc_pmic_get_power, .update_power = intel_cht_wc_pmic_update_power, + .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element, .power_table = power_table, .power_table_count = ARRAY_SIZE(power_table), }; diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 2579675b7082..1b49cbb1e21e 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -240,6 +240,7 @@ static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { .power_table_count = ARRAY_SIZE(power_table), .thermal_table = thermal_table, .thermal_table_count = ARRAY_SIZE(thermal_table), + .pmic_i2c_address = 0x34, }; static acpi_status intel_xpower_pmic_gpio_handler(u32 function, diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4385f00e1d05..bd943a71756c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -170,10 +170,6 @@ config DRM_KMS_CMA_HELPER bool depends on DRM select DRM_GEM_CMA_HELPER - select DRM_KMS_FB_HELPER - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT help Choose this if you need the KMS CMA helper functions diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d7dddb936f84..c898b19f335a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2722,7 +2722,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_irq_disable_all(adev); if (adev->mode_info.mode_config_initialized){ if (!amdgpu_device_has_dc_support(adev)) - drm_crtc_force_disable_all(adev->ddev); + drm_helper_force_disable_all(adev->ddev); else drm_atomic_helper_shutdown(adev->ddev); } diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index e9934de1b9cf..dd30f4e61a8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -27,6 +27,8 @@ #include <linux/slab.h> #include <asm/unaligned.h> +#include <drm/drm_util.h> + #define ATOM_DEBUG #include "atom.h" diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 4cfecdce29a3..1f0426d2fc2a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1682,7 +1682,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder, dce_v10_0_audio_write_sad_regs(encoder); dce_v10_0_audio_write_latency_fields(encoder, mode); - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) { DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); return; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 7c868916d90f..2280b971d758 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1724,7 +1724,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder, dce_v11_0_audio_write_sad_regs(encoder); dce_v11_0_audio_write_latency_fields(encoder, mode); - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) { DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); return; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 17eaaba36017..db443ec53d3a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1423,6 +1423,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, struct amdgpu_device *adev = dev->dev_private; struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; + struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); struct hdmi_avi_infoframe frame; u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; uint8_t *payload = buffer + 3; @@ -1430,7 +1431,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, ssize_t err; u32 tmp; - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) { DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); return; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 8c0576978d36..13da915991dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1616,7 +1616,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, dce_v8_0_audio_write_sad_regs(encoder); dce_v8_0_audio_write_latency_fields(encoder, mode); - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) { DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); return; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 60da1222afaa..748d6ff3e4f3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -137,6 +137,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) drm_encoder_cleanup(&amdgpu_encoder->base); kfree(amdgpu_encoder); drm_connector_cleanup(connector); + drm_dp_mst_put_port_malloc(amdgpu_dm_connector->port); kfree(amdgpu_dm_connector); } @@ -309,7 +310,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, amdgpu_dm_connector_funcs_reset(connector); DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n", - aconnector, connector->base.id, aconnector->mst_port); + aconnector, connector->base.id, aconnector->mst_port); + + drm_dp_mst_get_port_malloc(port); DRM_DEBUG_KMS(":%d\n", connector->base.id); @@ -325,12 +328,12 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n", - aconnector, connector->base.id, aconnector->mst_port); + aconnector, connector->base.id, aconnector->mst_port); - aconnector->port = NULL; if (aconnector->dc_sink) { amdgpu_dm_update_freesync_caps(connector, NULL); - dc_link_remove_remote_sink(aconnector->dc_link, aconnector->dc_sink); + dc_link_remove_remote_sink(aconnector->dc_link, + aconnector->dc_sink); dc_sink_release(aconnector->dc_sink); aconnector->dc_sink = NULL; } diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index 62f51f70606d..155ab177ce0b 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -16,8 +16,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_device.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_vblank.h> #include <drm/drm_plane_helper.h> #include <linux/clk.h> #include <linux/platform_data/simplefb.h> diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 206a76abf771..39a79f5718c4 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c @@ -16,12 +16,18 @@ #include <linux/clk.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_device.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_atomic_helper.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> #include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> #include "arcpgu.h" #include "arcpgu_regs.h" diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index 68629e614990..6530d88f7293 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c @@ -51,7 +51,6 @@ arcpgu_drm_connector_helper_funcs = { }; static const struct drm_connector_funcs arcpgu_drm_connector_funcs = { - .dpms = drm_helper_connector_dpms, .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = arcpgu_drm_connector_destroy, diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index da9360688b55..20dfb29561c2 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -270,13 +270,7 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) tm = adj->crtc_vtotal - adj->crtc_vsync_end; DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n", - crtc->base.id, crtc->name, - adj->base.id, adj->name, adj->vrefresh, adj->clock, - adj->crtc_hdisplay, adj->crtc_hsync_start, - adj->crtc_hsync_end, adj->crtc_htotal, - adj->crtc_vdisplay, adj->crtc_vsync_start, - adj->crtc_vsync_end, adj->crtc_vtotal, - adj->type, adj->flags); + crtc->base.id, crtc->name, DRM_MODE_ARG(adj)); DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); /* Now compute the divider for real */ diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index c2e41369adcf..2c9f8dd9733a 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -39,7 +39,9 @@ #include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_util.h> #include <drm/drm_crtc_helper.h> + #include "ast_drv.h" static void ast_dirty_update(struct ast_fbdev *afbdev, @@ -261,7 +263,7 @@ static void ast_fbdev_destroy(struct drm_device *dev, { struct ast_framebuffer *afb = &afbdev->afb; - drm_crtc_force_disable_all(dev); + drm_helper_force_disable_all(dev); drm_fb_helper_unregister_fbi(&afbdev->helper); if (afb->obj) { diff --git a/drivers/gpu/drm/bochs/Makefile b/drivers/gpu/drm/bochs/Makefile index 98ef60a19e8f..e9e0f8f5eb5b 100644 --- a/drivers/gpu/drm/bochs/Makefile +++ b/drivers/gpu/drm/bochs/Makefile @@ -1,3 +1,3 @@ -bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o +bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_hw.o obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index fb38c8b857b5..03711394f1ed 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -80,12 +80,6 @@ struct bochs_device { struct ttm_bo_device bdev; bool initialized; } ttm; - - /* fbdev */ - struct { - struct drm_framebuffer *fb; - struct drm_fb_helper helper; - } fb; }; struct bochs_bo { @@ -121,8 +115,9 @@ int bochs_hw_init(struct drm_device *dev); void bochs_hw_fini(struct drm_device *dev); void bochs_hw_setmode(struct bochs_device *bochs, - struct drm_display_mode *mode, - const struct drm_format_info *format); + struct drm_display_mode *mode); +void bochs_hw_setformat(struct bochs_device *bochs, + const struct drm_format_info *format); void bochs_hw_setbase(struct bochs_device *bochs, int x, int y, u64 addr); int bochs_hw_load_edid(struct bochs_device *bochs); @@ -141,15 +136,19 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset); -int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr); +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag); int bochs_bo_unpin(struct bochs_bo *bo); +int bochs_gem_prime_pin(struct drm_gem_object *obj); +void bochs_gem_prime_unpin(struct drm_gem_object *obj); +void *bochs_gem_prime_vmap(struct drm_gem_object *obj); +void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +int bochs_gem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma); + /* bochs_kms.c */ int bochs_kms_init(struct bochs_device *bochs); void bochs_kms_fini(struct bochs_device *bochs); /* bochs_fbdev.c */ -int bochs_fbdev_init(struct bochs_device *bochs); -void bochs_fbdev_fini(struct bochs_device *bochs); - extern const struct drm_mode_config_funcs bochs_mode_funcs; diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index f3dd66ae990a..cea42ac64d7e 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -16,10 +16,6 @@ static int bochs_modeset = -1; module_param_named(modeset, bochs_modeset, int, 0444); MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting"); -static bool enable_fbdev = true; -module_param_named(fbdev, enable_fbdev, bool, 0444); -MODULE_PARM_DESC(fbdev, "register fbdev device"); - /* ---------------------------------------------------------------------- */ /* drm interface */ @@ -27,7 +23,6 @@ static void bochs_unload(struct drm_device *dev) { struct bochs_device *bochs = dev->dev_private; - bochs_fbdev_fini(bochs); bochs_kms_fini(bochs); bochs_mm_fini(bochs); bochs_hw_fini(dev); @@ -58,9 +53,6 @@ static int bochs_load(struct drm_device *dev) if (ret) goto err; - if (enable_fbdev) - bochs_fbdev_init(bochs); - return 0; err: @@ -81,7 +73,8 @@ static const struct file_operations bochs_fops = { }; static struct drm_driver bochs_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET, + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | + DRIVER_PRIME, .fops = &bochs_fops, .name = "bochs-drm", .desc = "bochs dispi vga interface (qemu stdvga)", @@ -91,6 +84,14 @@ static struct drm_driver bochs_driver = { .gem_free_object_unlocked = bochs_gem_free_object, .dumb_create = bochs_dumb_create, .dumb_map_offset = bochs_dumb_mmap_offset, + + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_pin = bochs_gem_prime_pin, + .gem_prime_unpin = bochs_gem_prime_unpin, + .gem_prime_vmap = bochs_gem_prime_vmap, + .gem_prime_vunmap = bochs_gem_prime_vunmap, + .gem_prime_mmap = bochs_gem_prime_mmap, }; /* ---------------------------------------------------------------------- */ @@ -101,27 +102,16 @@ static int bochs_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct bochs_device *bochs = drm_dev->dev_private; - - drm_kms_helper_poll_disable(drm_dev); - - drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 1); - return 0; + return drm_mode_config_helper_suspend(drm_dev); } static int bochs_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct bochs_device *bochs = drm_dev->dev_private; - - drm_helper_resume_force_mode(drm_dev); - drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 0); - - drm_kms_helper_poll_enable(drm_dev); - return 0; + return drm_mode_config_helper_resume(drm_dev); } #endif @@ -165,6 +155,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, if (ret) goto err_unload; + drm_fbdev_generic_setup(dev, 32); return ret; err_unload: diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c deleted file mode 100644 index dd3c7df267da..000000000000 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include "bochs.h" -#include <drm/drm_gem_framebuffer_helper.h> - -/* ---------------------------------------------------------------------- */ - -static int bochsfb_mmap(struct fb_info *info, - struct vm_area_struct *vma) -{ - struct drm_fb_helper *fb_helper = info->par; - struct bochs_bo *bo = gem_to_bochs_bo(fb_helper->fb->obj[0]); - - return ttm_fbdev_mmap(vma, &bo->bo); -} - -static struct fb_ops bochsfb_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_mmap = bochsfb_mmap, -}; - -static int bochsfb_create_object(struct bochs_device *bochs, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_device *dev = bochs->dev; - struct drm_gem_object *gobj; - u32 size; - int ret = 0; - - size = mode_cmd->pitches[0] * mode_cmd->height; - ret = bochs_gem_create(dev, size, true, &gobj); - if (ret) - return ret; - - *gobj_p = gobj; - return ret; -} - -static int bochsfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct bochs_device *bochs = - container_of(helper, struct bochs_device, fb.helper); - struct fb_info *info; - struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_gem_object *gobj = NULL; - struct bochs_bo *bo = NULL; - int size, ret; - - if (sizes->surface_bpp != 32) - return -EINVAL; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = sizes->surface_width * 4; - mode_cmd.pixel_format = DRM_FORMAT_HOST_XRGB8888; - size = mode_cmd.pitches[0] * mode_cmd.height; - - /* alloc, pin & map bo */ - ret = bochsfb_create_object(bochs, &mode_cmd, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object %d\n", ret); - return ret; - } - - bo = gem_to_bochs_bo(gobj); - - ret = ttm_bo_reserve(&bo->bo, true, false, NULL); - if (ret) - return ret; - - ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); - if (ret) { - DRM_ERROR("failed to pin fbcon\n"); - ttm_bo_unreserve(&bo->bo); - return ret; - } - - ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, - &bo->kmap); - if (ret) { - DRM_ERROR("failed to kmap fbcon\n"); - ttm_bo_unreserve(&bo->bo); - return ret; - } - - ttm_bo_unreserve(&bo->bo); - - /* init fb device */ - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - DRM_ERROR("Failed to allocate fbi: %ld\n", PTR_ERR(info)); - return PTR_ERR(info); - } - - info->par = &bochs->fb.helper; - - fb = drm_gem_fbdev_fb_create(bochs->dev, sizes, 0, gobj, NULL); - if (IS_ERR(fb)) { - DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb)); - return PTR_ERR(fb); - } - - /* setup helper */ - bochs->fb.helper.fb = fb; - - strcpy(info->fix.id, "bochsdrmfb"); - - info->fbops = &bochsfb_ops; - - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); - drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width, - sizes->fb_height); - - info->screen_base = bo->kmap.virtual; - info->screen_size = size; - - drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node); - info->fix.smem_start = 0; - info->fix.smem_len = size; - return 0; -} - -static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = { - .fb_probe = bochsfb_create, -}; - -static struct drm_framebuffer * -bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 && - mode_cmd->pixel_format != DRM_FORMAT_BGRX8888) - return ERR_PTR(-EINVAL); - - return drm_gem_fb_create(dev, file, mode_cmd); -} - -const struct drm_mode_config_funcs bochs_mode_funcs = { - .fb_create = bochs_gem_fb_create, -}; - -int bochs_fbdev_init(struct bochs_device *bochs) -{ - return drm_fb_helper_fbdev_setup(bochs->dev, &bochs->fb.helper, - &bochs_fb_helper_funcs, 32, 1); -} - -void bochs_fbdev_fini(struct bochs_device *bochs) -{ - drm_fb_helper_fbdev_teardown(bochs->dev); -} diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index d0b4e1cee83e..3e04b2f0ec08 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -204,8 +204,7 @@ void bochs_hw_fini(struct drm_device *dev) } void bochs_hw_setmode(struct bochs_device *bochs, - struct drm_display_mode *mode, - const struct drm_format_info *format) + struct drm_display_mode *mode) { bochs->xres = mode->hdisplay; bochs->yres = mode->vdisplay; @@ -213,12 +212,8 @@ void bochs_hw_setmode(struct bochs_device *bochs, bochs->stride = mode->hdisplay * (bochs->bpp / 8); bochs->yres_virtual = bochs->fb_size / bochs->stride; - DRM_DEBUG_DRIVER("%dx%d @ %d bpp, format %c%c%c%c, vy %d\n", + DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", bochs->xres, bochs->yres, bochs->bpp, - (format->format >> 0) & 0xff, - (format->format >> 8) & 0xff, - (format->format >> 16) & 0xff, - (format->format >> 24) & 0xff, bochs->yres_virtual); bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ @@ -236,6 +231,16 @@ void bochs_hw_setmode(struct bochs_device *bochs, bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); +} + +void bochs_hw_setformat(struct bochs_device *bochs, + const struct drm_format_info *format) +{ + DRM_DEBUG_DRIVER("format %c%c%c%c\n", + (format->format >> 0) & 0xff, + (format->format >> 8) & 0xff, + (format->format >> 16) & 0xff, + (format->format >> 24) & 0xff); switch (format->format) { case DRM_FORMAT_XRGB8888: diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index f87c284dd93d..e9d5dbc34676 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -6,7 +6,10 @@ */ #include "bochs.h" +#include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_atomic_uapi.h> +#include <drm/drm_gem_framebuffer_helper.h> static int defx = 1024; static int defy = 768; @@ -18,115 +21,51 @@ MODULE_PARM_DESC(defy, "default y resolution"); /* ---------------------------------------------------------------------- */ -static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - default: - return; - } -} - -static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct bochs_device *bochs = - container_of(crtc, struct bochs_device, crtc); - struct bochs_bo *bo; - u64 gpu_addr = 0; - int ret; - - if (old_fb) { - bo = gem_to_bochs_bo(old_fb->obj[0]); - ret = ttm_bo_reserve(&bo->bo, true, false, NULL); - if (ret) { - DRM_ERROR("failed to reserve old_fb bo\n"); - } else { - bochs_bo_unpin(bo); - ttm_bo_unreserve(&bo->bo); - } - } - - if (WARN_ON(crtc->primary->fb == NULL)) - return -EINVAL; - - bo = gem_to_bochs_bo(crtc->primary->fb->obj[0]); - ret = ttm_bo_reserve(&bo->bo, true, false, NULL); - if (ret) - return ret; - - ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); - if (ret) { - ttm_bo_unreserve(&bo->bo); - return ret; - } - - ttm_bo_unreserve(&bo->bo); - bochs_hw_setbase(bochs, x, y, gpu_addr); - return 0; -} - -static int bochs_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, struct drm_framebuffer *old_fb) +static void bochs_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct bochs_device *bochs = container_of(crtc, struct bochs_device, crtc); - if (WARN_ON(crtc->primary->fb == NULL)) - return -EINVAL; - - bochs_hw_setmode(bochs, mode, crtc->primary->fb->format); - bochs_crtc_mode_set_base(crtc, x, y, old_fb); - return 0; + bochs_hw_setmode(bochs, &crtc->mode); } -static void bochs_crtc_prepare(struct drm_crtc *crtc) +static void bochs_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } -static void bochs_crtc_commit(struct drm_crtc *crtc) +static void bochs_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { -} + struct drm_device *dev = crtc->dev; + struct drm_pending_vblank_event *event; -static int bochs_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, - struct drm_modeset_acquire_ctx *ctx) -{ - struct bochs_device *bochs = - container_of(crtc, struct bochs_device, crtc); - struct drm_framebuffer *old_fb = crtc->primary->fb; - unsigned long irqflags; + if (crtc->state && crtc->state->event) { + unsigned long irqflags; - crtc->primary->fb = fb; - bochs_crtc_mode_set_base(crtc, 0, 0, old_fb); - if (event) { - spin_lock_irqsave(&bochs->dev->event_lock, irqflags); + spin_lock_irqsave(&dev->event_lock, irqflags); + event = crtc->state->event; + crtc->state->event = NULL; drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags); + spin_unlock_irqrestore(&dev->event_lock, irqflags); } - return 0; } + /* These provide the minimum set of functions required to handle a CRTC */ static const struct drm_crtc_funcs bochs_crtc_funcs = { - .set_config = drm_crtc_helper_set_config, + .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, - .page_flip = bochs_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; static const struct drm_crtc_helper_funcs bochs_helper_funcs = { - .dpms = bochs_crtc_dpms, - .mode_set = bochs_crtc_mode_set, - .mode_set_base = bochs_crtc_mode_set_base, - .prepare = bochs_crtc_prepare, - .commit = bochs_crtc_commit, + .mode_set_nofb = bochs_crtc_mode_set_nofb, + .atomic_enable = bochs_crtc_atomic_enable, + .atomic_flush = bochs_crtc_atomic_flush, }; static const uint32_t bochs_formats[] = { @@ -134,6 +73,59 @@ static const uint32_t bochs_formats[] = { DRM_FORMAT_BGRX8888, }; +static void bochs_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct bochs_device *bochs = plane->dev->dev_private; + struct bochs_bo *bo; + + if (!plane->state->fb) + return; + bo = gem_to_bochs_bo(plane->state->fb->obj[0]); + bochs_hw_setbase(bochs, + plane->state->crtc_x, + plane->state->crtc_y, + bo->bo.offset); + bochs_hw_setformat(bochs, plane->state->fb->format); +} + +static int bochs_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct bochs_bo *bo; + + if (!new_state->fb) + return 0; + bo = gem_to_bochs_bo(new_state->fb->obj[0]); + return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); +} + +static void bochs_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct bochs_bo *bo; + + if (!old_state->fb) + return; + bo = gem_to_bochs_bo(old_state->fb->obj[0]); + bochs_bo_unpin(bo); +} + +static const struct drm_plane_helper_funcs bochs_plane_helper_funcs = { + .atomic_update = bochs_plane_atomic_update, + .prepare_fb = bochs_plane_prepare_fb, + .cleanup_fb = bochs_plane_cleanup_fb, +}; + +static const struct drm_plane_funcs bochs_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_primary_helper_destroy, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + static struct drm_plane *bochs_primary_plane(struct drm_device *dev) { struct drm_plane *primary; @@ -146,16 +138,17 @@ static struct drm_plane *bochs_primary_plane(struct drm_device *dev) } ret = drm_universal_plane_init(dev, primary, 0, - &drm_primary_helper_funcs, + &bochs_plane_funcs, bochs_formats, ARRAY_SIZE(bochs_formats), NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) { kfree(primary); - primary = NULL; + return NULL; } + drm_plane_helper_add(primary, &bochs_plane_helper_funcs); return primary; } @@ -170,31 +163,6 @@ static void bochs_crtc_init(struct drm_device *dev) drm_crtc_helper_add(crtc, &bochs_helper_funcs); } -static void bochs_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ -} - -static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) -{ -} - -static void bochs_encoder_prepare(struct drm_encoder *encoder) -{ -} - -static void bochs_encoder_commit(struct drm_encoder *encoder) -{ -} - -static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { - .dpms = bochs_encoder_dpms, - .mode_set = bochs_encoder_mode_set, - .prepare = bochs_encoder_prepare, - .commit = bochs_encoder_commit, -}; - static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { .destroy = drm_encoder_cleanup, }; @@ -207,7 +175,6 @@ static void bochs_encoder_init(struct drm_device *dev) encoder->possible_crtcs = 0x1; drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); - drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); } @@ -266,6 +233,9 @@ static const struct drm_connector_funcs bochs_connector_connector_funcs = { .dpms = drm_helper_connector_dpms, .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 bochs_connector_init(struct drm_device *dev) @@ -287,6 +257,22 @@ static void bochs_connector_init(struct drm_device *dev) } } +static struct drm_framebuffer * +bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 && + mode_cmd->pixel_format != DRM_FORMAT_BGRX8888) + return ERR_PTR(-EINVAL); + + return drm_gem_fb_create(dev, file, mode_cmd); +} + +const struct drm_mode_config_funcs bochs_mode_funcs = { + .fb_create = bochs_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; int bochs_kms_init(struct bochs_device *bochs) { @@ -309,6 +295,8 @@ int bochs_kms_init(struct bochs_device *bochs) drm_connector_attach_encoder(&bochs->connector, &bochs->encoder); + drm_mode_config_reset(bochs->dev); + return 0; } diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 0980411e41bf..641a33f134ee 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -210,33 +210,28 @@ static void bochs_ttm_placement(struct bochs_bo *bo, int domain) bo->placement.num_busy_placement = c; } -static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) -{ - return bo->bo.offset; -} - -int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag) { struct ttm_operation_ctx ctx = { false, false }; int i, ret; if (bo->pin_count) { bo->pin_count++; - if (gpu_addr) - *gpu_addr = bochs_bo_gpu_offset(bo); return 0; } bochs_ttm_placement(bo, pl_flag); for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_reserve(&bo->bo, true, false, NULL); + if (ret) + return ret; ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); + ttm_bo_unreserve(&bo->bo); if (ret) return ret; bo->pin_count = 1; - if (gpu_addr) - *gpu_addr = bochs_bo_gpu_offset(bo); return 0; } @@ -256,7 +251,11 @@ int bochs_bo_unpin(struct bochs_bo *bo) for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_reserve(&bo->bo, true, false, NULL); + if (ret) + return ret; ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); + ttm_bo_unreserve(&bo->bo); if (ret) return ret; @@ -396,3 +395,52 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, drm_gem_object_put_unlocked(obj); return 0; } + +/* ---------------------------------------------------------------------- */ + +int bochs_gem_prime_pin(struct drm_gem_object *obj) +{ + struct bochs_bo *bo = gem_to_bochs_bo(obj); + + return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); +} + +void bochs_gem_prime_unpin(struct drm_gem_object *obj) +{ + struct bochs_bo *bo = gem_to_bochs_bo(obj); + + bochs_bo_unpin(bo); +} + +void *bochs_gem_prime_vmap(struct drm_gem_object *obj) +{ + struct bochs_bo *bo = gem_to_bochs_bo(obj); + bool is_iomem; + int ret; + + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); + if (ret) + return NULL; + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { + bochs_bo_unpin(bo); + return NULL; + } + return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); +} + +void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) +{ + struct bochs_bo *bo = gem_to_bochs_bo(obj); + + ttm_bo_kunmap(&bo->kmap); + bochs_bo_unpin(bo); +} + +int bochs_gem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct bochs_bo *bo = gem_to_bochs_bo(obj); + + return ttm_fbdev_mmap(vma, &bo->bo); +} diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 73d8ccb97742..2b6e0832d1cf 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -395,7 +395,7 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) #ifdef CONFIG_DRM_I2C_ADV7533 void adv7533_dsi_power_on(struct adv7511 *adv); void adv7533_dsi_power_off(struct adv7511 *adv); -void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode); +void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode); int adv7533_patch_registers(struct adv7511 *adv); int adv7533_patch_cec_registers(struct adv7511 *adv); int adv7533_attach_dsi(struct adv7511 *adv); @@ -411,7 +411,7 @@ static inline void adv7533_dsi_power_off(struct adv7511 *adv) } static inline void adv7533_mode_set(struct adv7511 *adv, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 85c2d407a52e..d0e98caa2e2a 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -676,8 +676,8 @@ static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, } static void adv7511_mode_set(struct adv7511 *adv7511, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adj_mode) { unsigned int low_refresh_rate; unsigned int hsync_polarity = 0; @@ -839,8 +839,8 @@ static void adv7511_bridge_disable(struct drm_bridge *bridge) } static void adv7511_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adj_mode) { struct adv7511 *adv = bridge_to_adv7511(bridge); diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 185b6d842166..5d5e7d9eded2 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -108,7 +108,7 @@ void adv7533_dsi_power_off(struct adv7511 *adv) regmap_write(adv->regmap_cec, 0x27, 0x0b); } -void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode) +void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode) { struct mipi_dsi_device *dsi = adv->dsi; int lanes, ret; diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index f8433c93f463..4cf7bc17ae14 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -1082,8 +1082,8 @@ static void anx78xx_bridge_disable(struct drm_bridge *bridge) } static void anx78xx_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); struct hdmi_avi_infoframe frame; @@ -1094,8 +1094,9 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge, mutex_lock(&anx78xx->lock); - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode, - false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &anx78xx->connector, + adjusted_mode); if (err) { DRM_ERROR("Failed to setup AVI infoframe: %d\n", err); goto unlock; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 753e96129ab7..4d5b47585834 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1361,8 +1361,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) } static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *orig_mode, - struct drm_display_mode *mode) + const struct drm_display_mode *orig_mode, + const struct drm_display_mode *mode) { struct analogix_dp_device *dp = bridge->driver_private; struct drm_display_info *display_info = &dp->connector.display_info; diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index f56c92f7af7c..ae8fc597eb38 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -11,11 +11,13 @@ #include <drm/drm_bridge.h> #include <drm/drm_panel.h> +#include <linux/gpio/consumer.h> #include <linux/of_graph.h> struct lvds_encoder { struct drm_bridge bridge; struct drm_bridge *panel_bridge; + struct gpio_desc *powerdown_gpio; }; static int lvds_encoder_attach(struct drm_bridge *bridge) @@ -28,54 +30,85 @@ static int lvds_encoder_attach(struct drm_bridge *bridge) bridge); } +static void lvds_encoder_enable(struct drm_bridge *bridge) +{ + struct lvds_encoder *lvds_encoder = container_of(bridge, + struct lvds_encoder, + bridge); + + if (lvds_encoder->powerdown_gpio) + gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0); +} + +static void lvds_encoder_disable(struct drm_bridge *bridge) +{ + struct lvds_encoder *lvds_encoder = container_of(bridge, + struct lvds_encoder, + bridge); + + if (lvds_encoder->powerdown_gpio) + gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); +} + static struct drm_bridge_funcs funcs = { .attach = lvds_encoder_attach, + .enable = lvds_encoder_enable, + .disable = lvds_encoder_disable, }; static int lvds_encoder_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct device_node *port; struct device_node *endpoint; struct device_node *panel_node; struct drm_panel *panel; struct lvds_encoder *lvds_encoder; - lvds_encoder = devm_kzalloc(&pdev->dev, sizeof(*lvds_encoder), - GFP_KERNEL); + lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return -ENOMEM; + lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(lvds_encoder->powerdown_gpio)) { + int err = PTR_ERR(lvds_encoder->powerdown_gpio); + + if (err != -EPROBE_DEFER) + dev_err(dev, "powerdown GPIO failure: %d\n", err); + return err; + } + /* Locate the panel DT node. */ - port = of_graph_get_port_by_id(pdev->dev.of_node, 1); + port = of_graph_get_port_by_id(dev->of_node, 1); if (!port) { - dev_dbg(&pdev->dev, "port 1 not found\n"); + dev_dbg(dev, "port 1 not found\n"); return -ENXIO; } endpoint = of_get_child_by_name(port, "endpoint"); of_node_put(port); if (!endpoint) { - dev_dbg(&pdev->dev, "no endpoint for port 1\n"); + dev_dbg(dev, "no endpoint for port 1\n"); return -ENXIO; } panel_node = of_graph_get_remote_port_parent(endpoint); of_node_put(endpoint); if (!panel_node) { - dev_dbg(&pdev->dev, "no remote endpoint for port 1\n"); + dev_dbg(dev, "no remote endpoint for port 1\n"); return -ENXIO; } panel = of_drm_find_panel(panel_node); of_node_put(panel_node); if (IS_ERR(panel)) { - dev_dbg(&pdev->dev, "panel not found, deferring probe\n"); + dev_dbg(dev, "panel not found, deferring probe\n"); return PTR_ERR(panel); } lvds_encoder->panel_bridge = - devm_drm_panel_bridge_add(&pdev->dev, - panel, DRM_MODE_CONNECTOR_LVDS); + devm_drm_panel_bridge_add(dev, panel, DRM_MODE_CONNECTOR_LVDS); if (IS_ERR(lvds_encoder->panel_bridge)) return PTR_ERR(lvds_encoder->panel_bridge); @@ -83,7 +116,7 @@ static int lvds_encoder_probe(struct platform_device *pdev) * but we need a bridge attached to our of_node for our user * to look up. */ - lvds_encoder->bridge.of_node = pdev->dev.of_node; + lvds_encoder->bridge.of_node = dev->of_node; lvds_encoder->bridge.funcs = &funcs; drm_bridge_add(&lvds_encoder->bridge); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 7cbaba213ef6..37baa79e95c3 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -134,8 +134,8 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { }; /** - * drm_panel_bridge_add - Creates a drm_bridge and drm_connector that - * just calls the appropriate functions from drm_panel. + * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that + * just calls the appropriate functions from &drm_panel. * * @panel: The drm_panel being wrapped. Must be non-NULL. * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be @@ -149,9 +149,12 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { * passed to drm_bridge_attach(). The drm_panel_prepare() and related * functions can be dropped from the encoder driver (they're now * called by the KMS helpers before calling into the encoder), along - * with connector creation. When done with the bridge, - * drm_bridge_detach() should be called as normal, then + * with connector creation. When done with the bridge (after + * drm_mode_config_cleanup() if the bridge has already been attached), then * drm_panel_bridge_remove() to free it. + * + * See devm_drm_panel_bridge_add() for an automatically manged version of this + * function. */ struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, u32 connector_type) @@ -210,6 +213,17 @@ static void devm_drm_panel_bridge_release(struct device *dev, void *res) drm_panel_bridge_remove(*bridge); } +/** + * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector + * that just calls the appropriate functions from &drm_panel. + * @dev: device to tie the bridge lifetime to + * @panel: The drm_panel being wrapped. Must be non-NULL. + * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be + * created. + * + * This is the managed version of drm_panel_bridge_add() which automatically + * calls drm_panel_bridge_remove() when @dev is unbound. + */ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, struct drm_panel *panel, u32 connector_type) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index bfa902013aa4..a5d58f7035c1 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -232,8 +232,8 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) } static void sii902x_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adj) + const struct drm_display_mode *mode, + const struct drm_display_mode *adj) { struct sii902x *sii902x = bridge_to_sii902x(bridge); struct regmap *regmap = sii902x->regmap; @@ -258,7 +258,8 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, if (ret) return; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &sii902x->connector, adj); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index a6e8f4591e63..0cc293a6ac24 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -1104,8 +1104,7 @@ static void sii8620_set_infoframes(struct sii8620 *ctx, int ret; ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, - mode, - true); + NULL, mode); if (ctx->use_packed_pixel) frm.avi.colorspace = HDMI_COLORSPACE_YUV422; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 2228689d9a5e..5cbb71a866d5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -5,6 +5,10 @@ * Copyright (c) 2017 Renesas Solutions Corp. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> */ + +#include <linux/dma-mapping.h> +#include <linux/module.h> + #include <drm/bridge/dw_hdmi.h> #include <sound/hdmi-codec.h> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 64c3cf027518..129f464cbeb1 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1344,7 +1344,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) u8 val; /* Initialise info frame from DRM mode */ - drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + drm_hdmi_avi_infoframe_from_display_mode(&frame, + &hdmi->connector, mode); if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV444; @@ -1998,8 +1999,8 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, } static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *orig_mode, - struct drm_display_mode *mode) + const struct drm_display_mode *orig_mode, + const struct drm_display_mode *mode) { struct dw_hdmi *hdmi = bridge->driver_private; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 2f4b145b73af..23a5977a3b0a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -248,7 +248,7 @@ static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi) * The controller should generate 2 frames before * preparing the peripheral. */ -static void dw_mipi_dsi_wait_for_two_frames(struct drm_display_mode *mode) +static void dw_mipi_dsi_wait_for_two_frames(const struct drm_display_mode *mode) { int refresh, two_frames; @@ -564,7 +564,7 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) } static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u32 val = 0, color = 0; @@ -607,7 +607,7 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) } static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { /* * TODO dw drv improvements @@ -642,7 +642,7 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) /* Get lane byte clock cycles. */ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, u32 hcomponent) { u32 frac, lbcc; @@ -658,7 +658,7 @@ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, } static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u32 htotal, hsa, hbp, lbcc; @@ -681,7 +681,7 @@ static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, } static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u32 vactive, vsa, vfp, vbp; @@ -818,7 +818,7 @@ static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi) } static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; void *priv_data = dsi->plat_data->priv_data; @@ -861,8 +861,8 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, } static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8e28e738cb52..4df07f4cbff5 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -203,7 +203,7 @@ struct tc_data { /* display edid */ struct edid *edid; /* current mode */ - struct drm_display_mode *mode; + const struct drm_display_mode *mode; u32 rev; u8 assr; @@ -648,7 +648,8 @@ err_dpcd_read: return ret; } -static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) +static int tc_set_video_mode(struct tc_data *tc, + const struct drm_display_mode *mode) { int ret; int vid_sync_dly; @@ -1113,8 +1114,8 @@ static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connec } static void tc_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adj) + const struct drm_display_mode *mode, + const struct drm_display_mode *adj) { struct tc_data *tc = bridge_to_tc(bridge); diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 4dd499c7d1ba..39df62acac69 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -10,6 +10,7 @@ */ #include <linux/module.h> #include <drm/drmP.h> +#include <drm/drm_util.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> @@ -256,6 +257,8 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, { struct drm_framebuffer *gfb = gfbdev->gfb; + drm_helper_force_disable_all(dev); + drm_fb_helper_unregister_fbi(&gfbdev->helper); vfree(gfbdev->sysram); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index ba7025041e46..138b2711d389 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -294,8 +294,8 @@ EXPORT_SYMBOL(drm_bridge_post_disable); * Note: the bridge passed should be the one closest to the encoder */ void drm_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { if (!bridge) return; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 1593dd6cdfb7..7dabbaf033a1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -93,15 +93,6 @@ struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx) } EXPORT_SYMBOL(drm_crtc_from_index); -/** - * drm_crtc_force_disable - Forcibly turn off a CRTC - * @crtc: CRTC to turn off - * - * Note: This should only be used by non-atomic legacy drivers. - * - * Returns: - * Zero on success, error code on failure. - */ int drm_crtc_force_disable(struct drm_crtc *crtc) { struct drm_mode_set set = { @@ -112,38 +103,6 @@ int drm_crtc_force_disable(struct drm_crtc *crtc) return drm_mode_set_config_internal(&set); } -EXPORT_SYMBOL(drm_crtc_force_disable); - -/** - * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs - * @dev: DRM device whose CRTCs to turn off - * - * Drivers may want to call this on unload to ensure that all displays are - * unlit and the GPU is in a consistent, low power state. Takes modeset locks. - * - * Note: This should only be used by non-atomic legacy drivers. For an atomic - * version look at drm_atomic_helper_shutdown(). - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_crtc_force_disable_all(struct drm_device *dev) -{ - struct drm_crtc *crtc; - int ret = 0; - - drm_modeset_lock_all(dev); - drm_for_each_crtc(crtc, dev) - if (crtc->enabled) { - ret = drm_crtc_force_disable(crtc); - if (ret) - goto out; - } -out: - drm_modeset_unlock_all(dev); - return ret; -} -EXPORT_SYMBOL(drm_crtc_force_disable_all); static unsigned int drm_num_crtcs(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a3c81850e755..747661f63fbb 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -93,6 +93,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) struct drm_connector_list_iter conn_iter; struct drm_device *dev = encoder->dev; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); + /* * We can expect this mutex to be locked if we are not panicking. * Locking is currently fubar in the panic handler. @@ -131,6 +133,8 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); + /* * We can expect this mutex to be locked if we are not panicking. * Locking is currently fubar in the panic handler. @@ -212,8 +216,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) */ void drm_helper_disable_unused_functions(struct drm_device *dev) { - if (drm_core_check_feature(dev, DRIVER_ATOMIC)) - DRM_ERROR("Called for atomic driver, this is not what you want.\n"); + WARN_ON(drm_drv_uses_atomic_modeset(dev)); drm_modeset_lock_all(dev); __drm_helper_disable_unused_functions(dev); @@ -281,6 +284,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_encoder *encoder; bool ret = true; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); + drm_warn_on_modeset_not_all_locked(dev); saved_enabled = crtc->enabled; @@ -386,9 +391,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (!encoder_funcs) continue; - DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", - encoder->base.id, encoder->name, - mode->base.id, mode->name); + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%s]\n", + encoder->base.id, encoder->name, mode->name); if (encoder_funcs->mode_set) encoder_funcs->mode_set(encoder, mode, adjusted_mode); @@ -540,6 +544,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, crtc_funcs = set->crtc->helper_private; + dev = set->crtc->dev; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); + if (!set->mode) set->fb = NULL; @@ -555,8 +562,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, return 0; } - dev = set->crtc->dev; - drm_warn_on_modeset_not_all_locked(dev); /* @@ -875,6 +880,8 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode) struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; + WARN_ON(drm_drv_uses_atomic_modeset(connector->dev)); + if (mode == connector->dpms) return 0; @@ -946,6 +953,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev) int encoder_dpms; bool ret; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); + drm_modeset_lock_all(dev); drm_for_each_crtc(crtc, dev) { @@ -984,3 +993,38 @@ void drm_helper_resume_force_mode(struct drm_device *dev) drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_helper_resume_force_mode); + +/** + * drm_helper_force_disable_all - Forcibly turn off all enabled CRTCs + * @dev: DRM device whose CRTCs to turn off + * + * Drivers may want to call this on unload to ensure that all displays are + * unlit and the GPU is in a consistent, low power state. Takes modeset locks. + * + * Note: This should only be used by non-atomic legacy drivers. For an atomic + * version look at drm_atomic_helper_shutdown(). + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_helper_force_disable_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + int ret = 0; + + drm_modeset_lock_all(dev); + drm_for_each_crtc(crtc, dev) + if (crtc->enabled) { + struct drm_mode_set set = { + .crtc = crtc, + }; + + ret = drm_mode_set_config_internal(&set); + if (ret) + goto out; + } +out: + drm_modeset_unlock_all(dev); + return ret; +} +EXPORT_SYMBOL(drm_helper_force_disable_all); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 86893448f486..216f2a9ee3d4 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -50,6 +50,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, const struct drm_framebuffer *fb); int drm_crtc_register_all(struct drm_device *dev); void drm_crtc_unregister_all(struct drm_device *dev); +int drm_crtc_force_disable(struct drm_crtc *crtc); struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index 31032407254d..e16aa5ae00b4 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -333,3 +333,44 @@ drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, return ret; } EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next); + +/** + * drm_atomic_helper_damage_merged - Merged plane damage + * @old_state: Old plane state for validation. + * @state: Plane state from which to iterate the damage clips. + * @rect: Returns the merged damage rectangle + * + * This function merges any valid plane damage clips into one rectangle and + * returns it in @rect. + * + * For details see: drm_atomic_helper_damage_iter_init() and + * drm_atomic_helper_damage_iter_next(). + * + * Returns: + * True if there is valid plane damage otherwise false. + */ +bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state, + struct drm_plane_state *state, + struct drm_rect *rect) +{ + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + bool valid = false; + + rect->x1 = INT_MAX; + rect->y1 = INT_MAX; + rect->x2 = 0; + rect->y2 = 0; + + drm_atomic_helper_damage_iter_init(&iter, old_state, state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + rect->x1 = min(rect->x1, clip.x1); + rect->y1 = min(rect->y1, clip.y1); + rect->x2 = max(rect->x2, clip.x2); + rect->y2 = max(rect->y2, clip.y2); + valid = true; + } + + return valid; +} +EXPORT_SYMBOL(drm_atomic_helper_damage_merged); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 2d6c491a0542..54120b6319e7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -154,6 +154,7 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate) default: WARN(1, "unknown DP link rate %d, using %x\n", link_rate, DP_LINK_BW_1_62); + /* fall through */ case 162000: return DP_LINK_BW_1_62; case 270000: @@ -171,6 +172,7 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) switch (link_bw) { default: WARN(1, "unknown DP link BW code %x, using 162000\n", link_bw); + /* fall through */ case DP_LINK_BW_1_62: return 162000; case DP_LINK_BW_2_7: @@ -192,11 +194,11 @@ drm_dp_dump_access(const struct drm_dp_aux *aux, const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-"; if (ret > 0) - drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n", - aux->name, offset, arrow, ret, min(ret, 20), buffer); + DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d) %*ph\n", + aux->name, offset, arrow, ret, min(ret, 20), buffer); else - drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d)\n", - aux->name, offset, arrow, ret); + DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d)\n", + aux->name, offset, arrow, ret); } /** @@ -552,6 +554,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], case DP_DS_16BPC: return 16; } + /* fall through */ default: return 0; } @@ -884,7 +887,8 @@ static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg, { msg->request = (i2c_msg->flags & I2C_M_RD) ? DP_AUX_I2C_READ : DP_AUX_I2C_WRITE; - msg->request |= DP_AUX_I2C_MOT; + if (!(i2c_msg->flags & I2C_M_STOP)) + msg->request |= DP_AUX_I2C_MOT; } /* @@ -1273,6 +1277,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x00, 0x22, 0xb9), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, /* LG LP140WF6-SPM1 eDP panel */ { OUI(0x00, 0x22, 0xb9), DEVICE_ID('s', 'i', 'v', 'a', 'r', 'T'), false, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, + /* Apple panels need some additional handling to support PSR */ + { OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) } }; #undef OUI diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 2ab16c9e6243..196ebba8af5f 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -46,7 +46,7 @@ static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, char *buf); static int test_calc_pbn_mode(void); -static void drm_dp_put_port(struct drm_dp_mst_port *port); +static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port); static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, int id, @@ -850,46 +850,212 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad) if (lct > 1) memcpy(mstb->rad, rad, lct / 2); INIT_LIST_HEAD(&mstb->ports); - kref_init(&mstb->kref); + kref_init(&mstb->topology_kref); + kref_init(&mstb->malloc_kref); return mstb; } -static void drm_dp_free_mst_port(struct kref *kref); - static void drm_dp_free_mst_branch_device(struct kref *kref) { - struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); - if (mstb->port_parent) { - if (list_empty(&mstb->port_parent->next)) - kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port); - } + struct drm_dp_mst_branch *mstb = + container_of(kref, struct drm_dp_mst_branch, malloc_kref); + + if (mstb->port_parent) + drm_dp_mst_put_port_malloc(mstb->port_parent); + kfree(mstb); } +/** + * DOC: Branch device and port refcounting + * + * Topology refcount overview + * ~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The refcounting schemes for &struct drm_dp_mst_branch and &struct + * drm_dp_mst_port are somewhat unusual. Both ports and branch devices have + * two different kinds of refcounts: topology refcounts, and malloc refcounts. + * + * Topology refcounts are not exposed to drivers, and are handled internally + * by the DP MST helpers. The helpers use them in order to prevent the + * in-memory topology state from being changed in the middle of critical + * operations like changing the internal state of payload allocations. This + * means each branch and port will be considered to be connected to the rest + * of the topology until it's topology refcount reaches zero. Additionally, + * for ports this means that their associated &struct drm_connector will stay + * registered with userspace until the port's refcount reaches 0. + * + * Malloc refcount overview + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Malloc references are used to keep a &struct drm_dp_mst_port or &struct + * drm_dp_mst_branch allocated even after all of its topology references have + * been dropped, so that the driver or MST helpers can safely access each + * branch's last known state before it was disconnected from the topology. + * When the malloc refcount of a port or branch reaches 0, the memory + * allocation containing the &struct drm_dp_mst_branch or &struct + * drm_dp_mst_port respectively will be freed. + * + * For &struct drm_dp_mst_branch, malloc refcounts are not currently exposed + * to drivers. As of writing this documentation, there are no drivers that + * have a usecase for accessing &struct drm_dp_mst_branch outside of the MST + * helpers. Exposing this API to drivers in a race-free manner would take more + * tweaking of the refcounting scheme, however patches are welcome provided + * there is a legitimate driver usecase for this. + * + * Refcount relationships in a topology + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Let's take a look at why the relationship between topology and malloc + * refcounts is designed the way it is. + * + * .. kernel-figure:: dp-mst/topology-figure-1.dot + * + * An example of topology and malloc refs in a DP MST topology with two + * active payloads. Topology refcount increments are indicated by solid + * lines, and malloc refcount increments are indicated by dashed lines. + * Each starts from the branch which incremented the refcount, and ends at + * the branch to which the refcount belongs to, i.e. the arrow points the + * same way as the C pointers used to reference a structure. + * + * As you can see in the above figure, every branch increments the topology + * refcount of it's children, and increments the malloc refcount of it's + * parent. Additionally, every payload increments the malloc refcount of it's + * assigned port by 1. + * + * So, what would happen if MSTB #3 from the above figure was unplugged from + * the system, but the driver hadn't yet removed payload #2 from port #3? The + * topology would start to look like the figure below. + * + * .. kernel-figure:: dp-mst/topology-figure-2.dot + * + * Ports and branch devices which have been released from memory are + * colored grey, and references which have been removed are colored red. + * + * Whenever a port or branch device's topology refcount reaches zero, it will + * decrement the topology refcounts of all its children, the malloc refcount + * of its parent, and finally its own malloc refcount. For MSTB #4 and port + * #4, this means they both have been disconnected from the topology and freed + * from memory. But, because payload #2 is still holding a reference to port + * #3, port #3 is removed from the topology but it's &struct drm_dp_mst_port + * is still accessible from memory. This also means port #3 has not yet + * decremented the malloc refcount of MSTB #3, so it's &struct + * drm_dp_mst_branch will also stay allocated in memory until port #3's + * malloc refcount reaches 0. + * + * This relationship is necessary because in order to release payload #2, we + * need to be able to figure out the last relative of port #3 that's still + * connected to the topology. In this case, we would travel up the topology as + * shown below. + * + * .. kernel-figure:: dp-mst/topology-figure-3.dot + * + * And finally, remove payload #2 by communicating with port #2 through + * sideband transactions. + */ + +/** + * drm_dp_mst_get_mstb_malloc() - Increment the malloc refcount of a branch + * device + * @mstb: The &struct drm_dp_mst_branch to increment the malloc refcount of + * + * Increments &drm_dp_mst_branch.malloc_kref. When + * &drm_dp_mst_branch.malloc_kref reaches 0, the memory allocation for @mstb + * will be released and @mstb may no longer be used. + * + * See also: drm_dp_mst_put_mstb_malloc() + */ +static void +drm_dp_mst_get_mstb_malloc(struct drm_dp_mst_branch *mstb) +{ + kref_get(&mstb->malloc_kref); + DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref)); +} + +/** + * drm_dp_mst_put_mstb_malloc() - Decrement the malloc refcount of a branch + * device + * @mstb: The &struct drm_dp_mst_branch to decrement the malloc refcount of + * + * Decrements &drm_dp_mst_branch.malloc_kref. When + * &drm_dp_mst_branch.malloc_kref reaches 0, the memory allocation for @mstb + * will be released and @mstb may no longer be used. + * + * See also: drm_dp_mst_get_mstb_malloc() + */ +static void +drm_dp_mst_put_mstb_malloc(struct drm_dp_mst_branch *mstb) +{ + DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref) - 1); + kref_put(&mstb->malloc_kref, drm_dp_free_mst_branch_device); +} + +static void drm_dp_free_mst_port(struct kref *kref) +{ + struct drm_dp_mst_port *port = + container_of(kref, struct drm_dp_mst_port, malloc_kref); + + drm_dp_mst_put_mstb_malloc(port->parent); + kfree(port); +} + +/** + * drm_dp_mst_get_port_malloc() - Increment the malloc refcount of an MST port + * @port: The &struct drm_dp_mst_port to increment the malloc refcount of + * + * Increments &drm_dp_mst_port.malloc_kref. When &drm_dp_mst_port.malloc_kref + * reaches 0, the memory allocation for @port will be released and @port may + * no longer be used. + * + * Because @port could potentially be freed at any time by the DP MST helpers + * if &drm_dp_mst_port.malloc_kref reaches 0, including during a call to this + * function, drivers that which to make use of &struct drm_dp_mst_port should + * ensure that they grab at least one main malloc reference to their MST ports + * in &drm_dp_mst_topology_cbs.add_connector. This callback is called before + * there is any chance for &drm_dp_mst_port.malloc_kref to reach 0. + * + * See also: drm_dp_mst_put_port_malloc() + */ +void +drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port) +{ + kref_get(&port->malloc_kref); + DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref)); +} +EXPORT_SYMBOL(drm_dp_mst_get_port_malloc); + +/** + * drm_dp_mst_put_port_malloc() - Decrement the malloc refcount of an MST port + * @port: The &struct drm_dp_mst_port to decrement the malloc refcount of + * + * Decrements &drm_dp_mst_port.malloc_kref. When &drm_dp_mst_port.malloc_kref + * reaches 0, the memory allocation for @port will be released and @port may + * no longer be used. + * + * See also: drm_dp_mst_get_port_malloc() + */ +void +drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port) +{ + DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref) - 1); + kref_put(&port->malloc_kref, drm_dp_free_mst_port); +} +EXPORT_SYMBOL(drm_dp_mst_put_port_malloc); + static void drm_dp_destroy_mst_branch_device(struct kref *kref) { - struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); + struct drm_dp_mst_branch *mstb = + container_of(kref, struct drm_dp_mst_branch, topology_kref); + struct drm_dp_mst_topology_mgr *mgr = mstb->mgr; struct drm_dp_mst_port *port, *tmp; bool wake_tx = false; - /* - * init kref again to be used by ports to remove mst branch when it is - * not needed anymore - */ - kref_init(kref); - - if (mstb->port_parent && list_empty(&mstb->port_parent->next)) - kref_get(&mstb->port_parent->kref); - - /* - * destroy all ports - don't need lock - * as there are no more references to the mst branch - * device at this point. - */ + mutex_lock(&mgr->lock); list_for_each_entry_safe(port, tmp, &mstb->ports, next) { list_del(&port->next); - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); } + mutex_unlock(&mgr->lock); /* drop any tx slots msg */ mutex_lock(&mstb->mgr->qlock); @@ -908,14 +1074,83 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) if (wake_tx) wake_up_all(&mstb->mgr->tx_waitq); - kref_put(kref, drm_dp_free_mst_branch_device); + drm_dp_mst_put_mstb_malloc(mstb); } -static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) +/** + * drm_dp_mst_topology_try_get_mstb() - Increment the topology refcount of a + * branch device unless its zero + * @mstb: &struct drm_dp_mst_branch to increment the topology refcount of + * + * Attempts to grab a topology reference to @mstb, if it hasn't yet been + * removed from the topology (e.g. &drm_dp_mst_branch.topology_kref has + * reached 0). Holding a topology reference implies that a malloc reference + * will be held to @mstb as long as the user holds the topology reference. + * + * Care should be taken to ensure that the user has at least one malloc + * reference to @mstb. If you already have a topology reference to @mstb, you + * should use drm_dp_mst_topology_get_mstb() instead. + * + * See also: + * drm_dp_mst_topology_get_mstb() + * drm_dp_mst_topology_put_mstb() + * + * Returns: + * * 1: A topology reference was grabbed successfully + * * 0: @port is no longer in the topology, no reference was grabbed + */ +static int __must_check +drm_dp_mst_topology_try_get_mstb(struct drm_dp_mst_branch *mstb) { - kref_put(&mstb->kref, drm_dp_destroy_mst_branch_device); + int ret = kref_get_unless_zero(&mstb->topology_kref); + + if (ret) + DRM_DEBUG("mstb %p (%d)\n", mstb, + kref_read(&mstb->topology_kref)); + + return ret; } +/** + * drm_dp_mst_topology_get_mstb() - Increment the topology refcount of a + * branch device + * @mstb: The &struct drm_dp_mst_branch to increment the topology refcount of + * + * Increments &drm_dp_mst_branch.topology_refcount without checking whether or + * not it's already reached 0. This is only valid to use in scenarios where + * you are already guaranteed to have at least one active topology reference + * to @mstb. Otherwise, drm_dp_mst_topology_try_get_mstb() must be used. + * + * See also: + * drm_dp_mst_topology_try_get_mstb() + * drm_dp_mst_topology_put_mstb() + */ +static void drm_dp_mst_topology_get_mstb(struct drm_dp_mst_branch *mstb) +{ + WARN_ON(kref_read(&mstb->topology_kref) == 0); + kref_get(&mstb->topology_kref); + DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref)); +} + +/** + * drm_dp_mst_topology_put_mstb() - release a topology reference to a branch + * device + * @mstb: The &struct drm_dp_mst_branch to release the topology reference from + * + * Releases a topology reference from @mstb by decrementing + * &drm_dp_mst_branch.topology_kref. + * + * See also: + * drm_dp_mst_topology_try_get_mstb() + * drm_dp_mst_topology_get_mstb() + */ +static void +drm_dp_mst_topology_put_mstb(struct drm_dp_mst_branch *mstb) +{ + DRM_DEBUG("mstb %p (%d)\n", + mstb, kref_read(&mstb->topology_kref) - 1); + kref_put(&mstb->topology_kref, drm_dp_destroy_mst_branch_device); +} static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) { @@ -930,19 +1165,18 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) case DP_PEER_DEVICE_MST_BRANCHING: mstb = port->mstb; port->mstb = NULL; - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); break; } } static void drm_dp_destroy_port(struct kref *kref) { - struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); + struct drm_dp_mst_port *port = + container_of(kref, struct drm_dp_mst_port, topology_kref); struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (!port->input) { - port->vcpi.num_slots = 0; - kfree(port->cached_edid); /* @@ -956,7 +1190,6 @@ static void drm_dp_destroy_port(struct kref *kref) * from an EDID retrieval */ mutex_lock(&mgr->destroy_connector_lock); - kref_get(&port->parent->kref); list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); @@ -967,25 +1200,95 @@ static void drm_dp_destroy_port(struct kref *kref) drm_dp_port_teardown_pdt(port, port->pdt); port->pdt = DP_PEER_DEVICE_NONE; } - kfree(port); + drm_dp_mst_put_port_malloc(port); } -static void drm_dp_put_port(struct drm_dp_mst_port *port) +/** + * drm_dp_mst_topology_try_get_port() - Increment the topology refcount of a + * port unless its zero + * @port: &struct drm_dp_mst_port to increment the topology refcount of + * + * Attempts to grab a topology reference to @port, if it hasn't yet been + * removed from the topology (e.g. &drm_dp_mst_port.topology_kref has reached + * 0). Holding a topology reference implies that a malloc reference will be + * held to @port as long as the user holds the topology reference. + * + * Care should be taken to ensure that the user has at least one malloc + * reference to @port. If you already have a topology reference to @port, you + * should use drm_dp_mst_topology_get_port() instead. + * + * See also: + * drm_dp_mst_topology_get_port() + * drm_dp_mst_topology_put_port() + * + * Returns: + * * 1: A topology reference was grabbed successfully + * * 0: @port is no longer in the topology, no reference was grabbed + */ +static int __must_check +drm_dp_mst_topology_try_get_port(struct drm_dp_mst_port *port) { - kref_put(&port->kref, drm_dp_destroy_port); + int ret = kref_get_unless_zero(&port->topology_kref); + + if (ret) + DRM_DEBUG("port %p (%d)\n", port, + kref_read(&port->topology_kref)); + + return ret; } -static struct drm_dp_mst_branch *drm_dp_mst_get_validated_mstb_ref_locked(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_branch *to_find) +/** + * drm_dp_mst_topology_get_port() - Increment the topology refcount of a port + * @port: The &struct drm_dp_mst_port to increment the topology refcount of + * + * Increments &drm_dp_mst_port.topology_refcount without checking whether or + * not it's already reached 0. This is only valid to use in scenarios where + * you are already guaranteed to have at least one active topology reference + * to @port. Otherwise, drm_dp_mst_topology_try_get_port() must be used. + * + * See also: + * drm_dp_mst_topology_try_get_port() + * drm_dp_mst_topology_put_port() + */ +static void drm_dp_mst_topology_get_port(struct drm_dp_mst_port *port) +{ + WARN_ON(kref_read(&port->topology_kref) == 0); + kref_get(&port->topology_kref); + DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->topology_kref)); +} + +/** + * drm_dp_mst_topology_put_port() - release a topology reference to a port + * @port: The &struct drm_dp_mst_port to release the topology reference from + * + * Releases a topology reference from @port by decrementing + * &drm_dp_mst_port.topology_kref. + * + * See also: + * drm_dp_mst_topology_try_get_port() + * drm_dp_mst_topology_get_port() + */ +static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port) +{ + DRM_DEBUG("port %p (%d)\n", + port, kref_read(&port->topology_kref) - 1); + kref_put(&port->topology_kref, drm_dp_destroy_port); +} + +static struct drm_dp_mst_branch * +drm_dp_mst_topology_get_mstb_validated_locked(struct drm_dp_mst_branch *mstb, + struct drm_dp_mst_branch *to_find) { struct drm_dp_mst_port *port; struct drm_dp_mst_branch *rmstb; - if (to_find == mstb) { - kref_get(&mstb->kref); + + if (to_find == mstb) return mstb; - } + list_for_each_entry(port, &mstb->ports, next) { if (port->mstb) { - rmstb = drm_dp_mst_get_validated_mstb_ref_locked(port->mstb, to_find); + rmstb = drm_dp_mst_topology_get_mstb_validated_locked( + port->mstb, to_find); if (rmstb) return rmstb; } @@ -993,27 +1296,37 @@ static struct drm_dp_mst_branch *drm_dp_mst_get_validated_mstb_ref_locked(struct return NULL; } -static struct drm_dp_mst_branch *drm_dp_get_validated_mstb_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) +static struct drm_dp_mst_branch * +drm_dp_mst_topology_get_mstb_validated(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb) { struct drm_dp_mst_branch *rmstb = NULL; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) - rmstb = drm_dp_mst_get_validated_mstb_ref_locked(mgr->mst_primary, mstb); + if (mgr->mst_primary) { + rmstb = drm_dp_mst_topology_get_mstb_validated_locked( + mgr->mst_primary, mstb); + + if (rmstb && !drm_dp_mst_topology_try_get_mstb(rmstb)) + rmstb = NULL; + } mutex_unlock(&mgr->lock); return rmstb; } -static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *to_find) +static struct drm_dp_mst_port * +drm_dp_mst_topology_get_port_validated_locked(struct drm_dp_mst_branch *mstb, + struct drm_dp_mst_port *to_find) { struct drm_dp_mst_port *port, *mport; list_for_each_entry(port, &mstb->ports, next) { - if (port == to_find) { - kref_get(&port->kref); + if (port == to_find) return port; - } + if (port->mstb) { - mport = drm_dp_mst_get_port_ref_locked(port->mstb, to_find); + mport = drm_dp_mst_topology_get_port_validated_locked( + port->mstb, to_find); if (mport) return mport; } @@ -1021,12 +1334,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ return NULL; } -static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) +static struct drm_dp_mst_port * +drm_dp_mst_topology_get_port_validated(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port) { struct drm_dp_mst_port *rport = NULL; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) - rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); + if (mgr->mst_primary) { + rport = drm_dp_mst_topology_get_port_validated_locked( + mgr->mst_primary, port); + + if (rport && !drm_dp_mst_topology_try_get_port(rport)) + rport = NULL; + } mutex_unlock(&mgr->lock); return rport; } @@ -1034,11 +1355,12 @@ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_t static struct drm_dp_mst_port *drm_dp_get_port(struct drm_dp_mst_branch *mstb, u8 port_num) { struct drm_dp_mst_port *port; + int ret; list_for_each_entry(port, &mstb->ports, next) { if (port->port_num == port_num) { - kref_get(&port->kref); - return port; + ret = drm_dp_mst_topology_try_get_port(port); + return ret ? port : NULL; } } @@ -1087,6 +1409,11 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) if (port->mstb) { port->mstb->mgr = port->mgr; port->mstb->port_parent = port; + /* + * Make sure this port's memory allocation stays + * around until it's child MSTB releases it + */ + drm_dp_mst_get_port_malloc(port); send_link = true; } @@ -1147,17 +1474,26 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, bool created = false; int old_pdt = 0; int old_ddps = 0; + port = drm_dp_get_port(mstb, port_msg->port_number); if (!port) { port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) return; - kref_init(&port->kref); + kref_init(&port->topology_kref); + kref_init(&port->malloc_kref); port->parent = mstb; port->port_num = port_msg->port_number; port->mgr = mstb->mgr; port->aux.name = "DPMST"; port->aux.dev = dev->dev; + + /* + * Make sure the memory allocation for our parent branch stays + * around until our own memory allocation is released + */ + drm_dp_mst_get_mstb_malloc(mstb); + created = true; } else { old_pdt = port->pdt; @@ -1177,18 +1513,20 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, for this list */ if (created) { mutex_lock(&mstb->mgr->lock); - kref_get(&port->kref); + drm_dp_mst_topology_get_port(port); list_add(&port->next, &mstb->ports); mutex_unlock(&mstb->mgr->lock); } if (old_ddps != port->ddps) { if (port->ddps) { - if (!port->input) - drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); + if (!port->input) { + drm_dp_send_enum_path_resources(mstb->mgr, + mstb, port); + } } else { port->available_pbn = 0; - } + } } if (old_pdt != port->pdt && !port->input) { @@ -1202,21 +1540,25 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, if (created && !port->input) { char proppath[255]; - build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath)); - port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); + build_mst_prop_path(mstb, port->port_num, proppath, + sizeof(proppath)); + port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, + port, + proppath); if (!port->connector) { /* remove it from the port list */ mutex_lock(&mstb->mgr->lock); list_del(&port->next); mutex_unlock(&mstb->mgr->lock); /* drop port list reference */ - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); goto out; } if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || port->pdt == DP_PEER_DEVICE_SST_SINK) && port->port_num >= DP_MST_LOGICAL_PORT_0) { - port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); + port->cached_edid = drm_get_edid(port->connector, + &port->aux.ddc); drm_connector_set_tile_property(port->connector); } (*mstb->mgr->cbs->register_connector)(port->connector); @@ -1224,7 +1566,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, out: /* put reference to this port */ - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); } static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, @@ -1259,7 +1601,7 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, dowork = true; } - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); if (dowork) queue_work(system_long_wq, &mstb->mgr->work); @@ -1270,7 +1612,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ { struct drm_dp_mst_branch *mstb; struct drm_dp_mst_port *port; - int i; + int i, ret; /* find the port by iterating down */ mutex_lock(&mgr->lock); @@ -1295,7 +1637,9 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ } } } - kref_get(&mstb->kref); + ret = drm_dp_mst_topology_try_get_mstb(mstb); + if (!ret) + mstb = NULL; out: mutex_unlock(&mgr->lock); return mstb; @@ -1325,19 +1669,22 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper( return NULL; } -static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid( - struct drm_dp_mst_topology_mgr *mgr, - uint8_t *guid) +static struct drm_dp_mst_branch * +drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr, + uint8_t *guid) { struct drm_dp_mst_branch *mstb; + int ret; /* find the port by iterating down */ mutex_lock(&mgr->lock); mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); - - if (mstb) - kref_get(&mstb->kref); + if (mstb) { + ret = drm_dp_mst_topology_try_get_mstb(mstb); + if (!ret) + mstb = NULL; + } mutex_unlock(&mgr->lock); return mstb; @@ -1362,10 +1709,11 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m drm_dp_send_enum_path_resources(mgr, mstb, port); if (port->mstb) { - mstb_child = drm_dp_get_validated_mstb_ref(mgr, port->mstb); + mstb_child = drm_dp_mst_topology_get_mstb_validated( + mgr, port->mstb); if (mstb_child) { drm_dp_check_and_send_link_address(mgr, mstb_child); - drm_dp_put_mst_branch_device(mstb_child); + drm_dp_mst_topology_put_mstb(mstb_child); } } } @@ -1375,16 +1723,19 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work); struct drm_dp_mst_branch *mstb; + int ret; mutex_lock(&mgr->lock); mstb = mgr->mst_primary; if (mstb) { - kref_get(&mstb->kref); + ret = drm_dp_mst_topology_try_get_mstb(mstb); + if (!ret) + mstb = NULL; } mutex_unlock(&mgr->lock); if (mstb) { drm_dp_check_and_send_link_address(mgr, mstb); - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); } } @@ -1695,22 +2046,40 @@ static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); } -static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_branch *mstb, - int *port_num) +/* + * Searches upwards in the topology starting from mstb to try to find the + * closest available parent of mstb that's still connected to the rest of the + * topology. This can be used in order to perform operations like releasing + * payloads, where the branch device which owned the payload may no longer be + * around and thus would require that the payload on the last living relative + * be freed instead. + */ +static struct drm_dp_mst_branch * +drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb, + int *port_num) { struct drm_dp_mst_branch *rmstb = NULL; struct drm_dp_mst_port *found_port; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) { + if (!mgr->mst_primary) + goto out; + + do { found_port = drm_dp_get_last_connected_port_to_mstb(mstb); + if (!found_port) + break; - if (found_port) { + if (drm_dp_mst_topology_try_get_mstb(found_port->parent)) { rmstb = found_port->parent; - kref_get(&rmstb->kref); *port_num = found_port->port_num; + } else { + /* Search again, starting from this parent */ + mstb = found_port->parent; } - } + } while (!rmstb); +out: mutex_unlock(&mgr->lock); return rmstb; } @@ -1726,19 +2095,15 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, u8 sinks[DRM_DP_MAX_SDP_STREAMS]; int i; - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) - return -EINVAL; - port_num = port->port_num; - mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); + mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); if (!mstb) { - mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); + mstb = drm_dp_get_last_connected_port_and_mstb(mgr, + port->parent, + &port_num); - if (!mstb) { - drm_dp_put_port(port); + if (!mstb) return -EINVAL; - } } txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -1757,17 +2122,24 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, drm_dp_queue_down_tx(mgr, txmsg); + /* + * FIXME: there is a small chance that between getting the last + * connected mstb and sending the payload message, the last connected + * mstb could also be removed from the topology. In the future, this + * needs to be fixed by restarting the + * drm_dp_get_last_connected_port_and_mstb() search in the event of a + * timeout if the topology is still connected to the system. + */ ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); if (ret > 0) { - if (txmsg->reply.reply_type == 1) { + if (txmsg->reply.reply_type == 1) ret = -EINVAL; - } else + else ret = 0; } kfree(txmsg); fail_put: - drm_dp_put_mst_branch_device(mstb); - drm_dp_put_port(port); + drm_dp_mst_topology_put_mstb(mstb); return ret; } @@ -1777,13 +2149,13 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_sideband_msg_tx *txmsg; int len, ret; - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return -EINVAL; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) { - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return -ENOMEM; } @@ -1799,7 +2171,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, ret = 0; } kfree(txmsg); - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return ret; } @@ -1872,15 +2244,16 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr, */ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) { - int i, j; - int cur_slots = 1; struct drm_dp_payload req_payload; struct drm_dp_mst_port *port; + int i, j; + int cur_slots = 1; mutex_lock(&mgr->payload_lock); for (i = 0; i < mgr->max_payloads; i++) { struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; struct drm_dp_payload *payload = &mgr->payloads[i]; + bool put_port = false; /* solve the current payloads - compare to the hw ones - update the hw view */ @@ -1888,11 +2261,20 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) if (vcpi) { port = container_of(vcpi, struct drm_dp_mst_port, vcpi); - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) { - mutex_unlock(&mgr->payload_lock); - return -EINVAL; + + /* Validated ports don't matter if we're releasing + * VCPI + */ + if (vcpi->num_slots) { + port = drm_dp_mst_topology_get_port_validated( + mgr, port); + if (!port) { + mutex_unlock(&mgr->payload_lock); + return -EINVAL; + } + put_port = true; } + req_payload.num_slots = vcpi->num_slots; req_payload.vcpi = vcpi->vcpi; } else { @@ -1924,8 +2306,8 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) } cur_slots += req_payload.num_slots; - if (port) - drm_dp_put_port(port); + if (put_port) + drm_dp_mst_topology_put_port(port); } for (i = 0; i < mgr->max_payloads; i++) { @@ -2024,7 +2406,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; - mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); + mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); if (!mstb) return -EINVAL; @@ -2048,7 +2430,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, } kfree(txmsg); fail_put: - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); return ret; } @@ -2158,7 +2540,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms /* give this the main reference */ mgr->mst_primary = mstb; - kref_get(&mgr->mst_primary->kref); + drm_dp_mst_topology_get_mstb(mgr->mst_primary); ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); @@ -2192,7 +2574,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms out_unlock: mutex_unlock(&mgr->lock); if (mstb) - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); return ret; } @@ -2357,7 +2739,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) mgr->down_rep_recv.initial_hdr.lct, mgr->down_rep_recv.initial_hdr.rad[0], mgr->down_rep_recv.msg[0]); - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); return 0; } @@ -2368,7 +2750,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) } memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); mutex_lock(&mgr->qlock); txmsg->state = DRM_DP_SIDEBAND_TX_RX; @@ -2441,7 +2823,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) } if (mstb) - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); } @@ -2501,7 +2883,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector enum drm_connector_status status = connector_status_disconnected; /* we need to search for the port in the mgr in case its gone */ - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return connector_status_disconnected; @@ -2526,7 +2908,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector break; } out: - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return status; } EXPORT_SYMBOL(drm_dp_mst_detect_port); @@ -2543,11 +2925,11 @@ bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, { bool ret = false; - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return ret; ret = port->has_audio; - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return ret; } EXPORT_SYMBOL(drm_dp_mst_port_has_audio); @@ -2567,7 +2949,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ struct edid *edid = NULL; /* we need to search for the port in the mgr in case its gone */ - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return NULL; @@ -2578,7 +2960,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ drm_connector_set_tile_property(connector); } port->has_audio = drm_detect_monitor_audio(edid); - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return edid; } EXPORT_SYMBOL(drm_dp_mst_get_edid); @@ -2629,43 +3011,98 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, } /** - * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state + * drm_dp_atomic_find_vcpi_slots() - Find and add VCPI slots to the state * @state: global atomic state * @mgr: MST topology manager for the port * @port: port to find vcpi slots for * @pbn: bandwidth required for the mode in PBN * - * RETURNS: - * Total slots in the atomic state assigned for this port or error + * Allocates VCPI slots to @port, replacing any previous VCPI allocations it + * may have had. Any atomic drivers which support MST must call this function + * in their &drm_encoder_helper_funcs.atomic_check() callback to change the + * current VCPI allocation for the new state, but only when + * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set + * to ensure compatibility with userspace applications that still use the + * legacy modesetting UAPI. + * + * Allocations set by this function are not checked against the bandwidth + * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). + * + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. + * + * See also: + * drm_dp_atomic_release_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * Total slots in the atomic state assigned for this port, or a negative error + * code if the port no longer exists */ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn) { struct drm_dp_mst_topology_state *topology_state; - int req_slots; + struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; + int prev_slots, req_slots, ret; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) return PTR_ERR(topology_state); - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (port == NULL) return -EINVAL; - req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", - req_slots, topology_state->avail_slots); - if (req_slots > topology_state->avail_slots) { - drm_dp_put_port(port); - return -ENOSPC; + /* Find the current allocation for this port, if any */ + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + vcpi = pos; + prev_slots = vcpi->vcpi; + + /* + * This should never happen, unless the driver tries + * releasing and allocating the same VCPI allocation, + * which is an error + */ + if (WARN_ON(!prev_slots)) { + DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", + port); + return -EINVAL; + } + + break; + } } + if (!vcpi) + prev_slots = 0; + + req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - topology_state->avail_slots -= req_slots; - DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", + port->connector->base.id, port->connector->name, + port, prev_slots, req_slots); + + /* Add the new allocation to the state */ + if (!vcpi) { + vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) { + ret = -ENOMEM; + goto out; + } + + drm_dp_mst_get_port_malloc(port); + vcpi->port = port; + list_add(&vcpi->next, &topology_state->vcpis); + } + vcpi->vcpi = req_slots; - drm_dp_put_port(port); - return req_slots; + ret = req_slots; +out: + drm_dp_mst_topology_put_port(port); + return ret; } EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); @@ -2673,31 +3110,57 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots * @state: global atomic state * @mgr: MST topology manager for the port - * @slots: number of vcpi slots to release + * @port: The port to release the VCPI slots from * - * RETURNS: - * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or - * negative error code + * Releases any VCPI slots that have been allocated to a port in the atomic + * state. Any atomic drivers which support MST must call this function in + * their &drm_connector_helper_funcs.atomic_check() callback when the + * connector will no longer have VCPI allocated (e.g. because it's CRTC was + * removed) when it had VCPI allocated in the previous atomic state. + * + * It is OK to call this even if @port has been removed from the system. + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check + * phase. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * 0 if all slots for this port were added back to + * &drm_dp_mst_topology_state.avail_slots or negative error code */ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, - int slots) + struct drm_dp_mst_port *port) { struct drm_dp_mst_topology_state *topology_state; + struct drm_dp_vcpi_allocation *pos; + bool found = false; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) return PTR_ERR(topology_state); - /* We cannot rely on port->vcpi.num_slots to update - * topology_state->avail_slots as the port may not exist if the parent - * branch device was unplugged. This should be fixed by tracking - * per-port slot allocation in drm_dp_mst_topology_state instead of - * depending on the caller to tell us how many slots to release. - */ - topology_state->avail_slots += slots; - DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", - slots, topology_state->avail_slots); + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + found = true; + break; + } + } + if (WARN_ON(!found)) { + DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", + port, &topology_state->base); + return -EINVAL; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); + if (pos->vcpi) { + drm_dp_mst_put_port_malloc(port); + pos->vcpi = 0; + } return 0; } @@ -2715,7 +3178,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, { int ret; - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return false; @@ -2723,9 +3186,10 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, return false; if (port->vcpi.vcpi > 0) { - DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); + DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", + port->vcpi.vcpi, port->vcpi.pbn, pbn); if (pbn == port->vcpi.pbn) { - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return true; } } @@ -2733,13 +3197,15 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); if (ret) { DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", - DIV_ROUND_UP(pbn, mgr->pbn_div), ret); + DIV_ROUND_UP(pbn, mgr->pbn_div), ret); goto out; } DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", - pbn, port->vcpi.num_slots); + pbn, port->vcpi.num_slots); - drm_dp_put_port(port); + /* Keep port allocated until it's payload has been removed */ + drm_dp_mst_get_port_malloc(port); + drm_dp_mst_topology_put_port(port); return true; out: return false; @@ -2749,12 +3215,12 @@ EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { int slots = 0; - port = drm_dp_get_validated_port_ref(mgr, port); + port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return slots; slots = port->vcpi.num_slots; - drm_dp_put_port(port); + drm_dp_mst_topology_put_port(port); return slots; } EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); @@ -2768,11 +3234,12 @@ EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); */ void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) - return; + /* + * A port with VCPI will remain allocated until it's VCPI is + * released, no verified ref needed + */ + port->vcpi.num_slots = 0; - drm_dp_put_port(port); } EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); @@ -2781,18 +3248,20 @@ EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); * @mgr: manager for this port * @port: unverified port to deallocate vcpi for */ -void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) +void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port) { - port = drm_dp_get_validated_port_ref(mgr, port); - if (!port) - return; + /* + * A port with VCPI will remain allocated until it's VCPI is + * released, no verified ref needed + */ drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); port->vcpi.num_slots = 0; port->vcpi.pbn = 0; port->vcpi.aligned_pbn = 0; port->vcpi.vcpi = 0; - drm_dp_put_port(port); + drm_dp_mst_put_port_malloc(port); } EXPORT_SYMBOL(drm_dp_mst_deallocate_vcpi); @@ -3076,13 +3545,6 @@ static void drm_dp_tx_work(struct work_struct *work) mutex_unlock(&mgr->qlock); } -static void drm_dp_free_mst_port(struct kref *kref) -{ - struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); - kref_put(&port->parent->kref, drm_dp_free_mst_branch_device); - kfree(port); -} - static void drm_dp_destroy_connector_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); @@ -3103,7 +3565,6 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) list_del(&port->next); mutex_unlock(&mgr->destroy_connector_lock); - kref_init(&port->kref); INIT_LIST_HEAD(&port->next); mgr->cbs->destroy_connector(mgr, port->connector); @@ -3111,13 +3572,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) drm_dp_port_teardown_pdt(port, port->pdt); port->pdt = DP_PEER_DEVICE_NONE; - if (!port->input && port->vcpi.vcpi > 0) { - drm_dp_mst_reset_vcpi_slots(mgr, port); - drm_dp_update_payload_part1(mgr); - drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); - } - - kref_put(&port->kref, drm_dp_free_mst_port); + drm_dp_mst_put_port_malloc(port); send_hotplug = true; } if (send_hotplug) @@ -3127,15 +3582,41 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) static struct drm_private_state * drm_dp_mst_duplicate_state(struct drm_private_obj *obj) { - struct drm_dp_mst_topology_state *state; + struct drm_dp_mst_topology_state *state, *old_state = + to_dp_mst_topology_state(obj->state); + struct drm_dp_vcpi_allocation *pos, *vcpi; - state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL; __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + INIT_LIST_HEAD(&state->vcpis); + + list_for_each_entry(pos, &old_state->vcpis, next) { + /* Prune leftover freed VCPI allocations */ + if (!pos->vcpi) + continue; + + vcpi = kmemdup(pos, sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) + goto fail; + + drm_dp_mst_get_port_malloc(vcpi->port); + list_add(&vcpi->next, &state->vcpis); + } + return &state->base; + +fail: + list_for_each_entry_safe(pos, vcpi, &state->vcpis, next) { + drm_dp_mst_put_port_malloc(pos->port); + kfree(pos); + } + kfree(state); + + return NULL; } static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, @@ -3143,14 +3624,99 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, { struct drm_dp_mst_topology_state *mst_state = to_dp_mst_topology_state(state); + struct drm_dp_vcpi_allocation *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &mst_state->vcpis, next) { + /* We only keep references to ports with non-zero VCPIs */ + if (pos->vcpi) + drm_dp_mst_put_port_malloc(pos->port); + kfree(pos); + } kfree(mst_state); } -static const struct drm_private_state_funcs mst_state_funcs = { +static inline int +drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state) +{ + struct drm_dp_vcpi_allocation *vcpi; + int avail_slots = 63, payload_count = 0; + + list_for_each_entry(vcpi, &mst_state->vcpis, next) { + /* Releasing VCPI is always OK-even if the port is gone */ + if (!vcpi->vcpi) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", + vcpi->port); + continue; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", + vcpi->port, vcpi->vcpi); + + avail_slots -= vcpi->vcpi; + if (avail_slots < 0) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", + vcpi->port, mst_state, + avail_slots + vcpi->vcpi); + return -ENOSPC; + } + + if (++payload_count > mgr->max_payloads) { + DRM_DEBUG_ATOMIC("[MST MGR:%p] state %p has too many payloads (max=%d)\n", + mgr, mst_state, mgr->max_payloads); + return -EINVAL; + } + } + DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", + mgr, mst_state, avail_slots, + 63 - avail_slots); + + return 0; +} + +/** + * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an + * atomic update is valid + * @state: Pointer to the new &struct drm_dp_mst_topology_state + * + * Checks the given topology state for an atomic update to ensure that it's + * valid. This includes checking whether there's enough bandwidth to support + * the new VCPI allocations in the atomic update. + * + * Any atomic drivers supporting DP MST must make sure to call this after + * checking the rest of their state in their + * &drm_mode_config_funcs.atomic_check() callback. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_atomic_release_vcpi_slots() + * + * Returns: + * + * 0 if the new state is valid, negative error code otherwise. + */ +int drm_dp_mst_atomic_check(struct drm_atomic_state *state) +{ + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; + int i, ret = 0; + + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(drm_dp_mst_atomic_check); + +const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { .atomic_duplicate_state = drm_dp_mst_duplicate_state, .atomic_destroy_state = drm_dp_mst_destroy_state, }; +EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs); /** * drm_atomic_get_mst_topology_state: get MST topology state @@ -3228,13 +3794,11 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; mst_state->mgr = mgr; - - /* max. time slots - one slot for MTP header */ - mst_state->avail_slots = 63; + INIT_LIST_HEAD(&mst_state->vcpis); drm_atomic_private_obj_init(dev, &mgr->base, &mst_state->base, - &mst_state_funcs); + &drm_dp_mst_topology_state_funcs); return 0; } @@ -3292,7 +3856,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs struct drm_dp_sideband_msg_tx *txmsg = NULL; int ret; - mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); + mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); if (!mstb) return -EREMOTEIO; @@ -3342,7 +3906,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs } out: kfree(txmsg); - drm_dp_put_mst_branch_device(mstb); + drm_dp_mst_topology_put_mstb(mstb); return ret; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index a5fe91b8c3c9..381581b01d48 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -264,14 +264,13 @@ void drm_minor_release(struct drm_minor *minor) * DOC: driver instance overview * * A device instance for a drm driver is represented by &struct drm_device. This - * is allocated with drm_dev_alloc(), usually from bus-specific ->probe() + * is initialized with drm_dev_init(), usually from bus-specific ->probe() * callbacks implemented by the driver. The driver then needs to initialize all * the various subsystems for the drm device like memory management, vblank * handling, modesetting support and intial output configuration plus obviously - * initialize all the corresponding hardware bits. An important part of this is - * also calling drm_dev_set_unique() to set the userspace-visible unique name of - * this device instance. Finally when everything is up and running and ready for - * userspace the device instance can be published using drm_dev_register(). + * initialize all the corresponding hardware bits. Finally when everything is up + * and running and ready for userspace the device instance can be published + * using drm_dev_register(). * * There is also deprecated support for initalizing device instances using * bus-specific helpers and the &drm_driver.load callback. But due to @@ -287,9 +286,6 @@ void drm_minor_release(struct drm_minor *minor) * Note that the lifetime rules for &drm_device instance has still a lot of * historical baggage. Hence use the reference counting provided by * drm_dev_get() and drm_dev_put() only carefully. - * - * It is recommended that drivers embed &struct drm_device into their own device - * structure, which is supported through drm_dev_init(). */ /** @@ -475,6 +471,9 @@ static void drm_fs_inode_free(struct inode *inode) * The initial ref-count of the object is 1. Use drm_dev_get() and * drm_dev_put() to take and drop further ref-counts. * + * It is recommended that drivers embed &struct drm_device into their own device + * structure. + * * Drivers that do not want to allocate their own device struct * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers * that do embed &struct drm_device it must be placed first in the overall @@ -765,7 +764,7 @@ static void remove_compat_control_link(struct drm_device *dev) * @flags: Flags passed to the driver's .load() function * * Register the DRM device @dev with the system, advertise device to user-space - * and start normal device operation. @dev must be allocated via drm_dev_alloc() + * and start normal device operation. @dev must be initialized via drm_dev_init() * previously. * * Never call this twice on any device! @@ -877,9 +876,9 @@ EXPORT_SYMBOL(drm_dev_unregister); * @dev: device of which to set the unique name * @name: unique name * - * Sets the unique name of a DRM device using the specified string. Drivers - * can use this at driver probe time if the unique name of the devices they - * drive is static. + * Sets the unique name of a DRM device using the specified string. This is + * already done by drm_dev_init(), drivers should only override the default + * unique name for backwards compatibility reasons. * * Return: 0 on success or a negative error code on failure. */ diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b506e3622b08..990b1909f9d7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3641,6 +3641,20 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) return oui == HDMI_FORUM_IEEE_OUI; } +static bool cea_db_is_vcdb(const u8 *db) +{ + if (cea_db_tag(db) != USE_EXTENDED_TAG) + return false; + + if (cea_db_payload_len(db) != 2) + return false; + + if (cea_db_extended_tag(db) != EXT_VIDEO_CAPABILITY_BLOCK) + return false; + + return true; +} + static bool cea_db_is_y420cmdb(const u8 *db) { if (cea_db_tag(db) != USE_EXTENDED_TAG) @@ -4223,41 +4237,6 @@ end: } EXPORT_SYMBOL(drm_detect_monitor_audio); -/** - * drm_rgb_quant_range_selectable - is RGB quantization range selectable? - * @edid: EDID block to scan - * - * Check whether the monitor reports the RGB quantization range selection - * as supported. The AVI infoframe can then be used to inform the monitor - * which quantization range (full or limited) is used. - * - * Return: True if the RGB quantization range is selectable, false otherwise. - */ -bool drm_rgb_quant_range_selectable(struct edid *edid) -{ - u8 *edid_ext; - int i, start, end; - - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return false; - - if (cea_db_offsets(edid_ext, &start, &end)) - return false; - - for_each_cea_db(edid_ext, i, start, end) { - if (cea_db_tag(&edid_ext[i]) == USE_EXTENDED_TAG && - cea_db_payload_len(&edid_ext[i]) == 2 && - cea_db_extended_tag(&edid_ext[i]) == - EXT_VIDEO_CAPABILITY_BLOCK) { - DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]); - return edid_ext[i + 2] & EDID_CEA_VCDB_QS; - } - } - - return false; -} -EXPORT_SYMBOL(drm_rgb_quant_range_selectable); /** * drm_default_rgb_quant_range - default RGB quantization range @@ -4278,6 +4257,16 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_default_rgb_quant_range); +static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db) +{ + struct drm_display_info *info = &connector->display_info; + + DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]); + + if (db[2] & EDID_CEA_VCDB_QS) + info->rgb_quant_range_selectable = true; +} + static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, const u8 *db) { @@ -4452,6 +4441,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, drm_parse_hdmi_forum_vsdb(connector, db); if (cea_db_is_y420cmdb(db)) drm_parse_y420cmdb_bitmap(connector, db); + if (cea_db_is_vcdb(db)) + drm_parse_vcdb(connector, db); } } @@ -4472,6 +4463,7 @@ drm_reset_display_info(struct drm_connector *connector) info->max_tmds_clock = 0; info->dvi_dual = false; info->has_hdmi_infoframe = false; + info->rgb_quant_range_selectable = false; memset(&info->hdmi, 0, sizeof(info->hdmi)); info->non_desktop = 0; @@ -4830,19 +4822,32 @@ void drm_set_preferred_mode(struct drm_connector *connector, } EXPORT_SYMBOL(drm_set_preferred_mode); +static bool is_hdmi2_sink(struct drm_connector *connector) +{ + /* + * FIXME: sil-sii8620 doesn't have a connector around when + * we need one, so we have to be prepared for a NULL connector. + */ + if (!connector) + return true; + + return connector->display_info.hdmi.scdc.supported || + connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; +} + /** * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with * data from a DRM display mode * @frame: HDMI AVI infoframe + * @connector: the connector * @mode: DRM display mode - * @is_hdmi2_sink: Sink is HDMI 2.0 compliant * * Return: 0 on success or a negative error code on failure. */ int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, - const struct drm_display_mode *mode, - bool is_hdmi2_sink) + struct drm_connector *connector, + const struct drm_display_mode *mode) { enum hdmi_picture_aspect picture_aspect; int err; @@ -4864,7 +4869,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we * have to make sure we dont break HDMI 1.4 sinks. */ - if (!is_hdmi2_sink && frame->video_code > 64) + if (!is_hdmi2_sink(connector) && frame->video_code > 64) frame->video_code = 0; /* @@ -4923,22 +4928,18 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe * quantization range information * @frame: HDMI AVI infoframe + * @connector: the connector * @mode: DRM display mode * @rgb_quant_range: RGB quantization range (Q) - * @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS) - * @is_hdmi2_sink: HDMI 2.0 sink, which has different default recommendations - * - * Note that @is_hdmi2_sink can be derived by looking at the - * &drm_scdc.supported flag stored in &drm_hdmi_info.scdc, - * &drm_display_info.hdmi, which can be found in &drm_connector.display_info. */ void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, + struct drm_connector *connector, const struct drm_display_mode *mode, - enum hdmi_quantization_range rgb_quant_range, - bool rgb_quant_range_selectable, - bool is_hdmi2_sink) + enum hdmi_quantization_range rgb_quant_range) { + const struct drm_display_info *info = &connector->display_info; + /* * CEA-861: * "A Source shall not send a non-zero Q value that does not correspond @@ -4949,7 +4950,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, * HDMI 2.0 recommends sending non-zero Q when it does match the * default RGB quantization range for the mode, even when QS=0. */ - if (rgb_quant_range_selectable || + if (info->rgb_quant_range_selectable || rgb_quant_range == drm_default_rgb_quant_range(mode)) frame->quantization_range = rgb_quant_range; else @@ -4968,7 +4969,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based * on on CEA-861-F. */ - if (!is_hdmi2_sink || + if (!is_hdmi2_sink(connector) || rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) frame->ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 5b516615881a..5f8074ffe7d9 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -17,20 +17,13 @@ * GNU General Public License for more details. */ -#include <drm/drmP.h> -#include <drm/drm_client.h> -#include <drm/drm_fb_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_print.h> +#include <drm/drm_plane.h> #include <linux/module.h> -struct drm_fbdev_cma { - struct drm_fb_helper fb_helper; -}; - /** * DOC: framebuffer cma helper functions * @@ -39,16 +32,8 @@ struct drm_fbdev_cma { * * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create * callback function to create a cma backed framebuffer. - * - * An fbdev framebuffer backed by cma is also available by calling - * drm_fb_cma_fbdev_init(). drm_fb_cma_fbdev_fini() tears it down. */ -static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper) -{ - return container_of(helper, struct drm_fbdev_cma, fb_helper); -} - /** * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer * @fb: The framebuffer @@ -119,121 +104,3 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, return paddr; } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); - -/** - * drm_fb_cma_fbdev_init() - Allocate and initialize fbdev emulation - * @dev: DRM device - * @preferred_bpp: Preferred bits per pixel for the device. - * @dev->mode_config.preferred_depth is used if this is zero. - * @max_conn_count: Maximum number of connectors. - * @dev->mode_config.num_connector is used if this is zero. - * - * Returns: - * Zero on success or negative error code on failure. - */ -int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp, - unsigned int max_conn_count) -{ - struct drm_fbdev_cma *fbdev_cma; - - /* dev->fb_helper will indirectly point to fbdev_cma after this call */ - fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count); - return PTR_ERR_OR_ZERO(fbdev_cma); -} -EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init); - -/** - * drm_fb_cma_fbdev_fini() - Teardown fbdev emulation - * @dev: DRM device - */ -void drm_fb_cma_fbdev_fini(struct drm_device *dev) -{ - if (dev->fb_helper) - drm_fbdev_cma_fini(to_fbdev_cma(dev->fb_helper)); -} -EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_fini); - -static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { - .fb_probe = drm_fb_helper_generic_probe, -}; - -/** - * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct - * @dev: DRM device - * @preferred_bpp: Preferred bits per pixel for the device - * @max_conn_count: Maximum number of connectors - * - * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. - */ -struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count) -{ - struct drm_fbdev_cma *fbdev_cma; - struct drm_fb_helper *fb_helper; - int ret; - - fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL); - if (!fbdev_cma) - return ERR_PTR(-ENOMEM); - - fb_helper = &fbdev_cma->fb_helper; - - ret = drm_client_init(dev, &fb_helper->client, "fbdev", NULL); - if (ret) - goto err_free; - - ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_cma_helper_funcs, - preferred_bpp, max_conn_count); - if (ret) - goto err_client_put; - - drm_client_add(&fb_helper->client); - - return fbdev_cma; - -err_client_put: - drm_client_release(&fb_helper->client); -err_free: - kfree(fbdev_cma); - - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); - -/** - * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct - * @fbdev_cma: The drm_fbdev_cma struct - */ -void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) -{ - drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); - /* All resources have now been freed by drm_fbdev_fb_destroy() */ -} -EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini); - -/** - * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode - * @fbdev_cma: The drm_fbdev_cma struct, may be NULL - * - * This function is usually called from the &drm_driver.lastclose callback. - */ -void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma) -{ - if (fbdev_cma) - drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma->fb_helper); -} -EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode); - -/** - * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events - * @fbdev_cma: The drm_fbdev_cma struct, may be NULL - * - * This function is usually called from the &drm_mode_config.output_poll_changed - * callback. - */ -void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma) -{ - if (fbdev_cma) - drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper); -} -EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d3af098b0922..31fcf94bf825 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1797,6 +1797,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int i; struct drm_fb_helper_surface_size sizes; int gamma_size = 0; + int best_depth = 0; memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; @@ -1804,7 +1805,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, sizes.fb_width = (u32)-1; sizes.fb_height = (u32)-1; - /* if driver picks 8 or 16 by default use that for both depth/bpp */ + /* + * If driver picks 8 or 16 by default use that for both depth/bpp + * to begin with + */ if (preferred_bpp != sizes.surface_bpp) sizes.surface_depth = sizes.surface_bpp = preferred_bpp; @@ -1839,6 +1843,55 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } } + /* + * If we run into a situation where, for example, the primary plane + * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth + * 16) we need to scale down the depth of the sizes we request. + */ + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; + struct drm_crtc *crtc = mode_set->crtc; + struct drm_plane *plane = crtc->primary; + int j; + + DRM_DEBUG("test CRTC %d primary plane\n", i); + + for (j = 0; j < plane->format_count; j++) { + const struct drm_format_info *fmt; + + fmt = drm_format_info(plane->format_types[j]); + + /* + * Do not consider YUV or other complicated formats + * for framebuffers. This means only legacy formats + * are supported (fmt->depth is a legacy field) but + * the framebuffer emulation can only deal with such + * formats, specifically RGB/BGA formats. + */ + if (fmt->depth == 0) + continue; + + /* We found a perfect fit, great */ + if (fmt->depth == sizes.surface_depth) { + best_depth = fmt->depth; + break; + } + + /* Skip depths above what we're looking for */ + if (fmt->depth > sizes.surface_depth) + continue; + + /* Best depth found so far */ + if (fmt->depth > best_depth) + best_depth = fmt->depth; + } + } + if (sizes.surface_depth != best_depth) { + DRM_INFO("requested bpp %d, scaled depth down to %d", + sizes.surface_bpp, best_depth); + sizes.surface_depth = best_depth; + } + crtc_count = 0; for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_display_mode *desired_mode; @@ -2866,7 +2919,7 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev, return 0; err_drm_fb_helper_fini: - drm_fb_helper_fini(fb_helper); + drm_fb_helper_fbdev_teardown(dev); return ret; } @@ -2961,18 +3014,16 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user) return 0; } -/* - * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of - * unregister_framebuffer() or fb_release(). - */ -static void drm_fbdev_fb_destroy(struct fb_info *info) +static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper) { - struct drm_fb_helper *fb_helper = info->par; struct fb_info *fbi = fb_helper->fbdev; struct fb_ops *fbops = NULL; void *shadow = NULL; - if (fbi->fbdefio) { + if (!fb_helper->dev) + return; + + if (fbi && fbi->fbdefio) { fb_deferred_io_cleanup(fbi); shadow = fbi->screen_buffer; fbops = fbi->fbops; @@ -2986,15 +3037,22 @@ static void drm_fbdev_fb_destroy(struct fb_info *info) } drm_client_framebuffer_delete(fb_helper->buffer); - /* - * FIXME: - * Remove conditional when all CMA drivers have been moved over to using - * drm_fbdev_generic_setup(). - */ - if (fb_helper->client.funcs) { - drm_client_release(&fb_helper->client); - kfree(fb_helper); - } +} + +static void drm_fbdev_release(struct drm_fb_helper *fb_helper) +{ + drm_fbdev_cleanup(fb_helper); + drm_client_release(&fb_helper->client); + kfree(fb_helper); +} + +/* + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of + * unregister_framebuffer() or fb_release(). + */ +static void drm_fbdev_fb_destroy(struct fb_info *info) +{ + drm_fbdev_release(info->par); } static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) @@ -3047,7 +3105,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, struct drm_framebuffer *fb; struct fb_info *fbi; u32 format; - int ret; DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", sizes->surface_width, sizes->surface_height, @@ -3064,10 +3121,8 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, fb = buffer->fb; fbi = drm_fb_helper_alloc_fbi(fb_helper); - if (IS_ERR(fbi)) { - ret = PTR_ERR(fbi); - goto err_free_buffer; - } + if (IS_ERR(fbi)) + return PTR_ERR(fbi); fbi->par = fb_helper; fbi->fbops = &drm_fbdev_fb_ops; @@ -3098,8 +3153,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, if (!fbops || !shadow) { kfree(fbops); vfree(shadow); - ret = -ENOMEM; - goto err_fb_info_destroy; + return -ENOMEM; } *fbops = *fbi->fbops; @@ -3111,13 +3165,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, } return 0; - -err_fb_info_destroy: - drm_fb_helper_fini(fb_helper); -err_free_buffer: - drm_client_framebuffer_delete(buffer); - - return ret; } EXPORT_SYMBOL(drm_fb_helper_generic_probe); @@ -3129,18 +3176,11 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client) { struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); - if (fb_helper->fbdev) { - drm_fb_helper_unregister_fbi(fb_helper); + if (fb_helper->fbdev) /* drm_fbdev_fb_destroy() takes care of cleanup */ - return; - } - - /* Did drm_fb_helper_fbdev_setup() run? */ - if (fb_helper->dev) - drm_fb_helper_fini(fb_helper); - - drm_client_release(client); - kfree(fb_helper); + drm_fb_helper_unregister_fbi(fb_helper); + else + drm_fbdev_release(fb_helper); } static int drm_fbdev_client_restore(struct drm_client_dev *client) @@ -3158,7 +3198,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) struct drm_device *dev = client->dev; int ret; - /* If drm_fb_helper_fbdev_setup() failed, we only try once */ + /* Setup is not retried if it has failed */ if (!fb_helper->dev && fb_helper->funcs) return 0; @@ -3170,15 +3210,34 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) return 0; } - ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs, - fb_helper->preferred_bpp, 0); - if (ret) { - fb_helper->dev = NULL; - fb_helper->fbdev = NULL; - return ret; - } + drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs); + + ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector); + if (ret) + goto err; + + ret = drm_fb_helper_single_add_all_connectors(fb_helper); + if (ret) + goto err_cleanup; + + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); + + ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp); + if (ret) + goto err_cleanup; return 0; + +err_cleanup: + drm_fbdev_cleanup(fb_helper); +err: + fb_helper->dev = NULL; + fb_helper->fbdev = NULL; + + DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); + + return ret; } static const struct drm_client_funcs drm_fbdev_client_funcs = { @@ -3237,6 +3296,10 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) drm_client_add(&fb_helper->client); + if (!preferred_bpp) + preferred_bpp = dev->mode_config.preferred_depth; + if (!preferred_bpp) + preferred_bpp = 32; fb_helper->preferred_bpp = preferred_bpp; ret = drm_fbdev_client_hotplug(&fb_helper->client); diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c index 12dea16f22a8..3da3bf5af405 100644 --- a/drivers/gpu/drm/drm_flip_work.c +++ b/drivers/gpu/drm/drm_flip_work.c @@ -22,6 +22,7 @@ */ #include <drm/drmP.h> +#include <drm/drm_util.h> #include <drm/drm_flip_work.h> /** diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index fcaea8f50513..7abcb265a108 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -27,6 +27,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_uapi.h> #include <drm/drm_print.h> +#include <drm/drm_util.h> #include "drm_internal.h" #include "drm_crtc_internal.h" diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 8b55ece97967..2896ff60552f 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -37,6 +37,7 @@ #include <linux/shmem_fs.h> #include <linux/dma-buf.h> #include <linux/mem_encrypt.h> +#include <linux/pagevec.h> #include <drm/drmP.h> #include <drm/drm_vma_manager.h> #include <drm/drm_gem.h> @@ -526,6 +527,17 @@ int drm_gem_create_mmap_offset(struct drm_gem_object *obj) } EXPORT_SYMBOL(drm_gem_create_mmap_offset); +/* + * Move pages to appropriate lru and release the pagevec, decrementing the + * ref count of those pages. + */ +static void drm_gem_check_release_pagevec(struct pagevec *pvec) +{ + check_move_unevictable_pages(pvec); + __pagevec_release(pvec); + cond_resched(); +} + /** * drm_gem_get_pages - helper to allocate backing pages for a GEM object * from shmem @@ -551,6 +563,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) { struct address_space *mapping; struct page *p, **pages; + struct pagevec pvec; int i, npages; /* This is the shared memory object that backs the GEM resource */ @@ -568,6 +581,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) if (pages == NULL) return ERR_PTR(-ENOMEM); + mapping_set_unevictable(mapping); + for (i = 0; i < npages; i++) { p = shmem_read_mapping_page(mapping, i); if (IS_ERR(p)) @@ -586,8 +601,14 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) return pages; fail: - while (i--) - put_page(pages[i]); + mapping_clear_unevictable(mapping); + pagevec_init(&pvec); + while (i--) { + if (!pagevec_add(&pvec, pages[i])) + drm_gem_check_release_pagevec(&pvec); + } + if (pagevec_count(&pvec)) + drm_gem_check_release_pagevec(&pvec); kvfree(pages); return ERR_CAST(p); @@ -605,6 +626,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, bool dirty, bool accessed) { int i, npages; + struct address_space *mapping; + struct pagevec pvec; + + mapping = file_inode(obj->filp)->i_mapping; + mapping_clear_unevictable(mapping); /* We already BUG_ON() for non-page-aligned sizes in * drm_gem_object_init(), so we should never hit this unless @@ -614,6 +640,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, npages = obj->size >> PAGE_SHIFT; + pagevec_init(&pvec); for (i = 0; i < npages; i++) { if (dirty) set_page_dirty(pages[i]); @@ -622,8 +649,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, mark_page_accessed(pages[i]); /* Undo the reference we took when populating the table */ - put_page(pages[i]); + if (!pagevec_add(&pvec, pages[i])) + drm_gem_check_release_pagevec(&pvec); } + if (pagevec_count(&pvec)) + drm_gem_check_release_pagevec(&pvec); kvfree(pages); } diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index acb466d25afc..65edb1ccb185 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -17,6 +17,7 @@ #include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_uapi.h> +#include <drm/drm_damage_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> @@ -136,10 +137,9 @@ EXPORT_SYMBOL(drm_gem_fb_create_handle); * @mode_cmd: Metadata from the userspace framebuffer creation request * @funcs: vtable to be used for the new framebuffer object * - * This can be used to set &drm_framebuffer_funcs for drivers that need the - * &drm_framebuffer_funcs.dirty callback. Use drm_gem_fb_create() if you don't - * need to change &drm_framebuffer_funcs. - * The function does buffer size validation. + * This function can be used to set &drm_framebuffer_funcs for drivers that need + * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to + * change &drm_framebuffer_funcs. The function does buffer size validation. * * Returns: * Pointer to a &drm_framebuffer on success or an error pointer on failure. @@ -215,8 +215,8 @@ static const struct drm_framebuffer_funcs drm_gem_fb_funcs = { * * If your hardware has special alignment or pitch requirements these should be * checked before calling this function. The function does buffer size - * validation. Use drm_gem_fb_create_with_funcs() if you need to set - * &drm_framebuffer_funcs.dirty. + * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer + * flushing. * * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. * The ADDFB2 IOCTL calls into this callback. @@ -233,6 +233,44 @@ drm_gem_fb_create(struct drm_device *dev, struct drm_file *file, } EXPORT_SYMBOL_GPL(drm_gem_fb_create); +static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = { + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, + .dirty = drm_atomic_helper_dirtyfb, +}; + +/** + * drm_gem_fb_create_with_dirty() - Helper function for the + * &drm_mode_config_funcs.fb_create callback + * @dev: DRM device + * @file: DRM file that holds the GEM handle(s) backing the framebuffer + * @mode_cmd: Metadata from the userspace framebuffer creation request + * + * This function creates a new framebuffer object described by + * &drm_mode_fb_cmd2. This description includes handles for the buffer(s) + * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty + * callback giving framebuffer flushing through the atomic machinery. Use + * drm_gem_fb_create() if you don't need the dirty callback. + * The function does buffer size validation. + * + * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes + * to enable userspace to use damage clips also with the ATOMIC IOCTL. + * + * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. + * The ADDFB2 IOCTL calls into this callback. + * + * Returns: + * Pointer to a &drm_framebuffer on success or an error pointer on failure. + */ +struct drm_framebuffer * +drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + return drm_gem_fb_create_with_funcs(dev, file, mode_cmd, + &drm_gem_fb_funcs_dirtyfb); +} +EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); + /** * drm_gem_fb_prepare_fb() - Prepare a GEM backed framebuffer * @plane: Plane diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 24a750436559..adce9a26bac9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -71,11 +71,6 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev) if (!nmode) return NULL; - if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { - kfree(nmode); - return NULL; - } - return nmode; } EXPORT_SYMBOL(drm_mode_create); @@ -92,8 +87,6 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) if (!mode) return; - drm_mode_object_unregister(dev, &mode->base); - kfree(mode); } EXPORT_SYMBOL(drm_mode_destroy); @@ -911,11 +904,9 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo); */ void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) { - int id = dst->base.id; struct list_head head = dst->head; *dst = *src; - dst->base.id = id; dst->head = head; } EXPORT_SYMBOL(drm_mode_copy); diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 2763a5ec845b..f2f71d71494a 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -217,9 +217,11 @@ int drm_of_encoder_active_endpoint(struct device_node *node, } EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); -/* +/** * drm_of_find_panel_or_bridge - return connected panel or bridge device * @np: device tree node containing encoder output ports + * @port: port in the device tree node + * @endpoint: endpoint in the device tree node * @panel: pointer to hold returned drm_panel * @bridge: pointer to hold returned drm_bridge * diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index c33f95e08e1b..dbd5b873e8f2 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -36,6 +36,9 @@ static LIST_HEAD(panel_list); * The DRM panel helpers allow drivers to register panel objects with a * central registry and provide functions to retrieve those panels in display * drivers. + * + * For easy integration into drivers using the &drm_bridge infrastructure please + * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add(). */ /** diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 5f650d8fc66b..4cfb56893b7f 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -220,6 +220,9 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, format_modifier_count++; } + if (format_modifier_count) + config->allow_fb_modifiers = true; + plane->modifier_count = format_modifier_count; plane->modifiers = kmalloc_array(format_modifier_count, sizeof(format_modifiers[0]), diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 98e091175921..cde71ee95a8f 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, write_sequnlock(&vblank->seqlock); } +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) +{ + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + + return vblank->max_vblank_count ?: dev->max_vblank_count; +} + /* * "No hw counter" fallback implementation of .get_vblank_counter() hook, * if there is no useable hardware frame counter available. */ static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) { - WARN_ON_ONCE(dev->max_vblank_count != 0); + WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0); return 0; } @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, ktime_t t_vblank; int count = DRM_TIMESTAMP_MAXRETRIES; int framedur_ns = vblank->framedur_ns; + u32 max_vblank_count = drm_max_vblank_count(dev, pipe); /* * Interrupts were disabled prior to this call, so deal with counter @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); - if (dev->max_vblank_count != 0) { + if (max_vblank_count) { /* trust the hw counter when it's around */ - diff = (cur_vblank - vblank->last) & dev->max_vblank_count; + diff = (cur_vblank - vblank->last) & max_vblank_count; } else if (rc && framedur_ns) { u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); @@ -1205,6 +1213,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_crtc_vblank_reset); /** + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value + * @crtc: CRTC in question + * @max_vblank_count: max hardware vblank counter value + * + * Update the maximum hardware vblank counter value for @crtc + * at runtime. Useful for hardware where the operation of the + * hardware vblank counter depends on the currently active + * display configuration. + * + * For example, if the hardware vblank counter does not work + * when a specific connector is active the maximum can be set + * to zero. And when that specific connector isn't active the + * maximum can again be set to the appropriate non-zero value. + * + * If used, must be called before drm_vblank_on(). + */ +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, + u32 max_vblank_count) +{ + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + + WARN_ON(dev->max_vblank_count); + WARN_ON(!READ_ONCE(vblank->inmodeset)); + + vblank->max_vblank_count = max_vblank_count; +} +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count); + +/** * drm_crtc_vblank_on - enable vblank events on a CRTC * @crtc: CRTC in question * diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2fd299a58297..dd02e8a323ef 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -246,8 +246,8 @@ already_disabled: } static void mic_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct exynos_mic *mic = bridge->driver_private; diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 2092a650df7d..b857df67aff0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -819,7 +819,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) return; } - ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, m, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, + &hdata->connector, m); if (!ret) ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf)); if (ret > 0) { diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index e6a62d5a00a3..15e32e5d9101 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -22,6 +22,7 @@ #include <drm/drmP.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> @@ -33,32 +34,15 @@ static struct kirin_dc_ops *dc_ops; static int kirin_drm_kms_cleanup(struct drm_device *dev) { - struct kirin_drm_private *priv = dev->dev_private; - - if (priv->fbdev) { - drm_fbdev_cma_fini(priv->fbdev); - priv->fbdev = NULL; - } - drm_kms_helper_poll_fini(dev); dc_ops->cleanup(to_platform_device(dev->dev)); drm_mode_config_cleanup(dev); - devm_kfree(dev->dev, priv); - dev->dev_private = NULL; return 0; } -static void kirin_fbdev_output_poll_changed(struct drm_device *dev) -{ - struct kirin_drm_private *priv = dev->dev_private; - - drm_fbdev_cma_hotplug_event(priv->fbdev); -} - static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { .fb_create = drm_gem_fb_create, - .output_poll_changed = kirin_fbdev_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -76,14 +60,8 @@ static void kirin_drm_mode_config_init(struct drm_device *dev) static int kirin_drm_kms_init(struct drm_device *dev) { - struct kirin_drm_private *priv; int ret; - priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev->dev_private = priv; dev_set_drvdata(dev->dev, dev); /* dev->mode_config initialization */ @@ -117,26 +95,14 @@ static int kirin_drm_kms_init(struct drm_device *dev) /* init kms poll for handling hpd */ drm_kms_helper_poll_init(dev); - priv->fbdev = drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_connector); - - if (IS_ERR(priv->fbdev)) { - DRM_ERROR("failed to initialize fbdev.\n"); - ret = PTR_ERR(priv->fbdev); - goto err_cleanup_poll; - } return 0; -err_cleanup_poll: - drm_kms_helper_poll_fini(dev); err_unbind_all: component_unbind_all(dev->dev, dev); err_dc_cleanup: dc_ops->cleanup(to_platform_device(dev->dev)); err_mode_config_cleanup: drm_mode_config_cleanup(dev); - devm_kfree(dev->dev, priv); - dev->dev_private = NULL; return ret; } @@ -199,6 +165,8 @@ static int kirin_drm_bind(struct device *dev) if (ret) goto err_kms_cleanup; + drm_fbdev_generic_setup(drm_dev, 32); + return 0; err_kms_cleanup: diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index 56cb62df065c..ad027d1cc826 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -19,10 +19,6 @@ struct kirin_dc_ops { void (*cleanup)(struct platform_device *pdev); }; -struct kirin_drm_private { - struct drm_fbdev_cma *fbdev; -}; - extern const struct kirin_dc_ops ade_dc_ops; #endif /* __KIRIN_DRM_DRV_H__ */ diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 544a8a2d3562..b91e48d2190d 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -359,10 +359,10 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, if (modes_changed) { drm_helper_probe_single_connector_modes(connector, 0, 0); - /* Disable the crtc to ensure a full modeset is - * performed whenever it's turned on again. */ if (crtc) - drm_crtc_force_disable(crtc); + drm_crtc_helper_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, + crtc->primary->fb); } return 0; diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a7c39f39793f..ecdb8070ed35 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -845,11 +845,12 @@ static int tda998x_write_aif(struct tda998x_priv *priv, } static void -tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode) +tda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode) { union hdmi_infoframe frame; - drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); + drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + &priv->connector, mode); frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame); @@ -1122,7 +1123,6 @@ static void tda998x_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_funcs tda998x_connector_funcs = { - .dpms = drm_helper_connector_dpms, .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, .detect = tda998x_connector_detect, @@ -1339,8 +1339,8 @@ static void tda998x_bridge_disable(struct drm_bridge *bridge) } static void tda998x_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); unsigned long tmds_clock; diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 19b5fe5016bf..c34bee16730d 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -40,7 +40,7 @@ i915-y := i915_drv.o \ i915_mm.o \ i915_params.o \ i915_pci.o \ - i915_suspend.o \ + i915_suspend.o \ i915_syncmap.o \ i915_sw_fence.o \ i915_sysfs.o \ diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 5e6a3013da49..16e0345b711f 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -24,7 +24,6 @@ #define _INTEL_DVO_H #include <linux/i2c.h> -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index c628be05fbfe..e1c860f80eb0 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -148,10 +148,10 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) gvt->types[i].avail_instance = min(low_avail / vgpu_types[i].low_mm, high_avail / vgpu_types[i].high_mm); - if (IS_GEN8(gvt->dev_priv)) + if (IS_GEN(gvt->dev_priv, 8)) sprintf(gvt->types[i].name, "GVTg_V4_%s", vgpu_types[i].name); - else if (IS_GEN9(gvt->dev_priv)) + else if (IS_GEN(gvt->dev_priv, 9)) sprintf(gvt->types[i].name, "GVTg_V5_%s", vgpu_types[i].name); diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 95478db9998b..33e8eed64423 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -865,7 +865,7 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine) int cmd_table_count; int ret; - if (!IS_GEN7(engine->i915)) + if (!IS_GEN(engine->i915, 7)) return; switch (engine->id) { diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 38dcee1ca062..d460ef522d9c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -48,7 +48,7 @@ static int i915_capabilities(struct seq_file *m, void *data) seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev_priv)); intel_device_info_dump_flags(info, &p); - intel_device_info_dump_runtime(info, &p); + intel_device_info_dump_runtime(RUNTIME_INFO(dev_priv), &p); intel_driver_caps_print(&dev_priv->caps, &p); kernel_param_lock(THIS_MODULE); @@ -297,11 +297,12 @@ out: } struct file_stats { - struct drm_i915_file_private *file_priv; + struct i915_address_space *vm; unsigned long count; u64 total, unbound; u64 global, shared; u64 active, inactive; + u64 closed; }; static int per_file_stats(int id, void *ptr, void *data) @@ -326,9 +327,7 @@ static int per_file_stats(int id, void *ptr, void *data) if (i915_vma_is_ggtt(vma)) { stats->global += vma->node.size; } else { - struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vma->vm); - - if (ppgtt->vm.file != stats->file_priv) + if (vma->vm != stats->vm) continue; } @@ -336,6 +335,9 @@ static int per_file_stats(int id, void *ptr, void *data) stats->active += vma->node.size; else stats->inactive += vma->node.size; + + if (i915_vma_is_closed(vma)) + stats->closed += vma->node.size; } return 0; @@ -343,7 +345,7 @@ static int per_file_stats(int id, void *ptr, void *data) #define print_file_stats(m, name, stats) do { \ if (stats.count) \ - seq_printf(m, "%s: %lu objects, %llu bytes (%llu active, %llu inactive, %llu global, %llu shared, %llu unbound)\n", \ + seq_printf(m, "%s: %lu objects, %llu bytes (%llu active, %llu inactive, %llu global, %llu shared, %llu unbound, %llu closed)\n", \ name, \ stats.count, \ stats.total, \ @@ -351,20 +353,19 @@ static int per_file_stats(int id, void *ptr, void *data) stats.inactive, \ stats.global, \ stats.shared, \ - stats.unbound); \ + stats.unbound, \ + stats.closed); \ } while (0) static void print_batch_pool_stats(struct seq_file *m, struct drm_i915_private *dev_priv) { struct drm_i915_gem_object *obj; - struct file_stats stats; struct intel_engine_cs *engine; + struct file_stats stats = {}; enum intel_engine_id id; int j; - memset(&stats, 0, sizeof(stats)); - for_each_engine(engine, dev_priv, id) { for (j = 0; j < ARRAY_SIZE(engine->batch_pool.cache_list); j++) { list_for_each_entry(obj, @@ -377,44 +378,47 @@ static void print_batch_pool_stats(struct seq_file *m, print_file_stats(m, "[k]batch pool", stats); } -static int per_file_ctx_stats(int idx, void *ptr, void *data) +static void print_context_stats(struct seq_file *m, + struct drm_i915_private *i915) { - struct i915_gem_context *ctx = ptr; - struct intel_engine_cs *engine; - enum intel_engine_id id; + struct file_stats kstats = {}; + struct i915_gem_context *ctx; - for_each_engine(engine, ctx->i915, id) { - struct intel_context *ce = to_intel_context(ctx, engine); + list_for_each_entry(ctx, &i915->contexts.list, link) { + struct intel_engine_cs *engine; + enum intel_engine_id id; - if (ce->state) - per_file_stats(0, ce->state->obj, data); - if (ce->ring) - per_file_stats(0, ce->ring->vma->obj, data); - } + for_each_engine(engine, i915, id) { + struct intel_context *ce = to_intel_context(ctx, engine); - return 0; -} + if (ce->state) + per_file_stats(0, ce->state->obj, &kstats); + if (ce->ring) + per_file_stats(0, ce->ring->vma->obj, &kstats); + } -static void print_context_stats(struct seq_file *m, - struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = &dev_priv->drm; - struct file_stats stats; - struct drm_file *file; + if (!IS_ERR_OR_NULL(ctx->file_priv)) { + struct file_stats stats = { .vm = &ctx->ppgtt->vm, }; + struct drm_file *file = ctx->file_priv->file; + struct task_struct *task; + char name[80]; - memset(&stats, 0, sizeof(stats)); + spin_lock(&file->table_lock); + idr_for_each(&file->object_idr, per_file_stats, &stats); + spin_unlock(&file->table_lock); - mutex_lock(&dev->struct_mutex); - if (dev_priv->kernel_context) - per_file_ctx_stats(0, dev_priv->kernel_context, &stats); + rcu_read_lock(); + task = pid_task(ctx->pid ?: file->pid, PIDTYPE_PID); + snprintf(name, sizeof(name), "%s/%d", + task ? task->comm : "<unknown>", + ctx->user_handle); + rcu_read_unlock(); - list_for_each_entry(file, &dev->filelist, lhead) { - struct drm_i915_file_private *fpriv = file->driver_priv; - idr_for_each(&fpriv->context_idr, per_file_ctx_stats, &stats); + print_file_stats(m, name, stats); + } } - mutex_unlock(&dev->struct_mutex); - print_file_stats(m, "[k]contexts", stats); + print_file_stats(m, "[k]contexts", kstats); } static int i915_gem_object_info(struct seq_file *m, void *data) @@ -426,14 +430,9 @@ static int i915_gem_object_info(struct seq_file *m, void *data) u64 size, mapped_size, purgeable_size, dpy_size, huge_size; struct drm_i915_gem_object *obj; unsigned int page_sizes = 0; - struct drm_file *file; char buf[80]; int ret; - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; - seq_printf(m, "%u objects, %llu bytes\n", dev_priv->mm.object_count, dev_priv->mm.object_memory); @@ -514,43 +513,14 @@ static int i915_gem_object_info(struct seq_file *m, void *data) buf, sizeof(buf))); seq_putc(m, '\n'); - print_batch_pool_stats(m, dev_priv); - mutex_unlock(&dev->struct_mutex); - - mutex_lock(&dev->filelist_mutex); - print_context_stats(m, dev_priv); - list_for_each_entry_reverse(file, &dev->filelist, lhead) { - struct file_stats stats; - struct drm_i915_file_private *file_priv = file->driver_priv; - struct i915_request *request; - struct task_struct *task; - - mutex_lock(&dev->struct_mutex); - memset(&stats, 0, sizeof(stats)); - stats.file_priv = file->driver_priv; - spin_lock(&file->table_lock); - idr_for_each(&file->object_idr, per_file_stats, &stats); - spin_unlock(&file->table_lock); - /* - * Although we have a valid reference on file->pid, that does - * not guarantee that the task_struct who called get_pid() is - * still alive (e.g. get_pid(current) => fork() => exit()). - * Therefore, we need to protect this ->comm access using RCU. - */ - request = list_first_entry_or_null(&file_priv->mm.request_list, - struct i915_request, - client_link); - rcu_read_lock(); - task = pid_task(request && request->gem_context->pid ? - request->gem_context->pid : file->pid, - PIDTYPE_PID); - print_file_stats(m, task ? task->comm : "<unknown>", stats); - rcu_read_unlock(); + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; - mutex_unlock(&dev->struct_mutex); - } - mutex_unlock(&dev->filelist_mutex); + print_batch_pool_stats(m, dev_priv); + print_context_stats(m, dev_priv); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -984,8 +954,8 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file) intel_runtime_pm_get(i915); gpu = i915_capture_gpu_state(i915); intel_runtime_pm_put(i915); - if (!gpu) - return -ENOMEM; + if (IS_ERR(gpu)) + return PTR_ERR(gpu); file->private_data = gpu; return 0; @@ -1018,7 +988,13 @@ i915_error_state_write(struct file *filp, static int i915_error_state_open(struct inode *inode, struct file *file) { - file->private_data = i915_first_error_state(inode->i_private); + struct i915_gpu_state *error; + + error = i915_first_error_state(inode->i_private); + if (IS_ERR(error)) + return PTR_ERR(error); + + file->private_data = error; return 0; } @@ -1032,30 +1008,6 @@ static const struct file_operations i915_error_state_fops = { }; #endif -static int -i915_next_seqno_set(void *data, u64 val) -{ - struct drm_i915_private *dev_priv = data; - struct drm_device *dev = &dev_priv->drm; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; - - intel_runtime_pm_get(dev_priv); - ret = i915_gem_set_global_seqno(dev, val); - intel_runtime_pm_put(dev_priv); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops, - NULL, i915_next_seqno_set, - "0x%llx\n"); - static int i915_frequency_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -1064,7 +1016,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { u16 rgvswctl = I915_READ16(MEMSWCTL); u16 rgvstat = I915_READ16(MEMSTAT_ILK); @@ -1785,7 +1737,7 @@ static int i915_emon_status(struct seq_file *m, void *unused) unsigned long temp, chipset, gfx; int ret; - if (!IS_GEN5(dev_priv)) + if (!IS_GEN(dev_priv, 5)) return -ENODEV; intel_runtime_pm_get(dev_priv); @@ -2034,7 +1986,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) seq_printf(m, "bit6 swizzle for Y-tiling = %s\n", swizzle_string(dev_priv->mm.bit_6_swizzle_y)); - if (IS_GEN3(dev_priv) || IS_GEN4(dev_priv)) { + if (IS_GEN_RANGE(dev_priv, 3, 4)) { seq_printf(m, "DDC = 0x%08x\n", I915_READ(DCC)); seq_printf(m, "DDC2 = 0x%08x\n", @@ -2070,124 +2022,6 @@ static int i915_swizzle_info(struct seq_file *m, void *data) return 0; } -static int per_file_ctx(int id, void *ptr, void *data) -{ - struct i915_gem_context *ctx = ptr; - struct seq_file *m = data; - struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; - - if (!ppgtt) { - seq_printf(m, " no ppgtt for context %d\n", - ctx->user_handle); - return 0; - } - - if (i915_gem_context_is_default(ctx)) - seq_puts(m, " default context:\n"); - else - seq_printf(m, " context %d:\n", ctx->user_handle); - ppgtt->debug_dump(ppgtt, m); - - return 0; -} - -static void gen8_ppgtt_info(struct seq_file *m, - struct drm_i915_private *dev_priv) -{ - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - struct intel_engine_cs *engine; - enum intel_engine_id id; - int i; - - if (!ppgtt) - return; - - for_each_engine(engine, dev_priv, id) { - seq_printf(m, "%s\n", engine->name); - for (i = 0; i < 4; i++) { - u64 pdp = I915_READ(GEN8_RING_PDP_UDW(engine, i)); - pdp <<= 32; - pdp |= I915_READ(GEN8_RING_PDP_LDW(engine, i)); - seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp); - } - } -} - -static void gen6_ppgtt_info(struct seq_file *m, - struct drm_i915_private *dev_priv) -{ - struct intel_engine_cs *engine; - enum intel_engine_id id; - - if (IS_GEN6(dev_priv)) - seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE)); - - for_each_engine(engine, dev_priv, id) { - seq_printf(m, "%s\n", engine->name); - if (IS_GEN7(dev_priv)) - seq_printf(m, "GFX_MODE: 0x%08x\n", - I915_READ(RING_MODE_GEN7(engine))); - seq_printf(m, "PP_DIR_BASE: 0x%08x\n", - I915_READ(RING_PP_DIR_BASE(engine))); - seq_printf(m, "PP_DIR_BASE_READ: 0x%08x\n", - I915_READ(RING_PP_DIR_BASE_READ(engine))); - seq_printf(m, "PP_DIR_DCLV: 0x%08x\n", - I915_READ(RING_PP_DIR_DCLV(engine))); - } - if (dev_priv->mm.aliasing_ppgtt) { - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - - seq_puts(m, "aliasing PPGTT:\n"); - seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.base.ggtt_offset); - - ppgtt->debug_dump(ppgtt, m); - } - - seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK)); -} - -static int i915_ppgtt_info(struct seq_file *m, void *data) -{ - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; - struct drm_file *file; - int ret; - - mutex_lock(&dev->filelist_mutex); - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - goto out_unlock; - - intel_runtime_pm_get(dev_priv); - - if (INTEL_GEN(dev_priv) >= 8) - gen8_ppgtt_info(m, dev_priv); - else if (INTEL_GEN(dev_priv) >= 6) - gen6_ppgtt_info(m, dev_priv); - - list_for_each_entry_reverse(file, &dev->filelist, lhead) { - struct drm_i915_file_private *file_priv = file->driver_priv; - struct task_struct *task; - - task = get_pid_task(file->pid, PIDTYPE_PID); - if (!task) { - ret = -ESRCH; - goto out_rpm; - } - seq_printf(m, "\nproc: %s\n", task->comm); - put_task_struct(task); - idr_for_each(&file_priv->context_idr, per_file_ctx, - (void *)(unsigned long)m); - } - -out_rpm: - intel_runtime_pm_put(dev_priv); - mutex_unlock(&dev->struct_mutex); -out_unlock: - mutex_unlock(&dev->filelist_mutex); - return ret; -} - static int count_irq_waiters(struct drm_i915_private *i915) { struct intel_engine_cs *engine; @@ -2948,14 +2782,7 @@ static void intel_seq_print_mode(struct seq_file *m, int tabs, for (i = 0; i < tabs; i++) seq_putc(m, '\t'); - seq_printf(m, "id %d:\"%s\" freq %d clock %d hdisp %d hss %d hse %d htot %d vdisp %d vss %d vse %d vtot %d type 0x%x flags 0x%x\n", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + seq_printf(m, DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); } static void intel_encoder_info(struct seq_file *m, @@ -3127,14 +2954,13 @@ static const char *plane_type(enum drm_plane_type type) return "unknown"; } -static const char *plane_rotation(unsigned int rotation) +static void plane_rotation(char *buf, size_t bufsize, unsigned int rotation) { - static char buf[48]; /* * According to doc only one DRM_MODE_ROTATE_ is allowed but this * will print them all to visualize if the values are misused */ - snprintf(buf, sizeof(buf), + snprintf(buf, bufsize, "%s%s%s%s%s%s(0x%08x)", (rotation & DRM_MODE_ROTATE_0) ? "0 " : "", (rotation & DRM_MODE_ROTATE_90) ? "90 " : "", @@ -3143,8 +2969,6 @@ static const char *plane_rotation(unsigned int rotation) (rotation & DRM_MODE_REFLECT_X) ? "FLIPX " : "", (rotation & DRM_MODE_REFLECT_Y) ? "FLIPY " : "", rotation); - - return buf; } static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) @@ -3157,6 +2981,7 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) struct drm_plane_state *state; struct drm_plane *plane = &intel_plane->base; struct drm_format_name_buf format_name; + char rot_str[48]; if (!plane->state) { seq_puts(m, "plane->state is NULL!\n"); @@ -3172,6 +2997,8 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) sprintf(format_name.str, "N/A"); } + plane_rotation(rot_str, sizeof(rot_str), state->rotation); + seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n", plane->base.id, plane_type(intel_plane->base.type), @@ -3186,7 +3013,7 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) (state->src_h >> 16), ((state->src_h & 0xffff) * 15625) >> 10, format_name.str, - plane_rotation(state->rotation)); + rot_str); } } @@ -3293,7 +3120,7 @@ static int i915_engine_info(struct seq_file *m, void *unused) seq_printf(m, "Global active requests: %d\n", dev_priv->gt.active_requests); seq_printf(m, "CS timestamp frequency: %u kHz\n", - dev_priv->info.cs_timestamp_frequency_khz); + RUNTIME_INFO(dev_priv)->cs_timestamp_frequency_khz); p = drm_seq_file_printer(m); for_each_engine(engine, dev_priv, id) @@ -3309,7 +3136,7 @@ static int i915_rcs_topology(struct seq_file *m, void *unused) struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_printer p = drm_seq_file_printer(m); - intel_device_info_dump_topology(&INTEL_INFO(dev_priv)->sseu, &p); + intel_device_info_dump_topology(&RUNTIME_INFO(dev_priv)->sseu, &p); return 0; } @@ -4213,9 +4040,6 @@ i915_drop_caches_set(void *data, u64 val) I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT); - if (ret == 0 && val & DROP_RESET_SEQNO) - ret = i915_gem_set_global_seqno(&i915->drm, 1); - if (val & DROP_RETIRE) i915_retire_requests(i915); @@ -4268,7 +4092,7 @@ i915_cache_sharing_get(void *data, u64 *val) struct drm_i915_private *dev_priv = data; u32 snpcr; - if (!(IS_GEN6(dev_priv) || IS_GEN7(dev_priv))) + if (!(IS_GEN_RANGE(dev_priv, 6, 7))) return -ENODEV; intel_runtime_pm_get(dev_priv); @@ -4288,7 +4112,7 @@ i915_cache_sharing_set(void *data, u64 val) struct drm_i915_private *dev_priv = data; u32 snpcr; - if (!(IS_GEN6(dev_priv) || IS_GEN7(dev_priv))) + if (!(IS_GEN_RANGE(dev_priv, 6, 7))) return -ENODEV; if (val > 3) @@ -4348,7 +4172,7 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { #define SS_MAX 6 - const struct intel_device_info *info = INTEL_INFO(dev_priv); + const struct intel_runtime_info *info = RUNTIME_INFO(dev_priv); u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2]; int s, ss; @@ -4404,7 +4228,7 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { #define SS_MAX 3 - const struct intel_device_info *info = INTEL_INFO(dev_priv); + const struct intel_runtime_info *info = RUNTIME_INFO(dev_priv); u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2]; int s, ss; @@ -4432,7 +4256,7 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv, if (IS_GEN9_BC(dev_priv)) sseu->subslice_mask[s] = - INTEL_INFO(dev_priv)->sseu.subslice_mask[s]; + RUNTIME_INFO(dev_priv)->sseu.subslice_mask[s]; for (ss = 0; ss < info->sseu.max_subslices; ss++) { unsigned int eu_cnt; @@ -4466,10 +4290,10 @@ static void broadwell_sseu_device_status(struct drm_i915_private *dev_priv, if (sseu->slice_mask) { sseu->eu_per_subslice = - INTEL_INFO(dev_priv)->sseu.eu_per_subslice; + RUNTIME_INFO(dev_priv)->sseu.eu_per_subslice; for (s = 0; s < fls(sseu->slice_mask); s++) { sseu->subslice_mask[s] = - INTEL_INFO(dev_priv)->sseu.subslice_mask[s]; + RUNTIME_INFO(dev_priv)->sseu.subslice_mask[s]; } sseu->eu_total = sseu->eu_per_subslice * sseu_subslice_total(sseu); @@ -4477,7 +4301,7 @@ static void broadwell_sseu_device_status(struct drm_i915_private *dev_priv, /* subtract fused off EU(s) from enabled slice(s) */ for (s = 0; s < fls(sseu->slice_mask); s++) { u8 subslice_7eu = - INTEL_INFO(dev_priv)->sseu.subslice_7eu[s]; + RUNTIME_INFO(dev_priv)->sseu.subslice_7eu[s]; sseu->eu_total -= hweight8(subslice_7eu); } @@ -4530,14 +4354,14 @@ static int i915_sseu_status(struct seq_file *m, void *unused) return -ENODEV; seq_puts(m, "SSEU Device Info\n"); - i915_print_sseu_info(m, true, &INTEL_INFO(dev_priv)->sseu); + i915_print_sseu_info(m, true, &RUNTIME_INFO(dev_priv)->sseu); seq_puts(m, "SSEU Device Status\n"); memset(&sseu, 0, sizeof(sseu)); - sseu.max_slices = INTEL_INFO(dev_priv)->sseu.max_slices; - sseu.max_subslices = INTEL_INFO(dev_priv)->sseu.max_subslices; + sseu.max_slices = RUNTIME_INFO(dev_priv)->sseu.max_slices; + sseu.max_subslices = RUNTIME_INFO(dev_priv)->sseu.max_subslices; sseu.max_eus_per_subslice = - INTEL_INFO(dev_priv)->sseu.max_eus_per_subslice; + RUNTIME_INFO(dev_priv)->sseu.max_eus_per_subslice; intel_runtime_pm_get(dev_priv); @@ -4545,7 +4369,7 @@ static int i915_sseu_status(struct seq_file *m, void *unused) cherryview_sseu_device_status(dev_priv, &sseu); } else if (IS_BROADWELL(dev_priv)) { broadwell_sseu_device_status(dev_priv, &sseu); - } else if (IS_GEN9(dev_priv)) { + } else if (IS_GEN(dev_priv, 9)) { gen9_sseu_device_status(dev_priv, &sseu); } else if (INTEL_GEN(dev_priv) >= 10) { gen10_sseu_device_status(dev_priv, &sseu); @@ -4906,7 +4730,6 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_context_status", i915_context_status, 0}, {"i915_forcewake_domains", i915_forcewake_domains, 0}, {"i915_swizzle_info", i915_swizzle_info, 0}, - {"i915_ppgtt_info", i915_ppgtt_info, 0}, {"i915_llc", i915_llc, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, @@ -4941,7 +4764,6 @@ static const struct i915_debugfs_files { {"i915_gpu_info", &i915_gpu_info_fops}, #endif {"i915_fifo_underrun_reset", &i915_fifo_underrun_reset_ops}, - {"i915_next_seqno", &i915_next_seqno_fops}, {"i915_pri_wm_latency", &i915_pri_wm_latency_fops}, {"i915_spr_wm_latency", &i915_spr_wm_latency_fops}, {"i915_cur_wm_latency", &i915_cur_wm_latency_fops}, @@ -5088,6 +4910,106 @@ static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data) } DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); +static int i915_dsc_fec_support_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc; + struct intel_dp *intel_dp; + struct drm_modeset_acquire_ctx ctx; + struct intel_crtc_state *crtc_state = NULL; + int ret = 0; + bool try_again = false; + + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + + do { + try_again = false; + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, + &ctx); + if (ret) { + ret = -EINTR; + break; + } + crtc = connector->state->crtc; + if (connector->status != connector_status_connected || !crtc) { + ret = -ENODEV; + break; + } + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) { + try_again = true; + continue; + } + break; + } else if (ret) { + break; + } + intel_dp = enc_to_intel_dp(&intel_attached_encoder(connector)->base); + crtc_state = to_intel_crtc_state(crtc->state); + seq_printf(m, "DSC_Enabled: %s\n", + yesno(crtc_state->dsc_params.compression_enable)); + if (intel_dp->dsc_dpcd) + seq_printf(m, "DSC_Sink_Support: %s\n", + yesno(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd))); + if (!intel_dp_is_edp(intel_dp)) + seq_printf(m, "FEC_Sink_Support: %s\n", + yesno(drm_dp_sink_supports_fec(intel_dp->fec_capable))); + } while (try_again); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +static ssize_t i915_dsc_fec_support_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + bool dsc_enable = false; + int ret; + struct drm_connector *connector = + ((struct seq_file *)file->private_data)->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + + if (len == 0) + return 0; + + DRM_DEBUG_DRIVER("Copied %zu bytes from user to force DSC\n", + len); + + ret = kstrtobool_from_user(ubuf, len, &dsc_enable); + if (ret < 0) + return ret; + + DRM_DEBUG_DRIVER("Got %s for DSC Enable\n", + (dsc_enable) ? "true" : "false"); + intel_dp->force_dsc_en = dsc_enable; + + *offp += len; + return len; +} + +static int i915_dsc_fec_support_open(struct inode *inode, + struct file *file) +{ + return single_open(file, i915_dsc_fec_support_show, + inode->i_private); +} + +static const struct file_operations i915_dsc_fec_support_fops = { + .owner = THIS_MODULE, + .open = i915_dsc_fec_support_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_dsc_fec_support_write +}; + /** * i915_debugfs_connector_add - add i915 specific connector debugfs files * @connector: pointer to a registered drm_connector @@ -5100,6 +5022,7 @@ DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); int i915_debugfs_connector_add(struct drm_connector *connector) { struct dentry *root = connector->debugfs_entry; + struct drm_i915_private *dev_priv = to_i915(connector->dev); /* The connector must have been registered beforehands. */ if (!root) @@ -5124,5 +5047,11 @@ int i915_debugfs_connector_add(struct drm_connector *connector) connector, &i915_hdcp_sink_capability_fops); } + if (INTEL_GEN(dev_priv) >= 10 && + (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector->connector_type == DRM_MODE_CONNECTOR_eDP)) + debugfs_create_file("i915_dsc_fec_support", S_IRUGO, root, + connector, &i915_dsc_fec_support_fops); + return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b310a897a4ad..75652dc1e24c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -41,7 +41,6 @@ #include <linux/vt.h> #include <acpi/video.h> -#include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/i915_drm.h> @@ -132,15 +131,15 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) switch (id) { case INTEL_PCH_IBX_DEVICE_ID_TYPE: DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); - WARN_ON(!IS_GEN5(dev_priv)); + WARN_ON(!IS_GEN(dev_priv, 5)); return PCH_IBX; case INTEL_PCH_CPT_DEVICE_ID_TYPE: DRM_DEBUG_KMS("Found CougarPoint PCH\n"); - WARN_ON(!IS_GEN6(dev_priv) && !IS_IVYBRIDGE(dev_priv)); + WARN_ON(!IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv)); return PCH_CPT; case INTEL_PCH_PPT_DEVICE_ID_TYPE: DRM_DEBUG_KMS("Found PantherPoint PCH\n"); - WARN_ON(!IS_GEN6(dev_priv) && !IS_IVYBRIDGE(dev_priv)); + WARN_ON(!IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv)); /* PantherPoint is CPT compatible */ return PCH_CPT; case INTEL_PCH_LPT_DEVICE_ID_TYPE: @@ -217,9 +216,9 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv) * make an educated guess as to which PCH is really there. */ - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) id = INTEL_PCH_IBX_DEVICE_ID_TYPE; - else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) + else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) id = INTEL_PCH_CPT_DEVICE_ID_TYPE; else if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv)) id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE; @@ -349,7 +348,7 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = min_t(int, INTEL_PPGTT(dev_priv), I915_GEM_PPGTT_FULL); break; case I915_PARAM_HAS_SEMAPHORES: - value = HAS_LEGACY_SEMAPHORES(dev_priv); + value = 0; break; case I915_PARAM_HAS_SECURE_BATCHES: value = capable(CAP_SYS_ADMIN); @@ -358,12 +357,12 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = i915_cmd_parser_get_version(dev_priv); break; case I915_PARAM_SUBSLICE_TOTAL: - value = sseu_subslice_total(&INTEL_INFO(dev_priv)->sseu); + value = sseu_subslice_total(&RUNTIME_INFO(dev_priv)->sseu); if (!value) return -ENODEV; break; case I915_PARAM_EU_TOTAL: - value = INTEL_INFO(dev_priv)->sseu.eu_total; + value = RUNTIME_INFO(dev_priv)->sseu.eu_total; if (!value) return -ENODEV; break; @@ -380,7 +379,7 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = HAS_POOLED_EU(dev_priv); break; case I915_PARAM_MIN_EU_IN_POOL: - value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool; + value = RUNTIME_INFO(dev_priv)->sseu.min_eu_in_pool; break; case I915_PARAM_HUC_STATUS: value = intel_huc_check_status(&dev_priv->huc); @@ -430,17 +429,17 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = intel_engines_has_context_isolation(dev_priv); break; case I915_PARAM_SLICE_MASK: - value = INTEL_INFO(dev_priv)->sseu.slice_mask; + value = RUNTIME_INFO(dev_priv)->sseu.slice_mask; if (!value) return -ENODEV; break; case I915_PARAM_SUBSLICE_MASK: - value = INTEL_INFO(dev_priv)->sseu.subslice_mask[0]; + value = RUNTIME_INFO(dev_priv)->sseu.subslice_mask[0]; if (!value) return -ENODEV; break; case I915_PARAM_CS_TIMESTAMP_FREQUENCY: - value = 1000 * INTEL_INFO(dev_priv)->cs_timestamp_frequency_khz; + value = 1000 * RUNTIME_INFO(dev_priv)->cs_timestamp_frequency_khz; break; case I915_PARAM_MMAP_GTT_COHERENT: value = INTEL_INFO(dev_priv)->has_coherent_ggtt; @@ -966,7 +965,7 @@ static int i915_mmio_setup(struct drm_i915_private *dev_priv) int mmio_bar; int mmio_size; - mmio_bar = IS_GEN2(dev_priv) ? 1 : 0; + mmio_bar = IS_GEN(dev_priv, 2) ? 1 : 0; /* * Before gen4, the registers and the GTT are behind different BARs. * However, from gen4 onwards, the registers and the GTT are shared @@ -1341,7 +1340,7 @@ intel_get_dram_info(struct drm_i915_private *dev_priv) /* Need to calculate bandwidth only for Gen9 */ if (IS_BROXTON(dev_priv)) ret = bxt_get_dram_info(dev_priv); - else if (IS_GEN9(dev_priv)) + else if (IS_GEN(dev_priv, 9)) ret = skl_get_dram_info(dev_priv); else ret = skl_dram_get_channels_info(dev_priv); @@ -1374,7 +1373,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) if (i915_inject_load_failure()) return -ENODEV; - intel_device_info_runtime_init(mkwrite_device_info(dev_priv)); + intel_device_info_runtime_init(dev_priv); if (HAS_PPGTT(dev_priv)) { if (intel_vgpu_active(dev_priv) && @@ -1436,7 +1435,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) pci_set_master(pdev); /* overlay on gen2 is broken and can't address above 1G */ - if (IS_GEN2(dev_priv)) { + if (IS_GEN(dev_priv, 2)) { ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(30)); if (ret) { DRM_ERROR("failed to set DMA mask\n"); @@ -1574,7 +1573,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) acpi_video_register(); } - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) intel_gpu_ips_init(dev_priv); intel_audio_init(dev_priv); @@ -1636,8 +1635,14 @@ static void i915_welcome_messages(struct drm_i915_private *dev_priv) if (drm_debug & DRM_UT_DRIVER) { struct drm_printer p = drm_debug_printer("i915 device info:"); - intel_device_info_dump(&dev_priv->info, &p); - intel_device_info_dump_runtime(&dev_priv->info, &p); + drm_printf(&p, "pciid=0x%04x rev=0x%02x platform=%s gen=%i\n", + INTEL_DEVID(dev_priv), + INTEL_REVID(dev_priv), + intel_platform_name(INTEL_INFO(dev_priv)->platform), + INTEL_GEN(dev_priv)); + + intel_device_info_dump_flags(INTEL_INFO(dev_priv), &p); + intel_device_info_dump_runtime(RUNTIME_INFO(dev_priv), &p); } if (IS_ENABLED(CONFIG_DRM_I915_DEBUG)) @@ -1674,7 +1679,7 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) /* Setup the write-once "constant" device info */ device_info = mkwrite_device_info(i915); memcpy(device_info, match_info, sizeof(*device_info)); - device_info->device_id = pdev->device; + RUNTIME_INFO(i915)->device_id = pdev->device; BUILD_BUG_ON(INTEL_MAX_PLATFORMS > BITS_PER_TYPE(device_info->platform_mask)); @@ -2174,7 +2179,7 @@ static int i915_drm_resume_early(struct drm_device *dev) intel_power_domains_resume(dev_priv); - intel_engines_sanitize(dev_priv); + intel_engines_sanitize(dev_priv, true); enable_rpm_wakeref_asserts(dev_priv); @@ -2226,6 +2231,7 @@ void i915_reset(struct drm_i915_private *i915, might_sleep(); lockdep_assert_held(&i915->drm.struct_mutex); + assert_rpm_wakelock_held(i915); GEM_BUG_ON(!test_bit(I915_RESET_BACKOFF, &error->flags)); if (!test_bit(I915_RESET_HANDOFF, &error->flags)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b1c31967194b..5df26ccda8a4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -46,7 +46,6 @@ #include <linux/reservation.h> #include <linux/shmem_fs.h> -#include <drm/drmP.h> #include <drm/intel-gtt.h> #include <drm/drm_legacy.h> /* for struct drm_dma_handle */ #include <drm/drm_gem.h> @@ -54,6 +53,7 @@ #include <drm/drm_cache.h> #include <drm/drm_util.h> #include <drm/drm_dsc.h> +#include <drm/drm_connector.h> #include "i915_fixed.h" #include "i915_params.h" @@ -90,8 +90,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20181204" -#define DRIVER_TIMESTAMP 1543944377 +#define DRIVER_DATE "20190110" +#define DRIVER_TIMESTAMP 1547162337 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions @@ -281,16 +281,14 @@ struct drm_i915_display_funcs { int (*get_fifo_size)(struct drm_i915_private *dev_priv, enum i9xx_plane_id i9xx_plane); int (*compute_pipe_wm)(struct intel_crtc_state *cstate); - int (*compute_intermediate_wm)(struct drm_device *dev, - struct intel_crtc *intel_crtc, - struct intel_crtc_state *newstate); + int (*compute_intermediate_wm)(struct intel_crtc_state *newstate); void (*initial_watermarks)(struct intel_atomic_state *state, struct intel_crtc_state *cstate); void (*atomic_update_watermarks)(struct intel_atomic_state *state, struct intel_crtc_state *cstate); void (*optimize_watermarks)(struct intel_atomic_state *state, struct intel_crtc_state *cstate); - int (*compute_global_watermarks)(struct drm_atomic_state *state); + int (*compute_global_watermarks)(struct intel_atomic_state *state); void (*update_wm)(struct intel_crtc *crtc); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, @@ -322,8 +320,8 @@ struct drm_i915_display_funcs { /* display clock increase/decrease */ /* pll clock increase/decrease */ - void (*load_csc_matrix)(struct drm_crtc_state *crtc_state); - void (*load_luts)(struct drm_crtc_state *crtc_state); + void (*load_csc_matrix)(struct intel_crtc_state *crtc_state); + void (*load_luts)(struct intel_crtc_state *crtc_state); }; #define CSR_VERSION(major, minor) ((major) << 16 | (minor)) @@ -509,6 +507,7 @@ struct i915_psr { ktime_t last_exit; bool sink_not_reliable; bool irq_aux_error; + u16 su_x_granularity; }; enum intel_pch { @@ -936,6 +935,8 @@ struct ddi_vbt_port_info { uint8_t supports_hdmi:1; uint8_t supports_dp:1; uint8_t supports_edp:1; + uint8_t supports_typec_usb:1; + uint8_t supports_tbt:1; uint8_t alternate_aux_channel; uint8_t alternate_ddc_pin; @@ -1430,7 +1431,8 @@ struct drm_i915_private { struct kmem_cache *dependencies; struct kmem_cache *priorities; - const struct intel_device_info info; + const struct intel_device_info __info; /* Use INTEL_INFO() to access. */ + struct intel_runtime_info __runtime; /* Use RUNTIME_INFO() to access. */ struct intel_driver_caps caps; /** @@ -1947,7 +1949,6 @@ struct drm_i915_private { struct list_head active_rings; struct list_head closed_vma; u32 active_requests; - u32 request_serial; /** * Is the GPU currently considered idle, or busy executing @@ -2191,17 +2192,12 @@ static inline unsigned int i915_sg_segment_size(void) return size; } -static inline const struct intel_device_info * -intel_info(const struct drm_i915_private *dev_priv) -{ - return &dev_priv->info; -} - -#define INTEL_INFO(dev_priv) intel_info((dev_priv)) +#define INTEL_INFO(dev_priv) (&(dev_priv)->__info) +#define RUNTIME_INFO(dev_priv) (&(dev_priv)->__runtime) #define DRIVER_CAPS(dev_priv) (&(dev_priv)->caps) -#define INTEL_GEN(dev_priv) ((dev_priv)->info.gen) -#define INTEL_DEVID(dev_priv) ((dev_priv)->info.device_id) +#define INTEL_GEN(dev_priv) (INTEL_INFO(dev_priv)->gen) +#define INTEL_DEVID(dev_priv) (RUNTIME_INFO(dev_priv)->device_id) #define REVID_FOREVER 0xff #define INTEL_REVID(dev_priv) ((dev_priv)->drm.pdev->revision) @@ -2212,8 +2208,12 @@ intel_info(const struct drm_i915_private *dev_priv) GENMASK((e) - 1, (s) - 1)) /* Returns true if Gen is in inclusive range [Start, End] */ -#define IS_GEN(dev_priv, s, e) \ - (!!((dev_priv)->info.gen_mask & INTEL_GEN_MASK((s), (e)))) +#define IS_GEN_RANGE(dev_priv, s, e) \ + (!!(INTEL_INFO(dev_priv)->gen_mask & INTEL_GEN_MASK((s), (e)))) + +#define IS_GEN(dev_priv, n) \ + (BUILD_BUG_ON_ZERO(!__builtin_constant_p(n)) + \ + INTEL_INFO(dev_priv)->gen == (n)) /* * Return true if revision is in range [since,until] inclusive. @@ -2223,7 +2223,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_REVID(p, since, until) \ (INTEL_REVID(p) >= (since) && INTEL_REVID(p) <= (until)) -#define IS_PLATFORM(dev_priv, p) ((dev_priv)->info.platform_mask & BIT(p)) +#define IS_PLATFORM(dev_priv, p) (INTEL_INFO(dev_priv)->platform_mask & BIT(p)) #define IS_I830(dev_priv) IS_PLATFORM(dev_priv, INTEL_I830) #define IS_I845G(dev_priv) IS_PLATFORM(dev_priv, INTEL_I845G) @@ -2245,7 +2245,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_IRONLAKE_M(dev_priv) (INTEL_DEVID(dev_priv) == 0x0046) #define IS_IVYBRIDGE(dev_priv) IS_PLATFORM(dev_priv, INTEL_IVYBRIDGE) #define IS_IVB_GT1(dev_priv) (IS_IVYBRIDGE(dev_priv) && \ - (dev_priv)->info.gt == 1) + INTEL_INFO(dev_priv)->gt == 1) #define IS_VALLEYVIEW(dev_priv) IS_PLATFORM(dev_priv, INTEL_VALLEYVIEW) #define IS_CHERRYVIEW(dev_priv) IS_PLATFORM(dev_priv, INTEL_CHERRYVIEW) #define IS_HASWELL(dev_priv) IS_PLATFORM(dev_priv, INTEL_HASWELL) @@ -2257,7 +2257,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_COFFEELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_COFFEELAKE) #define IS_CANNONLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_CANNONLAKE) #define IS_ICELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ICELAKE) -#define IS_MOBILE(dev_priv) ((dev_priv)->info.is_mobile) +#define IS_MOBILE(dev_priv) (INTEL_INFO(dev_priv)->is_mobile) #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev_priv) (IS_BROADWELL(dev_priv) && \ @@ -2268,11 +2268,13 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_BDW_ULX(dev_priv) (IS_BROADWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xf) == 0xe) #define IS_BDW_GT3(dev_priv) (IS_BROADWELL(dev_priv) && \ - (dev_priv)->info.gt == 3) + INTEL_INFO(dev_priv)->gt == 3) #define IS_HSW_ULT(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0A00) #define IS_HSW_GT3(dev_priv) (IS_HASWELL(dev_priv) && \ - (dev_priv)->info.gt == 3) + INTEL_INFO(dev_priv)->gt == 3) +#define IS_HSW_GT1(dev_priv) (IS_HASWELL(dev_priv) && \ + INTEL_INFO(dev_priv)->gt == 1) /* ULX machines are also considered ULT. */ #define IS_HSW_ULX(dev_priv) (INTEL_DEVID(dev_priv) == 0x0A0E || \ INTEL_DEVID(dev_priv) == 0x0A1E) @@ -2295,21 +2297,21 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_AML_ULX(dev_priv) (INTEL_DEVID(dev_priv) == 0x591C || \ INTEL_DEVID(dev_priv) == 0x87C0) #define IS_SKL_GT2(dev_priv) (IS_SKYLAKE(dev_priv) && \ - (dev_priv)->info.gt == 2) + INTEL_INFO(dev_priv)->gt == 2) #define IS_SKL_GT3(dev_priv) (IS_SKYLAKE(dev_priv) && \ - (dev_priv)->info.gt == 3) + INTEL_INFO(dev_priv)->gt == 3) #define IS_SKL_GT4(dev_priv) (IS_SKYLAKE(dev_priv) && \ - (dev_priv)->info.gt == 4) + INTEL_INFO(dev_priv)->gt == 4) #define IS_KBL_GT2(dev_priv) (IS_KABYLAKE(dev_priv) && \ - (dev_priv)->info.gt == 2) + INTEL_INFO(dev_priv)->gt == 2) #define IS_KBL_GT3(dev_priv) (IS_KABYLAKE(dev_priv) && \ - (dev_priv)->info.gt == 3) + INTEL_INFO(dev_priv)->gt == 3) #define IS_CFL_ULT(dev_priv) (IS_COFFEELAKE(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0x00F0) == 0x00A0) #define IS_CFL_GT2(dev_priv) (IS_COFFEELAKE(dev_priv) && \ - (dev_priv)->info.gt == 2) + INTEL_INFO(dev_priv)->gt == 2) #define IS_CFL_GT3(dev_priv) (IS_COFFEELAKE(dev_priv) && \ - (dev_priv)->info.gt == 3) + INTEL_INFO(dev_priv)->gt == 3) #define IS_CNL_WITH_PORT_F(dev_priv) (IS_CANNONLAKE(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0x0004) == 0x0004) @@ -2366,26 +2368,9 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_ICL_REVID(p, since, until) \ (IS_ICELAKE(p) && IS_REVID(p, since, until)) -/* - * The genX designation typically refers to the render engine, so render - * capability related checks should use IS_GEN, while display and other checks - * have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular - * chips, etc.). - */ -#define IS_GEN2(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(1))) -#define IS_GEN3(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(2))) -#define IS_GEN4(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(3))) -#define IS_GEN5(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(4))) -#define IS_GEN6(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(5))) -#define IS_GEN7(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(6))) -#define IS_GEN8(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(7))) -#define IS_GEN9(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(8))) -#define IS_GEN10(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(9))) -#define IS_GEN11(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(10))) - #define IS_LP(dev_priv) (INTEL_INFO(dev_priv)->is_lp) -#define IS_GEN9_LP(dev_priv) (IS_GEN9(dev_priv) && IS_LP(dev_priv)) -#define IS_GEN9_BC(dev_priv) (IS_GEN9(dev_priv) && !IS_LP(dev_priv)) +#define IS_GEN9_LP(dev_priv) (IS_GEN(dev_priv, 9) && IS_LP(dev_priv)) +#define IS_GEN9_BC(dev_priv) (IS_GEN(dev_priv, 9) && !IS_LP(dev_priv)) #define ENGINE_MASK(id) BIT(id) #define RENDER_RING ENGINE_MASK(RCS) @@ -2399,29 +2384,27 @@ intel_info(const struct drm_i915_private *dev_priv) #define ALL_ENGINES (~0) #define HAS_ENGINE(dev_priv, id) \ - (!!((dev_priv)->info.ring_mask & ENGINE_MASK(id))) + (!!(INTEL_INFO(dev_priv)->ring_mask & ENGINE_MASK(id))) #define HAS_BSD(dev_priv) HAS_ENGINE(dev_priv, VCS) #define HAS_BSD2(dev_priv) HAS_ENGINE(dev_priv, VCS2) #define HAS_BLT(dev_priv) HAS_ENGINE(dev_priv, BCS) #define HAS_VEBOX(dev_priv) HAS_ENGINE(dev_priv, VECS) -#define HAS_LEGACY_SEMAPHORES(dev_priv) IS_GEN7(dev_priv) - -#define HAS_LLC(dev_priv) ((dev_priv)->info.has_llc) -#define HAS_SNOOP(dev_priv) ((dev_priv)->info.has_snoop) +#define HAS_LLC(dev_priv) (INTEL_INFO(dev_priv)->has_llc) +#define HAS_SNOOP(dev_priv) (INTEL_INFO(dev_priv)->has_snoop) #define HAS_EDRAM(dev_priv) (!!((dev_priv)->edram_cap & EDRAM_ENABLED)) #define HAS_WT(dev_priv) ((IS_HASWELL(dev_priv) || \ IS_BROADWELL(dev_priv)) && HAS_EDRAM(dev_priv)) -#define HWS_NEEDS_PHYSICAL(dev_priv) ((dev_priv)->info.hws_needs_physical) +#define HWS_NEEDS_PHYSICAL(dev_priv) (INTEL_INFO(dev_priv)->hws_needs_physical) #define HAS_LOGICAL_RING_CONTEXTS(dev_priv) \ - ((dev_priv)->info.has_logical_ring_contexts) + (INTEL_INFO(dev_priv)->has_logical_ring_contexts) #define HAS_LOGICAL_RING_ELSQ(dev_priv) \ - ((dev_priv)->info.has_logical_ring_elsq) + (INTEL_INFO(dev_priv)->has_logical_ring_elsq) #define HAS_LOGICAL_RING_PREEMPTION(dev_priv) \ - ((dev_priv)->info.has_logical_ring_preemption) + (INTEL_INFO(dev_priv)->has_logical_ring_preemption) #define HAS_EXECLISTS(dev_priv) HAS_LOGICAL_RING_CONTEXTS(dev_priv) @@ -2435,12 +2418,12 @@ intel_info(const struct drm_i915_private *dev_priv) #define HAS_PAGE_SIZES(dev_priv, sizes) ({ \ GEM_BUG_ON((sizes) == 0); \ - ((sizes) & ~(dev_priv)->info.page_sizes) == 0; \ + ((sizes) & ~INTEL_INFO(dev_priv)->page_sizes) == 0; \ }) -#define HAS_OVERLAY(dev_priv) ((dev_priv)->info.display.has_overlay) +#define HAS_OVERLAY(dev_priv) (INTEL_INFO(dev_priv)->display.has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev_priv) \ - ((dev_priv)->info.display.overlay_needs_physical) + (INTEL_INFO(dev_priv)->display.overlay_needs_physical) /* Early gen2 have a totally busted CS tlb and require pinned batches. */ #define HAS_BROKEN_CS_TLB(dev_priv) (IS_I830(dev_priv) || IS_I845G(dev_priv)) @@ -2458,42 +2441,42 @@ intel_info(const struct drm_i915_private *dev_priv) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ -#define HAS_128_BYTE_Y_TILING(dev_priv) (!IS_GEN2(dev_priv) && \ +#define HAS_128_BYTE_Y_TILING(dev_priv) (!IS_GEN(dev_priv, 2) && \ !(IS_I915G(dev_priv) || \ IS_I915GM(dev_priv))) -#define SUPPORTS_TV(dev_priv) ((dev_priv)->info.display.supports_tv) -#define I915_HAS_HOTPLUG(dev_priv) ((dev_priv)->info.display.has_hotplug) +#define SUPPORTS_TV(dev_priv) (INTEL_INFO(dev_priv)->display.supports_tv) +#define I915_HAS_HOTPLUG(dev_priv) (INTEL_INFO(dev_priv)->display.has_hotplug) #define HAS_FW_BLC(dev_priv) (INTEL_GEN(dev_priv) > 2) -#define HAS_FBC(dev_priv) ((dev_priv)->info.display.has_fbc) +#define HAS_FBC(dev_priv) (INTEL_INFO(dev_priv)->display.has_fbc) #define HAS_CUR_FBC(dev_priv) (!HAS_GMCH_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 7) #define HAS_IPS(dev_priv) (IS_HSW_ULT(dev_priv) || IS_BROADWELL(dev_priv)) -#define HAS_DP_MST(dev_priv) ((dev_priv)->info.display.has_dp_mst) +#define HAS_DP_MST(dev_priv) (INTEL_INFO(dev_priv)->display.has_dp_mst) -#define HAS_DDI(dev_priv) ((dev_priv)->info.display.has_ddi) -#define HAS_FPGA_DBG_UNCLAIMED(dev_priv) ((dev_priv)->info.has_fpga_dbg) -#define HAS_PSR(dev_priv) ((dev_priv)->info.display.has_psr) +#define HAS_DDI(dev_priv) (INTEL_INFO(dev_priv)->display.has_ddi) +#define HAS_FPGA_DBG_UNCLAIMED(dev_priv) (INTEL_INFO(dev_priv)->has_fpga_dbg) +#define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr) -#define HAS_RC6(dev_priv) ((dev_priv)->info.has_rc6) -#define HAS_RC6p(dev_priv) ((dev_priv)->info.has_rc6p) +#define HAS_RC6(dev_priv) (INTEL_INFO(dev_priv)->has_rc6) +#define HAS_RC6p(dev_priv) (INTEL_INFO(dev_priv)->has_rc6p) #define HAS_RC6pp(dev_priv) (false) /* HW was never validated */ -#define HAS_CSR(dev_priv) ((dev_priv)->info.display.has_csr) +#define HAS_CSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_csr) -#define HAS_RUNTIME_PM(dev_priv) ((dev_priv)->info.has_runtime_pm) -#define HAS_64BIT_RELOC(dev_priv) ((dev_priv)->info.has_64bit_reloc) +#define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm) +#define HAS_64BIT_RELOC(dev_priv) (INTEL_INFO(dev_priv)->has_64bit_reloc) -#define HAS_IPC(dev_priv) ((dev_priv)->info.display.has_ipc) +#define HAS_IPC(dev_priv) (INTEL_INFO(dev_priv)->display.has_ipc) /* * For now, anything with a GuC requires uCode loading, and then supports * command submission once loaded. But these are logically independent * properties, so we have separate macros to test them. */ -#define HAS_GUC(dev_priv) ((dev_priv)->info.has_guc) -#define HAS_GUC_CT(dev_priv) ((dev_priv)->info.has_guc_ct) +#define HAS_GUC(dev_priv) (INTEL_INFO(dev_priv)->has_guc) +#define HAS_GUC_CT(dev_priv) (INTEL_INFO(dev_priv)->has_guc_ct) #define HAS_GUC_UCODE(dev_priv) (HAS_GUC(dev_priv)) #define HAS_GUC_SCHED(dev_priv) (HAS_GUC(dev_priv)) @@ -2502,11 +2485,11 @@ intel_info(const struct drm_i915_private *dev_priv) #define HAS_HUC_UCODE(dev_priv) (HAS_GUC(dev_priv)) /* Having a GuC is not the same as using a GuC */ -#define USES_GUC(dev_priv) intel_uc_is_using_guc() -#define USES_GUC_SUBMISSION(dev_priv) intel_uc_is_using_guc_submission() -#define USES_HUC(dev_priv) intel_uc_is_using_huc() +#define USES_GUC(dev_priv) intel_uc_is_using_guc(dev_priv) +#define USES_GUC_SUBMISSION(dev_priv) intel_uc_is_using_guc_submission(dev_priv) +#define USES_HUC(dev_priv) intel_uc_is_using_huc(dev_priv) -#define HAS_POOLED_EU(dev_priv) ((dev_priv)->info.has_pooled_eu) +#define HAS_POOLED_EU(dev_priv) (INTEL_INFO(dev_priv)->has_pooled_eu) #define INTEL_PCH_DEVICE_ID_MASK 0xff80 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -2546,12 +2529,12 @@ intel_info(const struct drm_i915_private *dev_priv) #define HAS_PCH_NOP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_NOP) #define HAS_PCH_SPLIT(dev_priv) (INTEL_PCH_TYPE(dev_priv) != PCH_NONE) -#define HAS_GMCH_DISPLAY(dev_priv) ((dev_priv)->info.display.has_gmch_display) +#define HAS_GMCH_DISPLAY(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch_display) #define HAS_LSPCON(dev_priv) (INTEL_GEN(dev_priv) >= 9) /* DPF == dynamic parity feature */ -#define HAS_L3_DPF(dev_priv) ((dev_priv)->info.has_l3_dpf) +#define HAS_L3_DPF(dev_priv) (INTEL_INFO(dev_priv)->has_l3_dpf) #define NUM_L3_SLICES(dev_priv) (IS_HSW_GT3(dev_priv) ? \ 2 : HAS_L3_DPF(dev_priv)) @@ -2916,9 +2899,9 @@ i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) __i915_gem_object_unpin_pages(obj); } -enum i915_mm_subclass { /* lockdep subclass for obj->mm.lock */ +enum i915_mm_subclass { /* lockdep subclass for obj->mm.lock/struct_mutex */ I915_MM_NORMAL = 0, - I915_MM_SHRINKER + I915_MM_SHRINKER /* called "recursively" from direct-reclaim-esque */ }; void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, @@ -3204,7 +3187,8 @@ unsigned long i915_gem_shrink(struct drm_i915_private *i915, unsigned long i915_gem_shrink_all(struct drm_i915_private *i915); void i915_gem_shrinker_register(struct drm_i915_private *i915); void i915_gem_shrinker_unregister(struct drm_i915_private *i915); -void i915_gem_shrinker_taints_mutex(struct mutex *mutex); +void i915_gem_shrinker_taints_mutex(struct drm_i915_private *i915, + struct mutex *mutex); /* i915_gem_tiling.c */ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) @@ -3313,7 +3297,7 @@ static inline void intel_unregister_dsm_handler(void) { return; } static inline struct intel_device_info * mkwrite_device_info(struct drm_i915_private *dev_priv) { - return (struct intel_device_info *)&dev_priv->info; + return (struct intel_device_info *)INTEL_INFO(dev_priv); } /* modesetting */ @@ -3599,90 +3583,6 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) } } -static inline bool -__i915_request_irq_complete(const struct i915_request *rq) -{ - struct intel_engine_cs *engine = rq->engine; - u32 seqno; - - /* Note that the engine may have wrapped around the seqno, and - * so our request->global_seqno will be ahead of the hardware, - * even though it completed the request before wrapping. We catch - * this by kicking all the waiters before resetting the seqno - * in hardware, and also signal the fence. - */ - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags)) - return true; - - /* The request was dequeued before we were awoken. We check after - * inspecting the hw to confirm that this was the same request - * that generated the HWS update. The memory barriers within - * the request execution are sufficient to ensure that a check - * after reading the value from hw matches this request. - */ - seqno = i915_request_global_seqno(rq); - if (!seqno) - return false; - - /* Before we do the heavier coherent read of the seqno, - * check the value (hopefully) in the CPU cacheline. - */ - if (__i915_request_completed(rq, seqno)) - return true; - - /* Ensure our read of the seqno is coherent so that we - * do not "miss an interrupt" (i.e. if this is the last - * request and the seqno write from the GPU is not visible - * by the time the interrupt fires, we will see that the - * request is incomplete and go back to sleep awaiting - * another interrupt that will never come.) - * - * Strictly, we only need to do this once after an interrupt, - * but it is easier and safer to do it every time the waiter - * is woken. - */ - if (engine->irq_seqno_barrier && - test_and_clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted)) { - struct intel_breadcrumbs *b = &engine->breadcrumbs; - - /* The ordering of irq_posted versus applying the barrier - * is crucial. The clearing of the current irq_posted must - * be visible before we perform the barrier operation, - * such that if a subsequent interrupt arrives, irq_posted - * is reasserted and our task rewoken (which causes us to - * do another __i915_request_irq_complete() immediately - * and reapply the barrier). Conversely, if the clear - * occurs after the barrier, then an interrupt that arrived - * whilst we waited on the barrier would not trigger a - * barrier on the next pass, and the read may not see the - * seqno update. - */ - engine->irq_seqno_barrier(engine); - - /* If we consume the irq, but we are no longer the bottom-half, - * the real bottom-half may not have serialised their own - * seqno check with the irq-barrier (i.e. may have inspected - * the seqno before we believe it coherent since they see - * irq_posted == false but we are still running). - */ - spin_lock_irq(&b->irq_lock); - if (b->irq_wait && b->irq_wait->tsk != current) - /* Note that if the bottom-half is changed as we - * are sending the wake-up, the new bottom-half will - * be woken by whomever made the change. We only have - * to worry about when we steal the irq-posted for - * ourself. - */ - wake_up_process(b->irq_wait->tsk); - spin_unlock_irq(&b->irq_lock); - - if (__i915_request_completed(rq, seqno)) - return true; - } - - return false; -} - void i915_memcpy_init_early(struct drm_i915_private *dev_priv); bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7399ac7a5629..ea85da393662 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -25,7 +25,6 @@ * */ -#include <drm/drmP.h> #include <drm/drm_vma_manager.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -859,58 +858,6 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains) obj->write_domain = 0; } -static inline int -__copy_to_user_swizzled(char __user *cpu_vaddr, - const char *gpu_vaddr, int gpu_offset, - int length) -{ - int ret, cpu_offset = 0; - - while (length > 0) { - int cacheline_end = ALIGN(gpu_offset + 1, 64); - int this_length = min(cacheline_end - gpu_offset, length); - int swizzled_gpu_offset = gpu_offset ^ 64; - - ret = __copy_to_user(cpu_vaddr + cpu_offset, - gpu_vaddr + swizzled_gpu_offset, - this_length); - if (ret) - return ret + length; - - cpu_offset += this_length; - gpu_offset += this_length; - length -= this_length; - } - - return 0; -} - -static inline int -__copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset, - const char __user *cpu_vaddr, - int length) -{ - int ret, cpu_offset = 0; - - while (length > 0) { - int cacheline_end = ALIGN(gpu_offset + 1, 64); - int this_length = min(cacheline_end - gpu_offset, length); - int swizzled_gpu_offset = gpu_offset ^ 64; - - ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset, - cpu_vaddr + cpu_offset, - this_length); - if (ret) - return ret + length; - - cpu_offset += this_length; - gpu_offset += this_length; - length -= this_length; - } - - return 0; -} - /* * Pins the specified object's pages and synchronizes the object with * GPU accesses. Sets needs_clflush to non-zero if the caller should @@ -1030,72 +977,23 @@ err_unpin: return ret; } -static void -shmem_clflush_swizzled_range(char *addr, unsigned long length, - bool swizzled) -{ - if (unlikely(swizzled)) { - unsigned long start = (unsigned long) addr; - unsigned long end = (unsigned long) addr + length; - - /* For swizzling simply ensure that we always flush both - * channels. Lame, but simple and it works. Swizzled - * pwrite/pread is far from a hotpath - current userspace - * doesn't use it at all. */ - start = round_down(start, 128); - end = round_up(end, 128); - - drm_clflush_virt_range((void *)start, end - start); - } else { - drm_clflush_virt_range(addr, length); - } - -} - -/* Only difference to the fast-path function is that this can handle bit17 - * and uses non-atomic copy and kmap functions. */ static int -shmem_pread_slow(struct page *page, int offset, int length, - char __user *user_data, - bool page_do_bit17_swizzling, bool needs_clflush) +shmem_pread(struct page *page, int offset, int len, char __user *user_data, + bool needs_clflush) { char *vaddr; int ret; vaddr = kmap(page); - if (needs_clflush) - shmem_clflush_swizzled_range(vaddr + offset, length, - page_do_bit17_swizzling); - if (page_do_bit17_swizzling) - ret = __copy_to_user_swizzled(user_data, vaddr, offset, length); - else - ret = __copy_to_user(user_data, vaddr + offset, length); - kunmap(page); + if (needs_clflush) + drm_clflush_virt_range(vaddr + offset, len); - return ret ? - EFAULT : 0; -} + ret = __copy_to_user(user_data, vaddr + offset, len); -static int -shmem_pread(struct page *page, int offset, int length, char __user *user_data, - bool page_do_bit17_swizzling, bool needs_clflush) -{ - int ret; - - ret = -ENODEV; - if (!page_do_bit17_swizzling) { - char *vaddr = kmap_atomic(page); - - if (needs_clflush) - drm_clflush_virt_range(vaddr + offset, length); - ret = __copy_to_user_inatomic(user_data, vaddr + offset, length); - kunmap_atomic(vaddr); - } - if (ret == 0) - return 0; + kunmap(page); - return shmem_pread_slow(page, offset, length, user_data, - page_do_bit17_swizzling, needs_clflush); + return ret ? -EFAULT : 0; } static int @@ -1104,15 +1002,10 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, { char __user *user_data; u64 remain; - unsigned int obj_do_bit17_swizzling; unsigned int needs_clflush; unsigned int idx, offset; int ret; - obj_do_bit17_swizzling = 0; - if (i915_gem_object_needs_bit17_swizzle(obj)) - obj_do_bit17_swizzling = BIT(17); - ret = mutex_lock_interruptible(&obj->base.dev->struct_mutex); if (ret) return ret; @@ -1130,7 +1023,6 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); ret = shmem_pread(page, offset, length, user_data, - page_to_phys(page) & obj_do_bit17_swizzling, needs_clflush); if (ret) break; @@ -1470,33 +1362,6 @@ out_unlock: return ret; } -static int -shmem_pwrite_slow(struct page *page, int offset, int length, - char __user *user_data, - bool page_do_bit17_swizzling, - bool needs_clflush_before, - bool needs_clflush_after) -{ - char *vaddr; - int ret; - - vaddr = kmap(page); - if (unlikely(needs_clflush_before || page_do_bit17_swizzling)) - shmem_clflush_swizzled_range(vaddr + offset, length, - page_do_bit17_swizzling); - if (page_do_bit17_swizzling) - ret = __copy_from_user_swizzled(vaddr, offset, user_data, - length); - else - ret = __copy_from_user(vaddr + offset, user_data, length); - if (needs_clflush_after) - shmem_clflush_swizzled_range(vaddr + offset, length, - page_do_bit17_swizzling); - kunmap(page); - - return ret ? -EFAULT : 0; -} - /* Per-page copy function for the shmem pwrite fastpath. * Flushes invalid cachelines before writing to the target if * needs_clflush_before is set and flushes out any written cachelines after @@ -1504,31 +1369,24 @@ shmem_pwrite_slow(struct page *page, int offset, int length, */ static int shmem_pwrite(struct page *page, int offset, int len, char __user *user_data, - bool page_do_bit17_swizzling, bool needs_clflush_before, bool needs_clflush_after) { + char *vaddr; int ret; - ret = -ENODEV; - if (!page_do_bit17_swizzling) { - char *vaddr = kmap_atomic(page); + vaddr = kmap(page); - if (needs_clflush_before) - drm_clflush_virt_range(vaddr + offset, len); - ret = __copy_from_user_inatomic(vaddr + offset, user_data, len); - if (needs_clflush_after) - drm_clflush_virt_range(vaddr + offset, len); + if (needs_clflush_before) + drm_clflush_virt_range(vaddr + offset, len); - kunmap_atomic(vaddr); - } - if (ret == 0) - return ret; + ret = __copy_from_user(vaddr + offset, user_data, len); + if (!ret && needs_clflush_after) + drm_clflush_virt_range(vaddr + offset, len); - return shmem_pwrite_slow(page, offset, len, user_data, - page_do_bit17_swizzling, - needs_clflush_before, - needs_clflush_after); + kunmap(page); + + return ret ? -EFAULT : 0; } static int @@ -1538,7 +1396,6 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, struct drm_i915_private *i915 = to_i915(obj->base.dev); void __user *user_data; u64 remain; - unsigned int obj_do_bit17_swizzling; unsigned int partial_cacheline_write; unsigned int needs_clflush; unsigned int offset, idx; @@ -1553,10 +1410,6 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, if (ret) return ret; - obj_do_bit17_swizzling = 0; - if (i915_gem_object_needs_bit17_swizzle(obj)) - obj_do_bit17_swizzling = BIT(17); - /* If we don't overwrite a cacheline completely we need to be * careful to have up-to-date data by first clflushing. Don't * overcomplicate things and flush the entire patch. @@ -1573,7 +1426,6 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); ret = shmem_pwrite(page, offset, length, user_data, - page_to_phys(page) & obj_do_bit17_swizzling, (offset | length) & partial_cacheline_write, needs_clflush & CLFLUSH_AFTER); if (ret) @@ -3227,13 +3079,6 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine, struct i915_request *request, bool stalled) { - /* - * Make sure this write is visible before we re-enable the interrupt - * handlers on another CPU, as tasklet_enable() resolves to just - * a compiler barrier which is insufficient for our purpose here. - */ - smp_store_mb(engine->irq_posted, 0); - if (request) request = i915_gem_reset_request(engine, request, stalled); @@ -3315,7 +3160,7 @@ static void nop_submit_request(struct i915_request *request) spin_lock_irqsave(&request->engine->timeline.lock, flags); __i915_request_submit(request); - intel_engine_init_global_seqno(request->engine, request->global_seqno); + intel_engine_write_global_seqno(request->engine, request->global_seqno); spin_unlock_irqrestore(&request->engine->timeline.lock, flags); } @@ -3356,7 +3201,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) /* * Make sure no request can slip through without getting completed by - * either this call here to intel_engine_init_global_seqno, or the one + * either this call here to intel_engine_write_global_seqno, or the one * in nop_submit_request. */ synchronize_rcu(); @@ -3384,6 +3229,9 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) if (!test_bit(I915_WEDGED, &i915->gpu_error.flags)) return true; + if (!i915->gt.scratch) /* Never full initialised, recovery impossible */ + return false; + GEM_TRACE("start\n"); /* @@ -3422,8 +3270,7 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) i915_retire_requests(i915); GEM_BUG_ON(i915->gt.active_requests); - if (!intel_gpu_reset(i915, ALL_ENGINES)) - intel_engines_sanitize(i915); + intel_engines_sanitize(i915, false); /* * Undo nop_submit_request. We prevent all new i915 requests from @@ -5027,8 +4874,6 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) void i915_gem_sanitize(struct drm_i915_private *i915) { - int err; - GEM_TRACE("\n"); mutex_lock(&i915->drm.struct_mutex); @@ -5053,11 +4898,7 @@ void i915_gem_sanitize(struct drm_i915_private *i915) * it may impact the display and we are uncertain about the stability * of the reset, so this could be applied to even earlier gen. */ - err = -ENODEV; - if (INTEL_GEN(i915) >= 5 && intel_has_gpu_reset(i915)) - err = WARN_ON(intel_gpu_reset(i915, ALL_ENGINES)); - if (!err) - intel_engines_sanitize(i915); + intel_engines_sanitize(i915, false); intel_uncore_forcewake_put(i915, FORCEWAKE_ALL); intel_runtime_pm_put(i915); @@ -5223,15 +5064,15 @@ void i915_gem_init_swizzling(struct drm_i915_private *dev_priv) I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | DISP_TILE_SURFACE_SWIZZLING); - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) return; I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); - else if (IS_GEN8(dev_priv)) + else if (IS_GEN(dev_priv, 8)) I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_BDW)); else BUG(); @@ -5253,10 +5094,10 @@ static void init_unused_rings(struct drm_i915_private *dev_priv) init_unused_ring(dev_priv, SRB1_BASE); init_unused_ring(dev_priv, SRB2_BASE); init_unused_ring(dev_priv, SRB3_BASE); - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { init_unused_ring(dev_priv, SRB0_BASE); init_unused_ring(dev_priv, SRB1_BASE); - } else if (IS_GEN3(dev_priv)) { + } else if (IS_GEN(dev_priv, 3)) { init_unused_ring(dev_priv, PRB1_BASE); init_unused_ring(dev_priv, PRB2_BASE); } @@ -5580,7 +5421,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv) } ret = i915_gem_init_scratch(dev_priv, - IS_GEN2(dev_priv) ? SZ_256K : PAGE_SIZE); + IS_GEN(dev_priv, 2) ? SZ_256K : PAGE_SIZE); if (ret) { GEM_BUG_ON(ret == -EIO); goto err_ggtt; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4ec386950f75..5933adbe3d99 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -86,7 +86,6 @@ */ #include <linux/log2.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h" @@ -311,7 +310,7 @@ static u32 default_desc_template(const struct drm_i915_private *i915, address_mode = INTEL_LEGACY_64B_CONTEXT; desc |= address_mode << GEN8_CTX_ADDRESSING_MODE_SHIFT; - if (IS_GEN8(i915)) + if (IS_GEN(i915, 8)) desc |= GEN8_CTX_L3LLC_COHERENT; /* TODO: WaDisableLiteRestore when we start using semaphore diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 82e2ca17a441..02f7298bfe57 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -27,7 +27,6 @@ #include <linux/dma-buf.h> #include <linux/reservation.h> -#include <drm/drmP.h> #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 02b83a5ed96c..f6855401f247 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -26,7 +26,6 @@ * */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 485b259127c3..e7994505d850 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -31,7 +31,6 @@ #include <linux/sync_file.h> #include <linux/uaccess.h> -#include <drm/drmP.h> #include <drm/drm_syncobj.h> #include <drm/i915_drm.h> @@ -1380,7 +1379,7 @@ eb_relocate_entry(struct i915_execbuffer *eb, * batchbuffers. */ if (reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && - IS_GEN6(eb->i915)) { + IS_GEN(eb->i915, 6)) { err = i915_vma_bind(target, target->obj->cache_level, PIN_GLOBAL); if (WARN_ONCE(err, @@ -1896,7 +1895,7 @@ static int i915_reset_gen7_sol_offsets(struct i915_request *rq) u32 *cs; int i; - if (!IS_GEN7(rq->i915) || rq->engine->id != RCS) { + if (!IS_GEN(rq->i915, 7) || rq->engine->id != RCS) { DRM_DEBUG("sol reset is gen7/rcs only\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/i915_gem_fence_reg.c b/drivers/gpu/drm/i915/i915_gem_fence_reg.c index d548ac05ccd7..d67c07cdd0b8 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence_reg.c +++ b/drivers/gpu/drm/i915/i915_gem_fence_reg.c @@ -21,7 +21,6 @@ * IN THE SOFTWARE. */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -193,9 +192,9 @@ static void fence_write(struct drm_i915_fence_reg *fence, * and explicitly managed for internal users. */ - if (IS_GEN2(fence->i915)) + if (IS_GEN(fence->i915, 2)) i830_write_fence_reg(fence, vma); - else if (IS_GEN3(fence->i915)) + else if (IS_GEN(fence->i915, 3)) i915_write_fence_reg(fence, vma); else i965_write_fence_reg(fence, vma); @@ -596,13 +595,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_i915_private *dev_priv) swizzle_y = I915_BIT_6_SWIZZLE_NONE; } } - } else if (IS_GEN5(dev_priv)) { + } else if (IS_GEN(dev_priv, 5)) { /* On Ironlake whatever DRAM config, GPU always do * same swizzling setup. */ swizzle_x = I915_BIT_6_SWIZZLE_9_10; swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { /* As far as we know, the 865 doesn't have these bit 6 * swizzling issues. */ @@ -647,7 +646,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_i915_private *dev_priv) } /* check for L-shaped memory aka modified enhanced addressing */ - if (IS_GEN4(dev_priv) && + if (IS_GEN(dev_priv, 4) && !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) { swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index add1fe7aeb93..a8807fbed0aa 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -33,7 +33,6 @@ #include <asm/set_memory.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -483,7 +482,7 @@ static void i915_address_space_init(struct i915_address_space *vm, * attempt holding the lock is immediately reported by lockdep. */ mutex_init(&vm->mutex); - i915_gem_shrinker_taints_mutex(&vm->mutex); + i915_gem_shrinker_taints_mutex(vm->i915, &vm->mutex); GEM_BUG_ON(!vm->total); drm_mm_init(&vm->mm, 0, vm->total); @@ -1423,8 +1422,6 @@ static int gen8_ppgtt_alloc_pdp(struct i915_address_space *vm, gen8_initialize_pd(vm, pd); gen8_ppgtt_set_pdpe(vm, pdp, pd, pdpe); GEM_BUG_ON(pdp->used_pdpes > i915_pdpes_per_pdp(vm)); - - mark_tlbs_dirty(i915_vm_to_ppgtt(vm)); } ret = gen8_ppgtt_alloc_pd(vm, pd, start, length); @@ -1490,84 +1487,6 @@ unwind: return -ENOMEM; } -static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt, - struct i915_page_directory_pointer *pdp, - u64 start, u64 length, - gen8_pte_t scratch_pte, - struct seq_file *m) -{ - struct i915_address_space *vm = &ppgtt->vm; - struct i915_page_directory *pd; - u32 pdpe; - - gen8_for_each_pdpe(pd, pdp, start, length, pdpe) { - struct i915_page_table *pt; - u64 pd_len = length; - u64 pd_start = start; - u32 pde; - - if (pdp->page_directory[pdpe] == ppgtt->vm.scratch_pd) - continue; - - seq_printf(m, "\tPDPE #%d\n", pdpe); - gen8_for_each_pde(pt, pd, pd_start, pd_len, pde) { - u32 pte; - gen8_pte_t *pt_vaddr; - - if (pd->page_table[pde] == ppgtt->vm.scratch_pt) - continue; - - pt_vaddr = kmap_atomic_px(pt); - for (pte = 0; pte < GEN8_PTES; pte += 4) { - u64 va = (pdpe << GEN8_PDPE_SHIFT | - pde << GEN8_PDE_SHIFT | - pte << GEN8_PTE_SHIFT); - int i; - bool found = false; - - for (i = 0; i < 4; i++) - if (pt_vaddr[pte + i] != scratch_pte) - found = true; - if (!found) - continue; - - seq_printf(m, "\t\t0x%llx [%03d,%03d,%04d]: =", va, pdpe, pde, pte); - for (i = 0; i < 4; i++) { - if (pt_vaddr[pte + i] != scratch_pte) - seq_printf(m, " %llx", pt_vaddr[pte + i]); - else - seq_puts(m, " SCRATCH "); - } - seq_puts(m, "\n"); - } - kunmap_atomic(pt_vaddr); - } - } -} - -static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) -{ - struct i915_address_space *vm = &ppgtt->vm; - const gen8_pte_t scratch_pte = vm->scratch_pte; - u64 start = 0, length = ppgtt->vm.total; - - if (use_4lvl(vm)) { - u64 pml4e; - struct i915_pml4 *pml4 = &ppgtt->pml4; - struct i915_page_directory_pointer *pdp; - - gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) { - if (pml4->pdps[pml4e] == ppgtt->vm.scratch_pdp) - continue; - - seq_printf(m, " PML4E #%llu\n", pml4e); - gen8_dump_pdp(ppgtt, pdp, start, length, scratch_pte, m); - } - } else { - gen8_dump_pdp(ppgtt, &ppgtt->pdp, start, length, scratch_pte, m); - } -} - static int gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt *ppgtt) { struct i915_address_space *vm = &ppgtt->vm; @@ -1672,7 +1591,6 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) gen8_ppgtt_notify_vgt(ppgtt, true); ppgtt->vm.cleanup = gen8_ppgtt_cleanup; - ppgtt->debug_dump = gen8_dump_ppgtt; ppgtt->vm.vma_ops.bind_vma = ppgtt_bind_vma; ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; @@ -1688,60 +1606,6 @@ err_free: return ERR_PTR(err); } -static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m) -{ - struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); - const gen6_pte_t scratch_pte = base->vm.scratch_pte; - struct i915_page_table *pt; - u32 pte, pde; - - gen6_for_all_pdes(pt, &base->pd, pde) { - gen6_pte_t *vaddr; - - if (pt == base->vm.scratch_pt) - continue; - - if (i915_vma_is_bound(ppgtt->vma, I915_VMA_GLOBAL_BIND)) { - u32 expected = - GEN6_PDE_ADDR_ENCODE(px_dma(pt)) | - GEN6_PDE_VALID; - u32 pd_entry = readl(ppgtt->pd_addr + pde); - - if (pd_entry != expected) - seq_printf(m, - "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n", - pde, - pd_entry, - expected); - - seq_printf(m, "\tPDE: %x\n", pd_entry); - } - - vaddr = kmap_atomic_px(base->pd.page_table[pde]); - for (pte = 0; pte < GEN6_PTES; pte += 4) { - int i; - - for (i = 0; i < 4; i++) - if (vaddr[pte + i] != scratch_pte) - break; - if (i == 4) - continue; - - seq_printf(m, "\t\t(%03d, %04d) %08llx: ", - pde, pte, - (pde * GEN6_PTES + pte) * I915_GTT_PAGE_SIZE); - for (i = 0; i < 4; i++) { - if (vaddr[pte + i] != scratch_pte) - seq_printf(m, " %08x", vaddr[pte + i]); - else - seq_puts(m, " SCRATCH"); - } - seq_puts(m, "\n"); - } - kunmap_atomic(vaddr); - } -} - /* Write pde (index) from the page directory @pd to the page table @pt */ static inline void gen6_write_pde(const struct gen6_hw_ppgtt *ppgtt, const unsigned int pde, @@ -2075,6 +1939,7 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + int err; /* * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt @@ -2090,9 +1955,17 @@ int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) * allocator works in address space sizes, so it's multiplied by page * size. We allocate at the top of the GTT to avoid fragmentation. */ - return i915_vma_pin(ppgtt->vma, - 0, GEN6_PD_ALIGN, - PIN_GLOBAL | PIN_HIGH); + err = i915_vma_pin(ppgtt->vma, + 0, GEN6_PD_ALIGN, + PIN_GLOBAL | PIN_HIGH); + if (err) + goto unpin; + + return 0; + +unpin: + ppgtt->pin_count = 0; + return err; } void gen6_ppgtt_unpin(struct i915_hw_ppgtt *base) @@ -2129,7 +2002,6 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup; - ppgtt->base.debug_dump = gen6_dump_ppgtt; ppgtt->base.vm.vma_ops.bind_vma = ppgtt_bind_vma; ppgtt->base.vm.vma_ops.unbind_vma = ppgtt_unbind_vma; @@ -2195,9 +2067,9 @@ int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv) { gtt_write_workarounds(dev_priv); - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) gen6_ppgtt_enable(dev_priv); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) gen7_ppgtt_enable(dev_priv); return 0; @@ -2279,7 +2151,7 @@ static bool needs_idle_maps(struct drm_i915_private *dev_priv) /* Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. */ - return IS_GEN5(dev_priv) && IS_MOBILE(dev_priv) && intel_vtd_active(); + return IS_GEN(dev_priv, 5) && IS_MOBILE(dev_priv) && intel_vtd_active(); } static void gen6_check_faults(struct drm_i915_private *dev_priv) @@ -2372,7 +2244,8 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, DMA_ATTR_NO_WARN)) return 0; - /* If the DMA remap fails, one cause can be that we have + /* + * If the DMA remap fails, one cause can be that we have * too many objects pinned in a small remapping table, * such as swiotlb. Incrementally purge all other objects and * try again - if there are no more pages to remove from @@ -2382,8 +2255,7 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, } while (i915_gem_shrink(to_i915(obj->base.dev), obj->base.size >> PAGE_SHIFT, NULL, I915_SHRINK_BOUND | - I915_SHRINK_UNBOUND | - I915_SHRINK_ACTIVE)); + I915_SHRINK_UNBOUND)); return -ENOSPC; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 4874da09a3c4..e2360f16427a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -413,8 +413,6 @@ struct i915_hw_ppgtt { struct i915_page_directory_pointer pdp; /* GEN8+ */ struct i915_page_directory pd; /* GEN6-7 */ }; - - void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; struct gen6_hw_ppgtt { diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c index 0d0144b2104c..fddde1033e74 100644 --- a/drivers/gpu/drm/i915/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/i915_gem_internal.c @@ -22,7 +22,6 @@ * */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index a6dd7c46de0d..ff3da64470dd 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -29,7 +29,8 @@ #include <drm/drm_vma_manager.h> #include <drm/drm_gem.h> -#include <drm/drmP.h> +#include <drm/drm_file.h> +#include <drm/drm_device.h> #include <drm/i915_drm.h> diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index ea90d3a0d511..6cc2b964c955 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -30,30 +30,27 @@ #include <linux/pci.h> #include <linux/dma-buf.h> #include <linux/vmalloc.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h" -static bool shrinker_lock(struct drm_i915_private *i915, bool *unlock) +static bool shrinker_lock(struct drm_i915_private *i915, + unsigned int flags, + bool *unlock) { - switch (mutex_trylock_recursive(&i915->drm.struct_mutex)) { + struct mutex *m = &i915->drm.struct_mutex; + + switch (mutex_trylock_recursive(m)) { case MUTEX_TRYLOCK_RECURSIVE: *unlock = false; return true; case MUTEX_TRYLOCK_FAILED: *unlock = false; - preempt_disable(); - do { - cpu_relax(); - if (mutex_trylock(&i915->drm.struct_mutex)) { - *unlock = true; - break; - } - } while (!need_resched()); - preempt_enable(); + if (flags & I915_SHRINK_ACTIVE && + mutex_lock_killable_nested(m, I915_MM_SHRINKER) == 0) + *unlock = true; return *unlock; case MUTEX_TRYLOCK_SUCCESS: @@ -160,7 +157,7 @@ i915_gem_shrink(struct drm_i915_private *i915, unsigned long scanned = 0; bool unlock; - if (!shrinker_lock(i915, &unlock)) + if (!shrinker_lock(i915, flags, &unlock)) return 0; /* @@ -357,7 +354,7 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) sc->nr_scanned = 0; - if (!shrinker_lock(i915, &unlock)) + if (!shrinker_lock(i915, 0, &unlock)) return SHRINK_STOP; freed = i915_gem_shrink(i915, @@ -388,31 +385,6 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) return sc->nr_scanned ? freed : SHRINK_STOP; } -static bool -shrinker_lock_uninterruptible(struct drm_i915_private *i915, bool *unlock, - int timeout_ms) -{ - unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms); - - do { - if (i915_gem_wait_for_idle(i915, - 0, MAX_SCHEDULE_TIMEOUT) == 0 && - shrinker_lock(i915, unlock)) - break; - - schedule_timeout_killable(1); - if (fatal_signal_pending(current)) - return false; - - if (time_after(jiffies, timeout)) { - pr_err("Unable to lock GPU to purge memory.\n"); - return false; - } - } while (1); - - return true; -} - static int i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) { @@ -421,7 +393,11 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) struct drm_i915_gem_object *obj; unsigned long unevictable, bound, unbound, freed_pages; - freed_pages = i915_gem_shrink_all(i915); + intel_runtime_pm_get(i915); + freed_pages = i915_gem_shrink(i915, -1UL, NULL, + I915_SHRINK_BOUND | + I915_SHRINK_UNBOUND); + intel_runtime_pm_put(i915); /* Because we may be allocating inside our own driver, we cannot * assert that there are no objects with pinned pages that are not @@ -447,10 +423,6 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) pr_info("Purging GPU memory, %lu pages freed, " "%lu pages still pinned.\n", freed_pages, unevictable); - if (unbound || bound) - pr_err("%lu and %lu pages still available in the " - "bound and unbound GPU page lists.\n", - bound, unbound); *(unsigned long *)ptr += freed_pages; return NOTIFY_DONE; @@ -464,23 +436,20 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr struct i915_vma *vma, *next; unsigned long freed_pages = 0; bool unlock; - int ret; - if (!shrinker_lock_uninterruptible(i915, &unlock, 5000)) + if (!shrinker_lock(i915, 0, &unlock)) return NOTIFY_DONE; /* Force everything onto the inactive lists */ - ret = i915_gem_wait_for_idle(i915, - I915_WAIT_LOCKED, - MAX_SCHEDULE_TIMEOUT); - if (ret) + if (i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT)) goto out; intel_runtime_pm_get(i915); freed_pages += i915_gem_shrink(i915, -1UL, NULL, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | - I915_SHRINK_ACTIVE | I915_SHRINK_VMAPS); intel_runtime_pm_put(i915); @@ -533,13 +502,40 @@ void i915_gem_shrinker_unregister(struct drm_i915_private *i915) unregister_shrinker(&i915->mm.shrinker); } -void i915_gem_shrinker_taints_mutex(struct mutex *mutex) +void i915_gem_shrinker_taints_mutex(struct drm_i915_private *i915, + struct mutex *mutex) { + bool unlock = false; + if (!IS_ENABLED(CONFIG_LOCKDEP)) return; + if (!lockdep_is_held_type(&i915->drm.struct_mutex, -1)) { + mutex_acquire(&i915->drm.struct_mutex.dep_map, + I915_MM_NORMAL, 0, _RET_IP_); + unlock = true; + } + fs_reclaim_acquire(GFP_KERNEL); - mutex_lock(mutex); - mutex_unlock(mutex); + + /* + * As we invariably rely on the struct_mutex within the shrinker, + * but have a complicated recursion dance, taint all the mutexes used + * within the shrinker with the struct_mutex. For completeness, we + * taint with all subclass of struct_mutex, even though we should + * only need tainting by I915_MM_NORMAL to catch possible ABBA + * deadlocks from using struct_mutex inside @mutex. + */ + mutex_acquire(&i915->drm.struct_mutex.dep_map, + I915_MM_SHRINKER, 0, _RET_IP_); + + mutex_acquire(&mutex->dep_map, 0, 0, _RET_IP_); + mutex_release(&mutex->dep_map, 0, _RET_IP_); + + mutex_release(&i915->drm.struct_mutex.dep_map, 0, _RET_IP_); + fs_reclaim_release(GFP_KERNEL); + + if (unlock) + mutex_release(&i915->drm.struct_mutex.dep_map, 0, _RET_IP_); } diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f29a7ff7c362..9df615eea2d8 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -26,7 +26,6 @@ * */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -102,7 +101,7 @@ static int i915_adjust_stolen(struct drm_i915_private *dev_priv, resource_size_t ggtt_start; ggtt_start = I915_READ(PGTBL_CTL); - if (IS_GEN4(dev_priv)) + if (IS_GEN(dev_priv, 4)) ggtt_start = (ggtt_start & PGTBL_ADDRESS_LO_MASK) | (ggtt_start & PGTBL_ADDRESS_HI_MASK) << 28; else @@ -156,7 +155,7 @@ static int i915_adjust_stolen(struct drm_i915_private *dev_priv, * GEN3 firmware likes to smash pci bridges into the stolen * range. Apparently this works. */ - if (r == NULL && !IS_GEN3(dev_priv)) { + if (r == NULL && !IS_GEN(dev_priv, 3)) { DRM_ERROR("conflict detected with stolen region: %pR\n", dsm); @@ -194,7 +193,8 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv, * Whether ILK really reuses the ELK register for this is unclear. * Let's see if we catch anyone with this supposedly enabled on ILK. */ - WARN(IS_GEN5(dev_priv), "ILK stolen reserved found? 0x%08x\n", reg_val); + WARN(IS_GEN(dev_priv, 5), "ILK stolen reserved found? 0x%08x\n", + reg_val); if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK)) return; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index d9dc9df523b5..16cc9ddbce34 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -27,7 +27,6 @@ #include <linux/string.h> #include <linux/bitops.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -87,7 +86,7 @@ u32 i915_gem_fence_size(struct drm_i915_private *i915, } /* Previous chips need a power-of-two fence region when tiling */ - if (IS_GEN3(i915)) + if (IS_GEN(i915, 3)) ggtt_size = 1024*1024; else ggtt_size = 512*1024; @@ -162,7 +161,7 @@ i915_tiling_ok(struct drm_i915_gem_object *obj, return false; } - if (IS_GEN2(i915) || + if (IS_GEN(i915, 2) || (tiling == I915_TILING_Y && HAS_128_BYTE_Y_TILING(i915))) tile_width = 128; else diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 9558582c105e..1fb6a7bb5054 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -22,7 +22,6 @@ * */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h" diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 07465123c166..5eaf586c4d48 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -594,13 +594,14 @@ static void print_error_obj(struct drm_i915_error_state_buf *m, static void err_print_capabilities(struct drm_i915_error_state_buf *m, const struct intel_device_info *info, + const struct intel_runtime_info *runtime, const struct intel_driver_caps *caps) { struct drm_printer p = i915_error_printer(m); intel_device_info_dump_flags(info, &p); intel_driver_caps_print(caps, &p); - intel_device_info_dump_topology(&info->sseu, &p); + intel_device_info_dump_topology(&runtime->sseu, &p); } static void err_print_params(struct drm_i915_error_state_buf *m, @@ -664,7 +665,9 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m, if (*error->error_msg) err_printf(m, "%s\n", error->error_msg); - err_printf(m, "Kernel: %s\n", init_utsname()->release); + err_printf(m, "Kernel: %s %s\n", + init_utsname()->release, + init_utsname()->machine); ts = ktime_to_timespec64(error->time); err_printf(m, "Time: %lld s %ld us\n", (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC); @@ -735,7 +738,7 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m, err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); } - if (IS_GEN7(m->i915)) + if (IS_GEN(m->i915, 7)) err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); for (i = 0; i < ARRAY_SIZE(error->engine); i++) { @@ -844,7 +847,8 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m, if (error->display) intel_display_print_error_state(m, error->display); - err_print_capabilities(m, &error->device_info, &error->driver_caps); + err_print_capabilities(m, &error->device_info, &error->runtime_info, + &error->driver_caps); err_print_params(m, &error->params); err_print_uc(m, &error->uc); } @@ -963,17 +967,10 @@ static void i915_error_object_free(struct drm_i915_error_object *obj) kfree(obj); } -static __always_inline void free_param(const char *type, void *x) -{ - if (!__builtin_strcmp(type, "char *")) - kfree(*(void **)x); -} static void cleanup_params(struct i915_gpu_state *error) { -#define FREE(T, x, ...) free_param(#T, &error->params.x); - I915_PARAMS_FOR_EACH(FREE); -#undef FREE + i915_params_free(&error->params); } static void cleanup_uc_state(struct i915_gpu_state *error) @@ -1037,7 +1034,7 @@ i915_error_object_create(struct drm_i915_private *i915, dma_addr_t dma; int ret; - if (!vma) + if (!vma || !vma->pages) return NULL; num_pages = min_t(u64, vma->size, vma->obj->base.size) >> PAGE_SHIFT; @@ -1314,7 +1311,7 @@ static void error_record_engine_registers(struct i915_gpu_state *error, if (!HWS_NEEDS_PHYSICAL(dev_priv)) { i915_reg_t mmio; - if (IS_GEN7(dev_priv)) { + if (IS_GEN(dev_priv, 7)) { switch (engine->id) { default: case RCS: @@ -1330,7 +1327,7 @@ static void error_record_engine_registers(struct i915_gpu_state *error, mmio = VEBOX_HWS_PGA_GEN7; break; } - } else if (IS_GEN6(engine->i915)) { + } else if (IS_GEN(engine->i915, 6)) { mmio = RING_HWS_PGA_GEN6(engine->mmio_base); } else { /* XXX: gen8 returns to sanity */ @@ -1352,10 +1349,10 @@ static void error_record_engine_registers(struct i915_gpu_state *error, ee->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(engine)); - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) ee->vm_info.pp_dir_base = I915_READ(RING_PP_DIR_BASE_READ(engine)); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) ee->vm_info.pp_dir_base = I915_READ(RING_PP_DIR_BASE(engine)); else if (INTEL_GEN(dev_priv) >= 8) @@ -1725,7 +1722,7 @@ static void capture_reg_state(struct i915_gpu_state *error) error->forcewake = I915_READ_FW(FORCEWAKE_VLV); } - if (IS_GEN7(dev_priv)) + if (IS_GEN(dev_priv, 7)) error->err_int = I915_READ(GEN7_ERR_INT); if (INTEL_GEN(dev_priv) >= 8) { @@ -1733,7 +1730,7 @@ static void capture_reg_state(struct i915_gpu_state *error) error->fault_data1 = I915_READ(GEN8_FAULT_TLB_DATA1); } - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { error->forcewake = I915_READ_FW(FORCEWAKE); error->gab_ctl = I915_READ(GAB_CTL); error->gfx_mode = I915_READ(GFX_MODE); @@ -1753,7 +1750,7 @@ static void capture_reg_state(struct i915_gpu_state *error) error->ccid = I915_READ(CCID); /* 3: Feature specific registers */ - if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) { + if (IS_GEN_RANGE(dev_priv, 6, 7)) { error->gam_ecochk = I915_READ(GAM_ECOCHK); error->gac_eco = I915_READ(GAC_ECO_BITS); } @@ -1777,7 +1774,7 @@ static void capture_reg_state(struct i915_gpu_state *error) error->ier = I915_READ(DEIER); error->gtier[0] = I915_READ(GTIER); error->ngtier = 1; - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { error->ier = I915_READ16(IER); } else if (!IS_VALLEYVIEW(dev_priv)) { error->ier = I915_READ(IER); @@ -1831,21 +1828,15 @@ static void capture_gen_state(struct i915_gpu_state *error) memcpy(&error->device_info, INTEL_INFO(i915), sizeof(error->device_info)); + memcpy(&error->runtime_info, + RUNTIME_INFO(i915), + sizeof(error->runtime_info)); error->driver_caps = i915->caps; } -static __always_inline void dup_param(const char *type, void *x) -{ - if (!__builtin_strcmp(type, "char *")) - *(void **)x = kstrdup(*(void **)x, GFP_ATOMIC); -} - static void capture_params(struct i915_gpu_state *error) { - error->params = i915_modparams; -#define DUP(T, x, ...) dup_param(#T, &error->params.x); - I915_PARAMS_FOR_EACH(DUP); -#undef DUP + i915_params_copy(&error->params, &i915_modparams); } static unsigned long capture_find_epoch(const struct i915_gpu_state *error) @@ -1907,9 +1898,16 @@ i915_capture_gpu_state(struct drm_i915_private *i915) { struct i915_gpu_state *error; + /* Check if GPU capture has been disabled */ + error = READ_ONCE(i915->gpu_error.first_error); + if (IS_ERR(error)) + return error; + error = kzalloc(sizeof(*error), GFP_ATOMIC); - if (!error) - return NULL; + if (!error) { + i915_disable_error_state(i915, -ENOMEM); + return ERR_PTR(-ENOMEM); + } kref_init(&error->ref); error->i915 = i915; @@ -1945,11 +1943,8 @@ void i915_capture_error_state(struct drm_i915_private *i915, return; error = i915_capture_gpu_state(i915); - if (!error) { - DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); - i915_disable_error_state(i915, -ENOMEM); + if (IS_ERR(error)) return; - } i915_error_capture_msg(i915, error, engine_mask, error_msg); DRM_INFO("%s\n", error->error_msg); @@ -1987,7 +1982,7 @@ i915_first_error_state(struct drm_i915_private *i915) spin_lock_irq(&i915->gpu_error.lock); error = i915->gpu_error.first_error; - if (error) + if (!IS_ERR_OR_NULL(error)) i915_gpu_state_get(error); spin_unlock_irq(&i915->gpu_error.lock); @@ -2000,10 +1995,11 @@ void i915_reset_error_state(struct drm_i915_private *i915) spin_lock_irq(&i915->gpu_error.lock); error = i915->gpu_error.first_error; - i915->gpu_error.first_error = NULL; + if (error != ERR_PTR(-ENODEV)) /* if disabled, always disabled */ + i915->gpu_error.first_error = NULL; spin_unlock_irq(&i915->gpu_error.lock); - if (!IS_ERR(error)) + if (!IS_ERR_OR_NULL(error)) i915_gpu_state_put(error); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index ff2652bbb0b0..6d9f45468ac1 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -45,6 +45,7 @@ struct i915_gpu_state { u32 reset_count; u32 suspend_count; struct intel_device_info device_info; + struct intel_runtime_info runtime_info; struct intel_driver_caps driver_caps; struct i915_params params; diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index e869daf9c8a9..73c3e8f519e8 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -28,7 +28,6 @@ */ #include <linux/compat.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d447d7d508f4..288b0662f7b7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -31,7 +31,6 @@ #include <linux/sysrq.h> #include <linux/slab.h> #include <linux/circ_buf.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h" @@ -950,7 +949,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) if (mode->flags & DRM_MODE_FLAG_INTERLACE) vtotal /= 2; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; else position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; @@ -1030,7 +1029,7 @@ static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, if (stime) *stime = ktime_get(); - if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { + if (IS_GEN(dev_priv, 2) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ @@ -1090,7 +1089,7 @@ static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, else position += vtotal - vbl_end; - if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { + if (IS_GEN(dev_priv, 2) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { *vpos = position; *hpos = 0; } else { @@ -1189,13 +1188,6 @@ static void notify_ring(struct intel_engine_cs *engine) rq = i915_request_get(waiter); tsk = wait->tsk; - } else { - if (engine->irq_seqno_barrier && - i915_seqno_passed(seqno, wait->seqno - 1)) { - set_bit(ENGINE_IRQ_BREADCRUMB, - &engine->irq_posted); - tsk = wait->tsk; - } } engine->breadcrumbs.irq_count++; @@ -2547,7 +2539,7 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, I915_WRITE(SDEIIR, pch_iir); } - if (IS_GEN5(dev_priv) && de_iir & DE_PCU_EVENT) + if (IS_GEN(dev_priv, 5) && de_iir & DE_PCU_EVENT) ironlake_rps_change_irq_handler(dev_priv); } @@ -3243,7 +3235,7 @@ void i915_clear_error_registers(struct drm_i915_private *dev_priv) { u32 eir; - if (!IS_GEN2(dev_priv)) + if (!IS_GEN(dev_priv, 2)) I915_WRITE(PGTBL_ER, I915_READ(PGTBL_ER)); if (INTEL_GEN(dev_priv) < 4) @@ -3586,11 +3578,8 @@ static void ironlake_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - if (IS_GEN5(dev_priv)) - I915_WRITE(HWSTAM, 0xffffffff); - GEN3_IRQ_RESET(DE); - if (IS_GEN7(dev_priv)) + if (IS_GEN(dev_priv, 7)) I915_WRITE(GEN7_ERR_INT, 0xffffffff); if (IS_HASWELL(dev_priv)) { @@ -4045,7 +4034,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev) } gt_irqs |= GT_RENDER_USER_INTERRUPT; - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { gt_irqs |= ILK_BSD_USER_INTERRUPT; } else { gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; @@ -4183,9 +4172,6 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT }; - if (HAS_L3_DPF(dev_priv)) - gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; - dev_priv->pm_ier = 0x0; dev_priv->pm_imr = ~dev_priv->pm_ier; GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]); @@ -4368,8 +4354,6 @@ static void i8xx_irq_reset(struct drm_device *dev) i9xx_pipestat_irq_reset(dev_priv); - I915_WRITE16(HWSTAM, 0xffff); - GEN2_IRQ_RESET(); } @@ -4537,8 +4521,6 @@ static void i915_irq_reset(struct drm_device *dev) i9xx_pipestat_irq_reset(dev_priv); - I915_WRITE(HWSTAM, 0xffffffff); - GEN3_IRQ_RESET(); } @@ -4648,8 +4630,6 @@ static void i965_irq_reset(struct drm_device *dev) i9xx_pipestat_irq_reset(dev_priv); - I915_WRITE(HWSTAM, 0xffffffff); - GEN3_IRQ_RESET(); } @@ -4836,7 +4816,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) >= 8) rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC; - if (IS_GEN2(dev_priv)) { + if (IS_GEN(dev_priv, 2)) { /* Gen2 doesn't have a hardware frame counter */ dev->max_vblank_count = 0; } else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { @@ -4852,7 +4832,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) * Gen2 doesn't have a hardware frame counter and so depends on * vblank interrupts to produce sane vblank seuquence numbers. */ - if (!IS_GEN2(dev_priv)) + if (!IS_GEN(dev_priv, 2)) dev->vblank_disable_immediate = true; /* Most platforms treat the display irq block as an always-on @@ -4924,14 +4904,14 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev->driver->disable_vblank = ironlake_disable_vblank; dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; } else { - if (IS_GEN2(dev_priv)) { + if (IS_GEN(dev_priv, 2)) { dev->driver->irq_preinstall = i8xx_irq_reset; dev->driver->irq_postinstall = i8xx_irq_postinstall; dev->driver->irq_handler = i8xx_irq_handler; dev->driver->irq_uninstall = i8xx_irq_reset; dev->driver->enable_vblank = i8xx_enable_vblank; dev->driver->disable_vblank = i8xx_disable_vblank; - } else if (IS_GEN3(dev_priv)) { + } else if (IS_GEN(dev_priv, 3)) { dev->driver->irq_preinstall = i915_irq_reset; dev->driver->irq_postinstall = i915_irq_postinstall; dev->driver->irq_uninstall = i915_irq_reset; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 2e0356561839..9f0539bdaa39 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -77,7 +77,7 @@ i915_param_named(error_capture, bool, 0600, "triaging and debugging hangs."); #endif -i915_param_named_unsafe(enable_hangcheck, bool, 0644, +i915_param_named_unsafe(enable_hangcheck, bool, 0600, "Periodically check GPU activity for detecting hangs. " "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); @@ -203,3 +203,33 @@ void i915_params_dump(const struct i915_params *params, struct drm_printer *p) I915_PARAMS_FOR_EACH(PRINT); #undef PRINT } + +static __always_inline void dup_param(const char *type, void *x) +{ + if (!__builtin_strcmp(type, "char *")) + *(void **)x = kstrdup(*(void **)x, GFP_ATOMIC); +} + +void i915_params_copy(struct i915_params *dest, const struct i915_params *src) +{ + *dest = *src; +#define DUP(T, x, ...) dup_param(#T, &dest->x); + I915_PARAMS_FOR_EACH(DUP); +#undef DUP +} + +static __always_inline void free_param(const char *type, void *x) +{ + if (!__builtin_strcmp(type, "char *")) { + kfree(*(void **)x); + *(void **)x = NULL; + } +} + +/* free the allocated members, *not* the passed in params itself */ +void i915_params_free(struct i915_params *params) +{ +#define FREE(T, x, ...) free_param(#T, ¶ms->x); + I915_PARAMS_FOR_EACH(FREE); +#undef FREE +} diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 7e56c516c815..6efcf330bdab 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -33,6 +33,15 @@ struct drm_printer; #define ENABLE_GUC_SUBMISSION BIT(0) #define ENABLE_GUC_LOAD_HUC BIT(1) +/* + * Invoke param, a function-like macro, for each i915 param, with arguments: + * + * param(type, name, value) + * + * type: parameter type, one of {bool, int, unsigned int, char *} + * name: name of the parameter + * value: initial/default value of the parameter + */ #define I915_PARAMS_FOR_EACH(param) \ param(char *, vbt_firmware, NULL) \ param(int, modeset, -1) \ @@ -78,6 +87,8 @@ struct i915_params { extern struct i915_params i915_modparams __read_mostly; void i915_params_dump(const struct i915_params *params, struct drm_printer *p); +void i915_params_copy(struct i915_params *dest, const struct i915_params *src); +void i915_params_free(struct i915_params *params); #endif diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 6350db5503cd..dd4aff2b256e 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -82,6 +82,7 @@ .display.has_overlay = 1, \ .display.overlay_needs_physical = 1, \ .display.has_gmch_display = 1, \ + .gpu_reset_clobbers_display = true, \ .hws_needs_physical = 1, \ .unfenced_needs_alignment = 1, \ .ring_mask = RENDER_RING, \ @@ -122,6 +123,7 @@ static const struct intel_device_info intel_i865g_info = { GEN(3), \ .num_pipes = 2, \ .display.has_gmch_display = 1, \ + .gpu_reset_clobbers_display = true, \ .ring_mask = RENDER_RING, \ .has_snoop = true, \ .has_coherent_ggtt = true, \ @@ -198,6 +200,7 @@ static const struct intel_device_info intel_pineview_info = { .num_pipes = 2, \ .display.has_hotplug = 1, \ .display.has_gmch_display = 1, \ + .gpu_reset_clobbers_display = true, \ .ring_mask = RENDER_RING, \ .has_snoop = true, \ .has_coherent_ggtt = true, \ @@ -228,6 +231,7 @@ static const struct intel_device_info intel_g45_info = { GEN4_FEATURES, PLATFORM(INTEL_G45), .ring_mask = RENDER_RING | BSD_RING, + .gpu_reset_clobbers_display = false, }; static const struct intel_device_info intel_gm45_info = { @@ -237,6 +241,7 @@ static const struct intel_device_info intel_gm45_info = { .display.has_fbc = 1, .display.supports_tv = 1, .ring_mask = RENDER_RING | BSD_RING, + .gpu_reset_clobbers_display = false, }; #define GEN5_FEATURES \ @@ -532,7 +537,6 @@ static const struct intel_device_info intel_skylake_gt4_info = { .display.has_fbc = 1, \ .display.has_psr = 1, \ .has_runtime_pm = 1, \ - .has_pooled_eu = 0, \ .display.has_csr = 1, \ .has_rc6 = 1, \ .display.has_dp_mst = 1, \ diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 2b2eb57ca71f..5b1ae5ed97b3 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1796,7 +1796,7 @@ static int gen8_enable_metric_set(struct i915_perf_stream *stream) * be read back from automatically triggered reports, as part of the * RPT_ID field. */ - if (IS_GEN(dev_priv, 9, 11)) { + if (IS_GEN_RANGE(dev_priv, 9, 11)) { I915_WRITE(GEN8_OA_DEBUG, _MASKED_BIT_ENABLE(GEN9_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS | GEN9_OA_DEBUG_INCLUDE_CLK_RATIO)); @@ -2646,7 +2646,7 @@ err: static u64 oa_exponent_to_ns(struct drm_i915_private *dev_priv, int exponent) { return div64_u64(1000000000ULL * (2ULL << exponent), - 1000ULL * INTEL_INFO(dev_priv)->cs_timestamp_frequency_khz); + 1000ULL * RUNTIME_INFO(dev_priv)->cs_timestamp_frequency_khz); } /** @@ -3415,7 +3415,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv) dev_priv->perf.oa.ops.read = gen8_oa_read; dev_priv->perf.oa.ops.oa_hw_tail_read = gen8_oa_hw_tail_read; - if (IS_GEN8(dev_priv) || IS_GEN9(dev_priv)) { + if (IS_GEN_RANGE(dev_priv, 8, 9)) { dev_priv->perf.oa.ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; dev_priv->perf.oa.ops.is_valid_mux_reg = @@ -3431,7 +3431,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv) dev_priv->perf.oa.ops.enable_metric_set = gen8_enable_metric_set; dev_priv->perf.oa.ops.disable_metric_set = gen8_disable_metric_set; - if (IS_GEN8(dev_priv)) { + if (IS_GEN(dev_priv, 8)) { dev_priv->perf.oa.ctx_oactxctrl_offset = 0x120; dev_priv->perf.oa.ctx_flexeu0_offset = 0x2ce; @@ -3442,7 +3442,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv) dev_priv->perf.oa.gen8_valid_ctx_bit = (1<<16); } - } else if (IS_GEN(dev_priv, 10, 11)) { + } else if (IS_GEN_RANGE(dev_priv, 10, 11)) { dev_priv->perf.oa.ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; dev_priv->perf.oa.ops.is_valid_mux_reg = @@ -3471,7 +3471,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv) spin_lock_init(&dev_priv->perf.oa.oa_buffer.ptr_lock); oa_sample_rate_hard_limit = 1000 * - (INTEL_INFO(dev_priv)->cs_timestamp_frequency_khz / 2); + (RUNTIME_INFO(dev_priv)->cs_timestamp_frequency_khz / 2); dev_priv->perf.sysctl_header = register_sysctl_table(dev_root); mutex_init(&dev_priv->perf.metrics_lock); diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index fe56465cdfd6..cbcb957b7141 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -13,7 +13,7 @@ static int query_topology_info(struct drm_i915_private *dev_priv, struct drm_i915_query_item *query_item) { - const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; struct drm_i915_query_topology_info topo; u32 slice_length, subslice_length, eu_length, total_length; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0a7d60509ca7..44958d994bfa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -139,6 +139,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG); } +#define VLV_DISPLAY_BASE 0x180000 +#define VLV_MIPI_BASE VLV_DISPLAY_BASE +#define BXT_MIPI_BASE 0x60000 + +#define DISPLAY_MMIO_BASE(dev_priv) (INTEL_INFO(dev_priv)->display_mmio_offset) + /* * Given the first two numbers __a and __b of arbitrarily many evenly spaced * numbers, pick the 0-based __index'th value. @@ -179,15 +185,15 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) * Device info offset array based helpers for groups of registers with unevenly * spaced base offsets. */ -#define _MMIO_PIPE2(pipe, reg) _MMIO(dev_priv->info.pipe_offsets[pipe] - \ - dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \ - dev_priv->info.display_mmio_offset) -#define _MMIO_TRANS2(pipe, reg) _MMIO(dev_priv->info.trans_offsets[(pipe)] - \ - dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \ - dev_priv->info.display_mmio_offset) -#define _CURSOR2(pipe, reg) _MMIO(dev_priv->info.cursor_offsets[(pipe)] - \ - dev_priv->info.cursor_offsets[PIPE_A] + (reg) + \ - dev_priv->info.display_mmio_offset) +#define _MMIO_PIPE2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->pipe_offsets[pipe] - \ + INTEL_INFO(dev_priv)->pipe_offsets[PIPE_A] + (reg) + \ + DISPLAY_MMIO_BASE(dev_priv)) +#define _MMIO_TRANS2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->trans_offsets[(pipe)] - \ + INTEL_INFO(dev_priv)->trans_offsets[TRANSCODER_A] + (reg) + \ + DISPLAY_MMIO_BASE(dev_priv)) +#define _CURSOR2(pipe, reg) _MMIO(INTEL_INFO(dev_priv)->cursor_offsets[(pipe)] - \ + INTEL_INFO(dev_priv)->cursor_offsets[PIPE_A] + (reg) + \ + DISPLAY_MMIO_BASE(dev_priv)) #define __MASKED_FIELD(mask, value) ((mask) << 16 | (value)) #define _MASKED_FIELD(mask, value) ({ \ @@ -347,6 +353,24 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN11_GRDOM_MEDIA4 (1 << 8) #define GEN11_GRDOM_VECS (1 << 13) #define GEN11_GRDOM_VECS2 (1 << 14) +#define GEN11_GRDOM_SFC0 (1 << 17) +#define GEN11_GRDOM_SFC1 (1 << 18) + +#define GEN11_VCS_SFC_RESET_BIT(instance) (GEN11_GRDOM_SFC0 << ((instance) >> 1)) +#define GEN11_VECS_SFC_RESET_BIT(instance) (GEN11_GRDOM_SFC0 << (instance)) + +#define GEN11_VCS_SFC_FORCED_LOCK(engine) _MMIO((engine)->mmio_base + 0x88C) +#define GEN11_VCS_SFC_FORCED_LOCK_BIT (1 << 0) +#define GEN11_VCS_SFC_LOCK_STATUS(engine) _MMIO((engine)->mmio_base + 0x890) +#define GEN11_VCS_SFC_USAGE_BIT (1 << 0) +#define GEN11_VCS_SFC_LOCK_ACK_BIT (1 << 1) + +#define GEN11_VECS_SFC_FORCED_LOCK(engine) _MMIO((engine)->mmio_base + 0x201C) +#define GEN11_VECS_SFC_FORCED_LOCK_BIT (1 << 0) +#define GEN11_VECS_SFC_LOCK_ACK(engine) _MMIO((engine)->mmio_base + 0x2018) +#define GEN11_VECS_SFC_LOCK_ACK_BIT (1 << 0) +#define GEN11_VECS_SFC_USAGE(engine) _MMIO((engine)->mmio_base + 0x2014) +#define GEN11_VECS_SFC_USAGE_BIT (1 << 0) #define RING_PP_DIR_BASE(engine) _MMIO((engine)->mmio_base + 0x228) #define RING_PP_DIR_BASE_READ(engine) _MMIO((engine)->mmio_base + 0x518) @@ -1866,6 +1890,10 @@ enum i915_power_well_id { #define CNL_PORT_TX_DW7_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 7)) #define CNL_PORT_TX_DW7_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 7)) +#define ICL_PORT_TX_DW7_AUX(port) _MMIO(_ICL_PORT_TX_DW_AUX(7, port)) +#define ICL_PORT_TX_DW7_GRP(port) _MMIO(_ICL_PORT_TX_DW_GRP(7, port)) +#define ICL_PORT_TX_DW7_LN0(port) _MMIO(_ICL_PORT_TX_DW_LN(7, 0, port)) +#define ICL_PORT_TX_DW7_LN(port, ln) _MMIO(_ICL_PORT_TX_DW_LN(7, ln, port)) #define N_SCALAR(x) ((x) << 24) #define N_SCALAR_MASK (0x7F << 24) @@ -2592,10 +2620,6 @@ enum i915_power_well_id { #define GEN11_GFX_DISABLE_LEGACY_MODE (1 << 3) -#define VLV_DISPLAY_BASE 0x180000 -#define VLV_MIPI_BASE VLV_DISPLAY_BASE -#define BXT_MIPI_BASE 0x60000 - #define VLV_GU_CTL0 _MMIO(VLV_DISPLAY_BASE + 0x2030) #define VLV_GU_CTL1 _MMIO(VLV_DISPLAY_BASE + 0x2034) #define SCPD0 _MMIO(0x209c) /* 915+ only */ @@ -3152,9 +3176,9 @@ enum i915_power_well_id { /* * Clock control & power management */ -#define _DPLL_A (dev_priv->info.display_mmio_offset + 0x6014) -#define _DPLL_B (dev_priv->info.display_mmio_offset + 0x6018) -#define _CHV_DPLL_C (dev_priv->info.display_mmio_offset + 0x6030) +#define _DPLL_A (DISPLAY_MMIO_BASE(dev_priv) + 0x6014) +#define _DPLL_B (DISPLAY_MMIO_BASE(dev_priv) + 0x6018) +#define _CHV_DPLL_C (DISPLAY_MMIO_BASE(dev_priv) + 0x6030) #define DPLL(pipe) _MMIO_PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C) #define VGA0 _MMIO(0x6000) @@ -3251,9 +3275,9 @@ enum i915_power_well_id { #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define _DPLL_A_MD (dev_priv->info.display_mmio_offset + 0x601c) -#define _DPLL_B_MD (dev_priv->info.display_mmio_offset + 0x6020) -#define _CHV_DPLL_C_MD (dev_priv->info.display_mmio_offset + 0x603c) +#define _DPLL_A_MD (DISPLAY_MMIO_BASE(dev_priv) + 0x601c) +#define _DPLL_B_MD (DISPLAY_MMIO_BASE(dev_priv) + 0x6020) +#define _CHV_DPLL_C_MD (DISPLAY_MMIO_BASE(dev_priv) + 0x603c) #define DPLL_MD(pipe) _MMIO_PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD) /* @@ -3325,7 +3349,7 @@ enum i915_power_well_id { #define DSTATE_PLL_D3_OFF (1 << 3) #define DSTATE_GFX_CLOCK_GATING (1 << 1) #define DSTATE_DOT_CLOCK_GATING (1 << 0) -#define DSPCLK_GATE_D _MMIO(dev_priv->info.display_mmio_offset + 0x6200) +#define DSPCLK_GATE_D _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x6200) # define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ # define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ # define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ @@ -3465,7 +3489,7 @@ enum i915_power_well_id { #define _PALETTE_A 0xa000 #define _PALETTE_B 0xa800 #define _CHV_PALETTE_C 0xc000 -#define PALETTE(pipe, i) _MMIO(dev_priv->info.display_mmio_offset + \ +#define PALETTE(pipe, i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + \ _PICK((pipe), _PALETTE_A, \ _PALETTE_B, _CHV_PALETTE_C) + \ (i) * 4) @@ -4298,7 +4322,7 @@ enum { /* Hotplug control (945+ only) */ -#define PORT_HOTPLUG_EN _MMIO(dev_priv->info.display_mmio_offset + 0x61110) +#define PORT_HOTPLUG_EN _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61110) #define PORTB_HOTPLUG_INT_EN (1 << 29) #define PORTC_HOTPLUG_INT_EN (1 << 28) #define PORTD_HOTPLUG_INT_EN (1 << 27) @@ -4328,7 +4352,7 @@ enum { #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) -#define PORT_HOTPLUG_STAT _MMIO(dev_priv->info.display_mmio_offset + 0x61114) +#define PORT_HOTPLUG_STAT _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61114) /* * HDMI/DP bits are g4x+ * @@ -4410,7 +4434,7 @@ enum { #define PORT_DFT_I9XX _MMIO(0x61150) #define DC_BALANCE_RESET (1 << 25) -#define PORT_DFT2_G4X _MMIO(dev_priv->info.display_mmio_offset + 0x61154) +#define PORT_DFT2_G4X _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61154) #define DC_BALANCE_RESET_VLV (1 << 31) #define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0)) #define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */ @@ -4695,7 +4719,7 @@ enum { #define PANEL_POWER_CYCLE_DELAY_SHIFT 0 /* Panel fitting */ -#define PFIT_CONTROL _MMIO(dev_priv->info.display_mmio_offset + 0x61230) +#define PFIT_CONTROL _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61230) #define PFIT_ENABLE (1 << 31) #define PFIT_PIPE_MASK (3 << 29) #define PFIT_PIPE_SHIFT 29 @@ -4713,7 +4737,7 @@ enum { #define PFIT_SCALING_PROGRAMMED (1 << 26) #define PFIT_SCALING_PILLAR (2 << 26) #define PFIT_SCALING_LETTER (3 << 26) -#define PFIT_PGM_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61234) +#define PFIT_PGM_RATIOS _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61234) /* Pre-965 */ #define PFIT_VERT_SCALE_SHIFT 20 #define PFIT_VERT_SCALE_MASK 0xfff00000 @@ -4725,25 +4749,25 @@ enum { #define PFIT_HORIZ_SCALE_SHIFT_965 0 #define PFIT_HORIZ_SCALE_MASK_965 0x00001fff -#define PFIT_AUTO_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61238) +#define PFIT_AUTO_RATIOS _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61238) -#define _VLV_BLC_PWM_CTL2_A (dev_priv->info.display_mmio_offset + 0x61250) -#define _VLV_BLC_PWM_CTL2_B (dev_priv->info.display_mmio_offset + 0x61350) +#define _VLV_BLC_PWM_CTL2_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61250) +#define _VLV_BLC_PWM_CTL2_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61350) #define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \ _VLV_BLC_PWM_CTL2_B) -#define _VLV_BLC_PWM_CTL_A (dev_priv->info.display_mmio_offset + 0x61254) -#define _VLV_BLC_PWM_CTL_B (dev_priv->info.display_mmio_offset + 0x61354) +#define _VLV_BLC_PWM_CTL_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61254) +#define _VLV_BLC_PWM_CTL_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61354) #define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, \ _VLV_BLC_PWM_CTL_B) -#define _VLV_BLC_HIST_CTL_A (dev_priv->info.display_mmio_offset + 0x61260) -#define _VLV_BLC_HIST_CTL_B (dev_priv->info.display_mmio_offset + 0x61360) +#define _VLV_BLC_HIST_CTL_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61260) +#define _VLV_BLC_HIST_CTL_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61360) #define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, \ _VLV_BLC_HIST_CTL_B) /* Backlight control */ -#define BLC_PWM_CTL2 _MMIO(dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */ +#define BLC_PWM_CTL2 _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61250) /* 965+ only */ #define BLM_PWM_ENABLE (1 << 31) #define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ #define BLM_PIPE_SELECT (1 << 29) @@ -4766,7 +4790,7 @@ enum { #define BLM_PHASE_IN_COUNT_MASK (0xff << 8) #define BLM_PHASE_IN_INCR_SHIFT (0) #define BLM_PHASE_IN_INCR_MASK (0xff << 0) -#define BLC_PWM_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61254) +#define BLC_PWM_CTL _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61254) /* * This is the most significant 15 bits of the number of backlight cycles in a * complete cycle of the modulated backlight control. @@ -4788,7 +4812,7 @@ enum { #define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ -#define BLC_HIST_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61260) +#define BLC_HIST_CTL _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61260) #define BLM_HISTOGRAM_ENABLE (1 << 31) /* New registers for PCH-split platforms. Safe where new bits show up, the @@ -5412,47 +5436,47 @@ enum { * is 20 bytes in each direction, hence the 5 fixed * data registers */ -#define _DPA_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64010) -#define _DPA_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64014) -#define _DPA_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64018) -#define _DPA_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6401c) -#define _DPA_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64020) -#define _DPA_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64024) - -#define _DPB_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64110) -#define _DPB_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64114) -#define _DPB_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64118) -#define _DPB_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6411c) -#define _DPB_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64120) -#define _DPB_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64124) - -#define _DPC_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64210) -#define _DPC_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64214) -#define _DPC_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64218) -#define _DPC_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6421c) -#define _DPC_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64220) -#define _DPC_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64224) - -#define _DPD_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64310) -#define _DPD_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64314) -#define _DPD_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64318) -#define _DPD_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6431c) -#define _DPD_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64320) -#define _DPD_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64324) - -#define _DPE_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64410) -#define _DPE_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64414) -#define _DPE_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64418) -#define _DPE_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6441c) -#define _DPE_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64420) -#define _DPE_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64424) - -#define _DPF_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64510) -#define _DPF_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64514) -#define _DPF_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64518) -#define _DPF_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6451c) -#define _DPF_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64520) -#define _DPF_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64524) +#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) +#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) +#define _DPA_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64018) +#define _DPA_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6401c) +#define _DPA_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64020) +#define _DPA_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64024) + +#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) +#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) +#define _DPB_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64118) +#define _DPB_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6411c) +#define _DPB_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64120) +#define _DPB_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64124) + +#define _DPC_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64210) +#define _DPC_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64214) +#define _DPC_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64218) +#define _DPC_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6421c) +#define _DPC_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64220) +#define _DPC_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64224) + +#define _DPD_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64310) +#define _DPD_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64314) +#define _DPD_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64318) +#define _DPD_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6431c) +#define _DPD_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64320) +#define _DPD_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64324) + +#define _DPE_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64410) +#define _DPE_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64414) +#define _DPE_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64418) +#define _DPE_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6441c) +#define _DPE_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64420) +#define _DPE_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64424) + +#define _DPF_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64510) +#define _DPF_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64514) +#define _DPF_AUX_CH_DATA2 (DISPLAY_MMIO_BASE(dev_priv) + 0x64518) +#define _DPF_AUX_CH_DATA3 (DISPLAY_MMIO_BASE(dev_priv) + 0x6451c) +#define _DPF_AUX_CH_DATA4 (DISPLAY_MMIO_BASE(dev_priv) + 0x64520) +#define _DPF_AUX_CH_DATA5 (DISPLAY_MMIO_BASE(dev_priv) + 0x64524) #define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL) #define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ @@ -5728,7 +5752,7 @@ enum { #define DPINVGTT_STATUS_MASK 0xff #define DPINVGTT_STATUS_MASK_CHV 0xfff -#define DSPARB _MMIO(dev_priv->info.display_mmio_offset + 0x70030) +#define DSPARB _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x70030) #define DSPARB_CSTART_MASK (0x7f << 7) #define DSPARB_CSTART_SHIFT 7 #define DSPARB_BSTART_MASK (0x7f) @@ -5763,7 +5787,7 @@ enum { #define DSPARB_SPRITEF_MASK_VLV (0xff << 8) /* pnv/gen4/g4x/vlv/chv */ -#define DSPFW1 _MMIO(dev_priv->info.display_mmio_offset + 0x70034) +#define DSPFW1 _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x70034) #define DSPFW_SR_SHIFT 23 #define DSPFW_SR_MASK (0x1ff << 23) #define DSPFW_CURSORB_SHIFT 16 @@ -5774,7 +5798,7 @@ enum { #define DSPFW_PLANEA_SHIFT 0 #define DSPFW_PLANEA_MASK (0x7f << 0) #define DSPFW_PLANEA_MASK_VLV (0xff << 0) /* vlv/chv */ -#define DSPFW2 _MMIO(dev_priv->info.display_mmio_offset + 0x70038) +#define DSPFW2 _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x70038) #define DSPFW_FBC_SR_EN (1 << 31) /* g4x */ #define DSPFW_FBC_SR_SHIFT 28 #define DSPFW_FBC_SR_MASK (0x7 << 28) /* g4x */ @@ -5790,7 +5814,7 @@ enum { #define DSPFW_SPRITEA_SHIFT 0 #define DSPFW_SPRITEA_MASK (0x7f << 0) /* g4x */ #define DSPFW_SPRITEA_MASK_VLV (0xff << 0) /* vlv/chv */ -#define DSPFW3 _MMIO(dev_priv->info.display_mmio_offset + 0x7003c) +#define DSPFW3 _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x7003c) #define DSPFW_HPLL_SR_EN (1 << 31) #define PINEVIEW_SELF_REFRESH_EN (1 << 30) #define DSPFW_CURSOR_SR_SHIFT 24 @@ -6206,35 +6230,35 @@ enum { * [10:1f] all * [30:32] all */ -#define SWF0(i) _MMIO(dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4) -#define SWF1(i) _MMIO(dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4) -#define SWF3(i) _MMIO(dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4) +#define SWF0(i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x70410 + (i) * 4) +#define SWF1(i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x71410 + (i) * 4) +#define SWF3(i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x72414 + (i) * 4) #define SWF_ILK(i) _MMIO(0x4F000 + (i) * 4) /* Pipe B */ -#define _PIPEBDSL (dev_priv->info.display_mmio_offset + 0x71000) -#define _PIPEBCONF (dev_priv->info.display_mmio_offset + 0x71008) -#define _PIPEBSTAT (dev_priv->info.display_mmio_offset + 0x71024) +#define _PIPEBDSL (DISPLAY_MMIO_BASE(dev_priv) + 0x71000) +#define _PIPEBCONF (DISPLAY_MMIO_BASE(dev_priv) + 0x71008) +#define _PIPEBSTAT (DISPLAY_MMIO_BASE(dev_priv) + 0x71024) #define _PIPEBFRAMEHIGH 0x71040 #define _PIPEBFRAMEPIXEL 0x71044 -#define _PIPEB_FRMCOUNT_G4X (dev_priv->info.display_mmio_offset + 0x71040) -#define _PIPEB_FLIPCOUNT_G4X (dev_priv->info.display_mmio_offset + 0x71044) +#define _PIPEB_FRMCOUNT_G4X (DISPLAY_MMIO_BASE(dev_priv) + 0x71040) +#define _PIPEB_FLIPCOUNT_G4X (DISPLAY_MMIO_BASE(dev_priv) + 0x71044) /* Display B control */ -#define _DSPBCNTR (dev_priv->info.display_mmio_offset + 0x71180) +#define _DSPBCNTR (DISPLAY_MMIO_BASE(dev_priv) + 0x71180) #define DISPPLANE_ALPHA_TRANS_ENABLE (1 << 15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) -#define _DSPBADDR (dev_priv->info.display_mmio_offset + 0x71184) -#define _DSPBSTRIDE (dev_priv->info.display_mmio_offset + 0x71188) -#define _DSPBPOS (dev_priv->info.display_mmio_offset + 0x7118C) -#define _DSPBSIZE (dev_priv->info.display_mmio_offset + 0x71190) -#define _DSPBSURF (dev_priv->info.display_mmio_offset + 0x7119C) -#define _DSPBTILEOFF (dev_priv->info.display_mmio_offset + 0x711A4) -#define _DSPBOFFSET (dev_priv->info.display_mmio_offset + 0x711A4) -#define _DSPBSURFLIVE (dev_priv->info.display_mmio_offset + 0x711AC) +#define _DSPBADDR (DISPLAY_MMIO_BASE(dev_priv) + 0x71184) +#define _DSPBSTRIDE (DISPLAY_MMIO_BASE(dev_priv) + 0x71188) +#define _DSPBPOS (DISPLAY_MMIO_BASE(dev_priv) + 0x7118C) +#define _DSPBSIZE (DISPLAY_MMIO_BASE(dev_priv) + 0x71190) +#define _DSPBSURF (DISPLAY_MMIO_BASE(dev_priv) + 0x7119C) +#define _DSPBTILEOFF (DISPLAY_MMIO_BASE(dev_priv) + 0x711A4) +#define _DSPBOFFSET (DISPLAY_MMIO_BASE(dev_priv) + 0x711A4) +#define _DSPBSURFLIVE (DISPLAY_MMIO_BASE(dev_priv) + 0x711AC) /* ICL DSI 0 and 1 */ #define _PIPEDSI0CONF 0x7b008 @@ -8786,7 +8810,7 @@ enum { #define GEN9_ENABLE_GPGPU_PREEMPTION (1 << 2) /* Audio */ -#define G4X_AUD_VID_DID _MMIO(dev_priv->info.display_mmio_offset + 0x62020) +#define G4X_AUD_VID_DID _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index cefefc11d922..d1355154886a 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -111,99 +111,10 @@ i915_request_remove_from_client(struct i915_request *request) spin_unlock(&file_priv->mm.lock); } -static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) +static void reserve_gt(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - struct i915_timeline *timeline; - enum intel_engine_id id; - int ret; - - /* Carefully retire all requests without writing to the rings */ - ret = i915_gem_wait_for_idle(i915, - I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED, - MAX_SCHEDULE_TIMEOUT); - if (ret) - return ret; - - GEM_BUG_ON(i915->gt.active_requests); - - /* If the seqno wraps around, we need to clear the breadcrumb rbtree */ - for_each_engine(engine, i915, id) { - GEM_TRACE("%s seqno %d (current %d) -> %d\n", - engine->name, - engine->timeline.seqno, - intel_engine_get_seqno(engine), - seqno); - - if (seqno == engine->timeline.seqno) - continue; - - kthread_park(engine->breadcrumbs.signaler); - - if (!i915_seqno_passed(seqno, engine->timeline.seqno)) { - /* Flush any waiters before we reuse the seqno */ - intel_engine_disarm_breadcrumbs(engine); - intel_engine_init_hangcheck(engine); - GEM_BUG_ON(!list_empty(&engine->breadcrumbs.signals)); - } - - /* Check we are idle before we fiddle with hw state! */ - GEM_BUG_ON(!intel_engine_is_idle(engine)); - GEM_BUG_ON(i915_gem_active_isset(&engine->timeline.last_request)); - - /* Finally reset hw state */ - intel_engine_init_global_seqno(engine, seqno); - engine->timeline.seqno = seqno; - - kthread_unpark(engine->breadcrumbs.signaler); - } - - list_for_each_entry(timeline, &i915->gt.timelines, link) - memset(timeline->global_sync, 0, sizeof(timeline->global_sync)); - - i915->gt.request_serial = seqno; - - return 0; -} - -int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno) -{ - struct drm_i915_private *i915 = to_i915(dev); - - lockdep_assert_held(&i915->drm.struct_mutex); - - if (seqno == 0) - return -EINVAL; - - /* HWS page needs to be set less than what we will inject to ring */ - return reset_all_global_seqno(i915, seqno - 1); -} - -static int reserve_gt(struct drm_i915_private *i915) -{ - int ret; - - /* - * Reservation is fine until we may need to wrap around - * - * By incrementing the serial for every request, we know that no - * individual engine may exceed that serial (as each is reset to 0 - * on any wrap). This protects even the most pessimistic of migrations - * of every request from all engines onto just one. - */ - while (unlikely(++i915->gt.request_serial == 0)) { - ret = reset_all_global_seqno(i915, 0); - if (ret) { - i915->gt.request_serial--; - return ret; - } - } - if (!i915->gt.active_requests++) i915_gem_unpark(i915); - - return 0; } static void unreserve_gt(struct drm_i915_private *i915) @@ -566,6 +477,38 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) return NOTIFY_DONE; } +static void ring_retire_requests(struct intel_ring *ring) +{ + struct i915_request *rq, *rn; + + list_for_each_entry_safe(rq, rn, &ring->request_list, ring_link) { + if (!i915_request_completed(rq)) + break; + + i915_request_retire(rq); + } +} + +static noinline struct i915_request * +i915_request_alloc_slow(struct intel_context *ce) +{ + struct intel_ring *ring = ce->ring; + struct i915_request *rq; + + if (list_empty(&ring->request_list)) + goto out; + + /* Ratelimit ourselves to prevent oom from malicious clients */ + rq = list_last_entry(&ring->request_list, typeof(*rq), ring_link); + cond_synchronize_rcu(rq->rcustate); + + /* Retire our old requests in the hope that we free some */ + ring_retire_requests(ring); + +out: + return kmem_cache_alloc(ce->gem_context->i915->requests, GFP_KERNEL); +} + /** * i915_request_alloc - allocate a request structure * @@ -608,13 +551,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) if (IS_ERR(ce)) return ERR_CAST(ce); - ret = reserve_gt(i915); - if (ret) - goto err_unpin; - - ret = intel_ring_wait_for_space(ce->ring, MIN_SPACE_FOR_ADD_REQUEST); - if (ret) - goto err_unreserve; + reserve_gt(i915); /* Move our oldest request to the slab-cache (if not in use!) */ rq = list_first_entry(&ce->ring->request_list, typeof(*rq), ring_link); @@ -654,15 +591,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) rq = kmem_cache_alloc(i915->requests, GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); if (unlikely(!rq)) { - i915_retire_requests(i915); - - /* Ratelimit ourselves to prevent oom from malicious clients */ - rq = i915_gem_active_raw(&ce->ring->timeline->last_request, - &i915->drm.struct_mutex); - if (rq) - cond_synchronize_rcu(rq->rcustate); - - rq = kmem_cache_alloc(i915->requests, GFP_KERNEL); + rq = i915_request_alloc_slow(ce); if (!rq) { ret = -ENOMEM; goto err_unreserve; @@ -707,9 +636,13 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) * i915_request_add() call can't fail. Note that the reserve may need * to be redone if the request is not actually submitted straight * away, e.g. because a GPU scheduler has deferred it. + * + * Note that due to how we add reserved_space to intel_ring_begin() + * we need to double our request to ensure that if we need to wrap + * around inside i915_request_add() there is sufficient space at + * the beginning of the ring as well. */ - rq->reserved_space = MIN_SPACE_FOR_ADD_REQUEST; - GEM_BUG_ON(rq->reserved_space < engine->emit_breadcrumb_sz); + rq->reserved_space = 2 * engine->emit_breadcrumb_sz * sizeof(u32); /* * Record the position of the start of the request so that @@ -719,11 +652,6 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) */ rq->head = rq->ring->emit; - /* Unconditionally invalidate GPU caches and TLBs. */ - ret = engine->emit_flush(rq, EMIT_INVALIDATE); - if (ret) - goto err_unwind; - ret = engine->request_alloc(rq); if (ret) goto err_unwind; @@ -748,7 +676,6 @@ err_unwind: kmem_cache_free(i915->requests, rq); err_unreserve: unreserve_gt(i915); -err_unpin: intel_context_unpin(ce); return ERR_PTR(ret); } @@ -776,34 +703,12 @@ i915_request_await_request(struct i915_request *to, struct i915_request *from) ret = i915_sw_fence_await_sw_fence_gfp(&to->submit, &from->submit, I915_FENCE_GFP); - return ret < 0 ? ret : 0; - } - - if (to->engine->semaphore.sync_to) { - u32 seqno; - - GEM_BUG_ON(!from->engine->semaphore.signal); - - seqno = i915_request_global_seqno(from); - if (!seqno) - goto await_dma_fence; - - if (seqno <= to->timeline->global_sync[from->engine->id]) - return 0; - - trace_i915_gem_ring_sync_to(to, from); - ret = to->engine->semaphore.sync_to(to, from); - if (ret) - return ret; - - to->timeline->global_sync[from->engine->id] = seqno; - return 0; + } else { + ret = i915_sw_fence_await_dma_fence(&to->submit, + &from->fence, 0, + I915_FENCE_GFP); } -await_dma_fence: - ret = i915_sw_fence_await_dma_fence(&to->submit, - &from->fence, 0, - I915_FENCE_GFP); return ret < 0 ? ret : 0; } @@ -979,8 +884,8 @@ void i915_request_add(struct i915_request *request) * should already have been reserved in the ring buffer. Let the ring * know that it is time to use that space up. */ + GEM_BUG_ON(request->reserved_space > request->ring->space); request->reserved_space = 0; - engine->emit_flush(request, EMIT_FLUSH); /* * Record the position of the start of the breadcrumb so that @@ -1298,13 +1203,7 @@ restart: set_current_state(state); wakeup: - /* - * Carefully check if the request is complete, giving time - * for the seqno to be visible following the interrupt. - * We also have to check in case we are kicked by the GPU - * reset in order to drop the struct_mutex. - */ - if (__i915_request_irq_complete(rq)) + if (i915_request_completed(rq)) break; /* @@ -1343,19 +1242,6 @@ complete: return timeout; } -static void ring_retire_requests(struct intel_ring *ring) -{ - struct i915_request *request, *next; - - list_for_each_entry_safe(request, next, - &ring->request_list, ring_link) { - if (!i915_request_completed(request)) - break; - - i915_request_retire(request); - } -} - void i915_retire_requests(struct drm_i915_private *i915) { struct intel_ring *ring, *tmp; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 90e9d170a0cd..d014b0605445 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -30,7 +30,6 @@ #include "i915_gem.h" #include "i915_scheduler.h" #include "i915_sw_fence.h" -#include "i915_scheduler.h" #include <uapi/drm/i915_drm.h> diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 8f3aa4dc0c98..f18afa2bac8d 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -24,7 +24,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "intel_drv.h" #include "i915_reg.h" @@ -65,7 +64,7 @@ int i915_save_state(struct drm_i915_private *dev_priv) i915_save_display(dev_priv); - if (IS_GEN4(dev_priv)) + if (IS_GEN(dev_priv, 4)) pci_read_config_word(pdev, GCDGMBUS, &dev_priv->regfile.saveGCDGMBUS); @@ -77,14 +76,14 @@ int i915_save_state(struct drm_i915_private *dev_priv) dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); /* Scratch space */ - if (IS_GEN2(dev_priv) && IS_MOBILE(dev_priv)) { + if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { for (i = 0; i < 7; i++) { dev_priv->regfile.saveSWF0[i] = I915_READ(SWF0(i)); dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i)); } for (i = 0; i < 3; i++) dev_priv->regfile.saveSWF3[i] = I915_READ(SWF3(i)); - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { for (i = 0; i < 7; i++) dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i)); } else if (HAS_GMCH_DISPLAY(dev_priv)) { @@ -108,7 +107,7 @@ int i915_restore_state(struct drm_i915_private *dev_priv) mutex_lock(&dev_priv->drm.struct_mutex); - if (IS_GEN4(dev_priv)) + if (IS_GEN(dev_priv, 4)) pci_write_config_word(pdev, GCDGMBUS, dev_priv->regfile.saveGCDGMBUS); i915_restore_display(dev_priv); @@ -122,14 +121,14 @@ int i915_restore_state(struct drm_i915_private *dev_priv) I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000); /* Scratch space */ - if (IS_GEN2(dev_priv) && IS_MOBILE(dev_priv)) { + if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { for (i = 0; i < 7; i++) { I915_WRITE(SWF0(i), dev_priv->regfile.saveSWF0[i]); I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]); } for (i = 0; i < 3; i++) I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]); - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { for (i = 0; i < 7; i++) I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]); } else if (HAS_GMCH_DISPLAY(dev_priv)) { diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 535caebd9813..c0cfe7ae2ba5 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -521,7 +521,9 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj, ssize_t ret; gpu = i915_first_error_state(i915); - if (gpu) { + if (IS_ERR(gpu)) { + ret = PTR_ERR(gpu); + } else if (gpu) { ret = i915_gpu_state_copy_to_buffer(gpu, buf, off, count); i915_gpu_state_put(gpu); } else { diff --git a/drivers/gpu/drm/i915/i915_timeline.h b/drivers/gpu/drm/i915/i915_timeline.h index ebd71b487220..38c1e15e927a 100644 --- a/drivers/gpu/drm/i915/i915_timeline.h +++ b/drivers/gpu/drm/i915/i915_timeline.h @@ -63,14 +63,6 @@ struct i915_timeline { * redundant and we can discard it without loss of generality. */ struct i915_syncmap *sync; - /** - * Separately to the inter-context seqno map above, we track the last - * barrier (e.g. semaphore wait) to the global engine timelines. Note - * that this tracks global_seqno rather than the context.seqno, and - * so it is subject to the limitations of hw wraparound and that we - * may need to revoke global_seqno (on pre-emption). - */ - u32 global_sync[I915_NUM_ENGINES]; struct list_head link; const char *name; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index b50c6b829715..33d90eca9cdd 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -6,7 +6,6 @@ #include <linux/types.h> #include <linux/tracepoint.h> -#include <drm/drmP.h> #include "i915_drv.h" #include "intel_drv.h" #include "intel_ringbuffer.h" @@ -585,35 +584,6 @@ TRACE_EVENT(i915_gem_evict_vm, TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm) ); -TRACE_EVENT(i915_gem_ring_sync_to, - TP_PROTO(struct i915_request *to, struct i915_request *from), - TP_ARGS(to, from), - - TP_STRUCT__entry( - __field(u32, dev) - __field(u32, from_class) - __field(u32, from_instance) - __field(u32, to_class) - __field(u32, to_instance) - __field(u32, seqno) - ), - - TP_fast_assign( - __entry->dev = from->i915->drm.primary->index; - __entry->from_class = from->engine->uabi_class; - __entry->from_instance = from->engine->instance; - __entry->to_class = to->engine->uabi_class; - __entry->to_instance = to->engine->instance; - __entry->seqno = from->global_seqno; - ), - - TP_printk("dev=%u, sync-from=%u:%u, sync-to=%u:%u, seqno=%u", - __entry->dev, - __entry->from_class, __entry->from_instance, - __entry->to_class, __entry->to_instance, - __entry->seqno) -); - TRACE_EVENT(i915_request_queue, TP_PROTO(struct i915_request *rq, u32 flags), TP_ARGS(rq, flags), diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 4dd793b78996..d9dcee4ec51f 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -1178,9 +1178,9 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); } -static bool gen11_dsi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int gen11_dsi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, base); @@ -1205,7 +1205,7 @@ static bool gen11_dsi_compute_config(struct intel_encoder *encoder, pipe_config->clock_set = true; pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5; - return true; + return 0; } static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index 6ba478e57b9b..9d142d038a7d 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -6,7 +6,6 @@ */ #include <linux/pci.h> #include <linux/acpi.h> -#include <drm/drmP.h> #include "i915_drv.h" #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 8cb02f28d30c..d8dbc9980281 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -29,7 +29,6 @@ * See intel_atomic_plane.c for the plane-specific atomic functionality. */ -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> @@ -233,7 +232,7 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta if (plane_state && plane_state->base.fb && plane_state->base.fb->format->is_yuv && plane_state->base.fb->format->num_planes > 1) { - if (IS_GEN9(dev_priv) && + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv)) { mode = SKL_PS_SCALER_MODE_NV12; } else if (icl_is_hdr_plane(to_intel_plane(plane_state->base.plane))) { diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 0a73e6e65c20..683a75dad4fb 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -31,7 +31,6 @@ * prepare/check/commit/cleanup steps. */ -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index ae55a6865d5c..202a58cf2d9f 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -27,7 +27,6 @@ #include <drm/intel_lpe_audio.h> #include "intel_drv.h" -#include <drm/drmP.h> #include <drm/drm_edid.h> #include "i915_drv.h" @@ -758,7 +757,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, struct drm_i915_private *dev_priv = kdev_to_i915(kdev); u32 tmp; - if (!IS_GEN9(dev_priv)) + if (!IS_GEN(dev_priv, 9)) return; i915_audio_component_get_power(kdev); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 6d3e0260d49c..140c218128cb 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -26,7 +26,6 @@ */ #include <drm/drm_dp_helper.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -453,7 +452,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, u8 bdb_version) * Only parse SDVO mappings on gens that could have SDVO. This isn't * accurate and doesn't have to be, as long as it's not too strict. */ - if (!IS_GEN(dev_priv, 3, 7)) { + if (!IS_GEN_RANGE(dev_priv, 3, 7)) { DRM_DEBUG_KMS("Skipping SDVO device mapping\n"); return; } @@ -1386,8 +1385,15 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, info->supports_dp = is_dp; info->supports_edp = is_edp; - DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", - port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); + if (bdb_version >= 195) + info->supports_typec_usb = child->dp_usb_type_c; + + if (bdb_version >= 209) + info->supports_tbt = child->tbt; + + DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d TCUSB:%d TBT:%d\n", + port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt, + info->supports_typec_usb, info->supports_tbt); if (is_edp && is_dvi) DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 447c5256f63a..4ed7105d7ff5 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -166,12 +166,6 @@ static void irq_enable(struct intel_engine_cs *engine) */ GEM_BUG_ON(!intel_irqs_enabled(engine->i915)); - /* Enabling the IRQ may miss the generation of the interrupt, but - * we still need to force the barrier before reading the seqno, - * just in case. - */ - set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); - /* Caller disables interrupts */ if (engine->irq_enable) { spin_lock(&engine->i915->irq_lock); @@ -683,16 +677,6 @@ static int intel_breadcrumbs_signaler(void *arg) } if (unlikely(do_schedule)) { - /* Before we sleep, check for a missed seqno */ - if (current->state & TASK_NORMAL && - !list_empty(&b->signals) && - engine->irq_seqno_barrier && - test_and_clear_bit(ENGINE_IRQ_BREADCRUMB, - &engine->irq_posted)) { - engine->irq_seqno_barrier(engine); - intel_engine_wakeup(engine); - } - sleep: if (kthread_should_park()) kthread_parkme(); @@ -859,16 +843,6 @@ void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine) else irq_disable(engine); - /* - * We set the IRQ_BREADCRUMB bit when we enable the irq presuming the - * GPU is active and may have already executed the MI_USER_INTERRUPT - * before the CPU is ready to receive. However, the engine is currently - * idle (we haven't started it yet), there is no possibility for a - * missed interrupt as we enabled the irq and so we can clear the - * immediate wakeup (until a real interrupt arrives for the waiter). - */ - clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); - spin_unlock_irqrestore(&b->irq_lock, flags); } diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 25e3aba9cded..2021e484a287 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -2140,7 +2140,7 @@ static int intel_pixel_rate_to_cdclk(struct drm_i915_private *dev_priv, { if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) return DIV_ROUND_UP(pixel_rate, 2); - else if (IS_GEN9(dev_priv) || + else if (IS_GEN(dev_priv, 9) || IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) return pixel_rate; else if (IS_CHERRYVIEW(dev_priv)) @@ -2176,7 +2176,7 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) { /* Display WA #1145: glk,cnl */ min_cdclk = max(316800, min_cdclk); - } else if (IS_GEN9(dev_priv) || IS_BROADWELL(dev_priv)) { + } else if (IS_GEN(dev_priv, 9) || IS_BROADWELL(dev_priv)) { /* Display WA #1144: skl,bxt */ min_cdclk = max(432000, min_cdclk); } @@ -2537,7 +2537,7 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) return 2 * max_cdclk_freq; - else if (IS_GEN9(dev_priv) || + else if (IS_GEN(dev_priv, 9) || IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) return max_cdclk_freq; else if (IS_CHERRYVIEW(dev_priv)) @@ -2785,9 +2785,9 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) dev_priv->display.get_cdclk = hsw_get_cdclk; else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) dev_priv->display.get_cdclk = vlv_get_cdclk; - else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) + else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk; - else if (IS_GEN5(dev_priv)) + else if (IS_GEN(dev_priv, 5)) dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk; else if (IS_GM45(dev_priv)) dev_priv->display.get_cdclk = gm45_get_cdclk; diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c index 5127da286a2b..37fd9ddf762e 100644 --- a/drivers/gpu/drm/i915/intel_color.c +++ b/drivers/gpu/drm/i915/intel_color.c @@ -74,12 +74,17 @@ #define ILK_CSC_COEFF_1_0 \ ((7 << 12) | ILK_CSC_COEFF_FP(CTM_COEFF_1_0, 8)) -static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state) +static bool lut_is_legacy(struct drm_property_blob *lut) { - return !state->degamma_lut && - !state->ctm && - state->gamma_lut && - drm_color_lut_size(state->gamma_lut) == LEGACY_LUT_LENGTH; + return drm_color_lut_size(lut) == LEGACY_LUT_LENGTH; +} + +static bool crtc_state_is_legacy_gamma(struct intel_crtc_state *crtc_state) +{ + return !crtc_state->base.degamma_lut && + !crtc_state->base.ctm && + crtc_state->base.gamma_lut && + lut_is_legacy(crtc_state->base.gamma_lut); } /* @@ -108,10 +113,10 @@ static u64 *ctm_mult_by_limited(u64 *result, const u64 *input) return result; } -static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *intel_crtc) +static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *crtc) { - int pipe = intel_crtc->pipe; - struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + int pipe = crtc->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0); I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0); @@ -132,14 +137,12 @@ static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *intel_crtc) I915_WRITE(PIPE_CSC_MODE(pipe), 0); } -static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state) +static void ilk_load_csc_matrix(struct intel_crtc_state *crtc_state) { - struct drm_crtc *crtc = crtc_state->crtc; - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int i, pipe = intel_crtc->pipe; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + int i, pipe = crtc->pipe; uint16_t coeffs[9] = { 0, }; - struct intel_crtc_state *intel_crtc_state = to_intel_crtc_state(crtc_state); bool limited_color_range = false; /* @@ -147,14 +150,14 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state) * do the range compression using the gamma LUT instead. */ if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) - limited_color_range = intel_crtc_state->limited_color_range; + limited_color_range = crtc_state->limited_color_range; - if (intel_crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 || - intel_crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) { - ilk_load_ycbcr_conversion_matrix(intel_crtc); + if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 || + crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) { + ilk_load_ycbcr_conversion_matrix(crtc); return; - } else if (crtc_state->ctm) { - struct drm_color_ctm *ctm = crtc_state->ctm->data; + } else if (crtc_state->base.ctm) { + struct drm_color_ctm *ctm = crtc_state->base.ctm->data; const u64 *input; u64 temp[9]; @@ -253,16 +256,15 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state) /* * Set up the pipe CSC unit on CherryView. */ -static void cherryview_load_csc_matrix(struct drm_crtc_state *state) +static void cherryview_load_csc_matrix(struct intel_crtc_state *crtc_state) { - struct drm_crtc *crtc = state->crtc; - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); - int pipe = to_intel_crtc(crtc)->pipe; + int pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; uint32_t mode; - if (state->ctm) { - struct drm_color_ctm *ctm = state->ctm->data; + if (crtc_state->base.ctm) { + struct drm_color_ctm *ctm = crtc_state->base.ctm->data; uint16_t coeffs[9] = { 0, }; int i; @@ -293,17 +295,17 @@ static void cherryview_load_csc_matrix(struct drm_crtc_state *state) I915_WRITE(CGM_PIPE_CSC_COEFF8(pipe), coeffs[8]); } - mode = (state->ctm ? CGM_PIPE_MODE_CSC : 0); - if (!crtc_state_is_legacy_gamma(state)) { - mode |= (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) | - (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0); + mode = (crtc_state->base.ctm ? CGM_PIPE_MODE_CSC : 0); + if (!crtc_state_is_legacy_gamma(crtc_state)) { + mode |= (crtc_state->base.degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) | + (crtc_state->base.gamma_lut ? CGM_PIPE_MODE_GAMMA : 0); } I915_WRITE(CGM_PIPE_MODE(pipe), mode); } -void intel_color_set_csc(struct drm_crtc_state *crtc_state) +void intel_color_set_csc(struct intel_crtc_state *crtc_state) { - struct drm_device *dev = crtc_state->crtc->dev; + struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); if (dev_priv->display.load_csc_matrix) @@ -311,14 +313,12 @@ void intel_color_set_csc(struct drm_crtc_state *crtc_state) } /* Loads the legacy palette/gamma unit for the CRTC. */ -static void i9xx_load_luts_internal(struct drm_crtc *crtc, - struct drm_property_blob *blob, - struct intel_crtc_state *crtc_state) +static void i9xx_load_luts_internal(struct intel_crtc_state *crtc_state, + struct drm_property_blob *blob) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; int i; if (HAS_GMCH_DISPLAY(dev_priv)) { @@ -353,53 +353,48 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc, } } -static void i9xx_load_luts(struct drm_crtc_state *crtc_state) +static void i9xx_load_luts(struct intel_crtc_state *crtc_state) { - i9xx_load_luts_internal(crtc_state->crtc, crtc_state->gamma_lut, - to_intel_crtc_state(crtc_state)); + i9xx_load_luts_internal(crtc_state, crtc_state->base.gamma_lut); } /* Loads the legacy palette/gamma unit for the CRTC on Haswell. */ -static void haswell_load_luts(struct drm_crtc_state *crtc_state) +static void haswell_load_luts(struct intel_crtc_state *crtc_state) { - struct drm_crtc *crtc = crtc_state->crtc; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *intel_crtc_state = - to_intel_crtc_state(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); bool reenable_ips = false; /* * Workaround : Do not read or write the pipe palette/gamma data while * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. */ - if (IS_HASWELL(dev_priv) && intel_crtc_state->ips_enabled && - (intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) { - hsw_disable_ips(intel_crtc_state); + if (IS_HASWELL(dev_priv) && crtc_state->ips_enabled && + (crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) { + hsw_disable_ips(crtc_state); reenable_ips = true; } - intel_crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT; - I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT); + crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT; + I915_WRITE(GAMMA_MODE(crtc->pipe), GAMMA_MODE_MODE_8BIT); i9xx_load_luts(crtc_state); if (reenable_ips) - hsw_enable_ips(intel_crtc_state); + hsw_enable_ips(crtc_state); } -static void bdw_load_degamma_lut(struct drm_crtc_state *state) +static void bdw_load_degamma_lut(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(state->crtc->dev); - enum pipe pipe = to_intel_crtc(state->crtc)->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); + enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; uint32_t i, lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; I915_WRITE(PREC_PAL_INDEX(pipe), PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT); - if (state->degamma_lut) { - struct drm_color_lut *lut = state->degamma_lut->data; + if (crtc_state->base.degamma_lut) { + struct drm_color_lut *lut = crtc_state->base.degamma_lut->data; for (i = 0; i < lut_size; i++) { uint32_t word = @@ -419,10 +414,10 @@ static void bdw_load_degamma_lut(struct drm_crtc_state *state) } } -static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset) +static void bdw_load_gamma_lut(struct intel_crtc_state *crtc_state, u32 offset) { - struct drm_i915_private *dev_priv = to_i915(state->crtc->dev); - enum pipe pipe = to_intel_crtc(state->crtc)->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); + enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; uint32_t i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; WARN_ON(offset & ~PAL_PREC_INDEX_VALUE_MASK); @@ -432,8 +427,8 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset) PAL_PREC_AUTO_INCREMENT | offset); - if (state->gamma_lut) { - struct drm_color_lut *lut = state->gamma_lut->data; + if (crtc_state->base.gamma_lut) { + struct drm_color_lut *lut = crtc_state->base.gamma_lut->data; for (i = 0; i < lut_size; i++) { uint32_t word = @@ -467,22 +462,21 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset) } /* Loads the palette/gamma unit for the CRTC on Broadwell+. */ -static void broadwell_load_luts(struct drm_crtc_state *state) +static void broadwell_load_luts(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(state->crtc->dev); - struct intel_crtc_state *intel_state = to_intel_crtc_state(state); - enum pipe pipe = to_intel_crtc(state->crtc)->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); + enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; - if (crtc_state_is_legacy_gamma(state)) { - haswell_load_luts(state); + if (crtc_state_is_legacy_gamma(crtc_state)) { + haswell_load_luts(crtc_state); return; } - bdw_load_degamma_lut(state); - bdw_load_gamma_lut(state, + bdw_load_degamma_lut(crtc_state); + bdw_load_gamma_lut(crtc_state, INTEL_INFO(dev_priv)->color.degamma_lut_size); - intel_state->gamma_mode = GAMMA_MODE_MODE_SPLIT; + crtc_state->gamma_mode = GAMMA_MODE_MODE_SPLIT; I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_SPLIT); POSTING_READ(GAMMA_MODE(pipe)); @@ -493,10 +487,10 @@ static void broadwell_load_luts(struct drm_crtc_state *state) I915_WRITE(PREC_PAL_INDEX(pipe), 0); } -static void glk_load_degamma_lut(struct drm_crtc_state *state) +static void glk_load_degamma_lut(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(state->crtc->dev); - enum pipe pipe = to_intel_crtc(state->crtc)->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); + enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; const uint32_t lut_size = 33; uint32_t i; @@ -523,49 +517,46 @@ static void glk_load_degamma_lut(struct drm_crtc_state *state) I915_WRITE(PRE_CSC_GAMC_DATA(pipe), (1 << 16)); } -static void glk_load_luts(struct drm_crtc_state *state) +static void glk_load_luts(struct intel_crtc_state *crtc_state) { - struct drm_crtc *crtc = state->crtc; - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc_state *intel_state = to_intel_crtc_state(state); - enum pipe pipe = to_intel_crtc(crtc)->pipe; + enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe; - glk_load_degamma_lut(state); + glk_load_degamma_lut(crtc_state); - if (crtc_state_is_legacy_gamma(state)) { - haswell_load_luts(state); + if (crtc_state_is_legacy_gamma(crtc_state)) { + haswell_load_luts(crtc_state); return; } - bdw_load_gamma_lut(state, 0); + bdw_load_gamma_lut(crtc_state, 0); - intel_state->gamma_mode = GAMMA_MODE_MODE_10BIT; + crtc_state->gamma_mode = GAMMA_MODE_MODE_10BIT; I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_10BIT); POSTING_READ(GAMMA_MODE(pipe)); } /* Loads the palette/gamma unit for the CRTC on CherryView. */ -static void cherryview_load_luts(struct drm_crtc_state *state) +static void cherryview_load_luts(struct intel_crtc_state *crtc_state) { - struct drm_crtc *crtc = state->crtc; + struct drm_crtc *crtc = crtc_state->base.crtc; struct drm_i915_private *dev_priv = to_i915(crtc->dev); enum pipe pipe = to_intel_crtc(crtc)->pipe; struct drm_color_lut *lut; uint32_t i, lut_size; uint32_t word0, word1; - if (crtc_state_is_legacy_gamma(state)) { + if (crtc_state_is_legacy_gamma(crtc_state)) { /* Turn off degamma/gamma on CGM block. */ I915_WRITE(CGM_PIPE_MODE(pipe), - (state->ctm ? CGM_PIPE_MODE_CSC : 0)); - i9xx_load_luts_internal(crtc, state->gamma_lut, - to_intel_crtc_state(state)); + (crtc_state->base.ctm ? CGM_PIPE_MODE_CSC : 0)); + i9xx_load_luts_internal(crtc_state, crtc_state->base.gamma_lut); return; } - if (state->degamma_lut) { - lut = state->degamma_lut->data; + if (crtc_state->base.degamma_lut) { + lut = crtc_state->base.degamma_lut->data; lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; for (i = 0; i < lut_size; i++) { /* Write LUT in U0.14 format. */ @@ -579,8 +570,8 @@ static void cherryview_load_luts(struct drm_crtc_state *state) } } - if (state->gamma_lut) { - lut = state->gamma_lut->data; + if (crtc_state->base.gamma_lut) { + lut = crtc_state->base.gamma_lut->data; lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; for (i = 0; i < lut_size; i++) { /* Write LUT in U0.10 format. */ @@ -595,29 +586,28 @@ static void cherryview_load_luts(struct drm_crtc_state *state) } I915_WRITE(CGM_PIPE_MODE(pipe), - (state->ctm ? CGM_PIPE_MODE_CSC : 0) | - (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) | - (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0)); + (crtc_state->base.ctm ? CGM_PIPE_MODE_CSC : 0) | + (crtc_state->base.degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) | + (crtc_state->base.gamma_lut ? CGM_PIPE_MODE_GAMMA : 0)); /* * Also program a linear LUT in the legacy block (behind the * CGM block). */ - i9xx_load_luts_internal(crtc, NULL, to_intel_crtc_state(state)); + i9xx_load_luts_internal(crtc_state, NULL); } -void intel_color_load_luts(struct drm_crtc_state *crtc_state) +void intel_color_load_luts(struct intel_crtc_state *crtc_state) { - struct drm_device *dev = crtc_state->crtc->dev; + struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_i915_private *dev_priv = to_i915(dev); dev_priv->display.load_luts(crtc_state); } -int intel_color_check(struct drm_crtc *crtc, - struct drm_crtc_state *crtc_state) +int intel_color_check(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); size_t gamma_length, degamma_length; degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size; @@ -627,10 +617,10 @@ int intel_color_check(struct drm_crtc *crtc, * We allow both degamma & gamma luts at the right size or * NULL. */ - if ((!crtc_state->degamma_lut || - drm_color_lut_size(crtc_state->degamma_lut) == degamma_length) && - (!crtc_state->gamma_lut || - drm_color_lut_size(crtc_state->gamma_lut) == gamma_length)) + if ((!crtc_state->base.degamma_lut || + drm_color_lut_size(crtc_state->base.degamma_lut) == degamma_length) && + (!crtc_state->base.gamma_lut || + drm_color_lut_size(crtc_state->base.gamma_lut) == gamma_length)) return 0; /* @@ -643,11 +633,11 @@ int intel_color_check(struct drm_crtc *crtc, return -EINVAL; } -void intel_color_init(struct drm_crtc *crtc) +void intel_color_init(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - drm_mode_crtc_set_gamma_size(crtc, 256); + drm_mode_crtc_set_gamma_size(&crtc->base, 256); if (IS_CHERRYVIEW(dev_priv)) { dev_priv->display.load_csc_matrix = cherryview_load_csc_matrix; @@ -669,7 +659,7 @@ void intel_color_init(struct drm_crtc *crtc) /* Enable color management support when we have degamma & gamma LUTs. */ if (INTEL_INFO(dev_priv)->color.degamma_lut_size != 0 && INTEL_INFO(dev_priv)->color.gamma_lut_size != 0) - drm_crtc_enable_color_mgmt(crtc, + drm_crtc_enable_color_mgmt(&crtc->base, INTEL_INFO(dev_priv)->color.degamma_lut_size, true, INTEL_INFO(dev_priv)->color.gamma_lut_size); diff --git a/drivers/gpu/drm/i915/intel_connector.c b/drivers/gpu/drm/i915/intel_connector.c index 18e370f607bc..ee16758747c5 100644 --- a/drivers/gpu/drm/i915/intel_connector.c +++ b/drivers/gpu/drm/i915/intel_connector.c @@ -27,7 +27,6 @@ #include <linux/i2c.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> -#include <drm/drmP.h> #include "intel_drv.h" #include "i915_drv.h" @@ -95,6 +94,10 @@ void intel_connector_destroy(struct drm_connector *connector) intel_panel_fini(&intel_connector->panel); drm_connector_cleanup(connector); + + if (intel_connector->port) + drm_dp_mst_put_port_malloc(intel_connector->port); + kfree(connector); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 68f2fb89ece3..e73458f693a5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -27,7 +27,6 @@ #include <linux/dmi.h> #include <linux/i2c.h> #include <linux/slab.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> @@ -322,7 +321,7 @@ intel_crt_mode_valid(struct drm_connector *connector, * DAC limit supposedly 355 MHz. */ max_clock = 270000; - else if (IS_GEN3(dev_priv) || IS_GEN4(dev_priv)) + else if (IS_GEN_RANGE(dev_priv, 3, 4)) max_clock = 400000; else max_clock = 350000; @@ -344,51 +343,52 @@ intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + + return 0; } -static bool pch_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int pch_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->has_pch_encoder = true; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + return 0; } -static bool hsw_crt_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int hsw_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* HSW/BDW FDI limited to 4k */ if (adjusted_mode->crtc_hdisplay > 4096 || adjusted_mode->crtc_hblank_start > 4096) - return false; + return -EINVAL; pipe_config->has_pch_encoder = true; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; @@ -397,7 +397,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, if (HAS_PCH_LPT(dev_priv)) { if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { DRM_DEBUG_KMS("LPT only supports 24bpp\n"); - return false; + return -EINVAL; } pipe_config->pipe_bpp = 24; @@ -406,7 +406,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, /* FDI must always be 2.7 GHz */ pipe_config->port_clock = 135000 * 2; - return true; + return 0; } static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) @@ -666,7 +666,7 @@ intel_crt_load_detect(struct intel_crt *crt, uint32_t pipe) /* Set the border color to purple. */ I915_WRITE(bclrpat_reg, 0x500050); - if (!IS_GEN2(dev_priv)) { + if (!IS_GEN(dev_priv, 2)) { uint32_t pipeconf = I915_READ(pipeconf_reg); I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); POSTING_READ(pipeconf_reg); @@ -981,7 +981,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) else crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) connector->interlace_allowed = 0; else connector->interlace_allowed = 1; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f3e1d6a0b7dd..b1ac89b514c1 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -494,103 +494,58 @@ static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ }; -struct icl_combo_phy_ddi_buf_trans { - u32 dw2_swing_select; - u32 dw2_swing_scalar; - u32 dw4_scaling; -}; - -/* Voltage Swing Programming for VccIO 0.85V for DP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_0_85V[] = { - /* Voltage mV db */ - { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ - { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ - { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ - { 0x2, 0x98, 0x900F }, /* 400 9.5 */ - { 0xB, 0x70, 0x0018 }, /* 600 0.0 */ - { 0xB, 0x70, 0x3015 }, /* 600 3.5 */ - { 0xB, 0x70, 0x6012 }, /* 600 6.0 */ - { 0x5, 0x00, 0x0018 }, /* 800 0.0 */ - { 0x5, 0x00, 0x3015 }, /* 800 3.5 */ - { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ -}; - -/* FIXME - After table is updated in Bspec */ -/* Voltage Swing Programming for VccIO 0.85V for eDP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_0_85V[] = { - /* Voltage mV db */ - { 0x0, 0x00, 0x00 }, /* 200 0.0 */ - { 0x0, 0x00, 0x00 }, /* 200 1.5 */ - { 0x0, 0x00, 0x00 }, /* 200 4.0 */ - { 0x0, 0x00, 0x00 }, /* 200 6.0 */ - { 0x0, 0x00, 0x00 }, /* 250 0.0 */ - { 0x0, 0x00, 0x00 }, /* 250 1.5 */ - { 0x0, 0x00, 0x00 }, /* 250 4.0 */ - { 0x0, 0x00, 0x00 }, /* 300 0.0 */ - { 0x0, 0x00, 0x00 }, /* 300 1.5 */ - { 0x0, 0x00, 0x00 }, /* 350 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for DP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_0_95V[] = { - /* Voltage mV db */ - { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ - { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ - { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ - { 0x2, 0x98, 0x900F }, /* 400 9.5 */ - { 0x4, 0x98, 0x0018 }, /* 600 0.0 */ - { 0x4, 0x98, 0x3015 }, /* 600 3.5 */ - { 0x4, 0x98, 0x6012 }, /* 600 6.0 */ - { 0x5, 0x76, 0x0018 }, /* 800 0.0 */ - { 0x5, 0x76, 0x3015 }, /* 800 3.5 */ - { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ +/* icl_combo_phy_ddi_translations */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ }; -/* FIXME - After table is updated in Bspec */ -/* Voltage Swing Programming for VccIO 0.95V for eDP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_0_95V[] = { - /* Voltage mV db */ - { 0x0, 0x00, 0x00 }, /* 200 0.0 */ - { 0x0, 0x00, 0x00 }, /* 200 1.5 */ - { 0x0, 0x00, 0x00 }, /* 200 4.0 */ - { 0x0, 0x00, 0x00 }, /* 200 6.0 */ - { 0x0, 0x00, 0x00 }, /* 250 0.0 */ - { 0x0, 0x00, 0x00 }, /* 250 1.5 */ - { 0x0, 0x00, 0x00 }, /* 250 4.0 */ - { 0x0, 0x00, 0x00 }, /* 300 0.0 */ - { 0x0, 0x00, 0x00 }, /* 300 1.5 */ - { 0x0, 0x00, 0x00 }, /* 350 0.0 */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = { + /* NT mV Trans mV db */ + { 0x0, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ + { 0x9, 0x7F, 0x31, 0x00, 0x0E }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ + { 0x9, 0x7F, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0x9, 0x7F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ }; -/* Voltage Swing Programming for VccIO 1.05V for DP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_1_05V[] = { - /* Voltage mV db */ - { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ - { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ - { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ - { 0x2, 0x98, 0x900F }, /* 400 9.5 */ - { 0x4, 0x98, 0x0018 }, /* 600 0.0 */ - { 0x4, 0x98, 0x3015 }, /* 600 3.5 */ - { 0x4, 0x98, 0x6012 }, /* 600 6.0 */ - { 0x5, 0x71, 0x0018 }, /* 800 0.0 */ - { 0x5, 0x71, 0x3015 }, /* 800 3.5 */ - { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ }; -/* FIXME - After table is updated in Bspec */ -/* Voltage Swing Programming for VccIO 1.05V for eDP */ -static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_1_05V[] = { - /* Voltage mV db */ - { 0x0, 0x00, 0x00 }, /* 200 0.0 */ - { 0x0, 0x00, 0x00 }, /* 200 1.5 */ - { 0x0, 0x00, 0x00 }, /* 200 4.0 */ - { 0x0, 0x00, 0x00 }, /* 200 6.0 */ - { 0x0, 0x00, 0x00 }, /* 250 0.0 */ - { 0x0, 0x00, 0x00 }, /* 250 1.5 */ - { 0x0, 0x00, 0x00 }, /* 250 4.0 */ - { 0x0, 0x00, 0x00 }, /* 300 0.0 */ - { 0x0, 0x00, 0x00 }, /* 300 1.5 */ - { 0x0, 0x00, 0x00 }, /* 350 0.0 */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = { + /* NT mV Trans mV db */ + { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ + { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ + { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 ALS */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ }; struct icl_mg_phy_ddi_buf_trans { @@ -871,43 +826,23 @@ cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries) } } -static const struct icl_combo_phy_ddi_buf_trans * +static const struct cnl_ddi_buf_trans * icl_get_combo_buf_trans(struct drm_i915_private *dev_priv, enum port port, - int type, int *n_entries) + int type, int rate, int *n_entries) { - u32 voltage = I915_READ(ICL_PORT_COMP_DW3(port)) & VOLTAGE_INFO_MASK; - - if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) { - switch (voltage) { - case VOLTAGE_INFO_0_85V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_0_85V); - return icl_combo_phy_ddi_translations_edp_0_85V; - case VOLTAGE_INFO_0_95V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_0_95V); - return icl_combo_phy_ddi_translations_edp_0_95V; - case VOLTAGE_INFO_1_05V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_1_05V); - return icl_combo_phy_ddi_translations_edp_1_05V; - default: - MISSING_CASE(voltage); - return NULL; - } - } else { - switch (voltage) { - case VOLTAGE_INFO_0_85V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hdmi_0_85V); - return icl_combo_phy_ddi_translations_dp_hdmi_0_85V; - case VOLTAGE_INFO_0_95V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hdmi_0_95V); - return icl_combo_phy_ddi_translations_dp_hdmi_0_95V; - case VOLTAGE_INFO_1_05V: - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hdmi_1_05V); - return icl_combo_phy_ddi_translations_dp_hdmi_1_05V; - default: - MISSING_CASE(voltage); - return NULL; - } + if (type == INTEL_OUTPUT_HDMI) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; + } else if (rate > 540000 && type == INTEL_OUTPUT_EDP) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); + return icl_combo_phy_ddi_translations_edp_hbr3; + } else if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; } + + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); + return icl_combo_phy_ddi_translations_dp_hbr2; } static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port port) @@ -918,8 +853,8 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por if (IS_ICELAKE(dev_priv)) { if (intel_port_is_combophy(dev_priv, port)) - icl_get_combo_buf_trans(dev_priv, port, - INTEL_OUTPUT_HDMI, &n_entries); + icl_get_combo_buf_trans(dev_priv, port, INTEL_OUTPUT_HDMI, + 0, &n_entries); else n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations); default_entry = n_entries - 1; @@ -1361,6 +1296,9 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, dco_freq += (((cfgcr1_val & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) * 24 * 1000) / 0x8000; + if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0)) + return 0; + return dco_freq / (p0 * p1 * p2 * 5); } @@ -1880,7 +1818,7 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) temp |= TRANS_DDI_MODE_SELECT_DVI; if (crtc_state->hdmi_scrambling) - temp |= TRANS_DDI_HDMI_SCRAMBLING_MASK; + temp |= TRANS_DDI_HDMI_SCRAMBLING; if (crtc_state->hdmi_high_tmds_clock_ratio) temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE; } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) { @@ -2275,13 +2213,14 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder, u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); enum port port = encoder->port; int n_entries; if (IS_ICELAKE(dev_priv)) { if (intel_port_is_combophy(dev_priv, port)) icl_get_combo_buf_trans(dev_priv, port, encoder->type, - &n_entries); + intel_dp->link_rate, &n_entries); else n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations); } else if (IS_CANNONLAKE(dev_priv)) { @@ -2462,14 +2401,15 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder, } static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv, - u32 level, enum port port, int type) + u32 level, enum port port, int type, + int rate) { - const struct icl_combo_phy_ddi_buf_trans *ddi_translations = NULL; + const struct cnl_ddi_buf_trans *ddi_translations = NULL; u32 n_entries, val; int ln; ddi_translations = icl_get_combo_buf_trans(dev_priv, port, type, - &n_entries); + rate, &n_entries); if (!ddi_translations) return; @@ -2478,34 +2418,23 @@ static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv, level = n_entries - 1; } - /* Set PORT_TX_DW5 Rterm Sel to 110b. */ + /* Set PORT_TX_DW5 */ val = I915_READ(ICL_PORT_TX_DW5_LN0(port)); - val &= ~RTERM_SELECT_MASK; + val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK | + TAP2_DISABLE | TAP3_DISABLE); + val |= SCALING_MODE_SEL(0x2); val |= RTERM_SELECT(0x6); - I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val); - - /* Program PORT_TX_DW5 */ - val = I915_READ(ICL_PORT_TX_DW5_LN0(port)); - /* Set DisableTap2 and DisableTap3 if MIPI DSI - * Clear DisableTap2 and DisableTap3 for all other Ports - */ - if (type == INTEL_OUTPUT_DSI) { - val |= TAP2_DISABLE; - val |= TAP3_DISABLE; - } else { - val &= ~TAP2_DISABLE; - val &= ~TAP3_DISABLE; - } + val |= TAP3_DISABLE; I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val); /* Program PORT_TX_DW2 */ val = I915_READ(ICL_PORT_TX_DW2_LN0(port)); val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | RCOMP_SCALAR_MASK); - val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_select); - val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_select); + val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel); + val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel); /* Program Rcomp scalar for every table entry */ - val |= RCOMP_SCALAR(ddi_translations[level].dw2_swing_scalar); + val |= RCOMP_SCALAR(0x98); I915_WRITE(ICL_PORT_TX_DW2_GRP(port), val); /* Program PORT_TX_DW4 */ @@ -2514,9 +2443,17 @@ static void icl_ddi_combo_vswing_program(struct drm_i915_private *dev_priv, val = I915_READ(ICL_PORT_TX_DW4_LN(port, ln)); val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | CURSOR_COEFF_MASK); - val |= ddi_translations[level].dw4_scaling; + val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1); + val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2); + val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff); I915_WRITE(ICL_PORT_TX_DW4_LN(port, ln), val); } + + /* Program PORT_TX_DW7 */ + val = I915_READ(ICL_PORT_TX_DW7_LN0(port)); + val &= ~N_SCALAR_MASK; + val |= N_SCALAR(ddi_translations[level].dw7_n_scalar); + I915_WRITE(ICL_PORT_TX_DW7_GRP(port), val); } static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, @@ -2581,7 +2518,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val); /* 5. Program swing and de-emphasis */ - icl_ddi_combo_vswing_program(dev_priv, level, port, type); + icl_ddi_combo_vswing_program(dev_priv, level, port, type, rate); /* 6. Set training enable to trigger update */ val = I915_READ(ICL_PORT_TX_DW5_LN0(port)); @@ -3603,6 +3540,24 @@ static void intel_disable_ddi(struct intel_encoder *encoder, intel_disable_ddi_dp(encoder, old_crtc_state, old_conn_state); } +static void intel_ddi_update_pipe_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + + intel_psr_enable(intel_dp, crtc_state); + intel_edp_drrs_enable(intel_dp, crtc_state); +} + +static void intel_ddi_update_pipe(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + intel_ddi_update_pipe_dp(encoder, crtc_state, conn_state); +} + static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, enum port port) @@ -3793,8 +3748,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, if (intel_dig_port->infoframe_enabled(encoder, pipe_config)) pipe_config->has_infoframe = true; - if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) == - TRANS_DDI_HDMI_SCRAMBLING_MASK) + if (temp & TRANS_DDI_HDMI_SCRAMBLING) pipe_config->hdmi_scrambling = true; if (temp & TRANS_DDI_HIGH_TMDS_CHAR_RATE) pipe_config->hdmi_high_tmds_clock_ratio = true; @@ -3875,9 +3829,9 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder, } } -static bool intel_ddi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_ddi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; @@ -3901,9 +3855,50 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder, } +static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + intel_dp_encoder_suspend(encoder); + + /* + * TODO: disconnect also from USB DP alternate mode once we have a + * way to handle the modeset restore in that mode during resume + * even if the sink has disappeared while being suspended. + */ + if (dig_port->tc_legacy_port) + icl_tc_phy_disconnect(i915, dig_port); +} + +static void intel_ddi_encoder_reset(struct drm_encoder *drm_encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(drm_encoder); + struct drm_i915_private *i915 = to_i915(drm_encoder->dev); + + if (intel_port_is_tc(i915, dig_port->base.port)) + intel_digital_port_connected(&dig_port->base); + + intel_dp_encoder_reset(drm_encoder); +} + +static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + struct drm_i915_private *i915 = to_i915(encoder->dev); + + intel_dp_encoder_flush_work(encoder); + + if (intel_port_is_tc(i915, dig_port->base.port)) + icl_tc_phy_disconnect(i915, dig_port); + + drm_encoder_cleanup(encoder); + kfree(dig_port); +} + static const struct drm_encoder_funcs intel_ddi_funcs = { - .reset = intel_dp_encoder_reset, - .destroy = intel_dp_encoder_destroy, + .reset = intel_ddi_encoder_reset, + .destroy = intel_ddi_encoder_destroy, }; static struct intel_connector * @@ -4147,16 +4142,16 @@ intel_ddi_max_lanes(struct intel_digital_port *intel_dport) void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) { + struct ddi_vbt_port_info *port_info = + &dev_priv->vbt.ddi_port_info[port]; struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; struct drm_encoder *encoder; bool init_hdmi, init_dp, init_lspcon = false; enum pipe pipe; - - init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi || - dev_priv->vbt.ddi_port_info[port].supports_hdmi); - init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp; + init_hdmi = port_info->supports_dvi || port_info->supports_hdmi; + init_dp = port_info->supports_dp; if (intel_bios_is_lspcon_present(dev_priv, port)) { /* @@ -4195,9 +4190,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_encoder->pre_enable = intel_ddi_pre_enable; intel_encoder->disable = intel_disable_ddi; intel_encoder->post_disable = intel_ddi_post_disable; + intel_encoder->update_pipe = intel_ddi_update_pipe; intel_encoder->get_hw_state = intel_ddi_get_hw_state; intel_encoder->get_config = intel_ddi_get_config; - intel_encoder->suspend = intel_dp_encoder_suspend; + intel_encoder->suspend = intel_ddi_encoder_suspend; intel_encoder->get_power_domains = intel_ddi_get_power_domains; intel_encoder->type = INTEL_OUTPUT_DDI; intel_encoder->power_domain = intel_port_to_power_domain(port); @@ -4216,6 +4212,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port); intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port); + intel_dig_port->tc_legacy_port = intel_port_is_tc(dev_priv, port) && + !port_info->supports_typec_usb && + !port_info->supports_tbt; + switch (port) { case PORT_A: intel_dig_port->ddi_io_power_domain = @@ -4274,6 +4274,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) } intel_infoframe_init(intel_dig_port); + + if (intel_port_is_tc(dev_priv, port)) + intel_digital_port_connected(intel_encoder); + return; err: diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 1e56319334f3..855a5074ad77 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -104,7 +104,7 @@ static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p) drm_printf(p, "has EU power gating: %s\n", yesno(sseu->has_eu_pg)); } -void intel_device_info_dump_runtime(const struct intel_device_info *info, +void intel_device_info_dump_runtime(const struct intel_runtime_info *info, struct drm_printer *p) { sseu_dump(&info->sseu, p); @@ -113,21 +113,6 @@ void intel_device_info_dump_runtime(const struct intel_device_info *info, info->cs_timestamp_frequency_khz); } -void intel_device_info_dump(const struct intel_device_info *info, - struct drm_printer *p) -{ - struct drm_i915_private *dev_priv = - container_of(info, struct drm_i915_private, info); - - drm_printf(p, "pciid=0x%04x rev=0x%02x platform=%s gen=%i\n", - INTEL_DEVID(dev_priv), - INTEL_REVID(dev_priv), - intel_platform_name(info->platform), - info->gen); - - intel_device_info_dump_flags(info, p); -} - void intel_device_info_dump_topology(const struct sseu_dev_info *sseu, struct drm_printer *p) { @@ -164,7 +149,7 @@ static u16 compute_eu_total(const struct sseu_dev_info *sseu) static void gen11_sseu_info_init(struct drm_i915_private *dev_priv) { - struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; u8 s_en; u32 ss_en, ss_en_mask; u8 eu_en; @@ -203,7 +188,7 @@ static void gen11_sseu_info_init(struct drm_i915_private *dev_priv) static void gen10_sseu_info_init(struct drm_i915_private *dev_priv) { - struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; const u32 fuse2 = I915_READ(GEN8_FUSE2); int s, ss; const int eu_mask = 0xff; @@ -280,7 +265,7 @@ static void gen10_sseu_info_init(struct drm_i915_private *dev_priv) static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv) { - struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; u32 fuse; fuse = I915_READ(CHV_FUSE_GT); @@ -334,7 +319,7 @@ static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv) static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) { struct intel_device_info *info = mkwrite_device_info(dev_priv); - struct sseu_dev_info *sseu = &info->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; int s, ss; u32 fuse2, eu_disable, subslice_mask; const u8 eu_mask = 0xff; @@ -437,7 +422,7 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv) { - struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; int s, ss; u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */ @@ -519,8 +504,7 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv) static void haswell_sseu_info_init(struct drm_i915_private *dev_priv) { - struct intel_device_info *info = mkwrite_device_info(dev_priv); - struct sseu_dev_info *sseu = &info->sseu; + struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; u32 fuse1; int s, ss; @@ -528,9 +512,9 @@ static void haswell_sseu_info_init(struct drm_i915_private *dev_priv) * There isn't a register to tell us how many slices/subslices. We * work off the PCI-ids here. */ - switch (info->gt) { + switch (INTEL_INFO(dev_priv)->gt) { default: - MISSING_CASE(info->gt); + MISSING_CASE(INTEL_INFO(dev_priv)->gt); /* fall through */ case 1: sseu->slice_mask = BIT(0); @@ -725,7 +709,7 @@ static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) /** * intel_device_info_runtime_init - initialize runtime info - * @info: intel device info struct + * @dev_priv: the i915 device * * Determine various intel_device_info fields at runtime. * @@ -739,29 +723,29 @@ static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) * - after the PCH has been detected, * - before the first usage of the fields it can tweak. */ -void intel_device_info_runtime_init(struct intel_device_info *info) +void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = - container_of(info, struct drm_i915_private, info); + struct intel_device_info *info = mkwrite_device_info(dev_priv); + struct intel_runtime_info *runtime = RUNTIME_INFO(dev_priv); enum pipe pipe; if (INTEL_GEN(dev_priv) >= 10) { for_each_pipe(dev_priv, pipe) - info->num_scalers[pipe] = 2; - } else if (IS_GEN9(dev_priv)) { - info->num_scalers[PIPE_A] = 2; - info->num_scalers[PIPE_B] = 2; - info->num_scalers[PIPE_C] = 1; + runtime->num_scalers[pipe] = 2; + } else if (IS_GEN(dev_priv, 9)) { + runtime->num_scalers[PIPE_A] = 2; + runtime->num_scalers[PIPE_B] = 2; + runtime->num_scalers[PIPE_C] = 1; } BUILD_BUG_ON(I915_NUM_ENGINES > BITS_PER_TYPE(intel_ring_mask_t)); - if (IS_GEN11(dev_priv)) + if (IS_GEN(dev_priv, 11)) for_each_pipe(dev_priv, pipe) - info->num_sprites[pipe] = 6; - else if (IS_GEN10(dev_priv) || IS_GEMINILAKE(dev_priv)) + runtime->num_sprites[pipe] = 6; + else if (IS_GEN(dev_priv, 10) || IS_GEMINILAKE(dev_priv)) for_each_pipe(dev_priv, pipe) - info->num_sprites[pipe] = 3; + runtime->num_sprites[pipe] = 3; else if (IS_BROXTON(dev_priv)) { /* * Skylake and Broxton currently don't expose the topmost plane as its @@ -772,22 +756,22 @@ void intel_device_info_runtime_init(struct intel_device_info *info) * down the line. */ - info->num_sprites[PIPE_A] = 2; - info->num_sprites[PIPE_B] = 2; - info->num_sprites[PIPE_C] = 1; + runtime->num_sprites[PIPE_A] = 2; + runtime->num_sprites[PIPE_B] = 2; + runtime->num_sprites[PIPE_C] = 1; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { for_each_pipe(dev_priv, pipe) - info->num_sprites[pipe] = 2; + runtime->num_sprites[pipe] = 2; } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) { for_each_pipe(dev_priv, pipe) - info->num_sprites[pipe] = 1; + runtime->num_sprites[pipe] = 1; } if (i915_modparams.disable_display) { DRM_INFO("Display disabled (module parameter)\n"); info->num_pipes = 0; } else if (HAS_DISPLAY(dev_priv) && - (IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) && + (IS_GEN_RANGE(dev_priv, 7, 8)) && HAS_PCH_SPLIT(dev_priv)) { u32 fuse_strap = I915_READ(FUSE_STRAP); u32 sfuse_strap = I915_READ(SFUSE_STRAP); @@ -811,7 +795,7 @@ void intel_device_info_runtime_init(struct intel_device_info *info) DRM_INFO("PipeC fused off\n"); info->num_pipes -= 1; } - } else if (HAS_DISPLAY(dev_priv) && IS_GEN9(dev_priv)) { + } else if (HAS_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 9) { u32 dfsm = I915_READ(SKL_DFSM); u8 disabled_mask = 0; bool invalid; @@ -851,20 +835,20 @@ void intel_device_info_runtime_init(struct intel_device_info *info) cherryview_sseu_info_init(dev_priv); else if (IS_BROADWELL(dev_priv)) broadwell_sseu_info_init(dev_priv); - else if (IS_GEN9(dev_priv)) + else if (IS_GEN(dev_priv, 9)) gen9_sseu_info_init(dev_priv); - else if (IS_GEN10(dev_priv)) + else if (IS_GEN(dev_priv, 10)) gen10_sseu_info_init(dev_priv); else if (INTEL_GEN(dev_priv) >= 11) gen11_sseu_info_init(dev_priv); - if (IS_GEN6(dev_priv) && intel_vtd_active()) { + if (IS_GEN(dev_priv, 6) && intel_vtd_active()) { DRM_INFO("Disabling ppGTT for VT-d support\n"); info->ppgtt = INTEL_PPGTT_NONE; } /* Initialize command stream timestamp frequency */ - info->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv); + runtime->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv); } void intel_driver_caps_print(const struct intel_driver_caps *caps, @@ -884,35 +868,44 @@ void intel_driver_caps_print(const struct intel_driver_caps *caps, void intel_device_info_init_mmio(struct drm_i915_private *dev_priv) { struct intel_device_info *info = mkwrite_device_info(dev_priv); - u32 media_fuse; + unsigned int logical_vdbox = 0; unsigned int i; + u32 media_fuse; if (INTEL_GEN(dev_priv) < 11) return; media_fuse = ~I915_READ(GEN11_GT_VEBOX_VDBOX_DISABLE); - info->vdbox_enable = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK; - info->vebox_enable = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >> - GEN11_GT_VEBOX_DISABLE_SHIFT; + RUNTIME_INFO(dev_priv)->vdbox_enable = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK; + RUNTIME_INFO(dev_priv)->vebox_enable = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >> + GEN11_GT_VEBOX_DISABLE_SHIFT; - DRM_DEBUG_DRIVER("vdbox enable: %04x\n", info->vdbox_enable); + DRM_DEBUG_DRIVER("vdbox enable: %04x\n", RUNTIME_INFO(dev_priv)->vdbox_enable); for (i = 0; i < I915_MAX_VCS; i++) { if (!HAS_ENGINE(dev_priv, _VCS(i))) continue; - if (!(BIT(i) & info->vdbox_enable)) { + if (!(BIT(i) & RUNTIME_INFO(dev_priv)->vdbox_enable)) { info->ring_mask &= ~ENGINE_MASK(_VCS(i)); DRM_DEBUG_DRIVER("vcs%u fused off\n", i); + continue; } + + /* + * In Gen11, only even numbered logical VDBOXes are + * hooked up to an SFC (Scaler & Format Converter) unit. + */ + if (logical_vdbox++ % 2 == 0) + RUNTIME_INFO(dev_priv)->vdbox_sfc_access |= BIT(i); } - DRM_DEBUG_DRIVER("vebox enable: %04x\n", info->vebox_enable); + DRM_DEBUG_DRIVER("vebox enable: %04x\n", RUNTIME_INFO(dev_priv)->vebox_enable); for (i = 0; i < I915_MAX_VECS; i++) { if (!HAS_ENGINE(dev_priv, _VECS(i))) continue; - if (!(BIT(i) & info->vebox_enable)) { + if (!(BIT(i) & RUNTIME_INFO(dev_priv)->vebox_enable)) { info->ring_mask &= ~ENGINE_MASK(_VECS(i)); DRM_DEBUG_DRIVER("vecs%u fused off\n", i); } diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 1caf24e2cf0b..957c6527f76b 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -89,6 +89,7 @@ enum intel_ppgtt { func(is_alpha_support); \ /* Keep has_* in alphabetical order */ \ func(has_64bit_reloc); \ + func(gpu_reset_clobbers_display); \ func(has_reset_engine); \ func(has_fpga_dbg); \ func(has_guc); \ @@ -152,12 +153,10 @@ struct sseu_dev_info { typedef u8 intel_ring_mask_t; struct intel_device_info { - u16 device_id; u16 gen_mask; u8 gen; u8 gt; /* GT number, 0 if undefined */ - u8 num_rings; intel_ring_mask_t ring_mask; /* Rings supported by the HW */ enum intel_platform platform; @@ -169,8 +168,6 @@ struct intel_device_info { u32 display_mmio_offset; u8 num_pipes; - u8 num_sprites[I915_MAX_PIPES]; - u8 num_scalers[I915_MAX_PIPES]; #define DEFINE_FLAG(name) u8 name:1 DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG); @@ -189,6 +186,20 @@ struct intel_device_info { int trans_offsets[I915_MAX_TRANSCODERS]; int cursor_offsets[I915_MAX_PIPES]; + struct color_luts { + u16 degamma_lut_size; + u16 gamma_lut_size; + } color; +}; + +struct intel_runtime_info { + u16 device_id; + + u8 num_sprites[I915_MAX_PIPES]; + u8 num_scalers[I915_MAX_PIPES]; + + u8 num_rings; + /* Slice/subslice/EU info */ struct sseu_dev_info sseu; @@ -198,10 +209,8 @@ struct intel_device_info { u8 vdbox_enable; u8 vebox_enable; - struct color_luts { - u16 degamma_lut_size; - u16 gamma_lut_size; - } color; + /* Media engine access to SFC per instance */ + u8 vdbox_sfc_access; }; struct intel_driver_caps { @@ -258,12 +267,10 @@ static inline void sseu_set_eus(struct sseu_dev_info *sseu, const char *intel_platform_name(enum intel_platform platform); -void intel_device_info_runtime_init(struct intel_device_info *info); -void intel_device_info_dump(const struct intel_device_info *info, - struct drm_printer *p); +void intel_device_info_runtime_init(struct drm_i915_private *dev_priv); void intel_device_info_dump_flags(const struct intel_device_info *info, struct drm_printer *p); -void intel_device_info_dump_runtime(const struct intel_device_info *info, +void intel_device_info_dump_runtime(const struct intel_runtime_info *info, struct drm_printer *p); void intel_device_info_dump_topology(const struct sseu_dev_info *sseu, struct drm_printer *p); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3da9c0f9e948..09e12a826cf2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -31,7 +31,6 @@ #include <linux/slab.h> #include <linux/vgaarb.h> #include <drm/drm_edid.h> -#include <drm/drmP.h> #include "intel_drv.h" #include "intel_frontbuffer.h" #include <drm/i915_drm.h> @@ -984,7 +983,7 @@ static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv, u32 line1, line2; u32 line_mask; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) line_mask = DSL_LINEMASK_GEN2; else line_mask = DSL_LINEMASK_GEN3; @@ -1110,7 +1109,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, u32 val; /* ILK FDI PLL is always enabled */ - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) return; /* On Haswell, DDI ports are responsible for the FDI PLL setup */ @@ -1850,7 +1849,7 @@ static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state) static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv) { - return IS_GEN2(dev_priv) ? 2048 : 4096; + return IS_GEN(dev_priv, 2) ? 2048 : 4096; } static unsigned int @@ -1863,7 +1862,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) case DRM_FORMAT_MOD_LINEAR: return cpp; case I915_FORMAT_MOD_X_TILED: - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) return 128; else return 512; @@ -1872,7 +1871,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) return 128; /* fall through */ case I915_FORMAT_MOD_Y_TILED: - if (IS_GEN2(dev_priv) || HAS_128_BYTE_Y_TILING(dev_priv)) + if (IS_GEN(dev_priv, 2) || HAS_128_BYTE_Y_TILING(dev_priv)) return 128; else return 512; @@ -3193,8 +3192,8 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, dspcntr = DISPLAY_PLANE_ENABLE | DISPPLANE_GAMMA_ENABLE; - if (IS_G4X(dev_priv) || IS_GEN5(dev_priv) || - IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) + if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) || + IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) @@ -3746,8 +3745,8 @@ __intel_display_resume(struct drm_device *dev, static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv) { - return intel_has_gpu_reset(dev_priv) && - INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv); + return (INTEL_INFO(dev_priv)->gpu_reset_clobbers_display && + intel_has_gpu_reset(dev_priv)); } void intel_prepare_reset(struct drm_i915_private *dev_priv) @@ -4120,7 +4119,7 @@ static void gen6_fdi_link_train(struct intel_crtc *crtc, temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; /* SNB-B */ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; @@ -4919,10 +4918,10 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, /* range checks */ if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || - (IS_GEN11(dev_priv) && + (IS_GEN(dev_priv, 11) && (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || - (!IS_GEN11(dev_priv) && + (!IS_GEN(dev_priv, 11) && (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { DRM_DEBUG_KMS("scaler_user index %u.%u: src %ux%u dst %ux%u " @@ -5213,7 +5212,7 @@ intel_post_enable_primary(struct drm_crtc *crtc, * FIXME: Need to fix the logic to work when we turn off all planes * but leave the pipe running. */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); /* Underruns don't always raise interrupts, so check manually. */ @@ -5234,7 +5233,7 @@ intel_pre_disable_primary_noatomic(struct drm_crtc *crtc) * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled. */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); hsw_disable_ips(to_intel_crtc_state(crtc->state)); @@ -5292,7 +5291,7 @@ static bool needs_nv12_wa(struct drm_i915_private *dev_priv, return false; /* WA Display #0827: Gen9:all */ - if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv)) + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv)) return true; return false; @@ -5365,7 +5364,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state, * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled. */ - if (IS_GEN2(dev_priv) && old_primary_state->visible && + if (IS_GEN(dev_priv, 2) && old_primary_state->visible && (modeset || !new_primary_state->base.visible)) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); } @@ -5578,6 +5577,26 @@ static void intel_encoders_post_pll_disable(struct drm_crtc *crtc, } } +static void intel_encoders_update_pipe(struct drm_crtc *crtc, + struct intel_crtc_state *crtc_state, + struct drm_atomic_state *old_state) +{ + struct drm_connector_state *conn_state; + struct drm_connector *conn; + int i; + + for_each_new_connector_in_state(old_state, conn, conn_state, i) { + struct intel_encoder *encoder = + to_intel_encoder(conn_state->best_encoder); + + if (conn_state->crtc != crtc) + continue; + + if (encoder->update_pipe) + encoder->update_pipe(encoder, crtc_state, conn_state); + } +} + static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, struct drm_atomic_state *old_state) { @@ -5641,7 +5660,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, * On ILK+ LUT must be loaded before the pipe is running but with * clocks enabled */ - intel_color_load_luts(&pipe_config->base); + intel_color_load_luts(pipe_config); if (dev_priv->display.initial_watermarks != NULL) dev_priv->display.initial_watermarks(old_intel_state, pipe_config); @@ -5752,7 +5771,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, haswell_set_pipemisc(pipe_config); - intel_color_set_csc(&pipe_config->base); + intel_color_set_csc(pipe_config); intel_crtc->active = true; @@ -5771,7 +5790,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, * On ILK+ LUT must be loaded before the pipe is running but with * clocks enabled */ - intel_color_load_luts(&pipe_config->base); + intel_color_load_luts(pipe_config); /* * Display WA #1153: enable hardware to bypass the alpha math @@ -6117,7 +6136,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config, i9xx_set_pipeconf(pipe_config); - intel_color_set_csc(&pipe_config->base); + intel_color_set_csc(pipe_config); intel_crtc->active = true; @@ -6137,7 +6156,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config, i9xx_pfit_enable(pipe_config); - intel_color_load_luts(&pipe_config->base); + intel_color_load_luts(pipe_config); dev_priv->display.initial_watermarks(old_intel_state, pipe_config); @@ -6184,7 +6203,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config, intel_crtc->active = true; - if (!IS_GEN2(dev_priv)) + if (!IS_GEN(dev_priv, 2)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); intel_encoders_pre_enable(crtc, pipe_config, old_state); @@ -6193,7 +6212,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config, i9xx_pfit_enable(pipe_config); - intel_color_load_luts(&pipe_config->base); + intel_color_load_luts(pipe_config); if (dev_priv->display.initial_watermarks != NULL) dev_priv->display.initial_watermarks(old_intel_state, @@ -6236,7 +6255,7 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state, * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe. */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) intel_wait_for_vblank(dev_priv, pipe); intel_encoders_disable(crtc, old_crtc_state, old_state); @@ -6261,7 +6280,7 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state, intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state); - if (!IS_GEN2(dev_priv)) + if (!IS_GEN(dev_priv, 2)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); if (!dev_priv->display.initial_watermarks) @@ -6868,7 +6887,7 @@ static bool transcoder_has_m2_n2(struct drm_i915_private *dev_priv, * Strictly speaking some registers are available before * gen7, but we only support DRRS on gen7+ */ - return IS_GEN7(dev_priv) || IS_CHERRYVIEW(dev_priv); + return IS_GEN(dev_priv, 7) || IS_CHERRYVIEW(dev_priv); } static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state, @@ -9005,7 +9024,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc, /* We currently do not free assignements of panel fitters on * ivb/hsw (since we don't use the higher upscaling modes which * differentiates them) so just WARN about this case for now. */ - if (IS_GEN7(dev_priv)) { + if (IS_GEN(dev_priv, 7)) { WARN_ON((tmp & PF_PIPE_SEL_MASK_IVB) != PF_PIPE_SEL_IVB(crtc->pipe)); } @@ -9995,7 +10014,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); u32 cntl = 0; - if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) + if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) cntl |= MCURSOR_TRICKLE_FEED_DISABLE; if (INTEL_GEN(dev_priv) <= 10) { @@ -10468,7 +10487,7 @@ static int i9xx_pll_refclk(struct drm_device *dev, return dev_priv->vbt.lvds_ssc_freq; else if (HAS_PCH_SPLIT(dev_priv)) return 120000; - else if (!IS_GEN2(dev_priv)) + else if (!IS_GEN(dev_priv, 2)) return 96000; else return 48000; @@ -10501,7 +10520,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; } - if (!IS_GEN2(dev_priv)) { + if (!IS_GEN(dev_priv, 2)) { if (IS_PINEVIEW(dev_priv)) clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); @@ -10653,20 +10672,17 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) /** * intel_wm_need_update - Check whether watermarks need updating - * @plane: drm plane - * @state: new plane state + * @cur: current plane state + * @new: new plane state * * Check current plane state versus the new one to determine whether * watermarks need to be recalculated. * * Returns true or false. */ -static bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state) +static bool intel_wm_need_update(struct intel_plane_state *cur, + struct intel_plane_state *new) { - struct intel_plane_state *new = to_intel_plane_state(state); - struct intel_plane_state *cur = to_intel_plane_state(plane->state); - /* Update watermarks on tiling or size changes. */ if (new->base.visible != cur->base.visible) return true; @@ -10775,7 +10791,8 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat /* must disable cxsr around plane enable/disable */ if (plane->id != PLANE_CURSOR) pipe_config->disable_cxsr = true; - } else if (intel_wm_need_update(&plane->base, plane_state)) { + } else if (intel_wm_need_update(to_intel_plane_state(plane->base.state), + to_intel_plane_state(plane_state))) { if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) { /* FIXME bollocks */ pipe_config->update_wm_pre = true; @@ -10817,7 +10834,7 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat * the w/a on all three platforms. */ if (plane->id == PLANE_SPRITE0 && - (IS_GEN5(dev_priv) || IS_GEN6(dev_priv) || + (IS_GEN_RANGE(dev_priv, 5, 6) || IS_IVYBRIDGE(dev_priv)) && (turn_on || (!needs_scaling(old_plane_state) && needs_scaling(to_intel_plane_state(plane_state))))) @@ -10954,8 +10971,7 @@ static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state) static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); @@ -10975,7 +10991,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } if (crtc_state->color_mgmt_changed) { - ret = intel_color_check(crtc, crtc_state); + ret = intel_color_check(pipe_config); if (ret) return ret; @@ -11004,9 +11020,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, * old state and the new state. We can program these * immediately. */ - ret = dev_priv->display.compute_intermediate_wm(dev, - intel_crtc, - pipe_config); + ret = dev_priv->display.compute_intermediate_wm(pipe_config); if (ret) { DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n"); return ret; @@ -11014,7 +11028,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } if (INTEL_GEN(dev_priv) >= 9) { - if (mode_changed) + if (mode_changed || pipe_config->update_pipe) ret = skl_update_scaler_crtc(pipe_config); if (!ret) @@ -11517,10 +11531,13 @@ encoder_retry: continue; encoder = to_intel_encoder(connector_state->best_encoder); - - if (!(encoder->compute_config(encoder, pipe_config, connector_state))) { - DRM_DEBUG_KMS("Encoder config failure\n"); - return -EINVAL; + ret = encoder->compute_config(encoder, pipe_config, + connector_state); + if (ret < 0) { + if (ret != -EDEADLK) + DRM_DEBUG_KMS("Encoder config failure: %d\n", + ret); + return ret; } } @@ -11964,7 +11981,7 @@ static void verify_wm_state(struct drm_crtc *crtc, if (INTEL_GEN(dev_priv) < 9 || !new_state->active) return; - skl_pipe_wm_get_hw_state(crtc, &hw_wm); + skl_pipe_wm_get_hw_state(intel_crtc, &hw_wm); sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal; skl_pipe_ddb_get_hw_state(intel_crtc, hw_ddb_y, hw_ddb_uv); @@ -12378,7 +12395,7 @@ static void update_scanline_offset(const struct intel_crtc_state *crtc_state) * However if queried just before the start of vblank we'll get an * answer that's slightly in the future. */ - if (IS_GEN2(dev_priv)) { + if (IS_GEN(dev_priv, 2)) { const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; int vtotal; @@ -12619,9 +12636,9 @@ static int intel_modeset_checks(struct drm_atomic_state *state) * phase. The code here should be run after the per-crtc and per-plane 'check' * handlers to ensure that all derived state has been updated. */ -static int calc_watermark_data(struct drm_atomic_state *state) +static int calc_watermark_data(struct intel_atomic_state *state) { - struct drm_device *dev = state->dev; + struct drm_device *dev = state->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); /* Is there platform-specific watermark information to calculate? */ @@ -12695,6 +12712,10 @@ static int intel_atomic_check(struct drm_device *dev, "[modeset]" : "[fastset]"); } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + if (any_ms) { ret = intel_modeset_checks(state); @@ -12713,7 +12734,7 @@ static int intel_atomic_check(struct drm_device *dev, return ret; intel_fbc_choose_crtc(dev_priv, intel_state); - return calc_watermark_data(state); + return calc_watermark_data(intel_state); } static int intel_atomic_prepare_commit(struct drm_device *dev, @@ -12755,9 +12776,14 @@ static void intel_update_crtc(struct drm_crtc *crtc, } else { intel_pre_plane_update(to_intel_crtc_state(old_crtc_state), pipe_config); + + if (pipe_config->update_pipe) + intel_encoders_update_pipe(crtc, pipe_config, state); } - if (new_plane_state) + if (pipe_config->update_pipe && !pipe_config->enable_fbc) + intel_fbc_disable(intel_crtc); + else if (new_plane_state) intel_fbc_enable(intel_crtc, pipe_config, new_plane_state); intel_begin_crtc_commit(crtc, old_crtc_state); @@ -13552,8 +13578,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, if (!modeset && (intel_cstate->base.color_mgmt_changed || intel_cstate->update_pipe)) { - intel_color_set_csc(&intel_cstate->base); - intel_color_load_luts(&intel_cstate->base); + intel_color_set_csc(intel_cstate); + intel_color_load_luts(intel_cstate); } /* Perform vblank evasion around commit operation */ @@ -13578,7 +13604,7 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - if (!IS_GEN2(dev_priv)) + if (!IS_GEN(dev_priv, 2)) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true); if (crtc_state->has_pch_encoder) { @@ -14040,7 +14066,7 @@ static void intel_crtc_init_scalers(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); int i; - crtc->num_scalers = dev_priv->info.num_scalers[crtc->pipe]; + crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[crtc->pipe]; if (!crtc->num_scalers) return; @@ -14126,7 +14152,7 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); - intel_color_init(&intel_crtc->base); + intel_color_init(intel_crtc); WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe); @@ -14185,7 +14211,7 @@ static bool has_edp_a(struct drm_i915_private *dev_priv) if ((I915_READ(DP_A) & DP_DETECTED) == 0) return false; - if (IS_GEN5(dev_priv) && (I915_READ(FUSE_STRAP) & ILK_eDP_A_DISABLE)) + if (IS_GEN(dev_priv, 5) && (I915_READ(FUSE_STRAP) & ILK_eDP_A_DISABLE)) return false; return true; @@ -14397,7 +14423,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) } vlv_dsi_init(dev_priv); - } else if (!IS_GEN2(dev_priv) && !IS_PINEVIEW(dev_priv)) { + } else if (!IS_GEN(dev_priv, 2) && !IS_PINEVIEW(dev_priv)) { bool found = false; if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { @@ -14431,7 +14457,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (IS_G4X(dev_priv) && (I915_READ(DP_D) & DP_DETECTED)) intel_dp_init(dev_priv, DP_D, PORT_D); - } else if (IS_GEN2(dev_priv)) + } else if (IS_GEN(dev_priv, 2)) intel_dvo_init(dev_priv); if (SUPPORTS_TV(dev_priv)) @@ -14629,7 +14655,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, * require the entire fb to accommodate that to avoid * potential runtime errors at plane configuration time. */ - if (IS_GEN9(dev_priv) && i == 0 && fb->width > 3840 && + if (IS_GEN(dev_priv, 9) && i == 0 && fb->width > 3840 && is_ccs_modifier(fb->modifier)) stride_alignment *= 4; @@ -14834,7 +14860,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; - } else if (!IS_GEN2(dev_priv)) { + } else if (!IS_GEN(dev_priv, 2)) { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_initial_plane_config = i9xx_get_initial_plane_config; @@ -14850,9 +14876,9 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) dev_priv->display.crtc_disable = i9xx_crtc_disable; } - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { dev_priv->display.fdi_link_train = ironlake_fdi_link_train; - } else if (IS_GEN6(dev_priv)) { + } else if (IS_GEN(dev_priv, 6)) { dev_priv->display.fdi_link_train = gen6_fdi_link_train; } else if (IS_IVYBRIDGE(dev_priv)) { /* FIXME: detect B0+ stepping and use auto training */ @@ -14984,12 +15010,12 @@ fail: static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv) { - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { u32 fdi_pll_clk = I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK; dev_priv->fdi_pll_freq = (fdi_pll_clk + 2) * 10000; - } else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) { + } else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) { dev_priv->fdi_pll_freq = 270000; } else { return; @@ -15105,10 +15131,10 @@ int intel_modeset_init(struct drm_device *dev) } /* maximum framebuffer dimensions */ - if (IS_GEN2(dev_priv)) { + if (IS_GEN(dev_priv, 2)) { dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; - } else if (IS_GEN3(dev_priv)) { + } else if (IS_GEN(dev_priv, 3)) { dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; } else { @@ -15119,7 +15145,7 @@ int intel_modeset_init(struct drm_device *dev) if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { dev->mode_config.cursor_width = IS_I845G(dev_priv) ? 64 : 512; dev->mode_config.cursor_height = 1023; - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { dev->mode_config.cursor_width = 64; dev->mode_config.cursor_height = 64; } else { @@ -15843,15 +15869,15 @@ intel_modeset_setup_hw_state(struct drm_device *dev, } if (IS_G4X(dev_priv)) { - g4x_wm_get_hw_state(dev); + g4x_wm_get_hw_state(dev_priv); g4x_wm_sanitize(dev_priv); } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - vlv_wm_get_hw_state(dev); + vlv_wm_get_hw_state(dev_priv); vlv_wm_sanitize(dev_priv); } else if (INTEL_GEN(dev_priv) >= 9) { - skl_wm_get_hw_state(dev); + skl_wm_get_hw_state(dev_priv); } else if (HAS_PCH_SPLIT(dev_priv)) { - ilk_wm_get_hw_state(dev); + ilk_wm_get_hw_state(dev_priv); } for_each_intel_crtc(dev, crtc) { diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 4262452963b3..c7c068662288 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -121,7 +121,7 @@ enum i9xx_plane_id { }; #define plane_name(p) ((p) + 'A') -#define sprite_name(p, s) ((p) * INTEL_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A') +#define sprite_name(p, s) ((p) * RUNTIME_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A') /* * Per-pipe plane identifier. @@ -311,12 +311,12 @@ struct intel_link_m_n { #define for_each_universal_plane(__dev_priv, __pipe, __p) \ for ((__p) = 0; \ - (__p) < INTEL_INFO(__dev_priv)->num_sprites[(__pipe)] + 1; \ + (__p) < RUNTIME_INFO(__dev_priv)->num_sprites[(__pipe)] + 1; \ (__p)++) #define for_each_sprite(__dev_priv, __p, __s) \ for ((__s) = 0; \ - (__s) < INTEL_INFO(__dev_priv)->num_sprites[(__p)]; \ + (__s) < RUNTIME_INFO(__dev_priv)->num_sprites[(__p)]; \ (__s)++) #define for_each_port_masked(__port, __ports_mask) \ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fdd2cbc56fa3..c1eda64ada9d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -32,7 +32,6 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <asm/byteorder.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> @@ -304,9 +303,11 @@ static int cnl_max_source_rate(struct intel_dp *intel_dp) static int icl_max_source_rate(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum port port = dig_port->base.port; - if (port == PORT_B) + if (intel_port_is_combophy(dev_priv, port) && + !intel_dp_is_edp(intel_dp)) return 540000; return 810000; @@ -344,7 +345,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) if (INTEL_GEN(dev_priv) >= 10) { source_rates = cnl_rates; size = ARRAY_SIZE(cnl_rates); - if (IS_GEN10(dev_priv)) + if (IS_GEN(dev_priv, 10)) max_rate = cnl_max_source_rate(intel_dp); else max_rate = icl_max_source_rate(intel_dp); @@ -1128,7 +1129,7 @@ static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp, to_i915(intel_dig_port->base.base.dev); uint32_t precharge, timeout; - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) precharge = 3; else precharge = 5; @@ -1808,7 +1809,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, } /* Optimize link config in order: max bpp, min clock, min lanes */ -static bool +static int intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, const struct link_config_limits *limits) @@ -1834,17 +1835,17 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, pipe_config->pipe_bpp = bpp; pipe_config->port_clock = link_clock; - return true; + return 0; } } } } - return false; + return -EINVAL; } /* Optimize link config in order: max bpp, min lanes, min clock */ -static bool +static int intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, const struct link_config_limits *limits) @@ -1870,13 +1871,13 @@ intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, pipe_config->pipe_bpp = bpp; pipe_config->port_clock = link_clock; - return true; + return 0; } } } } - return false; + return -EINVAL; } static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) @@ -1894,19 +1895,20 @@ static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) return 0; } -static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state, - struct link_config_limits *limits) +static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; u8 dsc_max_bpc; int pipe_bpp; + int ret; if (!intel_dp_supports_dsc(intel_dp, pipe_config)) - return false; + return -EINVAL; dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC, conn_state->max_requested_bpc); @@ -1914,7 +1916,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc); if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) { DRM_DEBUG_KMS("No DSC support for less than 8bpc\n"); - return false; + return -EINVAL; } /* @@ -1948,7 +1950,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, adjusted_mode->crtc_hdisplay); if (!dsc_max_output_bpp || !dsc_dp_slice_count) { DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n"); - return false; + return -EINVAL; } pipe_config->dsc_params.compressed_bpp = min_t(u16, dsc_max_output_bpp >> 4, @@ -1965,16 +1967,19 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc_params.dsc_split = true; } else { DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n"); - return false; + return -EINVAL; } } - if (intel_dp_compute_dsc_params(intel_dp, pipe_config) < 0) { + + ret = intel_dp_compute_dsc_params(intel_dp, pipe_config); + if (ret < 0) { DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d " "Compressed BPP = %d\n", pipe_config->pipe_bpp, pipe_config->dsc_params.compressed_bpp); - return false; + return ret; } + pipe_config->dsc_params.compression_enable = true; DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d " "Compressed Bpp = %d Slice Count = %d\n", @@ -1982,10 +1987,10 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc_params.compressed_bpp, pipe_config->dsc_params.slice_count); - return true; + return 0; } -static bool +static int intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -1994,7 +1999,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct link_config_limits limits; int common_len; - bool ret; + int ret; common_len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate); @@ -2051,10 +2056,12 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, &limits); /* enable compression if the mode doesn't fit available BW */ - if (!ret) { - if (!intel_dp_dsc_compute_config(intel_dp, pipe_config, - conn_state, &limits)) - return false; + DRM_DEBUG_KMS("Force DSC en = %d\n", intel_dp->force_dsc_en); + if (ret || intel_dp->force_dsc_en) { + ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, + conn_state, &limits); + if (ret < 0) + return ret; } if (pipe_config->dsc_params.compression_enable) { @@ -2079,10 +2086,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, intel_dp_max_data_rate(pipe_config->port_clock, pipe_config->lane_count)); } - return true; + return 0; } -bool +int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2098,6 +2105,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, to_intel_digital_connector_state(conn_state); bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N); + int ret; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) pipe_config->has_pch_encoder = true; @@ -2119,8 +2127,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, adjusted_mode); if (INTEL_GEN(dev_priv) >= 9) { - int ret; - ret = skl_update_scaler_crtc(pipe_config); if (ret) return ret; @@ -2135,20 +2141,21 @@ intel_dp_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; if (HAS_GMCH_DISPLAY(dev_priv) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - return false; + return -EINVAL; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) - return false; + return -EINVAL; pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && intel_dp_supports_fec(intel_dp, pipe_config); - if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state)) - return false; + ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state); + if (ret < 0) + return ret; if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { /* @@ -2196,7 +2203,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_psr_compute_config(intel_dp, pipe_config); - return true; + return 0; } void intel_dp_set_link_params(struct intel_dp *intel_dp, @@ -2585,7 +2592,7 @@ static void edp_panel_on(struct intel_dp *intel_dp) pp_ctrl_reg = _pp_ctrl_reg(intel_dp); pp = ironlake_get_pp_control(intel_dp); - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { /* ILK workaround: disable reset around power sequence */ pp &= ~PANEL_POWER_RESET; I915_WRITE(pp_ctrl_reg, pp); @@ -2593,7 +2600,7 @@ static void edp_panel_on(struct intel_dp *intel_dp) } pp |= PANEL_POWER_ON; - if (!IS_GEN5(dev_priv)) + if (!IS_GEN(dev_priv, 5)) pp |= PANEL_POWER_RESET; I915_WRITE(pp_ctrl_reg, pp); @@ -2602,7 +2609,7 @@ static void edp_panel_on(struct intel_dp *intel_dp) wait_panel_on(intel_dp); intel_dp->last_power_on = jiffies; - if (IS_GEN5(dev_priv)) { + if (IS_GEN(dev_priv, 5)) { pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); @@ -2831,7 +2838,7 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp, * 1. Wait for the start of vertical blank on the enabled pipe going to FDI * 2. Program DP PLL enable */ - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) intel_wait_for_vblank_if_active(dev_priv, !crtc->pipe); intel_dp->DP |= DP_PLL_ENABLE; @@ -3849,7 +3856,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp) } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { signal_levels = ivb_cpu_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; - } else if (IS_GEN6(dev_priv) && port == PORT_A) { + } else if (IS_GEN(dev_priv, 6) && port == PORT_A) { signal_levels = snb_cpu_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; } else { @@ -3991,6 +3998,42 @@ intel_dp_link_down(struct intel_encoder *encoder, } } +static void +intel_dp_extended_receiver_capabilities(struct intel_dp *intel_dp) +{ + u8 dpcd_ext[6]; + + /* + * Prior to DP1.3 the bit represented by + * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. + * if it is set DP_DPCD_REV at 0000h could be at a value less than + * the true capability of the panel. The only way to check is to + * then compare 0000h and 2200h. + */ + if (!(intel_dp->dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) + return; + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_DP13_DPCD_REV, + &dpcd_ext, sizeof(dpcd_ext)) != sizeof(dpcd_ext)) { + DRM_ERROR("DPCD failed read at extended capabilities\n"); + return; + } + + if (intel_dp->dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { + DRM_DEBUG_KMS("DPCD extended DPCD rev less than base DPCD rev\n"); + return; + } + + if (!memcmp(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext))) + return; + + DRM_DEBUG_KMS("Base DPCD: %*ph\n", + (int)sizeof(intel_dp->dpcd), intel_dp->dpcd); + + memcpy(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext)); +} + bool intel_dp_read_dpcd(struct intel_dp *intel_dp) { @@ -3998,6 +4041,8 @@ intel_dp_read_dpcd(struct intel_dp *intel_dp) sizeof(intel_dp->dpcd)) < 0) return false; /* aux transfer failed */ + intel_dp_extended_receiver_capabilities(intel_dp); + DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd); return intel_dp->dpcd[DP_DPCD_REV] != 0; @@ -5028,28 +5073,38 @@ static bool icl_combo_port_connected(struct drm_i915_private *dev_priv, return I915_READ(SDEISR) & SDE_DDI_HOTPLUG_ICP(port); } +static const char *tc_type_name(enum tc_port_type type) +{ + static const char * const names[] = { + [TC_PORT_UNKNOWN] = "unknown", + [TC_PORT_LEGACY] = "legacy", + [TC_PORT_TYPEC] = "typec", + [TC_PORT_TBT] = "tbt", + }; + + if (WARN_ON(type >= ARRAY_SIZE(names))) + type = TC_PORT_UNKNOWN; + + return names[type]; +} + static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, struct intel_digital_port *intel_dig_port, bool is_legacy, bool is_typec, bool is_tbt) { enum port port = intel_dig_port->base.port; enum tc_port_type old_type = intel_dig_port->tc_type; - const char *type_str; WARN_ON(is_legacy + is_typec + is_tbt != 1); - if (is_legacy) { + if (is_legacy) intel_dig_port->tc_type = TC_PORT_LEGACY; - type_str = "legacy"; - } else if (is_typec) { + else if (is_typec) intel_dig_port->tc_type = TC_PORT_TYPEC; - type_str = "typec"; - } else if (is_tbt) { + else if (is_tbt) intel_dig_port->tc_type = TC_PORT_TBT; - type_str = "tbt"; - } else { + else return; - } /* Types are not supposed to be changed at runtime. */ WARN_ON(old_type != TC_PORT_UNKNOWN && @@ -5057,12 +5112,9 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, if (old_type != intel_dig_port->tc_type) DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), - type_str); + tc_type_name(intel_dig_port->tc_type)); } -static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, - struct intel_digital_port *dig_port); - /* * This function implements the first part of the Connect Flow described by our * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading @@ -5097,6 +5149,7 @@ static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv, val = I915_READ(PORT_TX_DFLEXDPPMS); if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); + WARN_ON(dig_port->tc_legacy_port); return false; } @@ -5128,8 +5181,8 @@ static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv, * See the comment at the connect function. This implements the Disconnect * Flow. */ -static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, - struct intel_digital_port *dig_port) +void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port) { enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); @@ -5149,6 +5202,10 @@ static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, I915_WRITE(PORT_TX_DFLEXDPCSSS, val); } + DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", + port_name(dig_port->base.port), + tc_type_name(dig_port->tc_type)); + dig_port->tc_type = TC_PORT_UNKNOWN; } @@ -5170,7 +5227,14 @@ static bool icl_tc_port_connected(struct drm_i915_private *dev_priv, bool is_legacy, is_typec, is_tbt; u32 dpsp; - is_legacy = I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port); + /* + * WARN if we got a legacy port HPD, but VBT didn't mark the port as + * legacy. Treat the port as legacy from now on. + */ + if (WARN_ON(!intel_dig_port->tc_legacy_port && + I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port))) + intel_dig_port->tc_legacy_port = true; + is_legacy = intel_dig_port->tc_legacy_port; /* * The spec says we shouldn't be using the ISR bits for detecting @@ -5182,6 +5246,7 @@ static bool icl_tc_port_connected(struct drm_i915_private *dev_priv, if (!is_legacy && !is_typec && !is_tbt) { icl_tc_phy_disconnect(dev_priv, intel_dig_port); + return false; } @@ -5233,17 +5298,17 @@ bool intel_digital_port_connected(struct intel_encoder *encoder) if (INTEL_GEN(dev_priv) >= 11) return icl_digital_port_connected(encoder); - else if (IS_GEN10(dev_priv) || IS_GEN9_BC(dev_priv)) + else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv)) return spt_digital_port_connected(encoder); else if (IS_GEN9_LP(dev_priv)) return bxt_digital_port_connected(encoder); - else if (IS_GEN8(dev_priv)) + else if (IS_GEN(dev_priv, 8)) return bdw_digital_port_connected(encoder); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) return ivb_digital_port_connected(encoder); - else if (IS_GEN6(dev_priv)) + else if (IS_GEN(dev_priv, 6)) return snb_digital_port_connected(encoder); - else if (IS_GEN5(dev_priv)) + else if (IS_GEN(dev_priv, 5)) return ilk_digital_port_connected(encoder); MISSING_CASE(INTEL_GEN(dev_priv)); @@ -5490,7 +5555,7 @@ intel_dp_connector_unregister(struct drm_connector *connector) intel_connector_unregister(connector); } -void intel_dp_encoder_destroy(struct drm_encoder *encoder) +void intel_dp_encoder_flush_work(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -5513,9 +5578,14 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) } intel_dp_aux_fini(intel_dp); +} + +static void intel_dp_encoder_destroy(struct drm_encoder *encoder) +{ + intel_dp_encoder_flush_work(encoder); drm_encoder_cleanup(encoder); - kfree(intel_dig_port); + kfree(enc_to_dig_port(encoder)); } void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) @@ -5578,7 +5648,12 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port, } reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK; - return reply == DP_AUX_NATIVE_REPLY_ACK ? 0 : -EIO; + if (reply != DP_AUX_NATIVE_REPLY_ACK) { + DRM_DEBUG_KMS("Aksv write: no DP_AUX_NATIVE_REPLY_ACK %x\n", + reply); + return -EIO; + } + return 0; } static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port, @@ -6361,8 +6436,8 @@ void intel_edp_drrs_enable(struct intel_dp *intel_dp, } mutex_lock(&dev_priv->drrs.mutex); - if (WARN_ON(dev_priv->drrs.dp)) { - DRM_ERROR("DRRS already enabled\n"); + if (dev_priv->drrs.dp) { + DRM_DEBUG_KMS("DRRS already enabled\n"); goto unlock; } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index f05427b74e34..a19699023db1 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -23,16 +23,15 @@ * */ -#include <drm/drmP.h> #include "i915_drv.h" #include "intel_drv.h" #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> -static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dp_mst_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); @@ -41,15 +40,19 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; void *port = to_intel_connector(connector)->port; struct drm_atomic_state *state = pipe_config->base.state; + struct drm_crtc *crtc = pipe_config->base.crtc; + struct drm_crtc_state *old_crtc_state = + drm_atomic_get_old_crtc_state(state, crtc); int bpp; - int lane_count, slots = 0; + int lane_count, slots = + to_intel_crtc_state(old_crtc_state)->dp_m_n.tu; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; int mst_pbn; bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_pch_encoder = false; @@ -86,7 +89,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, if (slots < 0) { DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots); - return false; + return slots; } } @@ -104,38 +107,42 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); - return true; + return 0; } -static int intel_dp_mst_atomic_check(struct drm_connector *connector, - struct drm_connector_state *new_conn_state) +static int +intel_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) { struct drm_atomic_state *state = new_conn_state->state; - struct drm_connector_state *old_conn_state; - struct drm_crtc *old_crtc; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct intel_connector *intel_connector = + to_intel_connector(connector); + struct drm_crtc *new_crtc = new_conn_state->crtc; struct drm_crtc_state *crtc_state; - int slots, ret = 0; - - old_conn_state = drm_atomic_get_old_connector_state(state, connector); - old_crtc = old_conn_state->crtc; - if (!old_crtc) - return ret; + struct drm_dp_mst_topology_mgr *mgr; + int ret = 0; - crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); - slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; - if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { - struct drm_dp_mst_topology_mgr *mgr; - struct drm_encoder *old_encoder; + if (!old_conn_state->crtc) + return 0; - old_encoder = old_conn_state->best_encoder; - mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; + /* We only want to free VCPI if this state disables the CRTC on this + * connector + */ + if (new_crtc) { + crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); - ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); - if (ret) - DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); - else - to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; + if (!crtc_state || + !drm_atomic_crtc_needs_modeset(crtc_state) || + crtc_state->enable) + return 0; } + + mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr; + ret = drm_dp_atomic_release_vcpi_slots(state, mgr, + intel_connector->port); + return ret; } @@ -457,6 +464,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->get_hw_state = intel_dp_mst_get_hw_state; intel_connector->mst_port = intel_dp; intel_connector->port = port; + drm_dp_mst_get_port_malloc(port); connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f94a04b4ad87..d4ee09fb275a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -222,9 +222,9 @@ struct intel_encoder { enum intel_output_type (*compute_output_type)(struct intel_encoder *, struct intel_crtc_state *, struct drm_connector_state *); - bool (*compute_config)(struct intel_encoder *, - struct intel_crtc_state *, - struct drm_connector_state *); + int (*compute_config)(struct intel_encoder *, + struct intel_crtc_state *, + struct drm_connector_state *); void (*pre_pll_enable)(struct intel_encoder *, const struct intel_crtc_state *, const struct drm_connector_state *); @@ -243,6 +243,9 @@ struct intel_encoder { void (*post_pll_disable)(struct intel_encoder *, const struct intel_crtc_state *, const struct drm_connector_state *); + void (*update_pipe)(struct intel_encoder *, + const struct intel_crtc_state *, + const struct drm_connector_state *); /* Read out the current hw state of this connector, returning true if * the encoder is active. If the encoder is enabled it also set the pipe * it is connected to in the pipe parameter. */ @@ -1074,7 +1077,6 @@ struct intel_hdmi { } dp_dual_mode; bool has_hdmi_sink; bool has_audio; - bool rgb_quant_range_selectable; struct intel_connector *attached_connector; struct cec_notifier *cec_notifier; }; @@ -1209,6 +1211,9 @@ struct intel_dp { /* Displayport compliance testing */ struct intel_dp_compliance compliance; + + /* Display stream compression testing */ + bool force_dsc_en; }; enum lspcon_vendor { @@ -1234,6 +1239,7 @@ struct intel_digital_port { /* Used for DP and ICL+ TypeC/DP and TypeC/HDMI ports. */ enum aux_ch aux_ch; enum intel_display_power_domain ddi_io_power_domain; + bool tc_legacy_port:1; enum tc_port_type tc_type; void (*write_infoframe)(struct intel_encoder *encoder, @@ -1806,10 +1812,10 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, bool enable); void intel_dp_encoder_reset(struct drm_encoder *encoder); void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); -void intel_dp_encoder_destroy(struct drm_encoder *encoder); -bool intel_dp_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state); +void intel_dp_encoder_flush_work(struct drm_encoder *encoder); +int intel_dp_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, @@ -1874,6 +1880,8 @@ bool intel_dp_read_dpcd(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_max_data_rate(int max_link_clock, int max_lanes); bool intel_digital_port_connected(struct intel_encoder *encoder); +void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port); /* intel_dp_aux_backlight.c */ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector); @@ -1967,9 +1975,9 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); -bool intel_hdmi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state); +int intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, struct drm_connector *connector, bool high_tmds_clock_ratio, @@ -2200,16 +2208,16 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv); void gen6_rps_reset_ei(struct drm_i915_private *dev_priv); void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct i915_request *rq, struct intel_rps_client *rps); -void g4x_wm_get_hw_state(struct drm_device *dev); -void vlv_wm_get_hw_state(struct drm_device *dev); -void ilk_wm_get_hw_state(struct drm_device *dev); -void skl_wm_get_hw_state(struct drm_device *dev); +void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv); +void vlv_wm_get_hw_state(struct drm_i915_private *dev_priv); +void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv); +void skl_wm_get_hw_state(struct drm_i915_private *dev_priv); void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, struct skl_ddb_entry *ddb_y, struct skl_ddb_entry *ddb_uv); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb /* out */); -void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc, +void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, struct skl_pipe_wm *out); void g4x_wm_sanitize(struct drm_i915_private *dev_priv); void vlv_wm_sanitize(struct drm_i915_private *dev_priv); @@ -2327,10 +2335,10 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ struct intel_plane_state *intel_state); /* intel_color.c */ -void intel_color_init(struct drm_crtc *crtc); -int intel_color_check(struct drm_crtc *crtc, struct drm_crtc_state *state); -void intel_color_set_csc(struct drm_crtc_state *crtc_state); -void intel_color_load_luts(struct drm_crtc_state *crtc_state); +void intel_color_init(struct intel_crtc *crtc); +int intel_color_check(struct intel_crtc_state *crtc_state); +void intel_color_set_csc(struct intel_crtc_state *crtc_state); +void intel_color_load_luts(struct intel_crtc_state *crtc_state); /* intel_lspcon.c */ bool lspcon_init(struct intel_digital_port *intel_dig_port); diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index d968f1f13e09..fc7a09049f81 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -24,7 +24,6 @@ #ifndef _INTEL_DSI_H #define _INTEL_DSI_H -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index a1a8b3790e61..06a11c35a784 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -24,15 +24,15 @@ * */ -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> #include <drm/i915_drm.h> #include <linux/gpio/consumer.h> +#include <linux/mfd/intel_soc_pmic.h> #include <linux/slab.h> #include <video/mipi_display.h> #include <asm/intel-mid.h> -#include <video/mipi_display.h> +#include <asm/unaligned.h> #include "i915_drv.h" #include "intel_drv.h" #include "intel_dsi.h" @@ -393,7 +393,25 @@ static const u8 *mipi_exec_spi(struct intel_dsi *intel_dsi, const u8 *data) static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data) { - DRM_DEBUG_KMS("Skipping PMIC element execution\n"); +#ifdef CONFIG_PMIC_OPREGION + u32 value, mask, reg_address; + u16 i2c_address; + int ret; + + /* byte 0 aka PMIC Flag is reserved */ + i2c_address = get_unaligned_le16(data + 1); + reg_address = get_unaligned_le32(data + 3); + value = get_unaligned_le32(data + 7); + mask = get_unaligned_le32(data + 11); + + ret = intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address, + reg_address, + value, mask); + if (ret) + DRM_ERROR("%s failed, error: %d\n", __func__, ret); +#else + DRM_ERROR("Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n"); +#endif return data + 15; } diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 0042a7f69387..a6c82482a841 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -26,7 +26,6 @@ */ #include <linux/i2c.h> #include <linux/slab.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include "intel_drv.h" @@ -235,9 +234,9 @@ intel_dvo_mode_valid(struct drm_connector *connector, return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); } -static bool intel_dvo_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_dvo *intel_dvo = enc_to_dvo(encoder); const struct drm_display_mode *fixed_mode = @@ -254,10 +253,11 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, intel_fixed_panel_mode(fixed_mode, adjusted_mode); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - return true; + + return 0; } static void intel_dvo_pre_enable(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index ff5b7bc692ce..236cd040f271 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -261,6 +261,31 @@ static void __sprint_engine_name(char *name, const struct engine_info *info) info->instance) >= INTEL_ENGINE_CS_MAX_NAME); } +void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask) +{ + struct drm_i915_private *dev_priv = engine->i915; + i915_reg_t hwstam; + + /* + * Though they added more rings on g4x/ilk, they did not add + * per-engine HWSTAM until gen6. + */ + if (INTEL_GEN(dev_priv) < 6 && engine->class != RENDER_CLASS) + return; + + hwstam = RING_HWSTAM(engine->mmio_base); + if (INTEL_GEN(dev_priv) >= 3) + I915_WRITE(hwstam, mask); + else + I915_WRITE16(hwstam, mask); +} + +static void intel_engine_sanitize_mmio(struct intel_engine_cs *engine) +{ + /* Mask off all writes into the unknown HWSP */ + intel_engine_set_hwsp_writemask(engine, ~0u); +} + static int intel_engine_setup(struct drm_i915_private *dev_priv, enum intel_engine_id id) @@ -312,6 +337,9 @@ intel_engine_setup(struct drm_i915_private *dev_priv, ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier); + /* Scrub mmio state on takeover */ + intel_engine_sanitize_mmio(engine); + dev_priv->engine_class[info->class][info->instance] = engine; dev_priv->engine[id] = engine; return 0; @@ -365,7 +393,7 @@ int intel_engines_init_mmio(struct drm_i915_private *dev_priv) goto cleanup; } - device_info->num_rings = hweight32(mask); + RUNTIME_INFO(dev_priv)->num_rings = hweight32(mask); i915_check_and_clear_faults(dev_priv); @@ -426,27 +454,9 @@ cleanup: return err; } -void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno) +void intel_engine_write_global_seqno(struct intel_engine_cs *engine, u32 seqno) { - struct drm_i915_private *dev_priv = engine->i915; - - /* Our semaphore implementation is strictly monotonic (i.e. we proceed - * so long as the semaphore value in the register/page is greater - * than the sync value), so whenever we reset the seqno, - * so long as we reset the tracking semaphore value to 0, it will - * always be before the next request's seqno. If we don't reset - * the semaphore value, then when the seqno moves backwards all - * future waits will complete instantly (causing rendering corruption). - */ - if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) { - I915_WRITE(RING_SYNC_0(engine->mmio_base), 0); - I915_WRITE(RING_SYNC_1(engine->mmio_base), 0); - if (HAS_VEBOX(dev_priv)) - I915_WRITE(RING_SYNC_2(engine->mmio_base), 0); - } - intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno); - clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); /* After manually advancing the seqno, fake the interrupt in case * there are any waiters for that seqno. @@ -495,6 +505,9 @@ void intel_engine_setup_common(struct intel_engine_cs *engine) static void cleanup_status_page(struct intel_engine_cs *engine) { + /* Prevent writes into HWSP after returning the page to the system */ + intel_engine_set_hwsp_writemask(engine, ~0u); + if (HWS_NEEDS_PHYSICAL(engine->i915)) { void *addr = fetch_and_zero(&engine->status_page.page_addr); @@ -769,12 +782,12 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type) u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv) { - const struct sseu_dev_info *sseu = &(INTEL_INFO(dev_priv)->sseu); + const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; u32 mcr_s_ss_select; u32 slice = fls(sseu->slice_mask); u32 subslice = fls(sseu->subslice_mask[slice]); - if (IS_GEN10(dev_priv)) + if (IS_GEN(dev_priv, 10)) mcr_s_ss_select = GEN8_MCR_SLICE(slice) | GEN8_MCR_SUBSLICE(subslice); else if (INTEL_GEN(dev_priv) >= 11) @@ -1030,22 +1043,34 @@ void intel_engines_reset_default_submission(struct drm_i915_private *i915) engine->set_default_submission(engine); } +static bool reset_engines(struct drm_i915_private *i915) +{ + if (INTEL_INFO(i915)->gpu_reset_clobbers_display) + return false; + + return intel_gpu_reset(i915, ALL_ENGINES) == 0; +} + /** * intel_engines_sanitize: called after the GPU has lost power * @i915: the i915 device + * @force: ignore a failed reset and sanitize engine state anyway * * Anytime we reset the GPU, either with an explicit GPU reset or through a * PCI power cycle, the GPU loses state and we must reset our state tracking * to match. Note that calling intel_engines_sanitize() if the GPU has not * been reset results in much confusion! */ -void intel_engines_sanitize(struct drm_i915_private *i915) +void intel_engines_sanitize(struct drm_i915_private *i915, bool force) { struct intel_engine_cs *engine; enum intel_engine_id id; GEM_TRACE("\n"); + if (!reset_engines(i915) && !force) + return; + for_each_engine(engine, i915, id) { if (engine->reset.reset) engine->reset.reset(engine, NULL); @@ -1248,7 +1273,7 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, &engine->execlists; u64 addr; - if (engine->id == RCS && IS_GEN(dev_priv, 4, 7)) + if (engine->id == RCS && IS_GEN_RANGE(dev_priv, 4, 7)) drm_printf(m, "\tCCID: 0x%08x\n", I915_READ(CCID)); drm_printf(m, "\tRING_START: 0x%08x\n", I915_READ(RING_START(engine->mmio_base))); @@ -1269,16 +1294,6 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, drm_printf(m, "\tRING_IMR: %08x\n", I915_READ_IMR(engine)); } - if (HAS_LEGACY_SEMAPHORES(dev_priv)) { - drm_printf(m, "\tSYNC_0: 0x%08x\n", - I915_READ(RING_SYNC_0(engine->mmio_base))); - drm_printf(m, "\tSYNC_1: 0x%08x\n", - I915_READ(RING_SYNC_1(engine->mmio_base))); - if (HAS_VEBOX(dev_priv)) - drm_printf(m, "\tSYNC_2: 0x%08x\n", - I915_READ(RING_SYNC_2(engine->mmio_base))); - } - addr = intel_engine_get_active_head(engine); drm_printf(m, "\tACTHD: 0x%08x_%08x\n", upper_32_bits(addr), lower_32_bits(addr)); @@ -1532,11 +1547,6 @@ void intel_engine_dump(struct intel_engine_cs *engine, spin_unlock(&b->rb_lock); local_irq_restore(flags); - drm_printf(m, "IRQ? 0x%lx (breadcrumbs? %s)\n", - engine->irq_posted, - yesno(test_bit(ENGINE_IRQ_BREADCRUMB, - &engine->irq_posted))); - drm_printf(m, "HWSP:\n"); hexdump(m, engine->status_page.page_addr, PAGE_SIZE); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index f23570c44323..ccd5e110a19c 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -84,7 +84,7 @@ static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv, int lines; intel_fbc_get_plane_source_size(cache, NULL, &lines); - if (IS_GEN7(dev_priv)) + if (IS_GEN(dev_priv, 7)) lines = min(lines, 2048); else if (INTEL_GEN(dev_priv) >= 8) lines = min(lines, 2560); @@ -127,7 +127,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) cfb_pitch = params->fb.stride; /* FBC_CTL wants 32B or 64B units */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) cfb_pitch = (cfb_pitch / 32) - 1; else cfb_pitch = (cfb_pitch / 64) - 1; @@ -136,7 +136,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG(i), 0); - if (IS_GEN4(dev_priv)) { + if (IS_GEN(dev_priv, 4)) { u32 fbc_ctl2; /* Set it up... */ @@ -233,9 +233,9 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv) if (params->flags & PLANE_HAS_FENCE) { dpfc_ctl |= DPFC_CTL_FENCE_EN; - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) dpfc_ctl |= params->vma->fence->id; - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | params->vma->fence->id); @@ -243,7 +243,7 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv) params->crtc.fence_y_offset); } } else { - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { I915_WRITE(SNB_DPFC_CTL_SA, 0); I915_WRITE(DPFC_CPU_FENCE_OFFSET, 0); } @@ -282,7 +282,7 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) int threshold = dev_priv->fbc.threshold; /* Display WA #0529: skl, kbl, bxt. */ - if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv)) { + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv)) { u32 val = I915_READ(CHICKEN_MISC_4); val &= ~(FBC_STRIDE_OVERRIDE | FBC_STRIDE_MASK); @@ -581,10 +581,10 @@ static bool stride_is_valid(struct drm_i915_private *dev_priv, if (stride < 512) return false; - if (IS_GEN2(dev_priv) || IS_GEN3(dev_priv)) + if (IS_GEN(dev_priv, 2) || IS_GEN(dev_priv, 3)) return stride == 4096 || stride == 8192; - if (IS_GEN4(dev_priv) && !IS_G4X(dev_priv) && stride < 2048) + if (IS_GEN(dev_priv, 4) && !IS_G4X(dev_priv) && stride < 2048) return false; if (stride > 16384) @@ -603,7 +603,7 @@ static bool pixel_format_is_valid(struct drm_i915_private *dev_priv, case DRM_FORMAT_XRGB1555: case DRM_FORMAT_RGB565: /* 16bpp not supported on gen2 */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) return false; /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(dev_priv)) @@ -626,7 +626,10 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) struct intel_fbc *fbc = &dev_priv->fbc; unsigned int effective_w, effective_h, max_w, max_h; - if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) { + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + max_w = 5120; + max_h = 4096; + } else if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) { max_w = 4096; max_h = 4096; } else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) { @@ -784,7 +787,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) * having a Y offset that isn't divisible by 4 causes FIFO underrun * and screen flicker. */ - if (IS_GEN(dev_priv, 9, 10) && + if (IS_GEN_RANGE(dev_priv, 9, 10) && (fbc->state_cache.plane.adjusted_y & 3)) { fbc->no_fbc_reason = "plane Y offset is misaligned"; return false; @@ -839,7 +842,7 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); - if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv)) + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv)) params->gen9_wa_cfb_stride = DIV_ROUND_UP(cache->plane.src_w, 32 * fbc->threshold) * 8; } @@ -1126,8 +1129,6 @@ void intel_fbc_disable(struct intel_crtc *crtc) if (!fbc_supported(dev_priv)) return; - WARN_ON(crtc->active); - mutex_lock(&fbc->lock); if (fbc->crtc == crtc) __intel_fbc_disable(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index fb5bb5b32a60..a0c5046e170c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -37,7 +37,6 @@ #include <linux/init.h> #include <linux/vga_switcheroo.h> -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c index 77c123cc8817..9b39975c8389 100644 --- a/drivers/gpu/drm/i915/intel_fifo_underrun.c +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c @@ -260,9 +260,9 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, if (HAS_GMCH_DISPLAY(dev_priv)) i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); - else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv)) + else if (IS_GEN_RANGE(dev_priv, 5, 6)) ironlake_set_fifo_underrun_reporting(dev, pipe, enable); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); else if (INTEL_GEN(dev_priv) >= 8) broadwell_set_fifo_underrun_reporting(dev, pipe, enable); @@ -423,7 +423,7 @@ void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv) if (HAS_GMCH_DISPLAY(dev_priv)) i9xx_check_fifo_underruns(crtc); - else if (IS_GEN7(dev_priv)) + else if (IS_GEN(dev_priv, 7)) ivybridge_check_fifo_underruns(crtc); } diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index c3379bde266f..16f253deaf8d 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -60,7 +60,6 @@ * functions is deprecated and should be avoided. */ -#include <drm/drmP.h> #include "intel_drv.h" #include "intel_frontbuffer.h" diff --git a/drivers/gpu/drm/i915/intel_guc_fw.c b/drivers/gpu/drm/i915/intel_guc_fw.c index a67144ee5ceb..13ff7003c6be 100644 --- a/drivers/gpu/drm/i915/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/intel_guc_fw.c @@ -77,10 +77,6 @@ static void guc_fw_select(struct intel_uc_fw *guc_fw) guc_fw->path = I915_KBL_GUC_UCODE; guc_fw->major_ver_wanted = KBL_FW_MAJOR; guc_fw->minor_ver_wanted = KBL_FW_MINOR; - } else { - dev_info(dev_priv->drm.dev, - "%s: No firmware known for this platform!\n", - intel_uc_fw_type_repr(guc_fw->type)); } } @@ -115,7 +111,7 @@ static void guc_prepare_xfer(struct intel_guc *guc) else I915_WRITE(GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE); - if (IS_GEN9(dev_priv)) { + if (IS_GEN(dev_priv, 9)) { /* DOP Clock Gating Enable for GuC clocks */ I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE | I915_READ(GEN7_MISCCPCTL))); diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 1570dcbe249c..ab1c49b106f2 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -572,7 +572,8 @@ static void inject_preempt_context(struct work_struct *work) if (engine->id == RCS) { cs = gen8_emit_ggtt_write_rcs(cs, GUC_PREEMPT_FINISHED, - addr); + addr, + PIPE_CONTROL_CS_STALL); } else { cs = gen8_emit_ggtt_write(cs, GUC_PREEMPT_FINISHED, diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index e26d05a46451..51e9efec5116 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -24,144 +24,6 @@ #include "i915_drv.h" -static bool -ipehr_is_semaphore_wait(struct intel_engine_cs *engine, u32 ipehr) -{ - ipehr &= ~MI_SEMAPHORE_SYNC_MASK; - return ipehr == (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | - MI_SEMAPHORE_REGISTER); -} - -static struct intel_engine_cs * -semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr, - u64 offset) -{ - struct drm_i915_private *dev_priv = engine->i915; - u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK; - struct intel_engine_cs *signaller; - enum intel_engine_id id; - - for_each_engine(signaller, dev_priv, id) { - if (engine == signaller) - continue; - - if (sync_bits == signaller->semaphore.mbox.wait[engine->hw_id]) - return signaller; - } - - DRM_DEBUG_DRIVER("No signaller ring found for %s, ipehr 0x%08x\n", - engine->name, ipehr); - - return ERR_PTR(-ENODEV); -} - -static struct intel_engine_cs * -semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno) -{ - struct drm_i915_private *dev_priv = engine->i915; - void __iomem *vaddr; - u32 cmd, ipehr, head; - u64 offset = 0; - int i, backwards; - - /* - * This function does not support execlist mode - any attempt to - * proceed further into this function will result in a kernel panic - * when dereferencing ring->buffer, which is not set up in execlist - * mode. - * - * The correct way of doing it would be to derive the currently - * executing ring buffer from the current context, which is derived - * from the currently running request. Unfortunately, to get the - * current request we would have to grab the struct_mutex before doing - * anything else, which would be ill-advised since some other thread - * might have grabbed it already and managed to hang itself, causing - * the hang checker to deadlock. - * - * Therefore, this function does not support execlist mode in its - * current form. Just return NULL and move on. - */ - if (engine->buffer == NULL) - return NULL; - - ipehr = I915_READ(RING_IPEHR(engine->mmio_base)); - if (!ipehr_is_semaphore_wait(engine, ipehr)) - return NULL; - - /* - * HEAD is likely pointing to the dword after the actual command, - * so scan backwards until we find the MBOX. But limit it to just 3 - * or 4 dwords depending on the semaphore wait command size. - * Note that we don't care about ACTHD here since that might - * point at at batch, and semaphores are always emitted into the - * ringbuffer itself. - */ - head = I915_READ_HEAD(engine) & HEAD_ADDR; - backwards = (INTEL_GEN(dev_priv) >= 8) ? 5 : 4; - vaddr = (void __iomem *)engine->buffer->vaddr; - - for (i = backwards; i; --i) { - /* - * Be paranoid and presume the hw has gone off into the wild - - * our ring is smaller than what the hardware (and hence - * HEAD_ADDR) allows. Also handles wrap-around. - */ - head &= engine->buffer->size - 1; - - /* This here seems to blow up */ - cmd = ioread32(vaddr + head); - if (cmd == ipehr) - break; - - head -= 4; - } - - if (!i) - return NULL; - - *seqno = ioread32(vaddr + head + 4) + 1; - return semaphore_wait_to_signaller_ring(engine, ipehr, offset); -} - -static int semaphore_passed(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - struct intel_engine_cs *signaller; - u32 seqno; - - engine->hangcheck.deadlock++; - - signaller = semaphore_waits_for(engine, &seqno); - if (signaller == NULL) - return -1; - - if (IS_ERR(signaller)) - return 0; - - /* Prevent pathological recursion due to driver bugs */ - if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES) - return -1; - - if (intel_engine_signaled(signaller, seqno)) - return 1; - - /* cursory check for an unkickable deadlock */ - if (I915_READ_CTL(signaller) & RING_WAIT_SEMAPHORE && - semaphore_passed(signaller) < 0) - return -1; - - return 0; -} - -static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) -{ - struct intel_engine_cs *engine; - enum intel_engine_id id; - - for_each_engine(engine, dev_priv, id) - engine->hangcheck.deadlock = 0; -} - static bool instdone_unchanged(u32 current_instdone, u32 *old_instdone) { u32 tmp = current_instdone | *old_instdone; @@ -236,7 +98,7 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) if (ha != ENGINE_DEAD) return ha; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) return ENGINE_DEAD; /* Is the chip hanging on a WAIT_FOR_EVENT? @@ -252,37 +114,12 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) return ENGINE_WAIT_KICK; } - if (IS_GEN(dev_priv, 6, 7) && tmp & RING_WAIT_SEMAPHORE) { - switch (semaphore_passed(engine)) { - default: - return ENGINE_DEAD; - case 1: - i915_handle_error(dev_priv, ALL_ENGINES, 0, - "stuck semaphore on %s", - engine->name); - I915_WRITE_CTL(engine, tmp); - return ENGINE_WAIT_KICK; - case 0: - return ENGINE_WAIT; - } - } - return ENGINE_DEAD; } static void hangcheck_load_sample(struct intel_engine_cs *engine, struct intel_engine_hangcheck *hc) { - /* We don't strictly need an irq-barrier here, as we are not - * serving an interrupt request, be paranoid in case the - * barrier has side-effects (such as preventing a broken - * cacheline snoop) and so be sure that we can see the seqno - * advance. If the seqno should stick, due to a stale - * cacheline, we would erroneously declare the GPU hung. - */ - if (engine->irq_seqno_barrier) - engine->irq_seqno_barrier(engine); - hc->acthd = intel_engine_get_active_head(engine); hc->seqno = intel_engine_get_seqno(engine); } @@ -433,8 +270,6 @@ static void i915_hangcheck_elapsed(struct work_struct *work) for_each_engine(engine, dev_priv, id) { struct intel_engine_hangcheck hc; - semaphore_clear_deadlocks(dev_priv); - hangcheck_load_sample(engine, &hc); hangcheck_accumulate_sample(engine, &hc); hangcheck_store_sample(engine, &hc); diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 1bf487f94254..3fcb3b775948 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -6,7 +6,6 @@ * Sean Paul <seanpaul@chromium.org> */ -#include <drm/drmP.h> #include <drm/drm_hdcp.h> #include <linux/i2c.h> #include <linux/random.h> @@ -15,6 +14,7 @@ #include "i915_reg.h" #define KEY_LOAD_TRIES 5 +#define ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50 static bool intel_hdcp_is_ksv_valid(u8 *ksv) @@ -157,10 +157,11 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv) /* * Initiate loading the HDCP key from fuses. * - * BXT+ platforms, HDCP key needs to be loaded by SW. Only SKL and KBL - * differ in the key load trigger process from other platforms. + * BXT+ platforms, HDCP key needs to be loaded by SW. Only Gen 9 + * platforms except BXT and GLK, differ in the key load trigger process + * from other platforms. So GEN9_BC uses the GT Driver Mailbox i/f. */ - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv)) { mutex_lock(&dev_priv->pcu_lock); ret = sandybridge_pcode_write(dev_priv, SKL_PCODE_LOAD_HDCP_KEYS, 1); @@ -636,7 +637,8 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port, /* Wait for encryption confirmation */ if (intel_wait_for_register(dev_priv, PORT_HDCP_STATUS(port), - HDCP_STATUS_ENC, HDCP_STATUS_ENC, 20)) { + HDCP_STATUS_ENC, HDCP_STATUS_ENC, + ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) { DRM_ERROR("Timed out waiting for encryption\n"); return -ETIMEDOUT; } @@ -666,7 +668,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector) I915_WRITE(PORT_HDCP_CONF(port), 0); if (intel_wait_for_register(dev_priv, PORT_HDCP_STATUS(port), ~0, 0, - 20)) { + ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) { DRM_ERROR("Failed to disable HDCP, timeout clearing status\n"); return -ETIMEDOUT; } @@ -768,8 +770,7 @@ static void intel_hdcp_prop_work(struct work_struct *work) bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) { /* PORT E doesn't have HDCP, and PORT F is disabled */ - return ((INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) && - !IS_CHERRYVIEW(dev_priv) && port < PORT_E); + return INTEL_GEN(dev_priv) >= 9 && port < PORT_E; } int intel_hdcp_init(struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 07e803a604bd..ca195e6203c5 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -30,7 +30,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/hdmi.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -479,18 +478,14 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; - struct drm_connector *connector = &intel_hdmi->attached_connector->base; - bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported || - connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; union hdmi_infoframe frame; int ret; ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - adjusted_mode, - is_hdmi2_sink); + conn_state->connector, + adjusted_mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; @@ -503,12 +498,12 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode, + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + conn_state->connector, + adjusted_mode, crtc_state->limited_color_range ? HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL, - intel_hdmi->rgb_quant_range_selectable, - is_hdmi2_sink); + HDMI_QUANTIZATION_RANGE_FULL); drm_hdmi_avi_infoframe_content_type(&frame.avi, conn_state); @@ -1707,9 +1702,9 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector, return true; } -bool intel_hdmi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +int intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -1725,7 +1720,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink; @@ -1756,7 +1751,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, &clock_12bpc, &clock_10bpc, &clock_8bpc)) { DRM_ERROR("Can't support YCBCR420 output\n"); - return false; + return -EINVAL; } } @@ -1806,7 +1801,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, false, force_dvi) != MODE_OK) { DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); - return false; + return -EINVAL; } /* Set user selected PAR to incoming mode's member */ @@ -1825,7 +1820,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } } - return true; + return 0; } static void @@ -1835,7 +1830,6 @@ intel_hdmi_unset_edid(struct drm_connector *connector) intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; - intel_hdmi->rgb_quant_range_selectable = false; intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; intel_hdmi->dp_dual_mode.max_tmds_clock = 0; @@ -1919,9 +1913,6 @@ intel_hdmi_set_edid(struct drm_connector *connector) to_intel_connector(connector)->detect_edid = edid; if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { - intel_hdmi->rgb_quant_range_selectable = - drm_rgb_quant_range_selectable(edid); - intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index e24174d08fed..ae92d6560165 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/intel_huc_fw.c b/drivers/gpu/drm/i915/intel_huc_fw.c index f93d2384d482..7d7bfc7f7ca7 100644 --- a/drivers/gpu/drm/i915/intel_huc_fw.c +++ b/drivers/gpu/drm/i915/intel_huc_fw.c @@ -23,8 +23,8 @@ */ #define BXT_HUC_FW_MAJOR 01 -#define BXT_HUC_FW_MINOR 07 -#define BXT_BLD_NUM 1398 +#define BXT_HUC_FW_MINOR 8 +#define BXT_BLD_NUM 2893 #define SKL_HUC_FW_MAJOR 01 #define SKL_HUC_FW_MINOR 07 @@ -76,9 +76,6 @@ static void huc_fw_select(struct intel_uc_fw *huc_fw) huc_fw->path = I915_KBL_HUC_UCODE; huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR; huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR; - } else { - DRM_WARN("%s: No firmware known for this platform!\n", - intel_uc_fw_type_repr(huc_fw->type)); } } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 802d0394ccc4..c6159aff9dc8 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -29,7 +29,6 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/export.h> -#include <drm/drmP.h> #include <drm/drm_hdcp.h> #include "intel_drv.h" #include <drm/i915_drm.h> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d84c7815ee0c..1effbf49fa08 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -133,7 +133,6 @@ */ #include <linux/interrupt.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_gem_render_state.h" @@ -363,31 +362,12 @@ execlists_context_schedule_out(struct i915_request *rq, unsigned long status) trace_i915_request_out(rq); } -static void -execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) -{ - ASSIGN_CTX_PDP(ppgtt, reg_state, 3); - ASSIGN_CTX_PDP(ppgtt, reg_state, 2); - ASSIGN_CTX_PDP(ppgtt, reg_state, 1); - ASSIGN_CTX_PDP(ppgtt, reg_state, 0); -} - static u64 execlists_update_context(struct i915_request *rq) { - struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt; struct intel_context *ce = rq->hw_context; - u32 *reg_state = ce->lrc_reg_state; - reg_state[CTX_RING_TAIL+1] = intel_ring_set_tail(rq->ring, rq->tail); - - /* - * True 32b PPGTT with dynamic page allocation: update PDP - * registers and point the unallocated PDPs to scratch page. - * PML4 is allocated during ppgtt init, so this is not needed - * in 48-bit mode. - */ - if (!i915_vm_is_48bit(&ppgtt->vm)) - execlists_update_context_pdps(ppgtt, reg_state); + ce->lrc_reg_state[CTX_RING_TAIL + 1] = + intel_ring_set_tail(rq->ring, rq->tail); /* * Make sure the context image is complete before we submit it to HW. @@ -770,6 +750,13 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) execlists_clear_all_active(execlists); } +static inline void +invalidate_csb_entries(const u32 *first, const u32 *last) +{ + clflush((void *)first); + clflush((void *)last); +} + static void reset_csb_pointers(struct intel_engine_execlists *execlists) { const unsigned int reset_value = GEN8_CSB_ENTRIES - 1; @@ -785,6 +772,9 @@ static void reset_csb_pointers(struct intel_engine_execlists *execlists) */ execlists->csb_head = reset_value; WRITE_ONCE(*execlists->csb_write, reset_value); + + invalidate_csb_entries(&execlists->csb_status[0], + &execlists->csb_status[GEN8_CSB_ENTRIES - 1]); } static void nop_submission_tasklet(unsigned long data) @@ -1020,6 +1010,19 @@ static void process_csb(struct intel_engine_cs *engine) } while (head != tail); execlists->csb_head = head; + + /* + * Gen11 has proven to fail wrt global observation point between + * entry and tail update, failing on the ordering and thus + * we see an old entry in the context status buffer. + * + * Forcibly evict out entries for the next gpu csb update, + * to increase the odds that we get a fresh entries with non + * working hardware. The cost for doing so comes out mostly with + * the wash as hardware, working or not, will need to do the + * invalidation before. + */ + invalidate_csb_entries(&buf[0], &buf[GEN8_CSB_ENTRIES - 1]); } static void __execlists_submission_tasklet(struct intel_engine_cs *const engine) @@ -1247,29 +1250,88 @@ execlists_context_pin(struct intel_engine_cs *engine, return __execlists_context_pin(engine, ctx, ce); } +static int emit_pdps(struct i915_request *rq) +{ + const struct intel_engine_cs * const engine = rq->engine; + struct i915_hw_ppgtt * const ppgtt = rq->gem_context->ppgtt; + int err, i; + u32 *cs; + + GEM_BUG_ON(intel_vgpu_active(rq->i915)); + + /* + * Beware ye of the dragons, this sequence is magic! + * + * Small changes to this sequence can cause anything from + * GPU hangs to forcewake errors and machine lockups! + */ + + /* Flush any residual operations from the context load */ + err = engine->emit_flush(rq, EMIT_FLUSH); + if (err) + return err; + + /* Magic required to prevent forcewake errors! */ + err = engine->emit_flush(rq, EMIT_INVALIDATE); + if (err) + return err; + + cs = intel_ring_begin(rq, 4 * GEN8_3LVL_PDPES + 2); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + /* Ensure the LRI have landed before we invalidate & continue */ + *cs++ = MI_LOAD_REGISTER_IMM(2 * GEN8_3LVL_PDPES) | MI_LRI_FORCE_POSTED; + for (i = GEN8_3LVL_PDPES; i--; ) { + const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); + + *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(engine, i)); + *cs++ = upper_32_bits(pd_daddr); + *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(engine, i)); + *cs++ = lower_32_bits(pd_daddr); + } + *cs++ = MI_NOOP; + + intel_ring_advance(rq, cs); + + /* Be doubly sure the LRI have landed before proceeding */ + err = engine->emit_flush(rq, EMIT_FLUSH); + if (err) + return err; + + /* Re-invalidate the TLB for luck */ + return engine->emit_flush(rq, EMIT_INVALIDATE); +} + static int execlists_request_alloc(struct i915_request *request) { int ret; GEM_BUG_ON(!request->hw_context->pin_count); - /* Flush enough space to reduce the likelihood of waiting after + /* + * Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just * have to repeat work. */ request->reserved_space += EXECLISTS_REQUEST_SIZE; - ret = intel_ring_wait_for_space(request->ring, request->reserved_space); - if (ret) - return ret; - - /* Note that after this point, we have committed to using + /* + * Note that after this point, we have committed to using * this request as it is being used to both track the * state of engine initialisation and liveness of the * golden renderstate above. Think twice before you try * to cancel/unwind this request now. */ + /* Unconditionally invalidate GPU caches and TLBs. */ + if (i915_vm_is_48bit(&request->gem_context->ppgtt->vm)) + ret = request->engine->emit_flush(request, EMIT_INVALIDATE); + else + ret = emit_pdps(request); + if (ret) + return ret; + request->reserved_space -= EXECLISTS_REQUEST_SIZE; return 0; } @@ -1592,7 +1654,7 @@ static void enable_execlists(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; - I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff); + intel_engine_set_hwsp_writemask(engine, ~0u); /* HWSTAM */ /* * Make sure we're not enabling the new 12-deep CSB @@ -1633,6 +1695,7 @@ static bool unexpected_starting_state(struct intel_engine_cs *engine) static int gen8_init_common_ring(struct intel_engine_cs *engine) { intel_engine_apply_workarounds(engine); + intel_engine_apply_whitelist(engine); intel_mocs_init_engine(engine); @@ -1649,43 +1712,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) return 0; } -static int gen8_init_render_ring(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen8_init_common_ring(engine); - if (ret) - return ret; - - intel_engine_apply_whitelist(engine); - - /* We need to disable the AsyncFlip performance optimisations in order - * to use MI_WAIT_FOR_EVENT within the CS. It should already be - * programmed to '1' on all products. - * - * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv - */ - I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); - - I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); - - return 0; -} - -static int gen9_init_render_ring(struct intel_engine_cs *engine) -{ - int ret; - - ret = gen8_init_common_ring(engine); - if (ret) - return ret; - - intel_engine_apply_whitelist(engine); - - return 0; -} - static struct i915_request * execlists_reset_prepare(struct intel_engine_cs *engine) { @@ -1841,56 +1867,11 @@ static void execlists_reset_finish(struct intel_engine_cs *engine) atomic_read(&execlists->tasklet.count)); } -static int intel_logical_ring_emit_pdps(struct i915_request *rq) -{ - struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt; - struct intel_engine_cs *engine = rq->engine; - const int num_lri_cmds = GEN8_3LVL_PDPES * 2; - u32 *cs; - int i; - - cs = intel_ring_begin(rq, num_lri_cmds * 2 + 2); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(num_lri_cmds); - for (i = GEN8_3LVL_PDPES - 1; i >= 0; i--) { - const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); - - *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(engine, i)); - *cs++ = upper_32_bits(pd_daddr); - *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(engine, i)); - *cs++ = lower_32_bits(pd_daddr); - } - - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); - - return 0; -} - static int gen8_emit_bb_start(struct i915_request *rq, u64 offset, u32 len, const unsigned int flags) { u32 *cs; - int ret; - - /* Don't rely in hw updating PDPs, specially in lite-restore. - * Ideally, we should set Force PD Restore in ctx descriptor, - * but we can't. Force Restore would be a second option, but - * it is unsafe in case of lite-restore (because the ctx is - * not idle). PML4 is allocated during ppgtt init so this is - * not needed in 48-bit.*/ - if ((intel_engine_flag(rq->engine) & rq->gem_context->ppgtt->pd_dirty_rings) && - !i915_vm_is_48bit(&rq->gem_context->ppgtt->vm) && - !intel_vgpu_active(rq->i915)) { - ret = intel_logical_ring_emit_pdps(rq); - if (ret) - return ret; - - rq->gem_context->ppgtt->pd_dirty_rings &= ~intel_engine_flag(rq->engine); - } cs = intel_ring_begin(rq, 6); if (IS_ERR(cs)) @@ -1923,6 +1904,7 @@ static int gen8_emit_bb_start(struct i915_request *rq, *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; *cs++ = MI_NOOP; + intel_ring_advance(rq, cs); return 0; @@ -2007,7 +1989,7 @@ static int gen8_emit_flush_render(struct i915_request *request, * On GEN9: before VF_CACHE_INVALIDATE we need to emit a NULL * pipe control. */ - if (IS_GEN9(request->i915)) + if (IS_GEN(request->i915, 9)) vf_flush_wa = true; /* WaForGAMHang:kbl */ @@ -2078,10 +2060,18 @@ static void gen8_emit_breadcrumb_rcs(struct i915_request *request, u32 *cs) /* We're using qword write, seqno should be aligned to 8 bytes. */ BUILD_BUG_ON(I915_GEM_HWS_INDEX & 1); - cs = gen8_emit_ggtt_write_rcs(cs, request->global_seqno, - intel_hws_seqno_address(request->engine)); + cs = gen8_emit_ggtt_write_rcs(cs, + request->global_seqno, + intel_hws_seqno_address(request->engine), + PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | + PIPE_CONTROL_DEPTH_CACHE_FLUSH | + PIPE_CONTROL_DC_FLUSH_ENABLE | + PIPE_CONTROL_FLUSH_ENABLE | + PIPE_CONTROL_CS_STALL); + *cs++ = MI_USER_INTERRUPT; *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; + request->tail = intel_ring_offset(request, cs); assert_ring_tail_valid(request->ring, request->tail); @@ -2244,6 +2234,8 @@ static int logical_ring_init(struct intel_engine_cs *engine) if (ret) return ret; + intel_engine_init_workarounds(engine); + if (HAS_LOGICAL_RING_ELSQ(i915)) { execlists->submit_reg = i915->regs + i915_mmio_reg_offset(RING_EXECLIST_SQ_CONTENTS(engine)); @@ -2276,19 +2268,11 @@ static int logical_ring_init(struct intel_engine_cs *engine) int logical_render_ring_init(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; int ret; logical_ring_setup(engine); - if (HAS_L3_DPF(dev_priv)) - engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; - /* Override some for render ring. */ - if (INTEL_GEN(dev_priv) >= 9) - engine->init_hw = gen9_init_render_ring; - else - engine->init_hw = gen8_init_render_ring; engine->init_context = gen8_init_rcs_context; engine->emit_flush = gen8_emit_flush_render; engine->emit_breadcrumb = gen8_emit_breadcrumb_rcs; @@ -2310,7 +2294,6 @@ int logical_render_ring_init(struct intel_engine_cs *engine) } intel_engine_init_whitelist(engine); - intel_engine_init_workarounds(engine); return 0; } @@ -2325,9 +2308,9 @@ int logical_xcs_ring_init(struct intel_engine_cs *engine) static u32 make_rpcs(struct drm_i915_private *dev_priv) { - bool subslice_pg = INTEL_INFO(dev_priv)->sseu.has_subslice_pg; - u8 slices = hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask); - u8 subslices = hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]); + bool subslice_pg = RUNTIME_INFO(dev_priv)->sseu.has_subslice_pg; + u8 slices = hweight8(RUNTIME_INFO(dev_priv)->sseu.slice_mask); + u8 subslices = hweight8(RUNTIME_INFO(dev_priv)->sseu.subslice_mask[0]); u32 rpcs = 0; /* @@ -2362,7 +2345,7 @@ make_rpcs(struct drm_i915_private *dev_priv) * subslices are enabled, or a count between one and four on the first * slice. */ - if (IS_GEN11(dev_priv) && slices == 1 && subslices >= 4) { + if (IS_GEN(dev_priv, 11) && slices == 1 && subslices >= 4) { GEM_BUG_ON(subslices & 1); subslice_pg = false; @@ -2375,7 +2358,7 @@ make_rpcs(struct drm_i915_private *dev_priv) * must make an explicit request through RPCS for full * enablement. */ - if (INTEL_INFO(dev_priv)->sseu.has_slice_pg) { + if (RUNTIME_INFO(dev_priv)->sseu.has_slice_pg) { u32 mask, val = slices; if (INTEL_GEN(dev_priv) >= 11) { @@ -2403,17 +2386,17 @@ make_rpcs(struct drm_i915_private *dev_priv) rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val; } - if (INTEL_INFO(dev_priv)->sseu.has_eu_pg) { + if (RUNTIME_INFO(dev_priv)->sseu.has_eu_pg) { u32 val; - val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice << + val = RUNTIME_INFO(dev_priv)->sseu.eu_per_subslice << GEN8_RPCS_EU_MIN_SHIFT; GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK); val &= GEN8_RPCS_EU_MIN_MASK; rpcs |= val; - val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice << + val = RUNTIME_INFO(dev_priv)->sseu.eu_per_subslice << GEN8_RPCS_EU_MAX_SHIFT; GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK); val &= GEN8_RPCS_EU_MAX_MASK; @@ -2538,6 +2521,11 @@ static void execlists_init_reg_state(u32 *regs, * other PDP Descriptors are ignored. */ ASSIGN_CTX_PML4(ctx->ppgtt, regs); + } else { + ASSIGN_CTX_PDP(ctx->ppgtt, regs, 3); + ASSIGN_CTX_PDP(ctx->ppgtt, regs, 2); + ASSIGN_CTX_PDP(ctx->ppgtt, regs, 1); + ASSIGN_CTX_PDP(ctx->ppgtt, regs, 0); } if (rcs) { diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index 96a8d9524b0c..7d15be5932e0 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c @@ -462,10 +462,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, uint8_t buf[VIDEO_DIP_DATA_SIZE]; struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_lspcon *lspcon = &dig_port->lspcon; - struct intel_dp *intel_dp = &dig_port->dp; - struct drm_connector *connector = &intel_dp->attached_connector->base; - const struct drm_display_mode *mode = &crtc_state->base.adjusted_mode; - bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; + const struct drm_display_mode *adjusted_mode = + &crtc_state->base.adjusted_mode; if (!lspcon->active) { DRM_ERROR("Writing infoframes while LSPCON disabled ?\n"); @@ -473,7 +471,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, } ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - mode, is_hdmi2_sink); + conn_state->connector, + adjusted_mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; @@ -488,11 +487,12 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, frame.avi.colorspace = HDMI_COLORSPACE_RGB; } - drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode, + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + conn_state->connector, + adjusted_mode, crtc_state->limited_color_range ? HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL, - false, is_hdmi2_sink); + HDMI_QUANTIZATION_RANGE_FULL); ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf)); if (ret < 0) { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e6c5d985ea0a..904d16af89a8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -32,7 +32,6 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/vga_switcheroo.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -279,7 +278,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder, * special lvds dither control bit on pch-split platforms, dithering is * only controlled through the PIPECONF reg. */ - if (IS_GEN4(dev_priv)) { + if (IS_GEN(dev_priv, 4)) { /* * Bspec wording suggests that LVDS port dithering only exists * for 18bpp panels. @@ -379,9 +378,9 @@ intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); struct intel_lvds_encoder *lvds_encoder = @@ -395,7 +394,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, /* Should never happen!! */ if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) { DRM_ERROR("Can't support LVDS on pipe A\n"); - return false; + return -EINVAL; } if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) @@ -421,7 +420,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, adjusted_mode); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; if (HAS_PCH_SPLIT(dev_priv)) { pipe_config->has_pch_encoder = true; @@ -440,7 +439,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, * user's requested refresh rate. */ - return true; + return 0; } static enum drm_connector_status @@ -919,7 +918,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) intel_encoder->cloneable = 0; if (HAS_PCH_SPLIT(dev_priv)) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - else if (IS_GEN4(dev_priv)) + else if (IS_GEN(dev_priv, 4)) intel_encoder->crtc_mask = (1 << 0) | (1 << 1); else intel_encoder->crtc_mask = (1 << 1); diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c index 77e9871a8c9a..e976c5ce5479 100644 --- a/drivers/gpu/drm/i915/intel_mocs.c +++ b/drivers/gpu/drm/i915/intel_mocs.c @@ -193,7 +193,7 @@ static bool get_mocs_settings(struct drm_i915_private *dev_priv, } /* WaDisableSkipCaching:skl,bxt,kbl,glk */ - if (IS_GEN9(dev_priv)) { + if (IS_GEN(dev_priv, 9)) { int i; for (i = 0; i < table->size; i++) diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h index d89080d75b80..3d99d1271b2b 100644 --- a/drivers/gpu/drm/i915/intel_mocs.h +++ b/drivers/gpu/drm/i915/intel_mocs.h @@ -49,7 +49,6 @@ * context handling keep the MOCS in step. */ -#include <drm/drmP.h> #include "i915_drv.h" int intel_rcs_context_init_mocs(struct i915_request *rq); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index b8f106d9ecf8..30ae96c5c97c 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -30,7 +30,6 @@ #include <linux/firmware.h> #include <acpi/video.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "intel_opregion.h" diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 20ea7c99d13a..c81db81e4416 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -25,7 +25,6 @@ * * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_reg.h" @@ -541,7 +540,7 @@ static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 widt { u32 sw; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) sw = ALIGN((offset & 31) + width, 32); else sw = ALIGN((offset & 63) + width, 64); @@ -778,7 +777,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, u32 oconfig; oconfig = OCONF_CC_OUT_8BIT; - if (IS_GEN4(dev_priv)) + if (IS_GEN(dev_priv, 4)) oconfig |= OCONF_CSC_MODE_BT709; oconfig |= pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; @@ -1012,7 +1011,7 @@ static int check_overlay_src(struct drm_i915_private *dev_priv, if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) return -EINVAL; - if (IS_GEN4(dev_priv) && rec->stride_Y < 512) + if (IS_GEN(dev_priv, 4) && rec->stride_Y < 512) return -EINVAL; tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? @@ -1246,7 +1245,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, attrs->contrast = overlay->contrast; attrs->saturation = overlay->saturation; - if (!IS_GEN2(dev_priv)) { + if (!IS_GEN(dev_priv, 2)) { attrs->gamma0 = I915_READ(OGAMC0); attrs->gamma1 = I915_READ(OGAMC1); attrs->gamma2 = I915_READ(OGAMC2); @@ -1270,7 +1269,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, update_reg_attrs(overlay, overlay->regs); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) goto out_unlock; if (overlay->active) { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e6cd7b55c018..ee3e0842d542 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -563,7 +563,7 @@ static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc); } - if (IS_GEN4(dev_priv)) { + if (IS_GEN(dev_priv, 4)) { mask = BACKLIGHT_DUTY_CYCLE_MASK; } else { level <<= 1; @@ -929,7 +929,7 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 * that has backlight. */ - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); } @@ -1557,7 +1557,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu ctl = I915_READ(BLC_PWM_CTL); - if (IS_GEN2(dev_priv) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) + if (IS_GEN(dev_priv, 2) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; if (IS_PINEVIEW(dev_priv)) @@ -1886,7 +1886,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) panel->backlight.get = vlv_get_backlight; panel->backlight.hz_to_pwm = vlv_hz_to_pwm; } - } else if (IS_GEN4(dev_priv)) { + } else if (IS_GEN(dev_priv, 4)) { panel->backlight.setup = i965_setup_backlight; panel->backlight.enable = i965_enable_backlight; panel->backlight.disable = i965_disable_backlight; diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index f3c9010e332a..bdabcfab8090 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -427,13 +427,13 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, enum intel_pipe_crc_source *source, u32 *val, bool set_wa) { - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) return i8xx_pipe_crc_ctl_reg(source, val); else if (INTEL_GEN(dev_priv) < 5) return i9xx_pipe_crc_ctl_reg(dev_priv, pipe, source, val); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) return vlv_pipe_crc_ctl_reg(dev_priv, pipe, source, val); - else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv)) + else if (IS_GEN_RANGE(dev_priv, 5, 6)) return ilk_pipe_crc_ctl_reg(source, val); else return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa); @@ -544,13 +544,13 @@ static int intel_is_valid_crc_source(struct drm_i915_private *dev_priv, const enum intel_pipe_crc_source source) { - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) return i8xx_crc_source_valid(dev_priv, source); else if (INTEL_GEN(dev_priv) < 5) return i9xx_crc_source_valid(dev_priv, source); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) return vlv_crc_source_valid(dev_priv, source); - else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv)) + else if (IS_GEN_RANGE(dev_priv, 5, 6)) return ilk_crc_source_valid(dev_priv, source); else return ivb_crc_source_valid(dev_priv, source); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a26b4eddda25..83b01cde8113 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1399,10 +1399,9 @@ static int g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state) return 0; } -static int g4x_compute_intermediate_wm(struct drm_device *dev, - struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) +static int g4x_compute_intermediate_wm(struct intel_crtc_state *new_crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); struct g4x_wm_state *intermediate = &new_crtc_state->wm.g4x.intermediate; const struct g4x_wm_state *optimal = &new_crtc_state->wm.g4x.optimal; struct intel_atomic_state *intel_state = @@ -2032,10 +2031,9 @@ static void vlv_atomic_update_fifo(struct intel_atomic_state *state, #undef VLV_FIFO -static int vlv_compute_intermediate_wm(struct drm_device *dev, - struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) +static int vlv_compute_intermediate_wm(struct intel_crtc_state *new_crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); struct vlv_wm_state *intermediate = &new_crtc_state->wm.vlv.intermediate; const struct vlv_wm_state *optimal = &new_crtc_state->wm.vlv.optimal; struct intel_atomic_state *intel_state = @@ -2273,7 +2271,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) if (IS_I945GM(dev_priv)) wm_info = &i945_wm_info; - else if (!IS_GEN2(dev_priv)) + else if (!IS_GEN(dev_priv, 2)) wm_info = &i915_wm_info; else wm_info = &i830_a_wm_info; @@ -2287,7 +2285,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) crtc->base.primary->state->fb; int cpp; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) cpp = 4; else cpp = fb->format->cpp[0]; @@ -2302,7 +2300,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) planea_wm = wm_info->max_wm; } - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) wm_info = &i830_bc_wm_info; fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B); @@ -2314,7 +2312,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) crtc->base.primary->state->fb; int cpp; - if (IS_GEN2(dev_priv)) + if (IS_GEN(dev_priv, 2)) cpp = 4; else cpp = fb->format->cpp[0]; @@ -2626,13 +2624,12 @@ static unsigned int ilk_fbc_wm_reg_max(const struct drm_i915_private *dev_priv) } /* Calculate the maximum primary/sprite plane watermark */ -static unsigned int ilk_plane_wm_max(const struct drm_device *dev, +static unsigned int ilk_plane_wm_max(const struct drm_i915_private *dev_priv, int level, const struct intel_wm_config *config, enum intel_ddb_partitioning ddb_partitioning, bool is_sprite) { - struct drm_i915_private *dev_priv = to_i915(dev); unsigned int fifo_size = ilk_display_fifo_size(dev_priv); /* if sprites aren't enabled, sprites get nothing */ @@ -2668,7 +2665,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev, } /* Calculate the maximum cursor plane watermark */ -static unsigned int ilk_cursor_wm_max(const struct drm_device *dev, +static unsigned int ilk_cursor_wm_max(const struct drm_i915_private *dev_priv, int level, const struct intel_wm_config *config) { @@ -2677,19 +2674,19 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev, return 64; /* otherwise just report max that registers can hold */ - return ilk_cursor_wm_reg_max(to_i915(dev), level); + return ilk_cursor_wm_reg_max(dev_priv, level); } -static void ilk_compute_wm_maximums(const struct drm_device *dev, +static void ilk_compute_wm_maximums(const struct drm_i915_private *dev_priv, int level, const struct intel_wm_config *config, enum intel_ddb_partitioning ddb_partitioning, struct ilk_wm_maximums *max) { - max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false); - max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true); - max->cur = ilk_cursor_wm_max(dev, level, config); - max->fbc = ilk_fbc_wm_reg_max(to_i915(dev)); + max->pri = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, false); + max->spr = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, true); + max->cur = ilk_cursor_wm_max(dev_priv, level, config); + max->fbc = ilk_fbc_wm_reg_max(dev_priv); } static void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv, @@ -2926,7 +2923,7 @@ static void intel_fixup_spr_wm_latency(struct drm_i915_private *dev_priv, uint16_t wm[5]) { /* ILK sprite LP0 latency is 1300 ns */ - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) wm[0] = 13; } @@ -2934,7 +2931,7 @@ static void intel_fixup_cur_wm_latency(struct drm_i915_private *dev_priv, uint16_t wm[5]) { /* ILK cursor LP0 latency is 1300 ns */ - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) wm[0] = 13; } @@ -3061,7 +3058,7 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { snb_wm_latency_quirk(dev_priv); snb_wm_lp3_irq_quirk(dev_priv); } @@ -3073,7 +3070,7 @@ static void skl_setup_wm_latency(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Gen9 Plane", dev_priv->wm.skl_latency); } -static bool ilk_validate_pipe_wm(struct drm_device *dev, +static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv, struct intel_pipe_wm *pipe_wm) { /* LP0 watermark maximums depend on this pipe alone */ @@ -3085,7 +3082,7 @@ static bool ilk_validate_pipe_wm(struct drm_device *dev, struct ilk_wm_maximums max; /* LP0 watermarks always use 1/2 DDB partitioning */ - ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + ilk_compute_wm_maximums(dev_priv, 0, &config, INTEL_DDB_PART_1_2, &max); /* At least LP0 must be valid */ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) { @@ -3150,7 +3147,7 @@ static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate) if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) pipe_wm->linetime = hsw_compute_linetime_wm(cstate); - if (!ilk_validate_pipe_wm(dev, pipe_wm)) + if (!ilk_validate_pipe_wm(dev_priv, pipe_wm)) return -EINVAL; ilk_compute_wm_reg_maximums(dev_priv, 1, &max); @@ -3180,17 +3177,17 @@ static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate) * state and the new state. These can be programmed to the hardware * immediately. */ -static int ilk_compute_intermediate_wm(struct drm_device *dev, - struct intel_crtc *intel_crtc, - struct intel_crtc_state *newstate) +static int ilk_compute_intermediate_wm(struct intel_crtc_state *newstate) { + struct intel_crtc *intel_crtc = to_intel_crtc(newstate->base.crtc); + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); struct intel_pipe_wm *a = &newstate->wm.ilk.intermediate; struct intel_atomic_state *intel_state = to_intel_atomic_state(newstate->base.state); const struct intel_crtc_state *oldstate = intel_atomic_get_old_crtc_state(intel_state, intel_crtc); const struct intel_pipe_wm *b = &oldstate->wm.ilk.optimal; - int level, max_level = ilk_wm_max_level(to_i915(dev)); + int level, max_level = ilk_wm_max_level(dev_priv); /* * Start with the final, target watermarks, then combine with the @@ -3223,7 +3220,7 @@ static int ilk_compute_intermediate_wm(struct drm_device *dev, * there's no safe way to transition from the old state to * the new state, so we need to fail the atomic transaction. */ - if (!ilk_validate_pipe_wm(dev, a)) + if (!ilk_validate_pipe_wm(dev_priv, a)) return -EINVAL; /* @@ -3239,7 +3236,7 @@ static int ilk_compute_intermediate_wm(struct drm_device *dev, /* * Merge the watermarks from all active pipes for a specific level. */ -static void ilk_merge_wm_level(struct drm_device *dev, +static void ilk_merge_wm_level(struct drm_i915_private *dev_priv, int level, struct intel_wm_level *ret_wm) { @@ -3247,7 +3244,7 @@ static void ilk_merge_wm_level(struct drm_device *dev, ret_wm->enable = true; - for_each_intel_crtc(dev, intel_crtc) { + for_each_intel_crtc(&dev_priv->drm, intel_crtc) { const struct intel_pipe_wm *active = &intel_crtc->wm.active.ilk; const struct intel_wm_level *wm = &active->wm[level]; @@ -3272,12 +3269,11 @@ static void ilk_merge_wm_level(struct drm_device *dev, /* * Merge all low power watermarks for all active pipes. */ -static void ilk_wm_merge(struct drm_device *dev, +static void ilk_wm_merge(struct drm_i915_private *dev_priv, const struct intel_wm_config *config, const struct ilk_wm_maximums *max, struct intel_pipe_wm *merged) { - struct drm_i915_private *dev_priv = to_i915(dev); int level, max_level = ilk_wm_max_level(dev_priv); int last_enabled_level = max_level; @@ -3293,7 +3289,7 @@ static void ilk_wm_merge(struct drm_device *dev, for (level = 1; level <= max_level; level++) { struct intel_wm_level *wm = &merged->wm[level]; - ilk_merge_wm_level(dev, level, wm); + ilk_merge_wm_level(dev_priv, level, wm); if (level > last_enabled_level) wm->enable = false; @@ -3318,7 +3314,7 @@ static void ilk_wm_merge(struct drm_device *dev, * What we should check here is whether FBC can be * enabled sometime later. */ - if (IS_GEN5(dev_priv) && !merged->fbc_wm_enabled && + if (IS_GEN(dev_priv, 5) && !merged->fbc_wm_enabled && intel_fbc_is_active(dev_priv)) { for (level = 2; level <= max_level; level++) { struct intel_wm_level *wm = &merged->wm[level]; @@ -3335,22 +3331,20 @@ static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) } /* The value we need to program into the WM_LPx latency field */ -static unsigned int ilk_wm_lp_latency(struct drm_device *dev, int level) +static unsigned int ilk_wm_lp_latency(struct drm_i915_private *dev_priv, + int level) { - struct drm_i915_private *dev_priv = to_i915(dev); - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) return 2 * level; else return dev_priv->wm.pri_latency[level]; } -static void ilk_compute_wm_results(struct drm_device *dev, +static void ilk_compute_wm_results(struct drm_i915_private *dev_priv, const struct intel_pipe_wm *merged, enum intel_ddb_partitioning partitioning, struct ilk_wm_values *results) { - struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc; int level, wm_lp; @@ -3370,7 +3364,7 @@ static void ilk_compute_wm_results(struct drm_device *dev, * disabled. Doing otherwise could cause underruns. */ results->wm_lp[wm_lp - 1] = - (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) | + (ilk_wm_lp_latency(dev_priv, level) << WM1_LP_LATENCY_SHIFT) | (r->pri_val << WM1_LP_SR_SHIFT) | r->cur_val; @@ -3396,7 +3390,7 @@ static void ilk_compute_wm_results(struct drm_device *dev, } /* LP0 register values */ - for_each_intel_crtc(dev, intel_crtc) { + for_each_intel_crtc(&dev_priv->drm, intel_crtc) { enum pipe pipe = intel_crtc->pipe; const struct intel_wm_level *r = &intel_crtc->wm.active.ilk.wm[0]; @@ -3415,11 +3409,12 @@ static void ilk_compute_wm_results(struct drm_device *dev, /* Find the result with the highest level enabled. Check for enable_fbc_wm in * case both are at the same level. Prefer r1 in case they're the same. */ -static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev, - struct intel_pipe_wm *r1, - struct intel_pipe_wm *r2) +static struct intel_pipe_wm * +ilk_find_best_result(struct drm_i915_private *dev_priv, + struct intel_pipe_wm *r1, + struct intel_pipe_wm *r2) { - int level, max_level = ilk_wm_max_level(to_i915(dev)); + int level, max_level = ilk_wm_max_level(dev_priv); int level1 = 0, level2 = 0; for (level = 1; level <= max_level; level++) { @@ -3756,9 +3751,9 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state) if (!intel_has_sagv(dev_priv)) return false; - if (IS_GEN9(dev_priv)) + if (IS_GEN(dev_priv, 9)) sagv_block_time_us = 30; - else if (IS_GEN10(dev_priv)) + else if (IS_GEN(dev_priv, 10)) sagv_block_time_us = 20; else sagv_block_time_us = 10; @@ -4306,102 +4301,6 @@ icl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate, return total_data_rate; } -static uint16_t -skl_ddb_min_alloc(const struct drm_plane_state *pstate, const int plane) -{ - struct drm_framebuffer *fb = pstate->fb; - struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate); - uint32_t src_w, src_h; - uint32_t min_scanlines = 8; - uint8_t plane_bpp; - - if (WARN_ON(!fb)) - return 0; - - /* For packed formats, and uv-plane, return 0 */ - if (plane == 1 && fb->format->format != DRM_FORMAT_NV12) - return 0; - - /* For Non Y-tile return 8-blocks */ - if (fb->modifier != I915_FORMAT_MOD_Y_TILED && - fb->modifier != I915_FORMAT_MOD_Yf_TILED && - fb->modifier != I915_FORMAT_MOD_Y_TILED_CCS && - fb->modifier != I915_FORMAT_MOD_Yf_TILED_CCS) - return 8; - - /* - * Src coordinates are already rotated by 270 degrees for - * the 90/270 degree plane rotation cases (to match the - * GTT mapping), hence no need to account for rotation here. - */ - src_w = drm_rect_width(&intel_pstate->base.src) >> 16; - src_h = drm_rect_height(&intel_pstate->base.src) >> 16; - - /* Halve UV plane width and height for NV12 */ - if (plane == 1) { - src_w /= 2; - src_h /= 2; - } - - plane_bpp = fb->format->cpp[plane]; - - if (drm_rotation_90_or_270(pstate->rotation)) { - switch (plane_bpp) { - case 1: - min_scanlines = 32; - break; - case 2: - min_scanlines = 16; - break; - case 4: - min_scanlines = 8; - break; - case 8: - min_scanlines = 4; - break; - default: - WARN(1, "Unsupported pixel depth %u for rotation", - plane_bpp); - min_scanlines = 32; - } - } - - return DIV_ROUND_UP((4 * src_w * plane_bpp), 512) * min_scanlines/4 + 3; -} - -static void -skl_ddb_calc_min(const struct intel_crtc_state *cstate, int num_active, - uint16_t *minimum, uint16_t *uv_minimum) -{ - const struct drm_plane_state *pstate; - struct drm_plane *plane; - - drm_atomic_crtc_state_for_each_plane_state(plane, pstate, &cstate->base) { - enum plane_id plane_id = to_intel_plane(plane)->id; - struct intel_plane_state *plane_state = to_intel_plane_state(pstate); - - if (plane_id == PLANE_CURSOR) - continue; - - /* slave plane must be invisible and calculated from master */ - if (!pstate->visible || WARN_ON(plane_state->slave)) - continue; - - if (!plane_state->linked_plane) { - minimum[plane_id] = skl_ddb_min_alloc(pstate, 0); - uv_minimum[plane_id] = skl_ddb_min_alloc(pstate, 1); - } else { - enum plane_id y_plane_id = - plane_state->linked_plane->id; - - minimum[y_plane_id] = skl_ddb_min_alloc(pstate, 0); - minimum[plane_id] = skl_ddb_min_alloc(pstate, 1); - } - } - - minimum[PLANE_CURSOR] = skl_cursor_allocation(num_active); -} - static int skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, struct skl_ddb_allocation *ddb /* out */) @@ -4411,15 +4310,17 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb; - uint16_t alloc_size, start; - uint16_t minimum[I915_MAX_PLANES] = {}; - uint16_t uv_minimum[I915_MAX_PLANES] = {}; + struct skl_plane_wm *wm; + uint16_t alloc_size, start = 0; + uint16_t total[I915_MAX_PLANES] = {}; + uint16_t uv_total[I915_MAX_PLANES] = {}; u64 total_data_rate; enum plane_id plane_id; int num_active; u64 plane_data_rate[I915_MAX_PLANES] = {}; u64 uv_plane_data_rate[I915_MAX_PLANES] = {}; - uint16_t total_min_blocks = 0; + uint16_t blocks = 0; + int level; /* Clear the partitioning for disabled planes. */ memset(cstate->wm.skl.plane_ddb_y, 0, sizeof(cstate->wm.skl.plane_ddb_y)); @@ -4449,81 +4350,135 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, if (alloc_size == 0) return 0; - skl_ddb_calc_min(cstate, num_active, minimum, uv_minimum); + /* Allocate fixed number of blocks for cursor. */ + total[PLANE_CURSOR] = skl_cursor_allocation(num_active); + alloc_size -= total[PLANE_CURSOR]; + cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = + alloc->end - total[PLANE_CURSOR]; + cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end; + + if (total_data_rate == 0) + return 0; /* - * 1. Allocate the mininum required blocks for each active plane - * and allocate the cursor, it doesn't require extra allocation - * proportional to the data rate. + * Find the highest watermark level for which we can satisfy the block + * requirement of active planes. */ + for (level = ilk_wm_max_level(dev_priv); level >= 0; level--) { + blocks = 0; + for_each_plane_id_on_crtc(intel_crtc, plane_id) { + if (plane_id == PLANE_CURSOR) + continue; - for_each_plane_id_on_crtc(intel_crtc, plane_id) { - total_min_blocks += minimum[plane_id]; - total_min_blocks += uv_minimum[plane_id]; + wm = &cstate->wm.skl.optimal.planes[plane_id]; + blocks += wm->wm[level].plane_res_b; + blocks += wm->uv_wm[level].plane_res_b; + } + + if (blocks < alloc_size) { + alloc_size -= blocks; + break; + } } - if (total_min_blocks > alloc_size) { + if (level < 0) { DRM_DEBUG_KMS("Requested display configuration exceeds system DDB limitations"); - DRM_DEBUG_KMS("minimum required %d/%d\n", total_min_blocks, - alloc_size); + DRM_DEBUG_KMS("minimum required %d/%d\n", blocks, + alloc_size); return -EINVAL; } - alloc_size -= total_min_blocks; - cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR]; - cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end; - /* - * 2. Distribute the remaining space in proportion to the amount of - * data each plane needs to fetch from memory. - * - * FIXME: we may not allocate every single block here. + * Grant each plane the blocks it requires at the highest achievable + * watermark level, plus an extra share of the leftover blocks + * proportional to its relative data rate. */ - if (total_data_rate == 0) - return 0; - - start = alloc->start; for_each_plane_id_on_crtc(intel_crtc, plane_id) { - u64 data_rate, uv_data_rate; - uint16_t plane_blocks, uv_plane_blocks; + u64 rate; + u16 extra; if (plane_id == PLANE_CURSOR) continue; - data_rate = plane_data_rate[plane_id]; - /* - * allocation for (packed formats) or (uv-plane part of planar format): - * promote the expression to 64 bits to avoid overflowing, the - * result is < available as data_rate / total_data_rate < 1 + * We've accounted for all active planes; remaining planes are + * all disabled. */ - plane_blocks = minimum[plane_id]; - plane_blocks += div64_u64(alloc_size * data_rate, total_data_rate); + if (total_data_rate == 0) + break; - /* Leave disabled planes at (0,0) */ - if (data_rate) { - cstate->wm.skl.plane_ddb_y[plane_id].start = start; - cstate->wm.skl.plane_ddb_y[plane_id].end = start + plane_blocks; - } + wm = &cstate->wm.skl.optimal.planes[plane_id]; - start += plane_blocks; + rate = plane_data_rate[plane_id]; + extra = min_t(u16, alloc_size, + DIV64_U64_ROUND_UP(alloc_size * rate, + total_data_rate)); + total[plane_id] = wm->wm[level].plane_res_b + extra; + alloc_size -= extra; + total_data_rate -= rate; - /* Allocate DDB for UV plane for planar format/NV12 */ - uv_data_rate = uv_plane_data_rate[plane_id]; + if (total_data_rate == 0) + break; - uv_plane_blocks = uv_minimum[plane_id]; - uv_plane_blocks += div64_u64(alloc_size * uv_data_rate, total_data_rate); + rate = uv_plane_data_rate[plane_id]; + extra = min_t(u16, alloc_size, + DIV64_U64_ROUND_UP(alloc_size * rate, + total_data_rate)); + uv_total[plane_id] = wm->uv_wm[level].plane_res_b + extra; + alloc_size -= extra; + total_data_rate -= rate; + } + WARN_ON(alloc_size != 0 || total_data_rate != 0); + + /* Set the actual DDB start/end points for each plane */ + start = alloc->start; + for_each_plane_id_on_crtc(intel_crtc, plane_id) { + struct skl_ddb_entry *plane_alloc, *uv_plane_alloc; + + if (plane_id == PLANE_CURSOR) + continue; + + plane_alloc = &cstate->wm.skl.plane_ddb_y[plane_id]; + uv_plane_alloc = &cstate->wm.skl.plane_ddb_uv[plane_id]; /* Gen11+ uses a separate plane for UV watermarks */ - WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_plane_blocks); + WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_total[plane_id]); + + /* Leave disabled planes at (0,0) */ + if (total[plane_id]) { + plane_alloc->start = start; + start += total[plane_id]; + plane_alloc->end = start; + } - if (uv_data_rate) { - cstate->wm.skl.plane_ddb_uv[plane_id].start = start; - cstate->wm.skl.plane_ddb_uv[plane_id].end = - start + uv_plane_blocks; + if (uv_total[plane_id]) { + uv_plane_alloc->start = start; + start += uv_total[plane_id]; + uv_plane_alloc->end = start; } + } - start += uv_plane_blocks; + /* + * When we calculated watermark values we didn't know how high + * of a level we'd actually be able to hit, so we just marked + * all levels as "enabled." Go back now and disable the ones + * that aren't actually possible. + */ + for (level++; level <= ilk_wm_max_level(dev_priv); level++) { + for_each_plane_id_on_crtc(intel_crtc, plane_id) { + wm = &cstate->wm.skl.optimal.planes[plane_id]; + memset(&wm->wm[level], 0, sizeof(wm->wm[level])); + } + } + + /* + * Go back and disable the transition watermark if it turns out we + * don't have enough DDB blocks for it. + */ + for_each_plane_id_on_crtc(intel_crtc, plane_id) { + wm = &cstate->wm.skl.optimal.planes[plane_id]; + if (wm->trans_wm.plane_res_b > total[plane_id]) + memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); } return 0; @@ -4702,7 +4657,7 @@ skl_compute_plane_wm_params(const struct intel_crtc_state *cstate, wp->plane_blocks_per_line = div_fixed16(interm_pbpl, wp->y_min_scanlines); - } else if (wp->x_tiled && IS_GEN9(dev_priv)) { + } else if (wp->x_tiled && IS_GEN(dev_priv, 9)) { interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, wp->dbuf_block_size); wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl); @@ -4720,17 +4675,15 @@ skl_compute_plane_wm_params(const struct intel_crtc_state *cstate, return 0; } -static int skl_compute_plane_wm(const struct intel_crtc_state *cstate, - const struct intel_plane_state *intel_pstate, - uint16_t ddb_allocation, - int level, - const struct skl_wm_params *wp, - const struct skl_wm_level *result_prev, - struct skl_wm_level *result /* out */) +static void skl_compute_plane_wm(const struct intel_crtc_state *cstate, + const struct intel_plane_state *intel_pstate, + int level, + const struct skl_wm_params *wp, + const struct skl_wm_level *result_prev, + struct skl_wm_level *result /* out */) { struct drm_i915_private *dev_priv = to_i915(intel_pstate->base.plane->dev); - const struct drm_plane_state *pstate = &intel_pstate->base; uint32_t latency = dev_priv->wm.skl_latency[level]; uint_fixed_16_16_t method1, method2; uint_fixed_16_16_t selected_result; @@ -4738,10 +4691,6 @@ static int skl_compute_plane_wm(const struct intel_crtc_state *cstate, struct intel_atomic_state *state = to_intel_atomic_state(cstate->base.state); bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state); - uint32_t min_disp_buf_needed; - - if (latency == 0) - return level == 0 ? -EINVAL : 0; /* Display WA #1141: kbl,cfl */ if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) || @@ -4766,15 +4715,8 @@ static int skl_compute_plane_wm(const struct intel_crtc_state *cstate, wp->dbuf_block_size < 1) && (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) { selected_result = method2; - } else if (ddb_allocation >= - fixed16_to_u32_round_up(wp->plane_blocks_per_line)) { - if (IS_GEN9(dev_priv) && - !IS_GEMINILAKE(dev_priv)) - selected_result = min_fixed16(method1, method2); - else - selected_result = method2; } else if (latency >= wp->linetime_us) { - if (IS_GEN9(dev_priv) && + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv)) selected_result = min_fixed16(method1, method2); else @@ -4788,85 +4730,51 @@ static int skl_compute_plane_wm(const struct intel_crtc_state *cstate, res_lines = div_round_up_fixed16(selected_result, wp->plane_blocks_per_line); - /* Display WA #1125: skl,bxt,kbl,glk */ - if (level == 0 && wp->rc_surface) - res_blocks += fixed16_to_u32_round_up(wp->y_tile_minimum); - - /* Display WA #1126: skl,bxt,kbl,glk */ - if (level >= 1 && level <= 7) { - if (wp->y_tiled) { - res_blocks += fixed16_to_u32_round_up( - wp->y_tile_minimum); - res_lines += wp->y_min_scanlines; - } else { - res_blocks++; - } - - /* - * Make sure result blocks for higher latency levels are atleast - * as high as level below the current level. - * Assumption in DDB algorithm optimization for special cases. - * Also covers Display WA #1125 for RC. - */ - if (result_prev->plane_res_b > res_blocks) - res_blocks = result_prev->plane_res_b; - } - - if (INTEL_GEN(dev_priv) >= 11) { - if (wp->y_tiled) { - uint32_t extra_lines; - uint_fixed_16_16_t fp_min_disp_buf_needed; - - if (res_lines % wp->y_min_scanlines == 0) - extra_lines = wp->y_min_scanlines; - else - extra_lines = wp->y_min_scanlines * 2 - - res_lines % wp->y_min_scanlines; - - fp_min_disp_buf_needed = mul_u32_fixed16(res_lines + - extra_lines, - wp->plane_blocks_per_line); - min_disp_buf_needed = fixed16_to_u32_round_up( - fp_min_disp_buf_needed); - } else { - min_disp_buf_needed = DIV_ROUND_UP(res_blocks * 11, 10); - } - } else { - min_disp_buf_needed = res_blocks; - } - - if ((level > 0 && res_lines > 31) || - res_blocks >= ddb_allocation || - min_disp_buf_needed >= ddb_allocation) { - /* - * If there are no valid level 0 watermarks, then we can't - * support this display configuration. - */ - if (level) { - return 0; - } else { - struct drm_plane *plane = pstate->plane; + if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) { + /* Display WA #1125: skl,bxt,kbl */ + if (level == 0 && wp->rc_surface) + res_blocks += + fixed16_to_u32_round_up(wp->y_tile_minimum); + + /* Display WA #1126: skl,bxt,kbl */ + if (level >= 1 && level <= 7) { + if (wp->y_tiled) { + res_blocks += + fixed16_to_u32_round_up(wp->y_tile_minimum); + res_lines += wp->y_min_scanlines; + } else { + res_blocks++; + } - DRM_DEBUG_KMS("Requested display configuration exceeds system watermark limitations\n"); - DRM_DEBUG_KMS("[PLANE:%d:%s] blocks required = %u/%u, lines required = %u/31\n", - plane->base.id, plane->name, - res_blocks, ddb_allocation, res_lines); - return -EINVAL; + /* + * Make sure result blocks for higher latency levels are + * atleast as high as level below the current level. + * Assumption in DDB algorithm optimization for special + * cases. Also covers Display WA #1125 for RC. + */ + if (result_prev->plane_res_b > res_blocks) + res_blocks = result_prev->plane_res_b; } } /* The number of lines are ignored for the level 0 watermark. */ + if (level > 0 && res_lines > 31) + return; + + /* + * If res_lines is valid, assume we can use this watermark level + * for now. We'll come back and disable it after we calculate the + * DDB allocation if it turns out we don't actually have enough + * blocks to satisfy it. + */ result->plane_res_b = res_blocks; result->plane_res_l = res_lines; result->plane_en = true; - - return 0; } -static int +static void skl_compute_wm_levels(const struct intel_crtc_state *cstate, const struct intel_plane_state *intel_pstate, - uint16_t ddb_blocks, const struct skl_wm_params *wm_params, struct skl_wm_level *levels) { @@ -4874,25 +4782,15 @@ skl_compute_wm_levels(const struct intel_crtc_state *cstate, to_i915(intel_pstate->base.plane->dev); int level, max_level = ilk_wm_max_level(dev_priv); struct skl_wm_level *result_prev = &levels[0]; - int ret; for (level = 0; level <= max_level; level++) { struct skl_wm_level *result = &levels[level]; - ret = skl_compute_plane_wm(cstate, - intel_pstate, - ddb_blocks, - level, - wm_params, - result_prev, - result); - if (ret) - return ret; + skl_compute_plane_wm(cstate, intel_pstate, level, wm_params, + result_prev, result); result_prev = result; } - - return 0; } static uint32_t @@ -4920,8 +4818,7 @@ skl_compute_linetime_wm(const struct intel_crtc_state *cstate) static void skl_compute_transition_wm(const struct intel_crtc_state *cstate, const struct skl_wm_params *wp, - struct skl_plane_wm *wm, - uint16_t ddb_allocation) + struct skl_plane_wm *wm) { struct drm_device *dev = cstate->base.crtc->dev; const struct drm_i915_private *dev_priv = to_i915(dev); @@ -4969,12 +4866,13 @@ static void skl_compute_transition_wm(const struct intel_crtc_state *cstate, } - res_blocks += 1; - - if (res_blocks < ddb_allocation) { - wm->trans_wm.plane_res_b = res_blocks; - wm->trans_wm.plane_en = true; - } + /* + * Just assume we can enable the transition watermark. After + * computing the DDB we'll come back and disable it if that + * assumption turns out to be false. + */ + wm->trans_wm.plane_res_b = res_blocks + 1; + wm->trans_wm.plane_en = true; } static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, @@ -4982,7 +4880,6 @@ static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, enum plane_id plane_id, int color_plane) { struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_y[plane_id]); struct skl_wm_params wm_params; int ret; @@ -4991,12 +4888,8 @@ static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, if (ret) return ret; - ret = skl_compute_wm_levels(crtc_state, plane_state, - ddb_blocks, &wm_params, wm->wm); - if (ret) - return ret; - - skl_compute_transition_wm(crtc_state, &wm_params, wm, ddb_blocks); + skl_compute_wm_levels(crtc_state, plane_state, &wm_params, wm->wm); + skl_compute_transition_wm(crtc_state, &wm_params, wm); return 0; } @@ -5006,7 +4899,6 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, enum plane_id plane_id) { struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_uv[plane_id]); struct skl_wm_params wm_params; int ret; @@ -5018,10 +4910,7 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, if (ret) return ret; - ret = skl_compute_wm_levels(crtc_state, plane_state, - ddb_blocks, &wm_params, wm->uv_wm); - if (ret) - return ret; + skl_compute_wm_levels(crtc_state, plane_state, &wm_params, wm->uv_wm); return 0; } @@ -5251,15 +5140,14 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, return false; } -static int skl_update_pipe_wm(struct drm_crtc_state *cstate, +static int skl_update_pipe_wm(struct intel_crtc_state *cstate, const struct skl_pipe_wm *old_pipe_wm, struct skl_pipe_wm *pipe_wm, /* out */ bool *changed /* out */) { - struct intel_crtc_state *intel_cstate = to_intel_crtc_state(cstate); int ret; - ret = skl_build_pipe_wm(intel_cstate, pipe_wm); + ret = skl_build_pipe_wm(cstate, pipe_wm); if (ret) return ret; @@ -5272,14 +5160,14 @@ static int skl_update_pipe_wm(struct drm_crtc_state *cstate, } static uint32_t -pipes_modified(struct drm_atomic_state *state) +pipes_modified(struct intel_atomic_state *state) { - struct drm_crtc *crtc; - struct drm_crtc_state *cstate; + struct intel_crtc *crtc; + struct intel_crtc_state *cstate; uint32_t i, ret = 0; - for_each_new_crtc_in_state(state, crtc, cstate, i) - ret |= drm_crtc_mask(crtc); + for_each_new_intel_crtc_in_state(state, crtc, cstate, i) + ret |= drm_crtc_mask(&crtc->base); return ret; } @@ -5314,11 +5202,10 @@ skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state, } static int -skl_compute_ddb(struct drm_atomic_state *state) +skl_compute_ddb(struct intel_atomic_state *state) { - const struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb; + const struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct skl_ddb_allocation *ddb = &state->wm_results.ddb; struct intel_crtc_state *old_crtc_state; struct intel_crtc_state *new_crtc_state; struct intel_crtc *crtc; @@ -5326,7 +5213,7 @@ skl_compute_ddb(struct drm_atomic_state *state) memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb)); - for_each_oldnew_intel_crtc_in_state(intel_state, crtc, old_crtc_state, + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ret = skl_allocate_pipe_ddb(new_crtc_state, ddb); if (ret) @@ -5372,14 +5259,12 @@ skl_print_wm_changes(struct intel_atomic_state *state) } static int -skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) +skl_ddb_add_affected_pipes(struct intel_atomic_state *state, bool *changed) { - struct drm_device *dev = state->dev; + struct drm_device *dev = state->base.dev; const struct drm_i915_private *dev_priv = to_i915(dev); - const struct drm_crtc *crtc; - const struct drm_crtc_state *cstate; - struct intel_crtc *intel_crtc; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; uint32_t realloc_pipes = pipes_modified(state); int ret, i; @@ -5398,7 +5283,7 @@ skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) * since any racing commits that want to update them would need to * hold _all_ CRTC state mutexes. */ - for_each_new_crtc_in_state(state, crtc, cstate, i) + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) (*changed) = true; if (!*changed) @@ -5412,20 +5297,20 @@ skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) */ if (dev_priv->wm.distrust_bios_wm) { ret = drm_modeset_lock(&dev->mode_config.connection_mutex, - state->acquire_ctx); + state->base.acquire_ctx); if (ret) return ret; - intel_state->active_pipe_changes = ~0; + state->active_pipe_changes = ~0; /* - * We usually only initialize intel_state->active_crtcs if we + * We usually only initialize state->active_crtcs if we * we're doing a modeset; make sure this field is always * initialized during the sanitization process that happens * on the first commit too. */ - if (!intel_state->modeset) - intel_state->active_crtcs = dev_priv->active_crtcs; + if (!state->modeset) + state->active_crtcs = dev_priv->active_crtcs; } /* @@ -5441,21 +5326,19 @@ skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) * any other display updates race with this transaction, so we need * to grab the lock on *all* CRTC's. */ - if (intel_state->active_pipe_changes || intel_state->modeset) { + if (state->active_pipe_changes || state->modeset) { realloc_pipes = ~0; - intel_state->wm_results.dirty_pipes = ~0; + state->wm_results.dirty_pipes = ~0; } /* * We're not recomputing for the pipes not included in the commit, so * make sure we start with the current state. */ - for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) { - struct intel_crtc_state *cstate; - - cstate = intel_atomic_get_crtc_state(state, intel_crtc); - if (IS_ERR(cstate)) - return PTR_ERR(cstate); + for_each_intel_crtc_mask(dev, crtc, realloc_pipes) { + crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); } return 0; @@ -5522,12 +5405,12 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, } static int -skl_compute_wm(struct drm_atomic_state *state) +skl_compute_wm(struct intel_atomic_state *state) { - struct drm_crtc *crtc; - struct drm_crtc_state *cstate; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct skl_ddb_values *results = &intel_state->wm_results; + struct intel_crtc *crtc; + struct intel_crtc_state *cstate; + struct intel_crtc_state *old_crtc_state; + struct skl_ddb_values *results = &state->wm_results; struct skl_pipe_wm *pipe_wm; bool changed = false; int ret, i; @@ -5539,47 +5422,35 @@ skl_compute_wm(struct drm_atomic_state *state) if (ret || !changed) return ret; - ret = skl_compute_ddb(state); - if (ret) - return ret; - /* * Calculate WM's for all pipes that are part of this transaction. - * Note that the DDB allocation above may have added more CRTC's that + * Note that skl_ddb_add_affected_pipes may have added more CRTC's that * weren't otherwise being modified (and set bits in dirty_pipes) if * pipe allocations had to change. - * - * FIXME: Now that we're doing this in the atomic check phase, we - * should allow skl_update_pipe_wm() to return failure in cases where - * no suitable watermark values can be found. */ - for_each_new_crtc_in_state(state, crtc, cstate, i) { - struct intel_crtc_state *intel_cstate = - to_intel_crtc_state(cstate); + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, + cstate, i) { const struct skl_pipe_wm *old_pipe_wm = - &to_intel_crtc_state(crtc->state)->wm.skl.optimal; + &old_crtc_state->wm.skl.optimal; - pipe_wm = &intel_cstate->wm.skl.optimal; + pipe_wm = &cstate->wm.skl.optimal; ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm, &changed); if (ret) return ret; - ret = skl_wm_add_affected_planes(intel_state, - to_intel_crtc(crtc)); + ret = skl_wm_add_affected_planes(state, crtc); if (ret) return ret; if (changed) - results->dirty_pipes |= drm_crtc_mask(crtc); - - if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0) - /* This pipe's WM's did not change */ - continue; - - intel_cstate->update_wm_pre = true; + results->dirty_pipes |= drm_crtc_mask(&crtc->base); } - skl_print_wm_changes(intel_state); + ret = skl_compute_ddb(state); + if (ret) + return ret; + + skl_print_wm_changes(state); return 0; } @@ -5617,13 +5488,13 @@ static void skl_initial_wm(struct intel_atomic_state *state, mutex_unlock(&dev_priv->wm.wm_mutex); } -static void ilk_compute_wm_config(struct drm_device *dev, +static void ilk_compute_wm_config(struct drm_i915_private *dev_priv, struct intel_wm_config *config) { struct intel_crtc *crtc; /* Compute the currently _active_ config */ - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(&dev_priv->drm, crtc) { const struct intel_pipe_wm *wm = &crtc->wm.active.ilk; if (!wm->pipe_enabled) @@ -5637,25 +5508,24 @@ static void ilk_compute_wm_config(struct drm_device *dev, static void ilk_program_watermarks(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct ilk_wm_maximums max; struct intel_wm_config config = {}; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; - ilk_compute_wm_config(dev, &config); + ilk_compute_wm_config(dev_priv, &config); - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); + ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_1_2, &max); + ilk_wm_merge(dev_priv, &config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_GEN(dev_priv) >= 7 && config.num_pipes_active == 1 && config.sprites_enabled) { - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); + ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_5_6, &max); + ilk_wm_merge(dev_priv, &config, &max, &lp_wm_5_6); - best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); + best_lp_wm = ilk_find_best_result(dev_priv, &lp_wm_1_2, &lp_wm_5_6); } else { best_lp_wm = &lp_wm_1_2; } @@ -5663,7 +5533,7 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv) partitioning = (best_lp_wm == &lp_wm_1_2) ? INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6; - ilk_compute_wm_results(dev, best_lp_wm, partitioning, &results); + ilk_compute_wm_results(dev_priv, best_lp_wm, partitioning, &results); ilk_write_wm_values(dev_priv, &results); } @@ -5703,19 +5573,18 @@ static inline void skl_wm_level_from_reg_val(uint32_t val, PLANE_WM_LINES_MASK; } -void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc, +void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, struct skl_pipe_wm *out) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; int level, max_level; enum plane_id plane_id; uint32_t val; max_level = ilk_wm_max_level(dev_priv); - for_each_plane_id_on_crtc(intel_crtc, plane_id) { + for_each_plane_id_on_crtc(crtc, plane_id) { struct skl_plane_wm *wm = &out->planes[plane_id]; for (level = 0; level <= max_level; level++) { @@ -5735,30 +5604,27 @@ void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc, skl_wm_level_from_reg_val(val, &wm->trans_wm); } - if (!intel_crtc->active) + if (!crtc->active) return; out->linetime = I915_READ(PIPE_WM_LINETIME(pipe)); } -void skl_wm_get_hw_state(struct drm_device *dev) +void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); struct skl_ddb_values *hw = &dev_priv->wm.skl_hw; struct skl_ddb_allocation *ddb = &dev_priv->wm.skl_hw.ddb; - struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; + struct intel_crtc *crtc; struct intel_crtc_state *cstate; skl_ddb_get_hw_state(dev_priv, ddb); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - cstate = to_intel_crtc_state(crtc->state); + for_each_intel_crtc(&dev_priv->drm, crtc) { + cstate = to_intel_crtc_state(crtc->base.state); skl_pipe_wm_get_hw_state(crtc, &cstate->wm.skl.optimal); - if (intel_crtc->active) - hw->dirty_pipes |= drm_crtc_mask(crtc); + if (crtc->active) + hw->dirty_pipes |= drm_crtc_mask(&crtc->base); } if (dev_priv->active_crtcs) { @@ -5767,15 +5633,14 @@ void skl_wm_get_hw_state(struct drm_device *dev) } } -static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) +static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct ilk_wm_values *hw = &dev_priv->wm.hw; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->base.state); struct intel_pipe_wm *active = &cstate->wm.ilk.optimal; - enum pipe pipe = intel_crtc->pipe; + enum pipe pipe = crtc->pipe; static const i915_reg_t wm0_pipe_reg[] = { [PIPE_A] = WM0_PIPEA_ILK, [PIPE_B] = WM0_PIPEB_ILK, @@ -5788,7 +5653,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) memset(active, 0, sizeof(*active)); - active->pipe_enabled = intel_crtc->active; + active->pipe_enabled = crtc->active; if (active->pipe_enabled) { u32 tmp = hw->wm_pipe[pipe]; @@ -5816,7 +5681,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) active->wm[level].enable = true; } - intel_crtc->wm.active.ilk = *active; + crtc->wm.active.ilk = *active; } #define _FW_WM(value, plane) \ @@ -5926,9 +5791,8 @@ static void vlv_read_wm_values(struct drm_i915_private *dev_priv, #undef _FW_WM #undef _FW_WM_VLV -void g4x_wm_get_hw_state(struct drm_device *dev) +void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); struct g4x_wm_values *wm = &dev_priv->wm.g4x; struct intel_crtc *crtc; @@ -5936,7 +5800,7 @@ void g4x_wm_get_hw_state(struct drm_device *dev) wm->cxsr = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN; - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(&dev_priv->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct g4x_wm_state *active = &crtc->wm.active.g4x; @@ -6067,9 +5931,8 @@ void g4x_wm_sanitize(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->wm.wm_mutex); } -void vlv_wm_get_hw_state(struct drm_device *dev) +void vlv_wm_get_hw_state(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); struct vlv_wm_values *wm = &dev_priv->wm.vlv; struct intel_crtc *crtc; u32 val; @@ -6113,7 +5976,7 @@ void vlv_wm_get_hw_state(struct drm_device *dev) mutex_unlock(&dev_priv->pcu_lock); } - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(&dev_priv->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct vlv_wm_state *active = &crtc->wm.active.vlv; @@ -6230,15 +6093,14 @@ static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv) */ } -void ilk_wm_get_hw_state(struct drm_device *dev) +void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); struct ilk_wm_values *hw = &dev_priv->wm.hw; - struct drm_crtc *crtc; + struct intel_crtc *crtc; ilk_init_lp_watermarks(dev_priv); - for_each_crtc(dev, crtc) + for_each_intel_crtc(&dev_priv->drm, crtc) ilk_pipe_wm_get_hw_state(crtc); hw->wm_lp[0] = I915_READ(WM1_LP_ILK); @@ -7049,7 +6911,7 @@ static void gen9_enable_rps(struct drm_i915_private *dev_priv) intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); /* Program defaults and thresholds for RPS */ - if (IS_GEN9(dev_priv)) + if (IS_GEN(dev_priv, 9)) I915_WRITE(GEN6_RC_VIDEO_FREQ, GEN9_FREQUENCY(dev_priv->gt_pm.rps.rp1_freq)); @@ -7285,9 +7147,9 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv) rc6vids = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); - if (IS_GEN6(dev_priv) && ret) { + if (IS_GEN(dev_priv, 6) && ret) { DRM_DEBUG_DRIVER("Couldn't check for BIOS workaround\n"); - } else if (IS_GEN6(dev_priv) && (GEN6_DECODE_RC6_VID(rc6vids & 0xff) < 450)) { + } else if (IS_GEN(dev_priv, 6) && (GEN6_DECODE_RC6_VID(rc6vids & 0xff) < 450)) { DRM_DEBUG_DRIVER("You should update your BIOS. Correcting minimum rc6 voltage (%dmV->%dmV)\n", GEN6_DECODE_RC6_VID(rc6vids & 0xff), 450); rc6vids &= 0xffff00; @@ -7412,7 +7274,7 @@ static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv) val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE); - switch (INTEL_INFO(dev_priv)->sseu.eu_total) { + switch (RUNTIME_INFO(dev_priv)->sseu.eu_total) { case 8: /* (2 * 4) config */ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT); @@ -7987,7 +7849,7 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) { unsigned long val; - if (!IS_GEN5(dev_priv)) + if (!IS_GEN(dev_priv, 5)) return 0; spin_lock_irq(&mchdev_lock); @@ -8071,7 +7933,7 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) void i915_update_gfx_val(struct drm_i915_private *dev_priv) { - if (!IS_GEN5(dev_priv)) + if (!IS_GEN(dev_priv, 5)) return; spin_lock_irq(&mchdev_lock); @@ -8122,7 +7984,7 @@ unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) { unsigned long val; - if (!IS_GEN5(dev_priv)) + if (!IS_GEN(dev_priv, 5)) return 0; spin_lock_irq(&mchdev_lock); @@ -8410,7 +8272,7 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv) intel_freq_opcode(dev_priv, 450)); /* After setting max-softlimit, find the overclock max freq */ - if (IS_GEN6(dev_priv) || + if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv)) { u32 params = 0; @@ -9480,9 +9342,9 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) dev_priv->display.init_clock_gating = ivb_init_clock_gating; else if (IS_VALLEYVIEW(dev_priv)) dev_priv->display.init_clock_gating = vlv_init_clock_gating; - else if (IS_GEN6(dev_priv)) + else if (IS_GEN(dev_priv, 6)) dev_priv->display.init_clock_gating = gen6_init_clock_gating; - else if (IS_GEN5(dev_priv)) + else if (IS_GEN(dev_priv, 5)) dev_priv->display.init_clock_gating = ilk_init_clock_gating; else if (IS_G4X(dev_priv)) dev_priv->display.init_clock_gating = g4x_init_clock_gating; @@ -9490,11 +9352,11 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) dev_priv->display.init_clock_gating = i965gm_init_clock_gating; else if (IS_I965G(dev_priv)) dev_priv->display.init_clock_gating = i965g_init_clock_gating; - else if (IS_GEN3(dev_priv)) + else if (IS_GEN(dev_priv, 3)) dev_priv->display.init_clock_gating = gen3_init_clock_gating; else if (IS_I85X(dev_priv) || IS_I865G(dev_priv)) dev_priv->display.init_clock_gating = i85x_init_clock_gating; - else if (IS_GEN2(dev_priv)) + else if (IS_GEN(dev_priv, 2)) dev_priv->display.init_clock_gating = i830_init_clock_gating; else { MISSING_CASE(INTEL_DEVID(dev_priv)); @@ -9508,7 +9370,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv) /* For cxsr */ if (IS_PINEVIEW(dev_priv)) i915_pineview_get_mem_freq(dev_priv); - else if (IS_GEN5(dev_priv)) + else if (IS_GEN(dev_priv, 5)) i915_ironlake_get_mem_freq(dev_priv); /* For FIFO watermark updates */ @@ -9520,9 +9382,9 @@ void intel_init_pm(struct drm_i915_private *dev_priv) } else if (HAS_PCH_SPLIT(dev_priv)) { ilk_setup_wm_latency(dev_priv); - if ((IS_GEN5(dev_priv) && dev_priv->wm.pri_latency[1] && + if ((IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[1] && dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || - (!IS_GEN5(dev_priv) && dev_priv->wm.pri_latency[0] && + (!IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; dev_priv->display.compute_intermediate_wm = @@ -9563,12 +9425,12 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->display.update_wm = NULL; } else dev_priv->display.update_wm = pineview_update_wm; - } else if (IS_GEN4(dev_priv)) { + } else if (IS_GEN(dev_priv, 4)) { dev_priv->display.update_wm = i965_update_wm; - } else if (IS_GEN3(dev_priv)) { + } else if (IS_GEN(dev_priv, 3)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; - } else if (IS_GEN2(dev_priv)) { + } else if (IS_GEN(dev_priv, 2)) { if (INTEL_INFO(dev_priv)->num_pipes == 1) { dev_priv->display.update_wm = i845_update_wm; dev_priv->display.get_fifo_size = i845_get_fifo_size; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 419e56342523..0f6b2b4702e3 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -51,7 +51,6 @@ * must be correctly synchronized/cancelled when shutting down the pipe." */ -#include <drm/drmP.h> #include "intel_drv.h" #include "i915_drv.h" @@ -261,6 +260,32 @@ static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp) return val; } +static u16 intel_dp_get_su_x_granulartiy(struct intel_dp *intel_dp) +{ + u16 val; + ssize_t r; + + /* + * Returning the default X granularity if granularity not required or + * if DPCD read fails + */ + if (!(intel_dp->psr_dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED)) + return 4; + + r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &val, 2); + if (r != 2) + DRM_DEBUG_KMS("Unable to read DP_PSR2_SU_X_GRANULARITY\n"); + + /* + * Spec says that if the value read is 0 the default granularity should + * be used instead. + */ + if (r != 2 || val == 0) + val = 4; + + return val; +} + void intel_psr_init_dpcd(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = @@ -274,10 +299,16 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) DRM_DEBUG_KMS("eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); + if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) { + DRM_DEBUG_KMS("PSR support not currently available for this panel\n"); + return; + } + if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { DRM_DEBUG_KMS("Panel lacks power state control, PSR cannot be enabled\n"); return; } + dev_priv->psr.sink_support = true; dev_priv->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); @@ -309,6 +340,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (dev_priv->psr.sink_psr2_support) { dev_priv->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); + dev_priv->psr.su_x_granularity = + intel_dp_get_su_x_granulartiy(intel_dp); } } } @@ -388,13 +421,15 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) if (dev_priv->psr.psr2_enabled) { drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE); - dpcd_val |= DP_PSR_ENABLE_PSR2; + dpcd_val |= DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS; + } else { + if (dev_priv->psr.link_standby) + dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; + + if (INTEL_GEN(dev_priv) >= 8) + dpcd_val |= DP_PSR_CRC_VERIFICATION; } - if (dev_priv->psr.link_standby) - dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; - if (!dev_priv->psr.psr2_enabled && INTEL_GEN(dev_priv) >= 8) - dpcd_val |= DP_PSR_CRC_VERIFICATION; drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); @@ -468,9 +503,6 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) idle_frames = max(idle_frames, dev_priv->psr.sink_sync_latency + 1); val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; - /* FIXME: selective update is probably totally broken because it doesn't - * mesh at all with our frontbuffer tracking. And the hw alone isn't - * good enough. */ val |= EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE; if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) val |= EDP_Y_COORDINATE_ENABLE; @@ -519,7 +551,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { psr_max_h = 4096; psr_max_v = 2304; - } else if (IS_GEN9(dev_priv)) { + } else if (IS_GEN(dev_priv, 9)) { psr_max_h = 3640; psr_max_v = 2304; } @@ -531,6 +563,18 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } + /* + * HW sends SU blocks of size four scan lines, which means the starting + * X coordinate and Y granularity requirements will always be met. We + * only need to validate the SU block width is a multiple of + * x granularity. + */ + if (crtc_hdisplay % dev_priv->psr.su_x_granularity) { + DRM_DEBUG_KMS("PSR2 not enabled, hdisplay(%d) not multiple of %d\n", + crtc_hdisplay, dev_priv->psr.su_x_granularity); + return false; + } + return true; } @@ -641,17 +685,14 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_psr_setup_aux(intel_dp); - if (dev_priv->psr.psr2_enabled) { + if (dev_priv->psr.psr2_enabled && (IS_GEN(dev_priv, 9) && + !IS_GEMINILAKE(dev_priv))) { i915_reg_t reg = gen9_chicken_trans_reg(dev_priv, cpu_transcoder); u32 chicken = I915_READ(reg); - if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv)) - chicken |= (PSR2_VSC_ENABLE_PROG_HEADER - | PSR2_ADD_VERTICAL_LINE_COUNT); - - else - chicken &= ~VSC_DATA_SEL_SOFTWARE_CONTROL; + chicken |= PSR2_VSC_ENABLE_PROG_HEADER | + PSR2_ADD_VERTICAL_LINE_COUNT; I915_WRITE(reg, chicken); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fbeaec3994e7..26b7274a2d43 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -29,7 +29,6 @@ #include <linux/log2.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -133,7 +132,7 @@ gen4_render_ring_flush(struct i915_request *rq, u32 mode) cmd = MI_FLUSH; if (mode & EMIT_INVALIDATE) { cmd |= MI_EXE_FLUSH; - if (IS_G4X(rq->i915) || IS_GEN5(rq->i915)) + if (IS_G4X(rq->i915) || IS_GEN(rq->i915, 5)) cmd |= MI_INVALIDATE_ISP; } @@ -217,7 +216,7 @@ gen4_render_ring_flush(struct i915_request *rq, u32 mode) * really our business. That leaves only stall at scoreboard. */ static int -intel_emit_post_sync_nonzero_flush(struct i915_request *rq) +gen6_emit_post_sync_nonzero_flush(struct i915_request *rq) { u32 scratch_addr = i915_scratch_offset(rq->i915) + 2 * CACHELINE_BYTES; u32 *cs; @@ -257,7 +256,7 @@ gen6_render_ring_flush(struct i915_request *rq, u32 mode) int ret; /* Force SNB workarounds for PIPE_CONTROL flushes */ - ret = intel_emit_post_sync_nonzero_flush(rq); + ret = gen6_emit_post_sync_nonzero_flush(rq); if (ret) return ret; @@ -300,6 +299,37 @@ gen6_render_ring_flush(struct i915_request *rq, u32 mode) return 0; } +static void gen6_rcs_emit_breadcrumb(struct i915_request *rq, u32 *cs) +{ + /* First we do the gen6_emit_post_sync_nonzero_flush w/a */ + *cs++ = GFX_OP_PIPE_CONTROL(4); + *cs++ = PIPE_CONTROL_CS_STALL | PIPE_CONTROL_STALL_AT_SCOREBOARD; + *cs++ = 0; + *cs++ = 0; + + *cs++ = GFX_OP_PIPE_CONTROL(4); + *cs++ = PIPE_CONTROL_QW_WRITE; + *cs++ = i915_scratch_offset(rq->i915) | PIPE_CONTROL_GLOBAL_GTT; + *cs++ = 0; + + /* Finally we can flush and with it emit the breadcrumb */ + *cs++ = GFX_OP_PIPE_CONTROL(4); + *cs++ = (PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | + PIPE_CONTROL_DEPTH_CACHE_FLUSH | + PIPE_CONTROL_DC_FLUSH_ENABLE | + PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_CS_STALL); + *cs++ = intel_hws_seqno_address(rq->engine) | PIPE_CONTROL_GLOBAL_GTT; + *cs++ = rq->global_seqno; + + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + rq->tail = intel_ring_offset(rq, cs); + assert_ring_tail_valid(rq->ring, rq->tail); +} +static const int gen6_rcs_emit_breadcrumb_sz = 14; + static int gen7_render_ring_cs_stall_wa(struct i915_request *rq) { @@ -379,11 +409,86 @@ gen7_render_ring_flush(struct i915_request *rq, u32 mode) return 0; } -static void ring_setup_phys_status_page(struct intel_engine_cs *engine) +static void gen7_rcs_emit_breadcrumb(struct i915_request *rq, u32 *cs) +{ + *cs++ = GFX_OP_PIPE_CONTROL(4); + *cs++ = (PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | + PIPE_CONTROL_DEPTH_CACHE_FLUSH | + PIPE_CONTROL_DC_FLUSH_ENABLE | + PIPE_CONTROL_FLUSH_ENABLE | + PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL); + *cs++ = intel_hws_seqno_address(rq->engine); + *cs++ = rq->global_seqno; + + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + rq->tail = intel_ring_offset(rq, cs); + assert_ring_tail_valid(rq->ring, rq->tail); +} +static const int gen7_rcs_emit_breadcrumb_sz = 6; + +static void gen6_xcs_emit_breadcrumb(struct i915_request *rq, u32 *cs) +{ + *cs++ = MI_FLUSH_DW | MI_FLUSH_DW_OP_STOREDW; + *cs++ = intel_hws_seqno_address(rq->engine) | MI_FLUSH_DW_USE_GTT; + *cs++ = rq->global_seqno; + *cs++ = MI_USER_INTERRUPT; + + rq->tail = intel_ring_offset(rq, cs); + assert_ring_tail_valid(rq->ring, rq->tail); +} +static const int gen6_xcs_emit_breadcrumb_sz = 4; + +#define GEN7_XCS_WA 32 +static void gen7_xcs_emit_breadcrumb(struct i915_request *rq, u32 *cs) +{ + int i; + + *cs++ = MI_FLUSH_DW | MI_FLUSH_DW_OP_STOREDW; + *cs++ = intel_hws_seqno_address(rq->engine) | MI_FLUSH_DW_USE_GTT; + *cs++ = rq->global_seqno; + + for (i = 0; i < GEN7_XCS_WA; i++) { + *cs++ = MI_STORE_DWORD_INDEX; + *cs++ = I915_GEM_HWS_INDEX_ADDR; + *cs++ = rq->global_seqno; + } + + *cs++ = MI_FLUSH_DW; + *cs++ = 0; + *cs++ = 0; + + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + rq->tail = intel_ring_offset(rq, cs); + assert_ring_tail_valid(rq->ring, rq->tail); +} +static const int gen7_xcs_emit_breadcrumb_sz = 8 + GEN7_XCS_WA * 3; +#undef GEN7_XCS_WA + +static void set_hwstam(struct intel_engine_cs *engine, u32 mask) +{ + /* + * Keep the render interrupt unmasked as this papers over + * lost interrupts following a reset. + */ + if (engine->class == RENDER_CLASS) { + if (INTEL_GEN(engine->i915) >= 6) + mask &= ~BIT(0); + else + mask &= ~I915_USER_INTERRUPT; + } + + intel_engine_set_hwsp_writemask(engine, mask); +} + +static void set_hws_pga(struct intel_engine_cs *engine, phys_addr_t phys) { struct drm_i915_private *dev_priv = engine->i915; - struct page *page = virt_to_page(engine->status_page.page_addr); - phys_addr_t phys = PFN_PHYS(page_to_pfn(page)); u32 addr; addr = lower_32_bits(phys); @@ -393,15 +498,25 @@ static void ring_setup_phys_status_page(struct intel_engine_cs *engine) I915_WRITE(HWS_PGA, addr); } -static void intel_ring_setup_status_page(struct intel_engine_cs *engine) +static void ring_setup_phys_status_page(struct intel_engine_cs *engine) +{ + struct page *page = virt_to_page(engine->status_page.page_addr); + phys_addr_t phys = PFN_PHYS(page_to_pfn(page)); + + set_hws_pga(engine, phys); + set_hwstam(engine, ~0u); +} + +static void set_hwsp(struct intel_engine_cs *engine, u32 offset) { struct drm_i915_private *dev_priv = engine->i915; - i915_reg_t mmio; + i915_reg_t hwsp; - /* The ring status page addresses are no longer next to the rest of + /* + * The ring status page addresses are no longer next to the rest of * the ring registers as of gen7. */ - if (IS_GEN7(dev_priv)) { + if (IS_GEN(dev_priv, 7)) { switch (engine->id) { /* * No more rings exist on Gen7. Default case is only to shut up @@ -410,56 +525,55 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *engine) default: GEM_BUG_ON(engine->id); case RCS: - mmio = RENDER_HWS_PGA_GEN7; + hwsp = RENDER_HWS_PGA_GEN7; break; case BCS: - mmio = BLT_HWS_PGA_GEN7; + hwsp = BLT_HWS_PGA_GEN7; break; case VCS: - mmio = BSD_HWS_PGA_GEN7; + hwsp = BSD_HWS_PGA_GEN7; break; case VECS: - mmio = VEBOX_HWS_PGA_GEN7; + hwsp = VEBOX_HWS_PGA_GEN7; break; } - } else if (IS_GEN6(dev_priv)) { - mmio = RING_HWS_PGA_GEN6(engine->mmio_base); + } else if (IS_GEN(dev_priv, 6)) { + hwsp = RING_HWS_PGA_GEN6(engine->mmio_base); } else { - mmio = RING_HWS_PGA(engine->mmio_base); + hwsp = RING_HWS_PGA(engine->mmio_base); } - if (INTEL_GEN(dev_priv) >= 6) { - u32 mask = ~0u; + I915_WRITE(hwsp, offset); + POSTING_READ(hwsp); +} - /* - * Keep the render interrupt unmasked as this papers over - * lost interrupts following a reset. - */ - if (engine->id == RCS) - mask &= ~BIT(0); +static void flush_cs_tlb(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + i915_reg_t instpm = RING_INSTPM(engine->mmio_base); - I915_WRITE(RING_HWSTAM(engine->mmio_base), mask); - } + if (!IS_GEN_RANGE(dev_priv, 6, 7)) + return; - I915_WRITE(mmio, engine->status_page.ggtt_offset); - POSTING_READ(mmio); + /* ring should be idle before issuing a sync flush*/ + WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0); - /* Flush the TLB for this page */ - if (IS_GEN(dev_priv, 6, 7)) { - i915_reg_t reg = RING_INSTPM(engine->mmio_base); + I915_WRITE(instpm, + _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE | + INSTPM_SYNC_FLUSH)); + if (intel_wait_for_register(dev_priv, + instpm, INSTPM_SYNC_FLUSH, 0, + 1000)) + DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n", + engine->name); +} - /* ring should be idle before issuing a sync flush*/ - WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0); +static void ring_setup_status_page(struct intel_engine_cs *engine) +{ + set_hwsp(engine, engine->status_page.ggtt_offset); + set_hwstam(engine, ~0u); - I915_WRITE(reg, - _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE | - INSTPM_SYNC_FLUSH)); - if (intel_wait_for_register(dev_priv, - reg, INSTPM_SYNC_FLUSH, 0, - 1000)) - DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n", - engine->name); - } + flush_cs_tlb(engine); } static bool stop_ring(struct intel_engine_cs *engine) @@ -529,17 +643,10 @@ static int init_ring_common(struct intel_engine_cs *engine) if (HWS_NEEDS_PHYSICAL(dev_priv)) ring_setup_phys_status_page(engine); else - intel_ring_setup_status_page(engine); + ring_setup_status_page(engine); intel_engine_reset_breadcrumbs(engine); - if (HAS_LEGACY_SEMAPHORES(engine->i915)) { - I915_WRITE(RING_SYNC_0(engine->mmio_base), 0); - I915_WRITE(RING_SYNC_1(engine->mmio_base), 0); - if (HAS_VEBOX(dev_priv)) - I915_WRITE(RING_SYNC_2(engine->mmio_base), 0); - } - /* Enforce ordering by reading HEAD register back */ I915_READ_HEAD(engine); @@ -603,10 +710,6 @@ out: static struct i915_request *reset_prepare(struct intel_engine_cs *engine) { intel_engine_stop_cs(engine); - - if (engine->irq_seqno_barrier) - engine->irq_seqno_barrier(engine); - return i915_gem_find_active_request(engine); } @@ -679,7 +782,7 @@ static int init_render_ring(struct intel_engine_cs *engine) return ret; /* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */ - if (IS_GEN(dev_priv, 4, 6)) + if (IS_GEN_RANGE(dev_priv, 4, 6)) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); /* We need to disable the AsyncFlip performance optimisations in order @@ -688,22 +791,22 @@ static int init_render_ring(struct intel_engine_cs *engine) * * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv */ - if (IS_GEN(dev_priv, 6, 7)) + if (IS_GEN_RANGE(dev_priv, 6, 7)) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); /* Required for the hardware to program scanline values for waiting */ /* WaEnableFlushTlbInvalidationMode:snb */ - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT)); /* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */ - if (IS_GEN7(dev_priv)) + if (IS_GEN(dev_priv, 7)) I915_WRITE(GFX_MODE_GEN7, _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) | _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { /* From the Sandybridge PRM, volume 1 part 3, page 24: * "If this bit is set, STCunit will have LRA as replacement * policy. [...] This bit must be reset. LRA replacement @@ -713,7 +816,7 @@ static int init_render_ring(struct intel_engine_cs *engine) _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); } - if (IS_GEN(dev_priv, 6, 7)) + if (IS_GEN_RANGE(dev_priv, 6, 7)) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); if (INTEL_GEN(dev_priv) >= 6) @@ -722,33 +825,6 @@ static int init_render_ring(struct intel_engine_cs *engine) return 0; } -static u32 *gen6_signal(struct i915_request *rq, u32 *cs) -{ - struct drm_i915_private *dev_priv = rq->i915; - struct intel_engine_cs *engine; - enum intel_engine_id id; - int num_rings = 0; - - for_each_engine(engine, dev_priv, id) { - i915_reg_t mbox_reg; - - if (!(BIT(engine->hw_id) & GEN6_SEMAPHORES_MASK)) - continue; - - mbox_reg = rq->engine->semaphore.mbox.signal[engine->hw_id]; - if (i915_mmio_reg_valid(mbox_reg)) { - *cs++ = MI_LOAD_REGISTER_IMM(1); - *cs++ = i915_mmio_reg_offset(mbox_reg); - *cs++ = rq->global_seqno; - num_rings++; - } - } - if (num_rings & 1) - *cs++ = MI_NOOP; - - return cs; -} - static void cancel_requests(struct intel_engine_cs *engine) { struct i915_request *request; @@ -788,92 +864,41 @@ static void i9xx_submit_request(struct i915_request *request) static void i9xx_emit_breadcrumb(struct i915_request *rq, u32 *cs) { + *cs++ = MI_FLUSH; + *cs++ = MI_STORE_DWORD_INDEX; - *cs++ = I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT; + *cs++ = I915_GEM_HWS_INDEX_ADDR; *cs++ = rq->global_seqno; + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; rq->tail = intel_ring_offset(rq, cs); assert_ring_tail_valid(rq->ring, rq->tail); } +static const int i9xx_emit_breadcrumb_sz = 6; -static const int i9xx_emit_breadcrumb_sz = 4; - -static void gen6_sema_emit_breadcrumb(struct i915_request *rq, u32 *cs) -{ - return i9xx_emit_breadcrumb(rq, rq->engine->semaphore.signal(rq, cs)); -} - -static int -gen6_ring_sync_to(struct i915_request *rq, struct i915_request *signal) +#define GEN5_WA_STORES 8 /* must be at least 1! */ +static void gen5_emit_breadcrumb(struct i915_request *rq, u32 *cs) { - u32 dw1 = MI_SEMAPHORE_MBOX | - MI_SEMAPHORE_COMPARE | - MI_SEMAPHORE_REGISTER; - u32 wait_mbox = signal->engine->semaphore.mbox.wait[rq->engine->hw_id]; - u32 *cs; - - WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID); - - cs = intel_ring_begin(rq, 4); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = dw1 | wait_mbox; - /* Throughout all of the GEM code, seqno passed implies our current - * seqno is >= the last seqno executed. However for hardware the - * comparison is strictly greater than. - */ - *cs++ = signal->global_seqno - 1; - *cs++ = 0; - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); + int i; - return 0; -} + *cs++ = MI_FLUSH; -static void -gen5_seqno_barrier(struct intel_engine_cs *engine) -{ - /* MI_STORE are internally buffered by the GPU and not flushed - * either by MI_FLUSH or SyncFlush or any other combination of - * MI commands. - * - * "Only the submission of the store operation is guaranteed. - * The write result will be complete (coherent) some time later - * (this is practically a finite period but there is no guaranteed - * latency)." - * - * Empirically, we observe that we need a delay of at least 75us to - * be sure that the seqno write is visible by the CPU. - */ - usleep_range(125, 250); -} + BUILD_BUG_ON(GEN5_WA_STORES < 1); + for (i = 0; i < GEN5_WA_STORES; i++) { + *cs++ = MI_STORE_DWORD_INDEX; + *cs++ = I915_GEM_HWS_INDEX_ADDR; + *cs++ = rq->global_seqno; + } -static void -gen6_seqno_barrier(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; + *cs++ = MI_USER_INTERRUPT; - /* Workaround to force correct ordering between irq and seqno writes on - * ivb (and maybe also on snb) by reading from a CS register (like - * ACTHD) before reading the status page. - * - * Note that this effectively stalls the read by the time it takes to - * do a memory transaction, which more or less ensures that the write - * from the GPU has sufficient time to invalidate the CPU cacheline. - * Alternatively we could delay the interrupt from the CS ring to give - * the write time to land, but that would incur a delay after every - * batch i.e. much more frequent than a delay when waiting for the - * interrupt (with the same net latency). - * - * Also note that to prevent whole machine hangs on gen7, we have to - * take the spinlock to guard against concurrent cacheline access. - */ - spin_lock_irq(&dev_priv->uncore.lock); - POSTING_READ_FW(RING_ACTHD(engine->mmio_base)); - spin_unlock_irq(&dev_priv->uncore.lock); + rq->tail = intel_ring_offset(rq, cs); + assert_ring_tail_valid(rq->ring, rq->tail); } +static const int gen5_emit_breadcrumb_sz = GEN5_WA_STORES * 3 + 2; +#undef GEN5_WA_STORES static void gen5_irq_enable(struct intel_engine_cs *engine) @@ -948,6 +973,10 @@ gen6_irq_enable(struct intel_engine_cs *engine) I915_WRITE_IMR(engine, ~(engine->irq_enable_mask | engine->irq_keep_mask)); + + /* Flush/delay to ensure the RING_IMR is active before the GT IMR */ + POSTING_READ_FW(RING_IMR(engine->mmio_base)); + gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask); } @@ -966,6 +995,10 @@ hsw_vebox_irq_enable(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; I915_WRITE_IMR(engine, ~engine->irq_enable_mask); + + /* Flush/delay to ensure the RING_IMR is active before the GT IMR */ + POSTING_READ_FW(RING_IMR(engine->mmio_base)); + gen6_unmask_pm_irq(dev_priv, engine->irq_enable_mask); } @@ -1581,10 +1614,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) struct intel_engine_cs *engine = rq->engine; enum intel_engine_id id; const int num_rings = - /* Use an extended w/a on gen7 if signalling from other rings */ - (HAS_LEGACY_SEMAPHORES(i915) && IS_GEN7(i915)) ? - INTEL_INFO(i915)->num_rings - 1 : - 0; + IS_HSW_GT1(i915) ? RUNTIME_INFO(i915)->num_rings - 1 : 0; bool force_restore = false; int len; u32 *cs; @@ -1597,7 +1627,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) flags |= MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN; len = 4; - if (IS_GEN7(i915)) + if (IS_GEN(i915, 7)) len += 2 + (num_rings ? 4*num_rings + 6 : 0); if (flags & MI_FORCE_RESTORE) { GEM_BUG_ON(flags & MI_RESTORE_INHIBIT); @@ -1611,7 +1641,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) return PTR_ERR(cs); /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */ - if (IS_GEN7(i915)) { + if (IS_GEN(i915, 7)) { *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; if (num_rings) { struct intel_engine_cs *signaller; @@ -1658,7 +1688,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) */ *cs++ = MI_NOOP; - if (IS_GEN7(i915)) { + if (IS_GEN(i915, 7)) { if (num_rings) { struct intel_engine_cs *signaller; i915_reg_t last_reg = {}; /* keep gcc quiet */ @@ -1829,17 +1859,19 @@ static int ring_request_alloc(struct i915_request *request) GEM_BUG_ON(!request->hw_context->pin_count); - /* Flush enough space to reduce the likelihood of waiting after + /* + * Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just * have to repeat work. */ request->reserved_space += LEGACY_REQUEST_SIZE; - ret = intel_ring_wait_for_space(request->ring, request->reserved_space); + ret = switch_context(request); if (ret) return ret; - ret = switch_context(request); + /* Unconditionally invalidate GPU caches and TLBs. */ + ret = request->engine->emit_flush(request, EMIT_INVALIDATE); if (ret) return ret; @@ -1881,22 +1913,6 @@ static noinline int wait_for_space(struct intel_ring *ring, unsigned int bytes) return 0; } -int intel_ring_wait_for_space(struct intel_ring *ring, unsigned int bytes) -{ - GEM_BUG_ON(bytes > ring->effective_size); - if (unlikely(bytes > ring->effective_size - ring->emit)) - bytes += ring->size - ring->emit; - - if (unlikely(bytes > ring->space)) { - int ret = wait_for_space(ring, bytes); - if (unlikely(ret)) - return ret; - } - - GEM_BUG_ON(ring->space < bytes); - return 0; -} - u32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords) { struct intel_ring *ring = rq->ring; @@ -2129,77 +2145,15 @@ static int gen6_ring_flush(struct i915_request *rq, u32 mode) return gen6_flush_dw(rq, mode, MI_INVALIDATE_TLB); } -static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv, - struct intel_engine_cs *engine) -{ - int i; - - if (!HAS_LEGACY_SEMAPHORES(dev_priv)) - return; - - GEM_BUG_ON(INTEL_GEN(dev_priv) < 6); - engine->semaphore.sync_to = gen6_ring_sync_to; - engine->semaphore.signal = gen6_signal; - - /* - * The current semaphore is only applied on pre-gen8 - * platform. And there is no VCS2 ring on the pre-gen8 - * platform. So the semaphore between RCS and VCS2 is - * initialized as INVALID. - */ - for (i = 0; i < GEN6_NUM_SEMAPHORES; i++) { - static const struct { - u32 wait_mbox; - i915_reg_t mbox_reg; - } sem_data[GEN6_NUM_SEMAPHORES][GEN6_NUM_SEMAPHORES] = { - [RCS_HW] = { - [VCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_RV, .mbox_reg = GEN6_VRSYNC }, - [BCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_RB, .mbox_reg = GEN6_BRSYNC }, - [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_RVE, .mbox_reg = GEN6_VERSYNC }, - }, - [VCS_HW] = { - [RCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VR, .mbox_reg = GEN6_RVSYNC }, - [BCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VB, .mbox_reg = GEN6_BVSYNC }, - [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VVE, .mbox_reg = GEN6_VEVSYNC }, - }, - [BCS_HW] = { - [RCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_BR, .mbox_reg = GEN6_RBSYNC }, - [VCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_BV, .mbox_reg = GEN6_VBSYNC }, - [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_BVE, .mbox_reg = GEN6_VEBSYNC }, - }, - [VECS_HW] = { - [RCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VER, .mbox_reg = GEN6_RVESYNC }, - [VCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VEV, .mbox_reg = GEN6_VVESYNC }, - [BCS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VEB, .mbox_reg = GEN6_BVESYNC }, - }, - }; - u32 wait_mbox; - i915_reg_t mbox_reg; - - if (i == engine->hw_id) { - wait_mbox = MI_SEMAPHORE_SYNC_INVALID; - mbox_reg = GEN6_NOSYNC; - } else { - wait_mbox = sem_data[engine->hw_id][i].wait_mbox; - mbox_reg = sem_data[engine->hw_id][i].mbox_reg; - } - - engine->semaphore.mbox.wait[i] = wait_mbox; - engine->semaphore.mbox.signal[i] = mbox_reg; - } -} - static void intel_ring_init_irq(struct drm_i915_private *dev_priv, struct intel_engine_cs *engine) { if (INTEL_GEN(dev_priv) >= 6) { engine->irq_enable = gen6_irq_enable; engine->irq_disable = gen6_irq_disable; - engine->irq_seqno_barrier = gen6_seqno_barrier; } else if (INTEL_GEN(dev_priv) >= 5) { engine->irq_enable = gen5_irq_enable; engine->irq_disable = gen5_irq_disable; - engine->irq_seqno_barrier = gen5_seqno_barrier; } else if (INTEL_GEN(dev_priv) >= 3) { engine->irq_enable = i9xx_irq_enable; engine->irq_disable = i9xx_irq_disable; @@ -2231,7 +2185,6 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, GEM_BUG_ON(INTEL_GEN(dev_priv) >= 8); intel_ring_init_irq(dev_priv, engine); - intel_ring_init_semaphores(dev_priv, engine); engine->init_hw = init_ring_common; engine->reset.prepare = reset_prepare; @@ -2243,15 +2196,9 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, engine->emit_breadcrumb = i9xx_emit_breadcrumb; engine->emit_breadcrumb_sz = i9xx_emit_breadcrumb_sz; - if (HAS_LEGACY_SEMAPHORES(dev_priv)) { - int num_rings; - - engine->emit_breadcrumb = gen6_sema_emit_breadcrumb; - - num_rings = INTEL_INFO(dev_priv)->num_rings - 1; - engine->emit_breadcrumb_sz += num_rings * 3; - if (num_rings & 1) - engine->emit_breadcrumb_sz++; + if (IS_GEN(dev_priv, 5)) { + engine->emit_breadcrumb = gen5_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen5_emit_breadcrumb_sz; } engine->set_default_submission = i9xx_set_default_submission; @@ -2278,12 +2225,17 @@ int intel_init_render_ring_buffer(struct intel_engine_cs *engine) engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT; - if (INTEL_GEN(dev_priv) >= 6) { + if (INTEL_GEN(dev_priv) >= 7) { engine->init_context = intel_rcs_ctx_init; engine->emit_flush = gen7_render_ring_flush; - if (IS_GEN6(dev_priv)) - engine->emit_flush = gen6_render_ring_flush; - } else if (IS_GEN5(dev_priv)) { + engine->emit_breadcrumb = gen7_rcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen7_rcs_emit_breadcrumb_sz; + } else if (IS_GEN(dev_priv, 6)) { + engine->init_context = intel_rcs_ctx_init; + engine->emit_flush = gen6_render_ring_flush; + engine->emit_breadcrumb = gen6_rcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen6_rcs_emit_breadcrumb_sz; + } else if (IS_GEN(dev_priv, 5)) { engine->emit_flush = gen4_render_ring_flush; } else { if (INTEL_GEN(dev_priv) < 4) @@ -2313,13 +2265,21 @@ int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine) if (INTEL_GEN(dev_priv) >= 6) { /* gen6 bsd needs a special wa for tail updates */ - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) engine->set_default_submission = gen6_bsd_set_default_submission; engine->emit_flush = gen6_bsd_ring_flush; engine->irq_enable_mask = GT_BSD_USER_INTERRUPT; + + if (IS_GEN(dev_priv, 6)) { + engine->emit_breadcrumb = gen6_xcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen6_xcs_emit_breadcrumb_sz; + } else { + engine->emit_breadcrumb = gen7_xcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen7_xcs_emit_breadcrumb_sz; + } } else { engine->emit_flush = bsd_ring_flush; - if (IS_GEN5(dev_priv)) + if (IS_GEN(dev_priv, 5)) engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT; else engine->irq_enable_mask = I915_BSD_USER_INTERRUPT; @@ -2332,11 +2292,21 @@ int intel_init_blt_ring_buffer(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + GEM_BUG_ON(INTEL_GEN(dev_priv) < 6); + intel_ring_default_vfuncs(dev_priv, engine); engine->emit_flush = gen6_ring_flush; engine->irq_enable_mask = GT_BLT_USER_INTERRUPT; + if (IS_GEN(dev_priv, 6)) { + engine->emit_breadcrumb = gen6_xcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen6_xcs_emit_breadcrumb_sz; + } else { + engine->emit_breadcrumb = gen7_xcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen7_xcs_emit_breadcrumb_sz; + } + return intel_init_ring_buffer(engine); } @@ -2344,6 +2314,8 @@ int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + GEM_BUG_ON(INTEL_GEN(dev_priv) < 7); + intel_ring_default_vfuncs(dev_priv, engine); engine->emit_flush = gen6_ring_flush; @@ -2351,5 +2323,8 @@ int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine) engine->irq_enable = hsw_vebox_irq_enable; engine->irq_disable = hsw_vebox_irq_disable; + engine->emit_breadcrumb = gen7_xcs_emit_breadcrumb; + engine->emit_breadcrumb_sz = gen7_xcs_emit_breadcrumb_sz; + return intel_init_ring_buffer(engine); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 72edaa7ff411..3c1366c58cf3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -94,12 +94,12 @@ hangcheck_action_to_str(const enum intel_engine_hangcheck_action a) #define I915_MAX_SUBSLICES 8 #define instdone_slice_mask(dev_priv__) \ - (IS_GEN7(dev_priv__) ? \ - 1 : INTEL_INFO(dev_priv__)->sseu.slice_mask) + (IS_GEN(dev_priv__, 7) ? \ + 1 : RUNTIME_INFO(dev_priv__)->sseu.slice_mask) #define instdone_subslice_mask(dev_priv__) \ - (IS_GEN7(dev_priv__) ? \ - 1 : INTEL_INFO(dev_priv__)->sseu.subslice_mask[0]) + (IS_GEN(dev_priv__, 7) ? \ + 1 : RUNTIME_INFO(dev_priv__)->sseu.subslice_mask[0]) #define for_each_instdone_slice_subslice(dev_priv__, slice__, subslice__) \ for ((slice__) = 0, (subslice__) = 0; \ @@ -365,9 +365,6 @@ struct intel_engine_cs { struct drm_i915_gem_object *default_state; void *pinned_default_state; - unsigned long irq_posted; -#define ENGINE_IRQ_BREADCRUMB 0 - /* Rather than have every client wait upon all user interrupts, * with the herd waking after every interrupt and each doing the * heavyweight seqno dance, we delegate the task (of being the @@ -501,69 +498,8 @@ struct intel_engine_cs { */ void (*cancel_requests)(struct intel_engine_cs *engine); - /* Some chipsets are not quite as coherent as advertised and need - * an expensive kick to force a true read of the up-to-date seqno. - * However, the up-to-date seqno is not always required and the last - * seen value is good enough. Note that the seqno will always be - * monotonic, even if not coherent. - */ - void (*irq_seqno_barrier)(struct intel_engine_cs *engine); void (*cleanup)(struct intel_engine_cs *engine); - /* GEN8 signal/wait table - never trust comments! - * signal to signal to signal to signal to signal to - * RCS VCS BCS VECS VCS2 - * -------------------------------------------------------------------- - * RCS | NOP (0x00) | VCS (0x08) | BCS (0x10) | VECS (0x18) | VCS2 (0x20) | - * |------------------------------------------------------------------- - * VCS | RCS (0x28) | NOP (0x30) | BCS (0x38) | VECS (0x40) | VCS2 (0x48) | - * |------------------------------------------------------------------- - * BCS | RCS (0x50) | VCS (0x58) | NOP (0x60) | VECS (0x68) | VCS2 (0x70) | - * |------------------------------------------------------------------- - * VECS | RCS (0x78) | VCS (0x80) | BCS (0x88) | NOP (0x90) | VCS2 (0x98) | - * |------------------------------------------------------------------- - * VCS2 | RCS (0xa0) | VCS (0xa8) | BCS (0xb0) | VECS (0xb8) | NOP (0xc0) | - * |------------------------------------------------------------------- - * - * Generalization: - * f(x, y) := (x->id * NUM_RINGS * seqno_size) + (seqno_size * y->id) - * ie. transpose of g(x, y) - * - * sync from sync from sync from sync from sync from - * RCS VCS BCS VECS VCS2 - * -------------------------------------------------------------------- - * RCS | NOP (0x00) | VCS (0x28) | BCS (0x50) | VECS (0x78) | VCS2 (0xa0) | - * |------------------------------------------------------------------- - * VCS | RCS (0x08) | NOP (0x30) | BCS (0x58) | VECS (0x80) | VCS2 (0xa8) | - * |------------------------------------------------------------------- - * BCS | RCS (0x10) | VCS (0x38) | NOP (0x60) | VECS (0x88) | VCS2 (0xb0) | - * |------------------------------------------------------------------- - * VECS | RCS (0x18) | VCS (0x40) | BCS (0x68) | NOP (0x90) | VCS2 (0xb8) | - * |------------------------------------------------------------------- - * VCS2 | RCS (0x20) | VCS (0x48) | BCS (0x70) | VECS (0x98) | NOP (0xc0) | - * |------------------------------------------------------------------- - * - * Generalization: - * g(x, y) := (y->id * NUM_RINGS * seqno_size) + (seqno_size * x->id) - * ie. transpose of f(x, y) - */ - struct { -#define GEN6_SEMAPHORE_LAST VECS_HW -#define GEN6_NUM_SEMAPHORES (GEN6_SEMAPHORE_LAST + 1) -#define GEN6_SEMAPHORES_MASK GENMASK(GEN6_SEMAPHORE_LAST, 0) - struct { - /* our mbox written by others */ - u32 wait[GEN6_NUM_SEMAPHORES]; - /* mboxes this ring signals to */ - i915_reg_t signal[GEN6_NUM_SEMAPHORES]; - } mbox; - - /* AKA wait() */ - int (*sync_to)(struct i915_request *rq, - struct i915_request *signal); - u32 *(*signal)(struct i915_request *rq, u32 *cs); - } semaphore; - struct intel_engine_execlists execlists; /* Contexts are pinned whilst they are active on the GPU. The last @@ -808,7 +744,6 @@ void intel_legacy_submission_resume(struct drm_i915_private *dev_priv); int __must_check intel_ring_cacheline_align(struct i915_request *rq); -int intel_ring_wait_for_space(struct intel_ring *ring, unsigned int bytes); u32 __must_check *intel_ring_begin(struct i915_request *rq, unsigned int n); static inline void intel_ring_advance(struct i915_request *rq, u32 *cs) @@ -889,7 +824,7 @@ intel_ring_set_tail(struct intel_ring *ring, unsigned int tail) return tail; } -void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno); +void intel_engine_write_global_seqno(struct intel_engine_cs *engine, u32 seqno); void intel_engine_setup_common(struct intel_engine_cs *engine); int intel_engine_init_common(struct intel_engine_cs *engine); @@ -903,6 +838,8 @@ int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine); int intel_engine_stop_cs(struct intel_engine_cs *engine); void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine); +void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask); + u64 intel_engine_get_active_head(const struct intel_engine_cs *engine); u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine); @@ -947,15 +884,6 @@ static inline bool intel_engine_has_started(struct intel_engine_cs *engine, void intel_engine_get_instdone(struct intel_engine_cs *engine, struct intel_instdone *instdone); -/* - * Arbitrary size for largest possible 'add request' sequence. The code paths - * are complex and variable. Empirical measurement shows that the worst case - * is BDW at 192 bytes (6 + 6 + 36 dwords), then ILK at 136 bytes. However, - * we need to allocate double the largest single packet within that emission - * to account for tail wraparound (so 6 + 6 + 72 dwords for BDW). - */ -#define MIN_SPACE_FOR_ADD_REQUEST 336 - static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine) { return engine->status_page.ggtt_offset + I915_GEM_HWS_INDEX_ADDR; @@ -1055,7 +983,7 @@ static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset) } static inline u32 * -gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset) +gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset, u32 flags) { /* We're using qword write, offset should be aligned to 8 bytes. */ GEM_BUG_ON(!IS_ALIGNED(gtt_offset, 8)); @@ -1065,8 +993,7 @@ gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset) * following the batch. */ *cs++ = GFX_OP_PIPE_CONTROL(6); - *cs++ = PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_QW_WRITE; + *cs++ = flags | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_GLOBAL_GTT_IVB; *cs++ = gtt_offset; *cs++ = 0; *cs++ = value; @@ -1092,7 +1019,7 @@ gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset) return cs; } -void intel_engines_sanitize(struct drm_i915_private *i915); +void intel_engines_sanitize(struct drm_i915_private *i915, bool force); bool intel_engine_is_idle(struct intel_engine_cs *engine); bool intel_engines_are_idle(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 4350a5270423..9e9501f82f06 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -509,7 +509,7 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, * BIOS's own request bits, which are forced-on for these power wells * when exiting DC5/6. */ - if (IS_GEN9(dev_priv) && !IS_GEN9_LP(dev_priv) && + if (IS_GEN(dev_priv, 9) && !IS_GEN9_LP(dev_priv) && (id == SKL_DISP_PW_1 || id == SKL_DISP_PW_MISC_IO)) val |= I915_READ(regs->bios); @@ -3058,7 +3058,7 @@ static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv, * suspend/resume, so allow it unconditionally. */ mask = DC_STATE_EN_DC9; - } else if (IS_GEN10(dev_priv) || IS_GEN9_BC(dev_priv)) { + } else if (IS_GEN(dev_priv, 10) || IS_GEN9_BC(dev_priv)) { max_dc = 2; mask = 0; } else if (IS_GEN9_LP(dev_priv)) { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 5805ec1aba12..df2d830a7405 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/export.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -103,7 +102,6 @@ struct intel_sdvo { bool has_hdmi_monitor; bool has_hdmi_audio; - bool rgb_quant_range_selectable; /* DDC bus used by this SDVO encoder */ uint8_t ddc_bus; @@ -981,29 +979,30 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, } static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, - const struct intel_crtc_state *pipe_config) + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state) { + const struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)]; union hdmi_infoframe frame; int ret; ssize_t len; ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - &pipe_config->base.adjusted_mode, - false); + conn_state->connector, + adjusted_mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return false; } - if (intel_sdvo->rgb_quant_range_selectable) { - if (pipe_config->limited_color_range) - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_LIMITED; - else - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_FULL; - } + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + conn_state->connector, + adjusted_mode, + pipe_config->limited_color_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data)); if (len < 0) @@ -1108,9 +1107,9 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) pipe_config->clock_set = true; } -static bool intel_sdvo_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_sdvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo_connector_state *intel_sdvo_state = @@ -1135,7 +1134,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, */ if (IS_TV(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) - return false; + return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, intel_sdvo_connector, @@ -1145,7 +1144,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, } else if (IS_LVDS(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, intel_sdvo_connector->base.panel.fixed_mode)) - return false; + return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, intel_sdvo_connector, @@ -1154,7 +1153,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* * Make the CRTC code factor in the SDVO pixel multiplier. The @@ -1194,7 +1193,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, if (intel_sdvo_connector->is_hdmi) adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; - return true; + return 0; } #define UPDATE_PROPERTY(input, NAME) \ @@ -1316,7 +1315,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); - intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state); + intel_sdvo_set_avi_infoframe(intel_sdvo, + crtc_state, conn_state); } else intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); @@ -1802,8 +1802,6 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) if (intel_sdvo_connector->is_hdmi) { intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); - intel_sdvo->rgb_quant_range_selectable = - drm_rgb_quant_range_selectable(edid); } } else status = connector_status_disconnected; @@ -1852,7 +1850,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) intel_sdvo->has_hdmi_monitor = false; intel_sdvo->has_hdmi_audio = false; - intel_sdvo->rgb_quant_range_selectable = false; if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index d2e003d8f3db..8f3982c03925 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -29,7 +29,6 @@ * registers; newer ones are much simpler and we can use the new DRM plane * support. */ -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_fourcc.h> @@ -1087,7 +1086,7 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE; - if (IS_GEN6(dev_priv)) + if (IS_GEN(dev_priv, 6)) dvscntr |= DVS_TRICKLE_FEED_DISABLE; switch (fb->format->format) { @@ -1983,7 +1982,7 @@ static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) return false; - if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) return false; if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) @@ -2163,7 +2162,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane->check_plane = g4x_sprite_check; modifiers = i9xx_plane_format_modifiers; - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { formats = snb_plane_formats; num_formats = ARRAY_SIZE(snb_plane_formats); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 860f306a23ba..bd5536f0ec92 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -30,7 +30,6 @@ * Integrated TV-out support for the 915GM and 945GM. */ -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -870,7 +869,7 @@ intel_tv_get_config(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; } -static bool +static int intel_tv_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -880,10 +879,10 @@ intel_tv_compute_config(struct intel_encoder *encoder, &pipe_config->base.adjusted_mode; if (!tv_mode) - return false; + return -EINVAL; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; adjusted_mode->crtc_clock = tv_mode->clock; @@ -898,7 +897,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, * or whether userspace is doing something stupid. */ - return true; + return 0; } static void diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index b34c318b238d..731b82afe636 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -71,7 +71,7 @@ static int __get_default_guc_log_level(struct drm_i915_private *i915) { int guc_log_level; - if (!HAS_GUC(i915) || !intel_uc_is_using_guc()) + if (!HAS_GUC(i915) || !intel_uc_is_using_guc(i915)) guc_log_level = GUC_LOG_LEVEL_DISABLED; else if (IS_ENABLED(CONFIG_DRM_I915_DEBUG) || IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) @@ -112,11 +112,11 @@ static void sanitize_options_early(struct drm_i915_private *i915) DRM_DEBUG_DRIVER("enable_guc=%d (submission:%s huc:%s)\n", i915_modparams.enable_guc, - yesno(intel_uc_is_using_guc_submission()), - yesno(intel_uc_is_using_huc())); + yesno(intel_uc_is_using_guc_submission(i915)), + yesno(intel_uc_is_using_huc(i915))); /* Verify GuC firmware availability */ - if (intel_uc_is_using_guc() && !intel_uc_fw_is_selected(guc_fw)) { + if (intel_uc_is_using_guc(i915) && !intel_uc_fw_is_selected(guc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, !HAS_GUC(i915) ? "no GuC hardware" : @@ -124,7 +124,7 @@ static void sanitize_options_early(struct drm_i915_private *i915) } /* Verify HuC firmware availability */ - if (intel_uc_is_using_huc() && !intel_uc_fw_is_selected(huc_fw)) { + if (intel_uc_is_using_huc(i915) && !intel_uc_fw_is_selected(huc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, !HAS_HUC(i915) ? "no HuC hardware" : @@ -136,7 +136,7 @@ static void sanitize_options_early(struct drm_i915_private *i915) i915_modparams.guc_log_level = __get_default_guc_log_level(i915); - if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc()) { + if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc(i915)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "guc_log_level", i915_modparams.guc_log_level, !HAS_GUC(i915) ? "no GuC hardware" : @@ -354,7 +354,7 @@ int intel_uc_init_hw(struct drm_i915_private *i915) /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ - if (IS_GEN9(i915)) + if (IS_GEN(i915, 9)) attempts = 3; else attempts = 1; diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 25d73ada74ae..870faf9011b9 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -41,19 +41,19 @@ void intel_uc_fini(struct drm_i915_private *dev_priv); int intel_uc_suspend(struct drm_i915_private *dev_priv); int intel_uc_resume(struct drm_i915_private *dev_priv); -static inline bool intel_uc_is_using_guc(void) +static inline bool intel_uc_is_using_guc(struct drm_i915_private *i915) { GEM_BUG_ON(i915_modparams.enable_guc < 0); return i915_modparams.enable_guc > 0; } -static inline bool intel_uc_is_using_guc_submission(void) +static inline bool intel_uc_is_using_guc_submission(struct drm_i915_private *i915) { GEM_BUG_ON(i915_modparams.enable_guc < 0); return i915_modparams.enable_guc & ENABLE_GUC_SUBMISSION; } -static inline bool intel_uc_is_using_huc(void) +static inline bool intel_uc_is_using_huc(struct drm_i915_private *i915) { GEM_BUG_ON(i915_modparams.enable_guc < 0); return i915_modparams.enable_guc & ENABLE_GUC_LOAD_HUC; diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c index fd496416087c..becf05ebae4d 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/intel_uc_fw.c @@ -46,12 +46,17 @@ void intel_uc_fw_fetch(struct drm_i915_private *dev_priv, size_t size; int err; + if (!uc_fw->path) { + dev_info(dev_priv->drm.dev, + "%s: No firmware was defined for %s!\n", + intel_uc_fw_type_repr(uc_fw->type), + intel_platform_name(INTEL_INFO(dev_priv)->platform)); + return; + } + DRM_DEBUG_DRIVER("%s fw fetch %s\n", intel_uc_fw_type_repr(uc_fw->type), uc_fw->path); - if (!uc_fw->path) - return; - uc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING; DRM_DEBUG_DRIVER("%s fw fetch %s\n", intel_uc_fw_type_repr(uc_fw->type), diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 9289515108c3..fff468f17d2d 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -528,7 +528,7 @@ check_for_unclaimed_mmio(struct drm_i915_private *dev_priv) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) ret |= vlv_check_for_unclaimed_mmio(dev_priv); - if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) + if (IS_GEN_RANGE(dev_priv, 6, 7)) ret |= gen6_check_for_fifo_debug(dev_priv); return ret; @@ -556,7 +556,7 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv, dev_priv->uncore.funcs.force_wake_get(dev_priv, restore_forcewake); - if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) + if (IS_GEN_RANGE(dev_priv, 6, 7)) dev_priv->uncore.fifo_count = fifo_free_entries(dev_priv); spin_unlock_irq(&dev_priv->uncore.lock); @@ -1398,7 +1398,7 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) <= 5 || intel_vgpu_active(dev_priv)) return; - if (IS_GEN6(dev_priv)) { + if (IS_GEN(dev_priv, 6)) { dev_priv->uncore.fw_reset = 0; dev_priv->uncore.fw_set = FORCEWAKE_KERNEL; dev_priv->uncore.fw_clear = 0; @@ -1437,7 +1437,7 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv) FORCEWAKE_MEDIA_VEBOX_GEN11(i), FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i)); } - } else if (IS_GEN10(dev_priv) || IS_GEN9(dev_priv)) { + } else if (IS_GEN_RANGE(dev_priv, 9, 10)) { dev_priv->uncore.funcs.force_wake_get = fw_domains_get_with_fallback; dev_priv->uncore.funcs.force_wake_put = fw_domains_put; @@ -1503,7 +1503,7 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv) fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER, FORCEWAKE, FORCEWAKE_ACK); } - } else if (IS_GEN6(dev_priv)) { + } else if (IS_GEN(dev_priv, 6)) { dev_priv->uncore.funcs.force_wake_get = fw_domains_get_with_thread_status; dev_priv->uncore.funcs.force_wake_put = fw_domains_put; @@ -1567,13 +1567,13 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) dev_priv->uncore.pmic_bus_access_nb.notifier_call = i915_pmic_bus_access_notifier; - if (IS_GEN(dev_priv, 2, 4) || intel_vgpu_active(dev_priv)) { + if (IS_GEN_RANGE(dev_priv, 2, 4) || intel_vgpu_active(dev_priv)) { ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen2); ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen2); - } else if (IS_GEN5(dev_priv)) { + } else if (IS_GEN(dev_priv, 5)) { ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen5); ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen5); - } else if (IS_GEN(dev_priv, 6, 7)) { + } else if (IS_GEN_RANGE(dev_priv, 6, 7)) { ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen6); if (IS_VALLEYVIEW(dev_priv)) { @@ -1582,7 +1582,7 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) } else { ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen6); } - } else if (IS_GEN8(dev_priv)) { + } else if (IS_GEN(dev_priv, 8)) { if (IS_CHERRYVIEW(dev_priv)) { ASSIGN_FW_DOMAINS_TABLE(__chv_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, fwtable); @@ -1592,7 +1592,7 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen8); ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen6); } - } else if (IS_GEN(dev_priv, 9, 10)) { + } else if (IS_GEN_RANGE(dev_priv, 9, 10)) { ASSIGN_FW_DOMAINS_TABLE(__gen9_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, fwtable); ASSIGN_READ_MMIO_VFUNCS(dev_priv, fwtable); @@ -1931,6 +1931,103 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, return gen6_hw_domain_reset(dev_priv, hw_mask); } +static u32 gen11_lock_sfc(struct drm_i915_private *dev_priv, + struct intel_engine_cs *engine) +{ + u8 vdbox_sfc_access = RUNTIME_INFO(dev_priv)->vdbox_sfc_access; + i915_reg_t sfc_forced_lock, sfc_forced_lock_ack; + u32 sfc_forced_lock_bit, sfc_forced_lock_ack_bit; + i915_reg_t sfc_usage; + u32 sfc_usage_bit; + u32 sfc_reset_bit; + + switch (engine->class) { + case VIDEO_DECODE_CLASS: + if ((BIT(engine->instance) & vdbox_sfc_access) == 0) + return 0; + + sfc_forced_lock = GEN11_VCS_SFC_FORCED_LOCK(engine); + sfc_forced_lock_bit = GEN11_VCS_SFC_FORCED_LOCK_BIT; + + sfc_forced_lock_ack = GEN11_VCS_SFC_LOCK_STATUS(engine); + sfc_forced_lock_ack_bit = GEN11_VCS_SFC_LOCK_ACK_BIT; + + sfc_usage = GEN11_VCS_SFC_LOCK_STATUS(engine); + sfc_usage_bit = GEN11_VCS_SFC_USAGE_BIT; + sfc_reset_bit = GEN11_VCS_SFC_RESET_BIT(engine->instance); + break; + + case VIDEO_ENHANCEMENT_CLASS: + sfc_forced_lock = GEN11_VECS_SFC_FORCED_LOCK(engine); + sfc_forced_lock_bit = GEN11_VECS_SFC_FORCED_LOCK_BIT; + + sfc_forced_lock_ack = GEN11_VECS_SFC_LOCK_ACK(engine); + sfc_forced_lock_ack_bit = GEN11_VECS_SFC_LOCK_ACK_BIT; + + sfc_usage = GEN11_VECS_SFC_USAGE(engine); + sfc_usage_bit = GEN11_VECS_SFC_USAGE_BIT; + sfc_reset_bit = GEN11_VECS_SFC_RESET_BIT(engine->instance); + break; + + default: + return 0; + } + + /* + * Tell the engine that a software reset is going to happen. The engine + * will then try to force lock the SFC (if currently locked, it will + * remain so until we tell the engine it is safe to unlock; if currently + * unlocked, it will ignore this and all new lock requests). If SFC + * ends up being locked to the engine we want to reset, we have to reset + * it as well (we will unlock it once the reset sequence is completed). + */ + I915_WRITE_FW(sfc_forced_lock, + I915_READ_FW(sfc_forced_lock) | sfc_forced_lock_bit); + + if (__intel_wait_for_register_fw(dev_priv, + sfc_forced_lock_ack, + sfc_forced_lock_ack_bit, + sfc_forced_lock_ack_bit, + 1000, 0, NULL)) { + DRM_DEBUG_DRIVER("Wait for SFC forced lock ack failed\n"); + return 0; + } + + if (I915_READ_FW(sfc_usage) & sfc_usage_bit) + return sfc_reset_bit; + + return 0; +} + +static void gen11_unlock_sfc(struct drm_i915_private *dev_priv, + struct intel_engine_cs *engine) +{ + u8 vdbox_sfc_access = RUNTIME_INFO(dev_priv)->vdbox_sfc_access; + i915_reg_t sfc_forced_lock; + u32 sfc_forced_lock_bit; + + switch (engine->class) { + case VIDEO_DECODE_CLASS: + if ((BIT(engine->instance) & vdbox_sfc_access) == 0) + return; + + sfc_forced_lock = GEN11_VCS_SFC_FORCED_LOCK(engine); + sfc_forced_lock_bit = GEN11_VCS_SFC_FORCED_LOCK_BIT; + break; + + case VIDEO_ENHANCEMENT_CLASS: + sfc_forced_lock = GEN11_VECS_SFC_FORCED_LOCK(engine); + sfc_forced_lock_bit = GEN11_VECS_SFC_FORCED_LOCK_BIT; + break; + + default: + return; + } + + I915_WRITE_FW(sfc_forced_lock, + I915_READ_FW(sfc_forced_lock) & ~sfc_forced_lock_bit); +} + /** * gen11_reset_engines - reset individual engines * @dev_priv: i915 device @@ -1947,7 +2044,6 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, static int gen11_reset_engines(struct drm_i915_private *dev_priv, unsigned int engine_mask) { - struct intel_engine_cs *engine; const u32 hw_engine_mask[I915_NUM_ENGINES] = { [RCS] = GEN11_GRDOM_RENDER, [BCS] = GEN11_GRDOM_BLT, @@ -1958,21 +2054,30 @@ static int gen11_reset_engines(struct drm_i915_private *dev_priv, [VECS] = GEN11_GRDOM_VECS, [VECS2] = GEN11_GRDOM_VECS2, }; + struct intel_engine_cs *engine; + unsigned int tmp; u32 hw_mask; + int ret; BUILD_BUG_ON(VECS2 + 1 != I915_NUM_ENGINES); if (engine_mask == ALL_ENGINES) { hw_mask = GEN11_GRDOM_FULL; } else { - unsigned int tmp; - hw_mask = 0; - for_each_engine_masked(engine, dev_priv, engine_mask, tmp) + for_each_engine_masked(engine, dev_priv, engine_mask, tmp) { hw_mask |= hw_engine_mask[engine->id]; + hw_mask |= gen11_lock_sfc(dev_priv, engine); + } } - return gen6_hw_domain_reset(dev_priv, hw_mask); + ret = gen6_hw_domain_reset(dev_priv, hw_mask); + + if (engine_mask != ALL_ENGINES) + for_each_engine_masked(engine, dev_priv, engine_mask, tmp) + gen11_unlock_sfc(dev_priv, engine); + + return ret; } /** @@ -2173,7 +2278,7 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv) return gen8_reset_engines; else if (INTEL_GEN(dev_priv) >= 6) return gen6_reset_engines; - else if (IS_GEN5(dev_priv)) + else if (IS_GEN(dev_priv, 5)) return ironlake_do_reset; else if (IS_G4X(dev_priv)) return g4x_do_reset; @@ -2256,7 +2361,7 @@ bool intel_has_gpu_reset(struct drm_i915_private *dev_priv) bool intel_has_reset_engine(struct drm_i915_private *dev_priv) { - return (dev_priv->info.has_reset_engine && + return (INTEL_INFO(dev_priv)->has_reset_engine && i915_modparams.reset >= 2); } @@ -2321,7 +2426,7 @@ intel_uncore_forcewake_for_read(struct drm_i915_private *dev_priv, } else if (INTEL_GEN(dev_priv) >= 6) { fw_domains = __gen6_reg_read_fw_domains(offset); } else { - WARN_ON(!IS_GEN(dev_priv, 2, 5)); + WARN_ON(!IS_GEN_RANGE(dev_priv, 2, 5)); fw_domains = 0; } @@ -2341,12 +2446,12 @@ intel_uncore_forcewake_for_write(struct drm_i915_private *dev_priv, fw_domains = __gen11_fwtable_reg_write_fw_domains(offset); } else if (HAS_FWTABLE(dev_priv) && !IS_VALLEYVIEW(dev_priv)) { fw_domains = __fwtable_reg_write_fw_domains(offset); - } else if (IS_GEN8(dev_priv)) { + } else if (IS_GEN(dev_priv, 8)) { fw_domains = __gen8_reg_write_fw_domains(offset); - } else if (IS_GEN(dev_priv, 6, 7)) { + } else if (IS_GEN_RANGE(dev_priv, 6, 7)) { fw_domains = FORCEWAKE_RENDER; } else { - WARN_ON(!IS_GEN(dev_priv, 2, 5)); + WARN_ON(!IS_GEN_RANGE(dev_priv, 2, 5)); fw_domains = 0; } diff --git a/drivers/gpu/drm/i915/intel_vdsc.c b/drivers/gpu/drm/i915/intel_vdsc.c index c56ba0e04044..48537827616f 100644 --- a/drivers/gpu/drm/i915/intel_vdsc.c +++ b/drivers/gpu/drm/i915/intel_vdsc.c @@ -6,7 +6,6 @@ * Manasi Navare <manasi.d.navare@intel.com> */ -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 92cb82dd0c07..f82a415ea2ba 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -130,11 +130,11 @@ static inline int check_hw_restriction(struct drm_i915_private *i915, { int err = 0; - if (IS_GEN9(i915)) + if (IS_GEN(i915, 9)) err = gen9_check_dword_gap(guc_wopcm_base, guc_wopcm_size); if (!err && - (IS_GEN9(i915) || IS_CNL_REVID(i915, CNL_REVID_A0, CNL_REVID_A0))) + (IS_GEN(i915, 9) || IS_CNL_REVID(i915, CNL_REVID_A0, CNL_REVID_A0))) err = gen9_check_huc_fw_fits(guc_wopcm_size, huc_fw_size); return err; @@ -163,7 +163,7 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) u32 guc_wopcm_rsvd; int err; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return 0; GEM_BUG_ON(!wopcm->size); diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 4f41e326f3f3..3210ad4e08f7 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -366,7 +366,7 @@ static void skl_tune_iz_hashing(struct intel_engine_cs *engine) * Only consider slices where one, and only one, subslice has 7 * EUs */ - if (!is_power_of_2(INTEL_INFO(i915)->sseu.subslice_7eu[i])) + if (!is_power_of_2(RUNTIME_INFO(i915)->sseu.subslice_7eu[i])) continue; /* @@ -375,7 +375,7 @@ static void skl_tune_iz_hashing(struct intel_engine_cs *engine) * * -> 0 <= ss <= 3; */ - ss = ffs(INTEL_INFO(i915)->sseu.subslice_7eu[i]) - 1; + ss = ffs(RUNTIME_INFO(i915)->sseu.subslice_7eu[i]) - 1; vals[i] = 3 - ss; } @@ -639,10 +639,9 @@ wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 val) wa_write_masked_or(wal, reg, val, val); } -static void gen9_gt_workarounds_init(struct drm_i915_private *i915) +static void +gen9_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - /* WaDisableKillLogic:bxt,skl,kbl */ if (!IS_COFFEELAKE(i915)) wa_write_or(wal, @@ -666,11 +665,10 @@ static void gen9_gt_workarounds_init(struct drm_i915_private *i915) BDW_DISABLE_HDC_INVALIDATION); } -static void skl_gt_workarounds_init(struct drm_i915_private *i915) +static void +skl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - gen9_gt_workarounds_init(i915); + gen9_gt_workarounds_init(i915, wal); /* WaDisableGafsUnitClkGating:skl */ wa_write_or(wal, @@ -684,11 +682,10 @@ static void skl_gt_workarounds_init(struct drm_i915_private *i915) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } -static void bxt_gt_workarounds_init(struct drm_i915_private *i915) +static void +bxt_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - gen9_gt_workarounds_init(i915); + gen9_gt_workarounds_init(i915, wal); /* WaInPlaceDecompressionHang:bxt */ wa_write_or(wal, @@ -696,11 +693,10 @@ static void bxt_gt_workarounds_init(struct drm_i915_private *i915) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } -static void kbl_gt_workarounds_init(struct drm_i915_private *i915) +static void +kbl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - gen9_gt_workarounds_init(i915); + gen9_gt_workarounds_init(i915, wal); /* WaDisableDynamicCreditSharing:kbl */ if (IS_KBL_REVID(i915, 0, KBL_REVID_B0)) @@ -719,16 +715,16 @@ static void kbl_gt_workarounds_init(struct drm_i915_private *i915) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } -static void glk_gt_workarounds_init(struct drm_i915_private *i915) +static void +glk_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - gen9_gt_workarounds_init(i915); + gen9_gt_workarounds_init(i915, wal); } -static void cfl_gt_workarounds_init(struct drm_i915_private *i915) +static void +cfl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - gen9_gt_workarounds_init(i915); + gen9_gt_workarounds_init(i915, wal); /* WaDisableGafsUnitClkGating:cfl */ wa_write_or(wal, @@ -741,10 +737,10 @@ static void cfl_gt_workarounds_init(struct drm_i915_private *i915) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } -static void wa_init_mcr(struct drm_i915_private *dev_priv) +static void +wa_init_mcr(struct drm_i915_private *dev_priv, struct i915_wa_list *wal) { - const struct sseu_dev_info *sseu = &(INTEL_INFO(dev_priv)->sseu); - struct i915_wa_list *wal = &dev_priv->gt_wa_list; + const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; u32 mcr_slice_subslice_mask; /* @@ -804,11 +800,10 @@ static void wa_init_mcr(struct drm_i915_private *dev_priv) intel_calculate_mcr_s_ss_select(dev_priv)); } -static void cnl_gt_workarounds_init(struct drm_i915_private *i915) +static void +cnl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - wa_init_mcr(i915); + wa_init_mcr(i915, wal); /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ if (IS_CNL_REVID(i915, CNL_REVID_B0, CNL_REVID_B0)) @@ -822,11 +817,10 @@ static void cnl_gt_workarounds_init(struct drm_i915_private *i915) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } -static void icl_gt_workarounds_init(struct drm_i915_private *i915) +static void +icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - wa_init_mcr(i915); + wa_init_mcr(i915, wal); /* WaInPlaceDecompressionHang:icl */ wa_write_or(wal, @@ -879,12 +873,9 @@ static void icl_gt_workarounds_init(struct drm_i915_private *i915) GAMT_CHKN_DISABLE_L3_COH_PIPE); } -void intel_gt_init_workarounds(struct drm_i915_private *i915) +static void +gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal) { - struct i915_wa_list *wal = &i915->gt_wa_list; - - wa_init_start(wal, "GT"); - if (INTEL_GEN(i915) < 8) return; else if (IS_BROADWELL(i915)) @@ -892,22 +883,29 @@ void intel_gt_init_workarounds(struct drm_i915_private *i915) else if (IS_CHERRYVIEW(i915)) return; else if (IS_SKYLAKE(i915)) - skl_gt_workarounds_init(i915); + skl_gt_workarounds_init(i915, wal); else if (IS_BROXTON(i915)) - bxt_gt_workarounds_init(i915); + bxt_gt_workarounds_init(i915, wal); else if (IS_KABYLAKE(i915)) - kbl_gt_workarounds_init(i915); + kbl_gt_workarounds_init(i915, wal); else if (IS_GEMINILAKE(i915)) - glk_gt_workarounds_init(i915); + glk_gt_workarounds_init(i915, wal); else if (IS_COFFEELAKE(i915)) - cfl_gt_workarounds_init(i915); + cfl_gt_workarounds_init(i915, wal); else if (IS_CANNONLAKE(i915)) - cnl_gt_workarounds_init(i915); + cnl_gt_workarounds_init(i915, wal); else if (IS_ICELAKE(i915)) - icl_gt_workarounds_init(i915); + icl_gt_workarounds_init(i915, wal); else MISSING_CASE(INTEL_GEN(i915)); +} +void intel_gt_init_workarounds(struct drm_i915_private *i915) +{ + struct i915_wa_list *wal = &i915->gt_wa_list; + + wa_init_start(wal, "GT"); + gt_init_workarounds(i915, wal); wa_init_finish(wal); } @@ -955,8 +953,6 @@ wa_list_apply(struct drm_i915_private *dev_priv, const struct i915_wa_list *wal) intel_uncore_forcewake_put__locked(dev_priv, fw); spin_unlock_irqrestore(&dev_priv->uncore.lock, flags); - - DRM_DEBUG_DRIVER("Applied %u %s workarounds\n", wal->count, wal->name); } void intel_gt_apply_workarounds(struct drm_i915_private *dev_priv) @@ -1126,14 +1122,12 @@ void intel_engine_apply_whitelist(struct intel_engine_cs *engine) for (; i < RING_MAX_NONPRIV_SLOTS; i++) I915_WRITE(RING_FORCE_TO_NONPRIV(base, i), i915_mmio_reg_offset(RING_NOPID(base))); - - DRM_DEBUG_DRIVER("Applied %u %s workarounds\n", wal->count, wal->name); } -static void rcs_engine_wa_init(struct intel_engine_cs *engine) +static void +rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { struct drm_i915_private *i915 = engine->i915; - struct i915_wa_list *wal = &engine->wa_list; if (IS_ICELAKE(i915)) { /* This is not an Wa. Enable for better image quality */ @@ -1190,7 +1184,7 @@ static void rcs_engine_wa_init(struct intel_engine_cs *engine) GEN7_DISABLE_SAMPLER_PREFETCH); } - if (IS_GEN9(i915) || IS_CANNONLAKE(i915)) { + if (IS_GEN(i915, 9) || IS_CANNONLAKE(i915)) { /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,cnl */ wa_masked_en(wal, GEN7_FF_SLICE_CS_CHICKEN1, @@ -1211,7 +1205,7 @@ static void rcs_engine_wa_init(struct intel_engine_cs *engine) GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE); } - if (IS_GEN9(i915)) { + if (IS_GEN(i915, 9)) { /* WaContextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ wa_masked_en(wal, GEN9_CSFE_CHICKEN1_RCS, @@ -1237,10 +1231,10 @@ static void rcs_engine_wa_init(struct intel_engine_cs *engine) } } -static void xcs_engine_wa_init(struct intel_engine_cs *engine) +static void +xcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { struct drm_i915_private *i915 = engine->i915; - struct i915_wa_list *wal = &engine->wa_list; /* WaKBLVECSSemaphoreWaitPoll:kbl */ if (IS_KBL_REVID(i915, KBL_REVID_A0, KBL_REVID_E0)) { @@ -1250,6 +1244,18 @@ static void xcs_engine_wa_init(struct intel_engine_cs *engine) } } +static void +engine_init_workarounds(struct intel_engine_cs *engine, struct i915_wa_list *wal) +{ + if (I915_SELFTEST_ONLY(INTEL_GEN(engine->i915) < 8)) + return; + + if (engine->id == RCS) + rcs_engine_wa_init(engine, wal); + else + xcs_engine_wa_init(engine, wal); +} + void intel_engine_init_workarounds(struct intel_engine_cs *engine) { struct i915_wa_list *wal = &engine->wa_list; @@ -1258,12 +1264,7 @@ void intel_engine_init_workarounds(struct intel_engine_cs *engine) return; wa_init_start(wal, engine->name); - - if (engine->id == RCS) - rcs_engine_wa_init(engine); - else - xcs_engine_wa_init(engine); - + engine_init_workarounds(engine, wal); wa_init_finish(wal); } @@ -1273,11 +1274,5 @@ void intel_engine_apply_workarounds(struct intel_engine_cs *engine) } #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) -static bool intel_engine_verify_workarounds(struct intel_engine_cs *engine, - const char *from) -{ - return wa_list_verify(engine->i915, &engine->wa_list, from); -} - #include "selftests/intel_workarounds.c" #endif diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 26c065c8d2c0..6c10734e948d 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -972,7 +972,6 @@ static int gpu_write(struct i915_vma *vma, { struct i915_request *rq; struct i915_vma *batch; - int flags = 0; int err; GEM_BUG_ON(!intel_engine_can_store_dword(engine)); @@ -981,14 +980,14 @@ static int gpu_write(struct i915_vma *vma, if (err) return err; - rq = i915_request_alloc(engine, ctx); - if (IS_ERR(rq)) - return PTR_ERR(rq); - batch = gpu_write_dw(vma, dword * sizeof(u32), value); - if (IS_ERR(batch)) { - err = PTR_ERR(batch); - goto err_request; + if (IS_ERR(batch)) + return PTR_ERR(batch); + + rq = i915_request_alloc(engine, ctx); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_batch; } err = i915_vma_move_to_active(batch, rq, 0); @@ -996,21 +995,21 @@ static int gpu_write(struct i915_vma *vma, goto err_request; i915_gem_object_set_active_reference(batch->obj); - i915_vma_unpin(batch); - i915_vma_close(batch); - err = engine->emit_bb_start(rq, - batch->node.start, batch->node.size, - flags); + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); if (err) goto err_request; - err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + err = engine->emit_bb_start(rq, + batch->node.start, batch->node.size, + 0); +err_request: if (err) i915_request_skip(rq, err); - -err_request: i915_request_add(rq); +err_batch: + i915_vma_unpin(batch); + i915_vma_close(batch); return err; } @@ -1703,7 +1702,6 @@ int i915_gem_huge_page_mock_selftests(void) }; struct drm_i915_private *dev_priv; struct i915_hw_ppgtt *ppgtt; - struct pci_dev *pdev; int err; dev_priv = mock_gem_device(); @@ -1713,9 +1711,6 @@ int i915_gem_huge_page_mock_selftests(void) /* Pretend to be a device which supports the 48b PPGTT */ mkwrite_device_info(dev_priv)->ppgtt = INTEL_PPGTT_FULL_4LVL; - pdev = dev_priv->drm.pdev; - dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39)); - mutex_lock(&dev_priv->drm.struct_mutex); ppgtt = i915_ppgtt_create(dev_priv, ERR_PTR(-ENODEV)); if (IS_ERR(ppgtt)) { diff --git a/drivers/gpu/drm/i915/selftests/i915_gem.c b/drivers/gpu/drm/i915/selftests/i915_gem.c index d0aa19d17653..bdcc53e15e75 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem.c @@ -121,7 +121,7 @@ static void pm_resume(struct drm_i915_private *i915) */ intel_runtime_pm_get(i915); - intel_engines_sanitize(i915); + intel_engines_sanitize(i915, false); i915_gem_sanitize(i915); i915_gem_resume(i915); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 7d82043aff10..d00cdf3c2939 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -627,7 +627,7 @@ static int igt_ctx_exec(void *arg) ncontexts++; } pr_info("Submitted %lu contexts (across %u engines), filling %lu dwords\n", - ncontexts, INTEL_INFO(i915)->num_rings, ndwords); + ncontexts, RUNTIME_INFO(i915)->num_rings, ndwords); dw = 0; list_for_each_entry(obj, &objects, st_link) { @@ -732,7 +732,7 @@ static int igt_ctx_readonly(void *arg) } } pr_info("Submitted %lu dwords (across %u engines)\n", - ndwords, INTEL_INFO(i915)->num_rings); + ndwords, RUNTIME_INFO(i915)->num_rings); dw = 0; list_for_each_entry(obj, &objects, st_link) { @@ -1064,7 +1064,7 @@ static int igt_vm_isolation(void *arg) count += this; } pr_info("Checked %lu scratch offsets across %d engines\n", - count, INTEL_INFO(i915)->num_rings); + count, RUNTIME_INFO(i915)->num_rings); out_rpm: intel_runtime_pm_put(i915); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index c3999dd2021e..be7ecb66ad11 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -238,6 +238,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj, u32 *cpu; GEM_BUG_ON(view.partial.size > nreal); + cond_resched(); err = i915_gem_object_set_to_gtt_domain(obj, true); if (err) { diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c index 8cd34f6e6859..0e70df0230b8 100644 --- a/drivers/gpu/drm/i915/selftests/igt_spinner.c +++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c @@ -68,48 +68,65 @@ static u64 hws_address(const struct i915_vma *hws, return hws->node.start + seqno_offset(rq->fence.context); } -static int emit_recurse_batch(struct igt_spinner *spin, - struct i915_request *rq, - u32 arbitration_command) +static int move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) { - struct i915_address_space *vm = &rq->gem_context->ppgtt->vm; + int err; + + err = i915_vma_move_to_active(vma, rq, flags); + if (err) + return err; + + if (!i915_gem_object_has_active_reference(vma->obj)) { + i915_gem_object_get(vma->obj); + i915_gem_object_set_active_reference(vma->obj); + } + + return 0; +} + +struct i915_request * +igt_spinner_create_request(struct igt_spinner *spin, + struct i915_gem_context *ctx, + struct intel_engine_cs *engine, + u32 arbitration_command) +{ + struct i915_address_space *vm = &ctx->ppgtt->vm; + struct i915_request *rq = NULL; struct i915_vma *hws, *vma; u32 *batch; int err; vma = i915_vma_instance(spin->obj, vm, NULL); if (IS_ERR(vma)) - return PTR_ERR(vma); + return ERR_CAST(vma); hws = i915_vma_instance(spin->hws, vm, NULL); if (IS_ERR(hws)) - return PTR_ERR(hws); + return ERR_CAST(hws); err = i915_vma_pin(vma, 0, 0, PIN_USER); if (err) - return err; + return ERR_PTR(err); err = i915_vma_pin(hws, 0, 0, PIN_USER); if (err) goto unpin_vma; - err = i915_vma_move_to_active(vma, rq, 0); - if (err) + rq = i915_request_alloc(engine, ctx); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); goto unpin_hws; - - if (!i915_gem_object_has_active_reference(vma->obj)) { - i915_gem_object_get(vma->obj); - i915_gem_object_set_active_reference(vma->obj); } - err = i915_vma_move_to_active(hws, rq, 0); + err = move_to_active(vma, rq, 0); if (err) - goto unpin_hws; + goto cancel_rq; - if (!i915_gem_object_has_active_reference(hws->obj)) { - i915_gem_object_get(hws->obj); - i915_gem_object_set_active_reference(hws->obj); - } + err = move_to_active(hws, rq, 0); + if (err) + goto cancel_rq; batch = spin->batch; @@ -127,35 +144,18 @@ static int emit_recurse_batch(struct igt_spinner *spin, i915_gem_chipset_flush(spin->i915); - err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0); + err = engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0); +cancel_rq: + if (err) { + i915_request_skip(rq, err); + i915_request_add(rq); + } unpin_hws: i915_vma_unpin(hws); unpin_vma: i915_vma_unpin(vma); - return err; -} - -struct i915_request * -igt_spinner_create_request(struct igt_spinner *spin, - struct i915_gem_context *ctx, - struct intel_engine_cs *engine, - u32 arbitration_command) -{ - struct i915_request *rq; - int err; - - rq = i915_request_alloc(engine, ctx); - if (IS_ERR(rq)) - return rq; - - err = emit_recurse_batch(spin, rq, arbitration_command); - if (err) { - i915_request_add(rq); - return ERR_PTR(err); - } - - return rq; + return err ? ERR_PTR(err) : rq; } static u32 diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 5910da3e7d79..0aadbd9c7d56 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -103,52 +103,87 @@ static u64 hws_address(const struct i915_vma *hws, return hws->node.start + offset_in_page(sizeof(u32)*rq->fence.context); } -static int emit_recurse_batch(struct hang *h, - struct i915_request *rq) +static int move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) +{ + int err; + + err = i915_vma_move_to_active(vma, rq, flags); + if (err) + return err; + + if (!i915_gem_object_has_active_reference(vma->obj)) { + i915_gem_object_get(vma->obj); + i915_gem_object_set_active_reference(vma->obj); + } + + return 0; +} + +static struct i915_request * +hang_create_request(struct hang *h, struct intel_engine_cs *engine) { struct drm_i915_private *i915 = h->i915; struct i915_address_space *vm = - rq->gem_context->ppgtt ? - &rq->gem_context->ppgtt->vm : - &i915->ggtt.vm; + h->ctx->ppgtt ? &h->ctx->ppgtt->vm : &i915->ggtt.vm; + struct i915_request *rq = NULL; struct i915_vma *hws, *vma; unsigned int flags; u32 *batch; int err; + if (i915_gem_object_is_active(h->obj)) { + struct drm_i915_gem_object *obj; + void *vaddr; + + obj = i915_gem_object_create_internal(h->i915, PAGE_SIZE); + if (IS_ERR(obj)) + return ERR_CAST(obj); + + vaddr = i915_gem_object_pin_map(obj, + i915_coherent_map_type(h->i915)); + if (IS_ERR(vaddr)) { + i915_gem_object_put(obj); + return ERR_CAST(vaddr); + } + + i915_gem_object_unpin_map(h->obj); + i915_gem_object_put(h->obj); + + h->obj = obj; + h->batch = vaddr; + } + vma = i915_vma_instance(h->obj, vm, NULL); if (IS_ERR(vma)) - return PTR_ERR(vma); + return ERR_CAST(vma); hws = i915_vma_instance(h->hws, vm, NULL); if (IS_ERR(hws)) - return PTR_ERR(hws); + return ERR_CAST(hws); err = i915_vma_pin(vma, 0, 0, PIN_USER); if (err) - return err; + return ERR_PTR(err); err = i915_vma_pin(hws, 0, 0, PIN_USER); if (err) goto unpin_vma; - err = i915_vma_move_to_active(vma, rq, 0); - if (err) + rq = i915_request_alloc(engine, h->ctx); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); goto unpin_hws; - - if (!i915_gem_object_has_active_reference(vma->obj)) { - i915_gem_object_get(vma->obj); - i915_gem_object_set_active_reference(vma->obj); } - err = i915_vma_move_to_active(hws, rq, 0); + err = move_to_active(vma, rq, 0); if (err) - goto unpin_hws; + goto cancel_rq; - if (!i915_gem_object_has_active_reference(hws->obj)) { - i915_gem_object_get(hws->obj); - i915_gem_object_set_active_reference(hws->obj); - } + err = move_to_active(hws, rq, 0); + if (err) + goto cancel_rq; batch = h->batch; if (INTEL_GEN(i915) >= 8) { @@ -213,52 +248,16 @@ static int emit_recurse_batch(struct hang *h, err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags); +cancel_rq: + if (err) { + i915_request_skip(rq, err); + i915_request_add(rq); + } unpin_hws: i915_vma_unpin(hws); unpin_vma: i915_vma_unpin(vma); - return err; -} - -static struct i915_request * -hang_create_request(struct hang *h, struct intel_engine_cs *engine) -{ - struct i915_request *rq; - int err; - - if (i915_gem_object_is_active(h->obj)) { - struct drm_i915_gem_object *obj; - void *vaddr; - - obj = i915_gem_object_create_internal(h->i915, PAGE_SIZE); - if (IS_ERR(obj)) - return ERR_CAST(obj); - - vaddr = i915_gem_object_pin_map(obj, - i915_coherent_map_type(h->i915)); - if (IS_ERR(vaddr)) { - i915_gem_object_put(obj); - return ERR_CAST(vaddr); - } - - i915_gem_object_unpin_map(h->obj); - i915_gem_object_put(h->obj); - - h->obj = obj; - h->batch = vaddr; - } - - rq = i915_request_alloc(engine, h->ctx); - if (IS_ERR(rq)) - return rq; - - err = emit_recurse_batch(h, rq); - if (err) { - i915_request_add(rq); - return ERR_PTR(err); - } - - return rq; + return err ? ERR_PTR(err) : rq; } static u32 hws_seqno(const struct hang *h, const struct i915_request *rq) @@ -386,6 +385,30 @@ static int igt_global_reset(void *arg) return err; } +static int igt_wedged_reset(void *arg) +{ + struct drm_i915_private *i915 = arg; + + /* Check that we can recover a wedged device with a GPU reset */ + + igt_global_reset_lock(i915); + mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); + + i915_gem_set_wedged(i915); + GEM_BUG_ON(!i915_terminally_wedged(&i915->gpu_error)); + + set_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags); + i915_reset(i915, ALL_ENGINES, NULL); + GEM_BUG_ON(test_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags)); + + intel_runtime_pm_put(i915); + mutex_unlock(&i915->drm.struct_mutex); + igt_global_reset_unlock(i915); + + return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0; +} + static bool wait_for_idle(struct intel_engine_cs *engine) { return wait_for(intel_engine_is_idle(engine), IGT_IDLE_TIMEOUT) == 0; @@ -1449,10 +1472,182 @@ err_unlock: return err; } +static void __preempt_begin(void) +{ + preempt_disable(); +} + +static void __preempt_end(void) +{ + preempt_enable(); +} + +static void __softirq_begin(void) +{ + local_bh_disable(); +} + +static void __softirq_end(void) +{ + local_bh_enable(); +} + +static void __hardirq_begin(void) +{ + local_irq_disable(); +} + +static void __hardirq_end(void) +{ + local_irq_enable(); +} + +struct atomic_section { + const char *name; + void (*critical_section_begin)(void); + void (*critical_section_end)(void); +}; + +static int __igt_atomic_reset_engine(struct intel_engine_cs *engine, + const struct atomic_section *p, + const char *mode) +{ + struct tasklet_struct * const t = &engine->execlists.tasklet; + int err; + + GEM_TRACE("i915_reset_engine(%s:%s) under %s\n", + engine->name, mode, p->name); + + tasklet_disable_nosync(t); + p->critical_section_begin(); + + err = i915_reset_engine(engine, NULL); + + p->critical_section_end(); + tasklet_enable(t); + + if (err) + pr_err("i915_reset_engine(%s:%s) failed under %s\n", + engine->name, mode, p->name); + + return err; +} + +static int igt_atomic_reset_engine(struct intel_engine_cs *engine, + const struct atomic_section *p) +{ + struct drm_i915_private *i915 = engine->i915; + struct i915_request *rq; + struct hang h; + int err; + + err = __igt_atomic_reset_engine(engine, p, "idle"); + if (err) + return err; + + err = hang_init(&h, i915); + if (err) + return err; + + rq = hang_create_request(&h, engine); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto out; + } + + i915_request_get(rq); + i915_request_add(rq); + + if (wait_until_running(&h, rq)) { + err = __igt_atomic_reset_engine(engine, p, "active"); + } else { + pr_err("%s(%s): Failed to start request %llx, at %x\n", + __func__, engine->name, + rq->fence.seqno, hws_seqno(&h, rq)); + err = -EIO; + } + + if (err == 0) { + struct igt_wedge_me w; + + igt_wedge_on_timeout(&w, i915, HZ / 20 /* 50ms timeout*/) + i915_request_wait(rq, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); + if (i915_terminally_wedged(&i915->gpu_error)) + err = -EIO; + } + + i915_request_put(rq); +out: + hang_fini(&h); + return err; +} + +static void force_reset(struct drm_i915_private *i915) +{ + i915_gem_set_wedged(i915); + set_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags); + i915_reset(i915, 0, NULL); +} + +static int igt_atomic_reset(void *arg) +{ + static const struct atomic_section phases[] = { + { "preempt", __preempt_begin, __preempt_end }, + { "softirq", __softirq_begin, __softirq_end }, + { "hardirq", __hardirq_begin, __hardirq_end }, + { } + }; + struct drm_i915_private *i915 = arg; + int err = 0; + + /* Check that the resets are usable from atomic context */ + + if (USES_GUC_SUBMISSION(i915)) + return 0; /* guc is dead; long live the guc */ + + igt_global_reset_lock(i915); + mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); + + /* Flush any requests before we get started and check basics */ + force_reset(i915); + if (i915_terminally_wedged(&i915->gpu_error)) + goto unlock; + + if (intel_has_reset_engine(i915)) { + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, i915, id) { + const typeof(*phases) *p; + + for (p = phases; p->name; p++) { + err = igt_atomic_reset_engine(engine, p); + if (err) + goto out; + } + } + } + +out: + /* As we poke around the guts, do a full reset before continuing. */ + force_reset(i915); + +unlock: + intel_runtime_pm_put(i915); + mutex_unlock(&i915->drm.struct_mutex); + igt_global_reset_unlock(i915); + + return err; +} + int intel_hangcheck_live_selftests(struct drm_i915_private *i915) { static const struct i915_subtest tests[] = { SUBTEST(igt_global_reset), /* attempt to recover GPU first */ + SUBTEST(igt_wedged_reset), SUBTEST(igt_hang_sanitycheck), SUBTEST(igt_reset_idle_engine), SUBTEST(igt_reset_active_engine), @@ -1463,6 +1658,7 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_reset_evict_ppgtt), SUBTEST(igt_reset_evict_fence), SUBTEST(igt_handle_error), + SUBTEST(igt_atomic_reset), }; bool saved_hangcheck; int err; diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index ca461e3a5f27..00caaa00f02f 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -522,7 +522,7 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags) pr_info("Submitted %lu crescendo:%x requests across %d engines and %d contexts\n", count, flags, - INTEL_INFO(smoke->i915)->num_rings, smoke->ncontext); + RUNTIME_INFO(smoke->i915)->num_rings, smoke->ncontext); return 0; } @@ -550,7 +550,7 @@ static int smoke_random(struct preempt_smoke *smoke, unsigned int flags) pr_info("Submitted %lu random:%x requests across %d engines and %d contexts\n", count, flags, - INTEL_INFO(smoke->i915)->num_rings, smoke->ncontext); + RUNTIME_INFO(smoke->i915)->num_rings, smoke->ncontext); return 0; } diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index 67017d5175b8..8b3f3200a3bd 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -12,6 +12,51 @@ #include "igt_wedge_me.h" #include "mock_context.h" +#define REF_NAME_MAX (INTEL_ENGINE_CS_MAX_NAME + 4) +struct wa_lists { + struct i915_wa_list gt_wa_list; + struct { + char name[REF_NAME_MAX]; + struct i915_wa_list wa_list; + } engine[I915_NUM_ENGINES]; +}; + +static void +reference_lists_init(struct drm_i915_private *i915, struct wa_lists *lists) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + memset(lists, 0, sizeof(*lists)); + + wa_init_start(&lists->gt_wa_list, "GT_REF"); + gt_init_workarounds(i915, &lists->gt_wa_list); + wa_init_finish(&lists->gt_wa_list); + + for_each_engine(engine, i915, id) { + struct i915_wa_list *wal = &lists->engine[id].wa_list; + char *name = lists->engine[id].name; + + snprintf(name, REF_NAME_MAX, "%s_REF", engine->name); + + wa_init_start(wal, name); + engine_init_workarounds(engine, wal); + wa_init_finish(wal); + } +} + +static void +reference_lists_fini(struct drm_i915_private *i915, struct wa_lists *lists) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, i915, id) + intel_wa_list_free(&lists->engine[id].wa_list); + + intel_wa_list_free(&lists->gt_wa_list); +} + static struct drm_i915_gem_object * read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { @@ -326,16 +371,17 @@ out: return err; } -static bool verify_gt_engine_wa(struct drm_i915_private *i915, const char *str) +static bool verify_gt_engine_wa(struct drm_i915_private *i915, + struct wa_lists *lists, const char *str) { struct intel_engine_cs *engine; enum intel_engine_id id; bool ok = true; - ok &= intel_gt_verify_workarounds(i915, str); + ok &= wa_list_verify(i915, &lists->gt_wa_list, str); for_each_engine(engine, i915, id) - ok &= intel_engine_verify_workarounds(engine, str); + ok &= wa_list_verify(i915, &lists->engine[id].wa_list, str); return ok; } @@ -345,6 +391,7 @@ live_gpu_reset_gt_engine_workarounds(void *arg) { struct drm_i915_private *i915 = arg; struct i915_gpu_error *error = &i915->gpu_error; + struct wa_lists lists; bool ok; if (!intel_has_gpu_reset(i915)) @@ -353,19 +400,21 @@ live_gpu_reset_gt_engine_workarounds(void *arg) pr_info("Verifying after GPU reset...\n"); igt_global_reset_lock(i915); + intel_runtime_pm_get(i915); + reference_lists_init(i915, &lists); - ok = verify_gt_engine_wa(i915, "before reset"); + ok = verify_gt_engine_wa(i915, &lists, "before reset"); if (!ok) goto out; - intel_runtime_pm_get(i915); set_bit(I915_RESET_HANDOFF, &error->flags); i915_reset(i915, ALL_ENGINES, "live_workarounds"); - intel_runtime_pm_put(i915); - ok = verify_gt_engine_wa(i915, "after reset"); + ok = verify_gt_engine_wa(i915, &lists, "after reset"); out: + reference_lists_fini(i915, &lists); + intel_runtime_pm_put(i915); igt_global_reset_unlock(i915); return ok ? 0 : -ESRCH; @@ -380,6 +429,7 @@ live_engine_reset_gt_engine_workarounds(void *arg) struct igt_spinner spin; enum intel_engine_id id; struct i915_request *rq; + struct wa_lists lists; int ret = 0; if (!intel_has_reset_engine(i915)) @@ -390,23 +440,23 @@ live_engine_reset_gt_engine_workarounds(void *arg) return PTR_ERR(ctx); igt_global_reset_lock(i915); + intel_runtime_pm_get(i915); + reference_lists_init(i915, &lists); for_each_engine(engine, i915, id) { bool ok; pr_info("Verifying after %s reset...\n", engine->name); - ok = verify_gt_engine_wa(i915, "before reset"); + ok = verify_gt_engine_wa(i915, &lists, "before reset"); if (!ok) { ret = -ESRCH; goto err; } - intel_runtime_pm_get(i915); i915_reset_engine(engine, "live_workarounds"); - intel_runtime_pm_put(i915); - ok = verify_gt_engine_wa(i915, "after idle reset"); + ok = verify_gt_engine_wa(i915, &lists, "after idle reset"); if (!ok) { ret = -ESRCH; goto err; @@ -416,13 +466,10 @@ live_engine_reset_gt_engine_workarounds(void *arg) if (ret) goto err; - intel_runtime_pm_get(i915); - rq = igt_spinner_create_request(&spin, ctx, engine, MI_NOOP); if (IS_ERR(rq)) { ret = PTR_ERR(rq); igt_spinner_fini(&spin); - intel_runtime_pm_put(i915); goto err; } @@ -431,19 +478,16 @@ live_engine_reset_gt_engine_workarounds(void *arg) if (!igt_wait_for_spinner(&spin, rq)) { pr_err("Spinner failed to start\n"); igt_spinner_fini(&spin); - intel_runtime_pm_put(i915); ret = -ETIMEDOUT; goto err; } i915_reset_engine(engine, "live_workarounds"); - intel_runtime_pm_put(i915); - igt_spinner_end(&spin); igt_spinner_fini(&spin); - ok = verify_gt_engine_wa(i915, "after busy reset"); + ok = verify_gt_engine_wa(i915, &lists, "after busy reset"); if (!ok) { ret = -ESRCH; goto err; @@ -451,6 +495,8 @@ live_engine_reset_gt_engine_workarounds(void *arg) } err: + reference_lists_fini(i915, &lists); + intel_runtime_pm_put(i915); igt_global_reset_unlock(i915); kernel_context_close(ctx); diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index d0c44c18db42..50e1a0b1af7e 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -148,8 +148,6 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine) const unsigned long sz = PAGE_SIZE / 2; struct mock_ring *ring; - BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST > sz); - ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); if (!ring) return NULL; diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 43ed8b28aeaa..baa3c38919de 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -147,7 +147,7 @@ struct drm_i915_private *mock_gem_device(void) pdev->class = PCI_BASE_CLASS_DISPLAY << 16; pdev->dev.release = release_dev; dev_set_name(&pdev->dev, "mock"); - dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU) /* hack to disable iommu for the fake device; force identity mapping */ diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index 361e962a7969..3225621f820c 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -23,7 +23,6 @@ * Author: Jani Nikula <jani.nikula@intel.com> */ -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -257,9 +256,9 @@ static void band_gap_reset(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->sb_lock); } -static bool intel_dsi_compute_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) +static int intel_dsi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, @@ -285,7 +284,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - return false; + return -EINVAL; /* DSI uses short packets for sync events, so clear mode flags for DSI */ adjusted_mode->flags = 0; @@ -303,16 +302,16 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, ret = bxt_dsi_pll_compute(encoder, pipe_config); if (ret) - return false; + return -EINVAL; } else { ret = vlv_dsi_pll_compute(encoder, pipe_config); if (ret) - return false; + return -EINVAL; } pipe_config->clock_set = true; - return true; + return 0; } static bool glk_dsi_enable_io(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 862f3ec22131..12ad00d01063 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -981,7 +981,8 @@ static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi, u8 buffer[17]; ssize_t err; - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &hdmi->conn, mode); if (err < 0) { dev_err(hdmi->dev, "Failed to get AVI infoframe from mode: %zd\n", err); @@ -1370,8 +1371,8 @@ static void mtk_hdmi_bridge_post_disable(struct drm_bridge *bridge) } static void mtk_hdmi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge); diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3ee4d4a4ecba..1e360828ac38 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -152,6 +152,23 @@ static void meson_vpu_init(struct meson_drm *priv) writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } +static void meson_remove_framebuffers(void) +{ + struct apertures_struct *ap; + + ap = alloc_apertures(1); + if (!ap) + return; + + /* The framebuffer can be located anywhere in RAM */ + ap->ranges[0].base = 0; + ap->ranges[0].size = ~0; + + drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb", + false); + kfree(ap); +} + static int meson_drv_bind_master(struct device *dev, bool has_components) { struct platform_device *pdev = to_platform_device(dev); @@ -262,6 +279,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) if (ret) goto free_drm; + /* Remove early framebuffers (ie. simplefb) */ + meson_remove_framebuffers(); + drm_mode_config_init(drm); drm->mode_config.max_width = 3840; drm->mode_config.max_height = 2160; diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 807111ebfdd9..bc25001b8207 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -365,7 +365,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, unsigned int wr_clk = readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); - DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name); + DRM_DEBUG_DRIVER("\"%s\"\n", mode->name); /* Enable clocks */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); @@ -555,12 +555,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector, int vic = drm_match_cea_mode(mode); enum drm_mode_status status; - DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type, mode->flags); + DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); /* Check against non-VIC supported modes */ if (!vic) { @@ -650,8 +645,7 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct meson_drm *priv = dw_hdmi->priv; int vic = drm_match_cea_mode(mode); - DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", - mode->base.id, mode->name, vic); + DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); /* VENC + VENC-DVI Mode setup */ meson_venc_hdmi_mode_set(priv, vic, mode); diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 30726c9fe28c..6893934b26c0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -12,6 +12,7 @@ */ #include <linux/module.h> #include <drm/drmP.h> +#include <drm/drm_util.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 8f2359dc87b4..cc32ea5f4289 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -244,14 +244,8 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc) mode = &crtc->state->adjusted_mode; - DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mdp4_crtc->name, mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("%s: set mode: " DRM_MODE_FMT, + mdp4_crtc->name, DRM_MODE_ARG(mode)); mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 6a1ebdace391..48ce218b8463 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c @@ -58,14 +58,7 @@ static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder, mode = adjusted_mode; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); ctrl_pol = 0; if (mode->flags & DRM_MODE_FLAG_NHSYNC) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index a8fd14d4846b..ff8f2da160c0 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c @@ -104,14 +104,7 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, mode = adjusted_mode; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); mdp4_dtv_encoder->pixclock = mode->clock * 1000; diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index c9e34501a89e..fff77a4b12c2 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -273,14 +273,7 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, mode = adjusted_mode; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); mdp4_lcdc_encoder->pixclock = mode->clock * 1000; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c index c1962f29ec7d..976585d8bfd6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c @@ -134,14 +134,7 @@ void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder, { mode = adjusted_mode; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); pingpong_tearcheck_setup(encoder, mode); mdp5_crtc_set_pipeline(encoder->crtc); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index c5fde1a4191a..2f95e6525589 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -384,14 +384,7 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc) mode = &crtc->state->adjusted_mode; - DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - crtc->name, mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("%s: set mode: " DRM_MODE_FMT, crtc->name, DRM_MODE_ARG(mode)); mixer_width = mode->hdisplay; if (r_mixer) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index fcd44d1d1068..d2a56e55e53d 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -118,14 +118,7 @@ static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder, mode = adjusted_mode; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); ctrl_pol = 0; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index 7cebcb2b3a37..6153514db04c 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -16,6 +16,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <drm/drm_util.h> #include "mdp5_kms.h" #include "mdp5_smp.h" diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 08f3fc6771b7..9c6b31c2d79f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -168,7 +168,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, bool is_dual_dsi); int msm_dsi_host_power_off(struct mipi_dsi_host *host); int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, unsigned long *panel_flags); struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 38e481d2d606..610183db1daf 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -2424,7 +2424,7 @@ unlock_ret: } int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 80aa6344185e..979a8e929341 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -527,8 +527,8 @@ disable_phy: } static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { int id = dsi_mgr_bridge_get_id(bridge); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); @@ -536,14 +536,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, struct mipi_dsi_host *host = msm_dsi->host; bool is_dual_dsi = IS_DUAL_DSI(); - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) return; diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c index 931a5c97cccf..11166bf232ff 100644 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c @@ -52,22 +52,15 @@ static void edp_bridge_post_disable(struct drm_bridge *bridge) } static void edp_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct drm_device *dev = bridge->dev; struct drm_connector *connector; struct edp_bridge *edp_bridge = to_edp_bridge(bridge); struct msm_edp *edp = edp_bridge->edp; - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if ((connector->encoder != NULL) && diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 98d61c690260..03197b8959ba 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -101,7 +101,8 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) u32 val; int len; - drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); + drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + hdmi->connector, mode); len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); if (len < 0) { @@ -207,8 +208,8 @@ static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge) } static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 88ba003979e6..13e778825098 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -263,23 +263,12 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) drm_kms_helper_poll_init(drm); - mxsfb->fbdev = drm_fbdev_cma_init(drm, 32, - drm->mode_config.num_connector); - if (IS_ERR(mxsfb->fbdev)) { - ret = PTR_ERR(mxsfb->fbdev); - mxsfb->fbdev = NULL; - dev_err(drm->dev, "Failed to init FB CMA area\n"); - goto err_cma; - } - platform_set_drvdata(pdev, drm); drm_helper_hpd_irq_event(drm); return 0; -err_cma: - drm_irq_uninstall(drm); err_irq: drm_panel_detach(mxsfb->panel); err_vblank: @@ -290,11 +279,6 @@ err_vblank: static void mxsfb_unload(struct drm_device *drm) { - struct mxsfb_drm_private *mxsfb = drm->dev_private; - - if (mxsfb->fbdev) - drm_fbdev_cma_fini(mxsfb->fbdev); - drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); @@ -307,13 +291,6 @@ static void mxsfb_unload(struct drm_device *drm) pm_runtime_disable(drm->dev); } -static void mxsfb_lastclose(struct drm_device *drm) -{ - struct mxsfb_drm_private *mxsfb = drm->dev_private; - - drm_fbdev_cma_restore_mode(mxsfb->fbdev); -} - static void mxsfb_irq_preinstall(struct drm_device *drm) { struct mxsfb_drm_private *mxsfb = drm->dev_private; @@ -347,7 +324,6 @@ static struct drm_driver mxsfb_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC | DRIVER_HAVE_IRQ, - .lastclose = mxsfb_lastclose, .irq_handler = mxsfb_irq_handler, .irq_preinstall = mxsfb_irq_preinstall, .irq_uninstall = mxsfb_irq_preinstall, @@ -412,6 +388,8 @@ static int mxsfb_probe(struct platform_device *pdev) if (ret) goto err_unload; + drm_fbdev_generic_setup(drm, 32); + return 0; err_unload: diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index 5d0883fc805b..bedd6801edca 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -37,7 +37,6 @@ struct mxsfb_drm_private { struct drm_simple_display_pipe pipe; struct drm_connector connector; struct drm_panel *panel; - struct drm_fbdev_cma *fbdev; }; int mxsfb_setup_crtc(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 6a4ca139cf5d..8fd8124d72ba 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -750,7 +750,9 @@ static int nv17_tv_set_property(struct drm_encoder *encoder, /* Disable the crtc to ensure a full modeset is * performed whenever it's turned on again. */ if (crtc) - drm_crtc_force_disable(crtc); + drm_crtc_helper_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, + crtc->primary->fb); } return 0; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 26af45785939..67107f0b1299 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -561,7 +561,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) u32 max_ac_packet; union hdmi_infoframe avi_frame; union hdmi_infoframe vendor_frame; - bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false; + bool high_tmds_clock_ratio = false, scrambling = false; u8 config; int ret; int size; @@ -571,10 +571,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) return; hdmi = &nv_connector->base.display_info.hdmi; - scdc_supported = hdmi->scdc.supported; - ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, - scdc_supported); + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, + &nv_connector->base, mode); if (!ret) { /* We have an AVI InfoFrame, populate it to the display */ args.pwr.avi_infoframe_length @@ -680,6 +679,8 @@ nv50_msto_payload(struct nv50_msto *msto) struct nv50_mstm *mstm = mstc->mstm; int vcpi = mstc->port->vcpi.vcpi, i; + WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock)); + NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); for (i = 0; i < mstm->mgr.max_payloads; i++) { struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; @@ -704,14 +705,16 @@ nv50_msto_cleanup(struct nv50_msto *msto) struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; + if (!msto->disabled) + return; + NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) - drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); - if (msto->disabled) { - msto->mstc = NULL; - msto->head = NULL; - msto->disabled = false; - } + + drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); + + msto->mstc = NULL; + msto->head = NULL; + msto->disabled = false; } static void @@ -731,8 +734,10 @@ nv50_msto_prepare(struct nv50_msto *msto) (0x0100 << msto->head->base.index), }; + mutex_lock(&mstm->mgr.payload_lock); + NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0) { + if (mstc->port->vcpi.vcpi > 0) { struct drm_dp_payload *payload = nv50_msto_payload(msto); if (payload) { args.vcpi.start_slot = payload->start_slot; @@ -746,7 +751,9 @@ nv50_msto_prepare(struct nv50_msto *msto) msto->encoder.name, msto->head->base.base.name, args.vcpi.start_slot, args.vcpi.num_slots, args.vcpi.pbn, args.vcpi.aligned_pbn); + nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); + mutex_unlock(&mstm->mgr.payload_lock); } static int @@ -754,16 +761,23 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstm *mstm = mstc->mstm; - int bpp = conn_state->connector->display_info.bpc * 3; + int bpp = connector->display_info.bpc * 3; int slots; - mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); + mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, + bpp); - slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); - if (slots < 0) - return slots; + if (drm_atomic_crtc_needs_modeset(crtc_state) && + !drm_connector_is_unregistered(connector)) { + slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, + mstc->port, mstc->pbn); + if (slots < 0) + return slots; + } return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, mstc->native); @@ -829,8 +843,7 @@ nv50_msto_disable(struct drm_encoder *encoder) struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; - if (mstc->port) - drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); + drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); mstm->modified = true; @@ -927,12 +940,43 @@ nv50_mstc_get_modes(struct drm_connector *connector) return ret; } +static int +nv50_mstc_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) +{ + struct drm_atomic_state *state = new_conn_state->state; + struct nv50_mstc *mstc = nv50_mstc(connector); + struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_crtc_state *crtc_state; + struct drm_crtc *new_crtc = new_conn_state->crtc; + + if (!old_conn_state->crtc) + return 0; + + /* We only want to free VCPI if this state disables the CRTC on this + * connector + */ + if (new_crtc) { + crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + if (!crtc_state || + !drm_atomic_crtc_needs_modeset(crtc_state) || + crtc_state->enable) + return 0; + } + + return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); +} + static const struct drm_connector_helper_funcs nv50_mstc_help = { .get_modes = nv50_mstc_get_modes, .mode_valid = nv50_mstc_mode_valid, .best_encoder = nv50_mstc_best_encoder, .atomic_best_encoder = nv50_mstc_atomic_best_encoder, + .atomic_check = nv50_mstc_atomic_check, }; static enum drm_connector_status @@ -942,7 +986,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force) enum drm_connector_status conn_status; int ret; - if (!mstc->port) + if (drm_connector_is_unregistered(connector)) return connector_status_disconnected; ret = pm_runtime_get_sync(connector->dev->dev); @@ -961,7 +1005,10 @@ static void nv50_mstc_destroy(struct drm_connector *connector) { struct nv50_mstc *mstc = nv50_mstc(connector); + drm_connector_cleanup(&mstc->connector); + drm_dp_mst_put_port_malloc(mstc->port); + kfree(mstc); } @@ -1009,6 +1056,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); drm_connector_set_path_property(&mstc->connector, path); + drm_dp_mst_get_port_malloc(port); return 0; } @@ -1073,10 +1121,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); - drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL); - mstc->port = NULL; - drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); - drm_connector_put(&mstc->connector); } @@ -1099,11 +1143,8 @@ nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, int ret; ret = nv50_mstc_new(mstm, port, path, &mstc); - if (ret) { - if (mstc) - mstc->connector.funcs->destroy(&mstc->connector); + if (ret) return NULL; - } return &mstc->connector; } @@ -2117,6 +2158,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) return ret; } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index f326ffd86766..5d273a655479 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -453,7 +453,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) if (drm_drv_uses_atomic_modeset(dev)) drm_atomic_helper_shutdown(dev); else - drm_crtc_force_disable_all(dev); + drm_helper_force_disable_all(dev); } /* disable flip completion events */ diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index b81302c4bf9e..874d8f3cbff6 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -305,14 +305,9 @@ static int omap_connector_mode_valid(struct drm_connector *connector, drm_mode_destroy(dev, new_mode); done: - DBG("connector: mode %s: " - "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + DBG("connector: mode %s: " DRM_MODE_FMT, (ret == MODE_OK) ? "valid" : "invalid", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type, mode->flags); + DRM_MODE_ARG(mode)); return ret; } diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index caffc547ef97..40acf4ce7c9f 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -427,12 +427,8 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_display_mode *mode = &crtc->state->adjusted_mode; - DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - omap_crtc->name, mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, - mode->type, mode->flags); + DBG("%s: set mode: " DRM_MODE_FMT, + omap_crtc->name, DRM_MODE_ARG(mode)); drm_display_mode_to_videomode(mode, &omap_crtc->vm); } diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 933ebc9f9faa..148b6b20274f 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -76,8 +76,8 @@ static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder, struct hdmi_avi_infoframe avi; int r; - r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode, - false); + r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, + adjusted_mode); if (r == 0) dssdev->ops->hdmi.set_infoframe(dssdev, &avi); } diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index aee99194499f..851c59f07eb1 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -16,6 +16,7 @@ */ #include <drm/drm_crtc.h> +#include <drm/drm_util.h> #include <drm/drm_fb_helper.h> #include "omap_drv.h" diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 3f3537719beb..a71f44191273 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -204,6 +204,15 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels +config DRM_PANEL_TPO_TPG110 + tristate "TPO TPG 800x400 panel" + depends on OF && SPI && GPIOLIB + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for TPO TPG110 + 400CH LTPS TFT LCD Single Chip Digital Driver for up to + 800x400 LCD panels. + config DRM_PANEL_TRULY_NT35597_WQXGA tristate "Truly WQXGA" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 4396658a7996..cd14ca39c6e0 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -21,4 +21,5 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index ca4ae45dd307..8e5724b63f1f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -70,18 +70,12 @@ static inline struct innolux_panel *to_innolux_panel(struct drm_panel *panel) static int innolux_panel_disable(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err; if (!innolux->enabled) return 0; backlight_disable(innolux->backlight); - err = mipi_dsi_dcs_set_display_off(innolux->link); - if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); - innolux->enabled = false; return 0; @@ -95,6 +89,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel) if (!innolux->prepared) return 0; + err = mipi_dsi_dcs_set_display_off(innolux->link); + if (err < 0) + DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", + err); + err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); if (err < 0) { DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c new file mode 100644 index 000000000000..5a9f8f4d5d24 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Panel driver for the TPO TPG110 400CH LTPS TFT LCD Single Chip + * Digital Driver. + * + * This chip drives a TFT LCD, so it does not know what kind of + * display is actually connected to it, so the width and height of that + * display needs to be supplied from the machine configuration. + * + * Author: + * Linus Walleij <linus.walleij@linaro.org> + */ +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#include <linux/backlight.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#define TPG110_TEST 0x00 +#define TPG110_CHIPID 0x01 +#define TPG110_CTRL1 0x02 +#define TPG110_RES_MASK GENMASK(2, 0) +#define TPG110_RES_800X480 0x07 +#define TPG110_RES_640X480 0x06 +#define TPG110_RES_480X272 0x05 +#define TPG110_RES_480X640 0x04 +#define TPG110_RES_480X272_D 0x01 /* Dual scan: outputs 800x480 */ +#define TPG110_RES_400X240_D 0x00 /* Dual scan: outputs 800x480 */ +#define TPG110_CTRL2 0x03 +#define TPG110_CTRL2_PM BIT(0) +#define TPG110_CTRL2_RES_PM_CTRL BIT(7) + +/** + * struct tpg110_panel_mode - lookup struct for the supported modes + */ +struct tpg110_panel_mode { + /** + * @name: the name of this panel + */ + const char *name; + /** + * @magic: the magic value from the detection register + */ + u32 magic; + /** + * @mode: the DRM display mode for this panel + */ + struct drm_display_mode mode; + /** + * @bus_flags: the DRM bus flags for this panel e.g. inverted clock + */ + u32 bus_flags; +}; + +/** + * struct tpg110 - state container for the TPG110 panel + */ +struct tpg110 { + /** + * @dev: the container device + */ + struct device *dev; + /** + * @spi: the corresponding SPI device + */ + struct spi_device *spi; + /** + * @panel: the DRM panel instance for this device + */ + struct drm_panel panel; + /** + * @backlight: backlight for this panel + */ + struct backlight_device *backlight; + /** + * @panel_type: the panel mode as detected + */ + const struct tpg110_panel_mode *panel_mode; + /** + * @width: the width of this panel in mm + */ + u32 width; + /** + * @height: the height of this panel in mm + */ + u32 height; + /** + * @grestb: reset GPIO line + */ + struct gpio_desc *grestb; +}; + +/* + * TPG110 modes, these are the simple modes, the dualscan modes that + * take 400x240 or 480x272 in and display as 800x480 are not listed. + */ +static const struct tpg110_panel_mode tpg110_modes[] = { + { + .name = "800x480 RGB", + .magic = TPG110_RES_800X480, + .mode = { + .clock = 33200, + .hdisplay = 800, + .hsync_start = 800 + 40, + .hsync_end = 800 + 40 + 1, + .htotal = 800 + 40 + 1 + 216, + .vdisplay = 480, + .vsync_start = 480 + 10, + .vsync_end = 480 + 10 + 1, + .vtotal = 480 + 10 + 1 + 35, + .vrefresh = 60, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + }, + { + .name = "640x480 RGB", + .magic = TPG110_RES_640X480, + .mode = { + .clock = 25200, + .hdisplay = 640, + .hsync_start = 640 + 24, + .hsync_end = 640 + 24 + 1, + .htotal = 640 + 24 + 1 + 136, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 1, + .vtotal = 480 + 18 + 1 + 27, + .vrefresh = 60, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + }, + { + .name = "480x272 RGB", + .magic = TPG110_RES_480X272, + .mode = { + .clock = 9000, + .hdisplay = 480, + .hsync_start = 480 + 2, + .hsync_end = 480 + 2 + 1, + .htotal = 480 + 2 + 1 + 43, + .vdisplay = 272, + .vsync_start = 272 + 2, + .vsync_end = 272 + 2 + 1, + .vtotal = 272 + 2 + 1 + 12, + .vrefresh = 60, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + }, + { + .name = "480x640 RGB", + .magic = TPG110_RES_480X640, + .mode = { + .clock = 20500, + .hdisplay = 480, + .hsync_start = 480 + 2, + .hsync_end = 480 + 2 + 1, + .htotal = 480 + 2 + 1 + 43, + .vdisplay = 640, + .vsync_start = 640 + 4, + .vsync_end = 640 + 4 + 1, + .vtotal = 640 + 4 + 1 + 8, + .vrefresh = 60, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + }, + { + .name = "400x240 RGB", + .magic = TPG110_RES_400X240_D, + .mode = { + .clock = 8300, + .hdisplay = 400, + .hsync_start = 400 + 20, + .hsync_end = 400 + 20 + 1, + .htotal = 400 + 20 + 1 + 108, + .vdisplay = 240, + .vsync_start = 240 + 2, + .vsync_end = 240 + 2 + 1, + .vtotal = 240 + 2 + 1 + 20, + .vrefresh = 60, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + }, +}; + +static inline struct tpg110 * +to_tpg110(struct drm_panel *panel) +{ + return container_of(panel, struct tpg110, panel); +} + +static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, + u8 address, u8 outval) +{ + struct spi_message m; + struct spi_transfer t[2]; + u8 buf[2]; + int ret; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + if (write) { + /* + * Clear address bit 0, 1 when writing, just to be sure + * The actual bit indicating a write here is bit 1, bit + * 0 is just surplus to pad it up to 8 bits. + */ + buf[0] = address << 2; + buf[0] &= ~0x03; + buf[1] = outval; + + t[0].bits_per_word = 8; + t[0].tx_buf = &buf[0]; + t[0].len = 1; + + t[1].tx_buf = &buf[1]; + t[1].len = 1; + t[1].bits_per_word = 8; + } else { + /* Set address bit 0 to 1 to read */ + buf[0] = address << 1; + buf[0] |= 0x01; + + /* + * The last bit/clock is Hi-Z turnaround cycle, so we need + * to send only 7 bits here. The 8th bit is the high impedance + * turn-around cycle. + */ + t[0].bits_per_word = 7; + t[0].tx_buf = &buf[0]; + t[0].len = 1; + + t[1].rx_buf = &buf[1]; + t[1].len = 1; + t[1].bits_per_word = 8; + } + + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + ret = spi_sync(tpg->spi, &m); + if (ret) { + DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret); + return ret; + } + if (write) + return 0; + /* Read */ + return buf[1]; +} + +static u8 tpg110_read_reg(struct tpg110 *tpg, u8 address) +{ + return tpg110_readwrite_reg(tpg, false, address, 0); +} + +static void tpg110_write_reg(struct tpg110 *tpg, u8 address, u8 outval) +{ + tpg110_readwrite_reg(tpg, true, address, outval); +} + +static int tpg110_startup(struct tpg110 *tpg) +{ + u8 val; + int i; + + /* De-assert the reset signal */ + gpiod_set_value_cansleep(tpg->grestb, 0); + usleep_range(1000, 2000); + DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n"); + + /* Test display communication */ + tpg110_write_reg(tpg, TPG110_TEST, 0x55); + val = tpg110_read_reg(tpg, TPG110_TEST); + if (val != 0x55) { + DRM_DEV_ERROR(tpg->dev, "failed communication test\n"); + return -ENODEV; + } + + val = tpg110_read_reg(tpg, TPG110_CHIPID); + DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n", + val >> 4, val & 0x0f); + + /* Show display resolution */ + val = tpg110_read_reg(tpg, TPG110_CTRL1); + val &= TPG110_RES_MASK; + switch (val) { + case TPG110_RES_400X240_D: + DRM_DEV_INFO(tpg->dev, + "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); + break; + case TPG110_RES_480X272_D: + DRM_DEV_INFO(tpg->dev, + "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); + break; + case TPG110_RES_480X640: + DRM_DEV_INFO(tpg->dev, "480x640 RGB\n"); + break; + case TPG110_RES_480X272: + DRM_DEV_INFO(tpg->dev, "480x272 RGB\n"); + break; + case TPG110_RES_640X480: + DRM_DEV_INFO(tpg->dev, "640x480 RGB\n"); + break; + case TPG110_RES_800X480: + DRM_DEV_INFO(tpg->dev, "800x480 RGB\n"); + break; + default: + DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); + break; + } + + /* From the producer side, this is the same resolution */ + if (val == TPG110_RES_480X272_D) + val = TPG110_RES_480X272; + + for (i = 0; i < ARRAY_SIZE(tpg110_modes); i++) { + const struct tpg110_panel_mode *pm; + + pm = &tpg110_modes[i]; + if (pm->magic == val) { + tpg->panel_mode = pm; + break; + } + } + if (i == ARRAY_SIZE(tpg110_modes)) { + DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n", + val); + return -ENODEV; + } + + val = tpg110_read_reg(tpg, TPG110_CTRL2); + DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n", + (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); + /* Take control over resolution and standby */ + val |= TPG110_CTRL2_RES_PM_CTRL; + tpg110_write_reg(tpg, TPG110_CTRL2, val); + + return 0; +} + +static int tpg110_disable(struct drm_panel *panel) +{ + struct tpg110 *tpg = to_tpg110(panel); + u8 val; + + /* Put chip into standby */ + val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); + val &= ~TPG110_CTRL2_PM; + tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); + + backlight_disable(tpg->backlight); + + return 0; +} + +static int tpg110_enable(struct drm_panel *panel) +{ + struct tpg110 *tpg = to_tpg110(panel); + u8 val; + + backlight_enable(tpg->backlight); + + /* Take chip out of standby */ + val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); + val |= TPG110_CTRL2_PM; + tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); + + return 0; +} + +/** + * tpg110_get_modes() - return the appropriate mode + * @panel: the panel to get the mode for + * + * This currently does not present a forest of modes, instead it + * presents the mode that is configured for the system under use, + * and which is detected by reading the registers of the display. + */ +static int tpg110_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct tpg110 *tpg = to_tpg110(panel); + struct drm_display_mode *mode; + + strncpy(connector->display_info.name, tpg->panel_mode->name, + DRM_DISPLAY_INFO_LEN); + connector->display_info.width_mm = tpg->width; + connector->display_info.height_mm = tpg->height; + connector->display_info.bus_flags = tpg->panel_mode->bus_flags; + + mode = drm_mode_duplicate(panel->drm, &tpg->panel_mode->mode); + drm_mode_set_name(mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + mode->width_mm = tpg->width; + mode->height_mm = tpg->height; + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs tpg110_drm_funcs = { + .disable = tpg110_disable, + .enable = tpg110_enable, + .get_modes = tpg110_get_modes, +}; + +static int tpg110_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct device_node *np = dev->of_node; + struct tpg110 *tpg; + int ret; + + tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL); + if (!tpg) + return -ENOMEM; + tpg->dev = dev; + + /* We get the physical display dimensions from the DT */ + ret = of_property_read_u32(np, "width-mm", &tpg->width); + if (ret) + DRM_DEV_ERROR(dev, "no panel width specified\n"); + ret = of_property_read_u32(np, "height-mm", &tpg->height); + if (ret) + DRM_DEV_ERROR(dev, "no panel height specified\n"); + + /* Look for some optional backlight */ + tpg->backlight = devm_of_find_backlight(dev); + if (IS_ERR(tpg->backlight)) + return PTR_ERR(tpg->backlight); + + /* This asserts the GRESTB signal, putting the display into reset */ + tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); + if (IS_ERR(tpg->grestb)) { + DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); + return -ENODEV; + } + + spi->bits_per_word = 8; + spi->mode |= SPI_3WIRE_HIZ; + ret = spi_setup(spi); + if (ret < 0) { + DRM_DEV_ERROR(dev, "spi setup failed.\n"); + return ret; + } + tpg->spi = spi; + + ret = tpg110_startup(tpg); + if (ret) + return ret; + + drm_panel_init(&tpg->panel); + tpg->panel.dev = dev; + tpg->panel.funcs = &tpg110_drm_funcs; + spi_set_drvdata(spi, tpg); + + return drm_panel_add(&tpg->panel); +} + +static int tpg110_remove(struct spi_device *spi) +{ + struct tpg110 *tpg = spi_get_drvdata(spi); + + drm_panel_remove(&tpg->panel); + return 0; +} + +static const struct of_device_id tpg110_match[] = { + { .compatible = "tpo,tpg110", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tpg110_match); + +static struct spi_driver tpg110_driver = { + .probe = tpg110_probe, + .remove = tpg110_remove, + .driver = { + .name = "tpo-tpg110-panel", + .of_match_table = tpg110_match, + }, +}; +module_spi_driver(tpg110_driver); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_DESCRIPTION("TPO TPG110 panel driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index dffc5093ff16..2e100f644236 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -25,6 +25,8 @@ /* QXL cmd/ring handling */ +#include <drm/drm_util.h> + #include "qxl_drv.h" #include "qxl_object.h" diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 72a1784dae54..1f8fddcc34d6 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -48,8 +48,8 @@ static int qxl_alloc_client_monitors_config(struct qxl_device *qdev, } if (!qdev->client_monitors_config) { qdev->client_monitors_config = kzalloc( - sizeof(struct qxl_monitors_config) + - sizeof(struct qxl_head) * count, GFP_KERNEL); + struct_size(qdev->client_monitors_config, + heads, count), GFP_KERNEL); if (!qdev->client_monitors_config) return -ENOMEM; } diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index e55cbeee7a53..ac98ad561870 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -27,6 +27,8 @@ #include <linux/slab.h> #include <asm/unaligned.h> +#include <drm/drm_util.h> + #define ATOM_DEBUG #include "atom.h" diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index 770e31f5fd1b..96f71114237a 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -516,21 +516,17 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder, if (!connector) return -EINVAL; - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) { DRM_ERROR("failed to setup AVI infoframe: %d\n", err); return err; } if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { - if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { - if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) - frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; - else - frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; - } else { - frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; - } + drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, + radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); } err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 9d3ac8b981da..b190478ad087 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1646,7 +1646,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) if (rdev->mode_info.mode_config_initialized) { drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); - drm_crtc_force_disable_all(rdev->ddev); + drm_helper_force_disable_all(rdev->ddev); radeon_fbdev_fini(rdev); radeon_afmt_fini(rdev); drm_mode_config_cleanup(rdev->ddev); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 222a1fa41d7c..7e3257e8fd56 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -24,6 +24,7 @@ * Alex Deucher */ #include <drm/drmP.h> +#include <drm/drm_util.h> #include <drm/drm_crtc_helper.h> #include <drm/radeon_drm.h> #include "radeon.h" diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 90dacab67be5..771b460c7216 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -11,7 +11,6 @@ #include <linux/mutex.h> #include <linux/sys_soc.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> @@ -22,6 +21,7 @@ #include "rcar_du_crtc.h" #include "rcar_du_drv.h" +#include "rcar_du_encoder.h" #include "rcar_du_kms.h" #include "rcar_du_plane.h" #include "rcar_du_regs.h" @@ -316,26 +316,6 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); } -void rcar_du_crtc_route_output(struct drm_crtc *crtc, - enum rcar_du_output output) -{ - struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_du_device *rcdu = rcrtc->group->dev; - - /* - * Store the route from the CRTC output to the DU output. The DU will be - * configured when starting the CRTC. - */ - rcrtc->outputs |= BIT(output); - - /* - * Store RGB routing to DPAD0, the hardware will be configured when - * starting the CRTC. - */ - if (output == RCAR_DU_OUTPUT_DPAD0) - rcdu->dpad0_source = rcrtc->index; -} - static unsigned int plane_zpos(struct rcar_du_plane *plane) { return plane->plane.state->normalized_zpos; @@ -655,6 +635,24 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) * CRTC Functions */ +static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(state); + struct drm_encoder *encoder; + + /* Store the routes from the CRTC output to the DU outputs. */ + rstate->outputs = 0; + + drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) { + struct rcar_du_encoder *renc = to_rcar_encoder(encoder); + + rstate->outputs |= BIT(renc->output); + } + + return 0; +} + static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -678,8 +676,6 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, crtc->state->event = NULL; } spin_unlock_irq(&crtc->dev->event_lock); - - rcrtc->outputs = 0; } static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, @@ -755,6 +751,7 @@ enum drm_mode_status rcar_du_crtc_mode_valid(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs crtc_helper_funcs = { + .atomic_check = rcar_du_crtc_atomic_check, .atomic_begin = rcar_du_crtc_atomic_begin, .atomic_flush = rcar_du_crtc_atomic_flush, .atomic_enable = rcar_du_crtc_atomic_enable, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 59ac6e7d22c9..bcb35b0b7612 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -14,7 +14,6 @@ #include <linux/spinlock.h> #include <linux/wait.h> -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <media/vsp1.h> @@ -37,7 +36,6 @@ struct rcar_du_vsp; * @vblank_lock: protects vblank_wait and vblank_count * @vblank_wait: wait queue used to signal vertical blanking * @vblank_count: number of vertical blanking interrupts to wait for - * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC * @group: CRTC group this CRTC belongs to * @vsp: VSP feeding video to this CRTC * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC @@ -61,8 +59,6 @@ struct rcar_du_crtc { wait_queue_head_t vblank_wait; unsigned int vblank_count; - unsigned int outputs; - struct rcar_du_group *group; struct rcar_du_vsp *vsp; unsigned int vsp_pipe; @@ -77,11 +73,13 @@ struct rcar_du_crtc { * struct rcar_du_crtc_state - Driver-specific CRTC state * @state: base DRM CRTC state * @crc: CRC computation configuration + * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC */ struct rcar_du_crtc_state { struct drm_crtc_state state; struct vsp1_du_crc_config crc; + unsigned int outputs; }; #define to_rcar_crtc_state(s) container_of(s, struct rcar_du_crtc_state, state) @@ -102,8 +100,6 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc); void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc); -void rcar_du_crtc_route_output(struct drm_crtc *crtc, - enum rcar_du_output output); void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc); void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index f50a3b1864bb..d1f305694367 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/wait.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_cma_helper.h> @@ -36,7 +35,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7743_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -59,7 +57,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7743_info = { static const struct rcar_du_device_info rzg1_du_r8a7745_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -81,7 +78,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = { static const struct rcar_du_device_info rzg1_du_r8a77470_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -105,8 +101,34 @@ static const struct rcar_du_device_info rzg1_du_r8a77470_info = { }, }; +static const struct rcar_du_device_info rcar_du_r8a774c0_info = { + .gen = 3, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK + | RCAR_DU_FEATURE_VSP1_SOURCE, + .channels_mask = BIT(1) | BIT(0), + .routes = { + /* + * R8A774C0 has one RGB output and two LVDS outputs + */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(0) | BIT(1), + .port = 0, + }, + [RCAR_DU_OUTPUT_LVDS0] = { + .possible_crtcs = BIT(0), + .port = 1, + }, + [RCAR_DU_OUTPUT_LVDS1] = { + .possible_crtcs = BIT(1), + .port = 2, + }, + }, + .num_lvds = 2, + .lvds_clk_mask = BIT(1) | BIT(0), +}; + static const struct rcar_du_device_info rcar_du_r8a7779_info = { - .gen = 2, + .gen = 1, .features = RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -129,7 +151,6 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { static const struct rcar_du_device_info rcar_du_r8a7790_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .quirks = RCAR_DU_QUIRK_ALIGN_128B, @@ -159,7 +180,6 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { static const struct rcar_du_device_info rcar_du_r8a7791_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -183,7 +203,6 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = { static const struct rcar_du_device_info rcar_du_r8a7792_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -203,7 +222,6 @@ static const struct rcar_du_device_info rcar_du_r8a7792_info = { static const struct rcar_du_device_info rcar_du_r8a7794_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, .channels_mask = BIT(1) | BIT(0), @@ -226,7 +244,6 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = { static const struct rcar_du_device_info rcar_du_r8a7795_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, @@ -260,7 +277,6 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = { static const struct rcar_du_device_info rcar_du_r8a7796_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, @@ -290,7 +306,6 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = { static const struct rcar_du_device_info rcar_du_r8a77965_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, @@ -320,7 +335,6 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = { static const struct rcar_du_device_info rcar_du_r8a77970_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, @@ -342,7 +356,6 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = { static const struct rcar_du_device_info rcar_du_r8a7799x_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK - | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE, .channels_mask = BIT(1) | BIT(0), .routes = { @@ -372,6 +385,7 @@ static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info }, { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info }, { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info }, + { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info }, { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info }, { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info }, { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info }, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index a68da79b424e..6c187d0bf7c2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -20,13 +20,13 @@ struct clk; struct device; struct drm_device; +struct drm_property; struct rcar_du_device; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0) /* Per-CRTC IRQ and clock */ -#define RCAR_DU_FEATURE_EXT_CTRL_REGS BIT(1) /* Has extended control registers */ -#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(2) /* Has inputs from VSP1 */ -#define RCAR_DU_FEATURE_INTERLACED BIT(3) /* HW supports interlaced */ -#define RCAR_DU_FEATURE_TVM_SYNC BIT(4) /* Has TV switch/sync modes */ +#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(1) /* Has inputs from VSP1 */ +#define RCAR_DU_FEATURE_INTERLACED BIT(2) /* HW supports interlaced */ +#define RCAR_DU_FEATURE_TVM_SYNC BIT(3) /* Has TV switch/sync modes */ #define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ @@ -89,6 +89,7 @@ struct rcar_du_device { } props; unsigned int dpad0_source; + unsigned int dpad1_source; unsigned int vspd1_sink; }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 1877764bd6d9..f16209499117 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -9,7 +9,6 @@ #include <linux/export.h> -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h> @@ -22,17 +21,7 @@ * Encoder */ -static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - - rcar_du_crtc_route_output(crtc_state->crtc, renc->output); -} - static const struct drm_encoder_helper_funcs encoder_helper_funcs = { - .atomic_mode_set = rcar_du_encoder_mode_set, }; static const struct drm_encoder_funcs encoder_funcs = { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index ce3cbc85695e..552f2a02e5b5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h @@ -10,10 +10,8 @@ #ifndef __RCAR_DU_ENCODER_H__ #define __RCAR_DU_ENCODER_H__ -#include <drm/drm_crtc.h> #include <drm/drm_encoder.h> -struct drm_panel; struct rcar_du_device; struct rcar_du_encoder { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index cebf313c6e1f..9eee47969e77 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -147,7 +147,7 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) rcar_du_group_setup_pins(rgrp); - if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { + if (rcdu->info->gen >= 2) { rcar_du_group_setup_defr8(rgrp); rcar_du_group_setup_didsr(rgrp); } @@ -262,7 +262,7 @@ int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) unsigned int index; int ret; - if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) + if (rcdu->info->gen < 2) return 0; /* @@ -287,9 +287,50 @@ int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) return 0; } +static void rcar_du_group_set_dpad_levels(struct rcar_du_group *rgrp) +{ + static const u32 doflr_values[2] = { + DOFLR_HSYCFL0 | DOFLR_VSYCFL0 | DOFLR_ODDFL0 | + DOFLR_DISPFL0 | DOFLR_CDEFL0 | DOFLR_RGBFL0, + DOFLR_HSYCFL1 | DOFLR_VSYCFL1 | DOFLR_ODDFL1 | + DOFLR_DISPFL1 | DOFLR_CDEFL1 | DOFLR_RGBFL1, + }; + static const u32 dpad_mask = BIT(RCAR_DU_OUTPUT_DPAD1) + | BIT(RCAR_DU_OUTPUT_DPAD0); + struct rcar_du_device *rcdu = rgrp->dev; + u32 doflr = DOFLR_CODE; + unsigned int i; + + if (rcdu->info->gen < 2) + return; + + /* + * The DPAD outputs can't be controlled directly. However, the parallel + * output of the DU channels routed to DPAD can be set to fixed levels + * through the DOFLR group register. Use this to turn the DPAD on or off + * by driving fixed low-level signals at the output of any DU channel + * not routed to a DPAD output. This doesn't affect the DU output + * signals going to other outputs, such as the internal LVDS and HDMI + * encoders. + */ + + for (i = 0; i < rgrp->num_crtcs; ++i) { + struct rcar_du_crtc_state *rstate; + struct rcar_du_crtc *rcrtc; + + rcrtc = &rcdu->crtcs[rgrp->index * 2 + i]; + rstate = to_rcar_crtc_state(rcrtc->crtc.state); + + if (!(rstate->outputs & dpad_mask)) + doflr |= doflr_values[i]; + } + + rcar_du_group_write(rgrp, DOFLR, doflr); +} + int rcar_du_group_set_routing(struct rcar_du_group *rgrp) { - struct rcar_du_crtc *crtc0 = &rgrp->dev->crtcs[rgrp->index * 2]; + struct rcar_du_device *rcdu = rgrp->dev; u32 dorcr = rcar_du_group_read(rgrp, DORCR); dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); @@ -299,12 +340,14 @@ int rcar_du_group_set_routing(struct rcar_du_group *rgrp) * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1 * by default. */ - if (crtc0->outputs & BIT(RCAR_DU_OUTPUT_DPAD1)) + if (rcdu->dpad1_source == rgrp->index * 2) dorcr |= DORCR_PG2D_DS1; else dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; rcar_du_group_write(rgrp, DORCR, dorcr); + rcar_du_group_set_dpad_levels(rgrp); + return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 9c7007d45408..e4b248e368d6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -7,7 +7,6 @@ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> @@ -278,6 +277,28 @@ static int rcar_du_atomic_check(struct drm_device *dev, static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; + struct rcar_du_device *rcdu = dev->dev_private; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + unsigned int i; + + /* + * Store RGB routing to DPAD0 and DPAD1, the hardware will be configured + * when starting the CRTCs. + */ + rcdu->dpad1_source = -1; + + for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) { + struct rcar_du_crtc_state *rcrtc_state = + to_rcar_crtc_state(crtc_state); + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0)) + rcdu->dpad0_source = rcrtc->index; + + if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1)) + rcdu->dpad1_source = rcrtc->index; + } /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts index 579753e04f3b..8bee4e787a0a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts @@ -7,70 +7,63 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - lvds@feb90000 { - compatible = "renesas,r8a7790-lvds"; - reg = <0 0xfeb90000 0 0x1c>; +&{/} { + #address-cells = <2>; + #size-cells = <2>; - ports { - #address-cells = <1>; - #size-cells = <0>; + lvds@feb90000 { + compatible = "renesas,r8a7790-lvds"; + reg = <0 0xfeb90000 0 0x1c>; - port@0 { - reg = <0>; - lvds0_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds0_out: endpoint { - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { }; }; - - lvds@feb94000 { - compatible = "renesas,r8a7790-lvds"; - reg = <0 0xfeb94000 0 0x1c>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - lvds1_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds1_out: endpoint { - }; - }; + port@1 { + reg = <1>; + lvds0_out: endpoint { }; }; }; }; - fragment@1 { - target-path = "/display@feb00000/ports"; - __overlay__ { - port@1 { - endpoint { - remote-endpoint = <&lvds0_input>; + lvds@feb94000 { + compatible = "renesas,r8a7790-lvds"; + reg = <0 0xfeb94000 0 0x1c>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds1_input: endpoint { }; }; - port@2 { - endpoint { - remote-endpoint = <&lvds1_input>; + port@1 { + reg = <1>; + lvds1_out: endpoint { }; }; }; }; }; + +&{/display@feb00000/ports} { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + port@2 { + endpoint { + remote-endpoint = <&lvds1_input>; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts index cb9da1f3942b..92c0509971ec 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts @@ -7,44 +7,37 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - lvds@feb90000 { - compatible = "renesas,r8a7791-lvds"; - reg = <0 0xfeb90000 0 0x1c>; +&{/} { + #address-cells = <2>; + #size-cells = <2>; - ports { - #address-cells = <1>; - #size-cells = <0>; + lvds@feb90000 { + compatible = "renesas,r8a7791-lvds"; + reg = <0 0xfeb90000 0 0x1c>; - port@0 { - reg = <0>; - lvds0_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds0_out: endpoint { - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { }; }; - }; - }; - - fragment@1 { - target-path = "/display@feb00000/ports"; - __overlay__ { port@1 { - endpoint { - remote-endpoint = <&lvds0_input>; + reg = <1>; + lvds0_out: endpoint { }; }; }; }; }; + +&{/display@feb00000/ports} { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts index e7b8804dc3c1..c8b93f21de0f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts @@ -7,44 +7,37 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - lvds@feb90000 { - compatible = "renesas,r8a7793-lvds"; - reg = <0 0xfeb90000 0 0x1c>; +&{/} { + #address-cells = <2>; + #size-cells = <2>; - ports { - #address-cells = <1>; - #size-cells = <0>; + lvds@feb90000 { + compatible = "renesas,r8a7793-lvds"; + reg = <0 0xfeb90000 0 0x1c>; - port@0 { - reg = <0>; - lvds0_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds0_out: endpoint { - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { }; }; - }; - }; - - fragment@1 { - target-path = "/display@feb00000/ports"; - __overlay__ { port@1 { - endpoint { - remote-endpoint = <&lvds0_input>; + reg = <1>; + lvds0_out: endpoint { }; }; }; }; }; + +&{/display@feb00000/ports} { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts index a1327443e6fa..16c2d03cb016 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts @@ -7,44 +7,37 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/soc"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - lvds@feb90000 { - compatible = "renesas,r8a7795-lvds"; - reg = <0 0xfeb90000 0 0x14>; +&{/soc} { + #address-cells = <2>; + #size-cells = <2>; - ports { - #address-cells = <1>; - #size-cells = <0>; + lvds@feb90000 { + compatible = "renesas,r8a7795-lvds"; + reg = <0 0xfeb90000 0 0x14>; - port@0 { - reg = <0>; - lvds0_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds0_out: endpoint { - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { }; }; }; }; +}; - fragment@1 { - target-path = "/soc/display@feb00000/ports"; - __overlay__ { - port@3 { - endpoint { - remote-endpoint = <&lvds0_input>; - }; - }; +&{/soc/display@feb00000/ports} { + port@3 { + endpoint { + remote-endpoint = <&lvds0_input>; }; }; }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts index b23d6466c415..680e923ac036 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts @@ -7,44 +7,37 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/soc"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - lvds@feb90000 { - compatible = "renesas,r8a7796-lvds"; - reg = <0 0xfeb90000 0 0x14>; +&{/soc} { + #address-cells = <2>; + #size-cells = <2>; - ports { - #address-cells = <1>; - #size-cells = <0>; + lvds@feb90000 { + compatible = "renesas,r8a7796-lvds"; + reg = <0 0xfeb90000 0 0x14>; - port@0 { - reg = <0>; - lvds0_input: endpoint { - }; - }; - port@1 { - reg = <1>; - lvds0_out: endpoint { - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { }; }; }; }; +}; - fragment@1 { - target-path = "/soc/display@feb00000/ports"; - __overlay__ { - port@3 { - endpoint { - remote-endpoint = <&lvds0_input>; - }; - }; +&{/soc/display@feb00000/ports} { + port@3 { + endpoint { + remote-endpoint = <&lvds0_input>; }; }; }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 39d5ae3fdf72..fa6b9aabc832 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -7,7 +7,6 @@ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index 2f223a4c1d33..81bbf207ad0e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -10,8 +10,7 @@ #ifndef __RCAR_DU_PLANE_H__ #define __RCAR_DU_PLANE_H__ -#include <drm/drmP.h> -#include <drm/drm_crtc.h> +#include <drm/drm_plane.h> struct rcar_du_format_info; struct rcar_du_group; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 4576119e7777..dec314a687e0 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -7,7 +7,6 @@ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index e8c14dc5cb93..db232037f24a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h @@ -10,8 +10,7 @@ #ifndef __RCAR_DU_VSP_H__ #define __RCAR_DU_VSP_H__ -#include <drm/drmP.h> -#include <drm/drm_crtc.h> +#include <drm/drm_plane.h> struct rcar_du_format_info; struct rcar_du_vsp; diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c index 75490a3e0a2a..452461dc96f2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c @@ -7,10 +7,12 @@ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <drm/bridge/dw_hdmi.h> +#include <drm/drm_modes.h> #define RCAR_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL dividers */ #define RCAR_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conductance) */ @@ -35,6 +37,20 @@ static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { { ~0UL, 0x0000, 0x0000, 0x0000 }, }; +static enum drm_mode_status +rcar_hdmi_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + /* + * The maximum supported clock frequency is 297 MHz, as shown in the PHY + * parameters table. + */ + if (mode->clock > 297000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, const struct dw_hdmi_plat_data *pdata, unsigned long mpixelclock) @@ -59,6 +75,7 @@ static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, } static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = { + .mode_valid = rcar_hdmi_mode_valid, .configure_phy = rcar_hdmi_phy_configure, }; diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 534a128a869d..96d749a35b25 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -520,8 +520,8 @@ static void rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds) } static void rcar_lvds_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -785,6 +785,7 @@ static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = { static const struct of_device_id rcar_lvds_of_table[] = { { .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info }, + { .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info }, { .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_r8a7790_info }, { .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info }, { .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info }, diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 7ee359bcee62..ef8486e5e2cd 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -467,7 +467,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) } static int -dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, +dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps) { diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 1c02b3e61299..27c945e030a0 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -295,7 +295,9 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, union hdmi_infoframe frame; int rc; - rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); + rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + &hdmi->connector, + mode); if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) frame.avi.colorspace = HDMI_COLORSPACE_YUV444; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index ea18cb2a76c0..08bec50d9c5d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -128,42 +128,6 @@ err_gem_object_unreference: } static void -rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - struct drm_encoder *encoder; - u32 encoder_mask = 0; - int i; - - for_each_old_crtc_in_state(state, crtc, crtc_state, i) { - encoder_mask |= crtc_state->encoder_mask; - encoder_mask |= crtc->state->encoder_mask; - } - - drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) - rockchip_drm_psr_inhibit_get(encoder); -} - -static void -rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - struct drm_encoder *encoder; - u32 encoder_mask = 0; - int i; - - for_each_old_crtc_in_state(state, crtc, crtc_state, i) { - encoder_mask |= crtc_state->encoder_mask; - encoder_mask |= crtc->state->encoder_mask; - } - - drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) - rockchip_drm_psr_inhibit_put(encoder); -} - -static void rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c index 01ff3c858875..22a70ab6e214 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c @@ -13,6 +13,7 @@ */ #include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/drm_crtc_helper.h> #include "rockchip_drm_drv.h" @@ -109,6 +110,42 @@ int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder) } EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put); +void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_encoder *encoder; + u32 encoder_mask = 0; + int i; + + for_each_old_crtc_in_state(state, crtc, crtc_state, i) { + encoder_mask |= crtc_state->encoder_mask; + encoder_mask |= crtc->state->encoder_mask; + } + + drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) + rockchip_drm_psr_inhibit_get(encoder); +} +EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state); + +void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_encoder *encoder; + u32 encoder_mask = 0; + int i; + + for_each_old_crtc_in_state(state, crtc, crtc_state, i) { + encoder_mask |= crtc_state->encoder_mask; + encoder_mask |= crtc->state->encoder_mask; + } + + drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) + rockchip_drm_psr_inhibit_put(encoder); +} +EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state); + /** * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder * @encoder: encoder to obtain the PSR encoder diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h index 860c62494496..25350ba3237b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h @@ -20,6 +20,9 @@ void rockchip_drm_psr_flush_all(struct drm_device *dev); int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder); int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder); +void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state); +void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state); + int rockchip_drm_psr_register(struct drm_encoder *encoder, int (*psr_set)(struct drm_encoder *, bool enable)); void rockchip_drm_psr_unregister(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index db8358e6d230..619b6db05d58 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -15,6 +15,7 @@ #include <drm/drm.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> +#include <drm/drm_atomic_uapi.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_flip_work.h> @@ -45,14 +46,26 @@ #include "rockchip_drm_vop.h" #include "rockchip_rgb.h" -#define VOP_WIN_SET(x, win, name, v) \ +#define VOP_WIN_SET(vop, win, name, v) \ vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) -#define VOP_SCL_SET(x, win, name, v) \ +#define VOP_SCL_SET(vop, win, name, v) \ vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name) -#define VOP_SCL_SET_EXT(x, win, name, v) \ +#define VOP_SCL_SET_EXT(vop, win, name, v) \ vop_reg_set(vop, &win->phy->scl->ext->name, \ win->base, ~0, v, #name) +#define VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, name, v) \ + do { \ + if (win_yuv2yuv && win_yuv2yuv->name.mask) \ + vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \ + } while (0) + +#define VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, win_yuv2yuv, name, v) \ + do { \ + if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \ + vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \ + } while (0) + #define VOP_INTR_SET_MASK(vop, name, mask, v) \ vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) @@ -73,8 +86,11 @@ #define VOP_INTR_GET_TYPE(vop, name, type) \ vop_get_intr_type(vop, &vop->data->intr->name, type) -#define VOP_WIN_GET(x, win, name) \ - vop_read_reg(x, win->offset, win->phy->name) +#define VOP_WIN_GET(vop, win, name) \ + vop_read_reg(vop, win->offset, win->phy->name) + +#define VOP_WIN_HAS_REG(win, name) \ + (!!(win->phy->name.mask)) #define VOP_WIN_GET_YRGBADDR(vop, win) \ vop_readl(vop, win->base + win->phy->yrgb_mst.offset) @@ -85,6 +101,18 @@ #define to_vop(x) container_of(x, struct vop, crtc) #define to_vop_win(x) container_of(x, struct vop_win, base) +/* + * The coefficients of the following matrix are all fixed points. + * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. + * They are all represented in two's complement. + */ +static const uint32_t bt601_yuv2rgb[] = { + 0x4A8, 0x0, 0x662, + 0x4A8, 0x1E6F, 0x1CBF, + 0x4A8, 0x812, 0x0, + 0x321168, 0x0877CF, 0x2EB127 +}; + enum vop_pending { VOP_PENDING_FB_UNREF, }; @@ -92,6 +120,7 @@ enum vop_pending { struct vop_win { struct drm_plane base; const struct vop_win_data *data; + const struct vop_win_yuv2yuv_data *yuv2yuv_data; struct vop *vop; }; @@ -686,6 +715,11 @@ static int vop_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + if (fb->format->is_yuv && state->rotation & DRM_MODE_REFLECT_Y) { + DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n"); + return -EINVAL; + } + return 0; } @@ -713,6 +747,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct vop_win *vop_win = to_vop_win(plane); const struct vop_win_data *win = vop_win->data; + const struct vop_win_yuv2yuv_data *win_yuv2yuv = vop_win->yuv2yuv_data; struct vop *vop = to_vop(state->crtc); struct drm_framebuffer *fb = state->fb; unsigned int actual_w, actual_h; @@ -728,6 +763,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, bool rb_swap; int win_index = VOP_WIN_TO_INDEX(vop_win); int format; + int is_yuv = fb->format->is_yuv; + int i; /* * can't update plane when vop is disabled. @@ -761,6 +798,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, offset += (src->y1 >> 16) * fb->pitches[0]; dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; + /* + * For y-mirroring we need to move address + * to the beginning of the last line. + */ + if (state->rotation & DRM_MODE_REFLECT_Y) + dma_addr += (actual_h - 1) * fb->pitches[0]; + format = vop_convert_format(fb->format->format); spin_lock(&vop->reg_lock); @@ -768,7 +812,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); - if (fb->format->is_yuv) { + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); + VOP_WIN_SET(vop, win, y_mir_en, + (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0); + VOP_WIN_SET(vop, win, x_mir_en, + (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); + + if (is_yuv) { int hsub = drm_format_horz_chroma_subsampling(fb->format->format); int vsub = drm_format_vert_chroma_subsampling(fb->format->format); int bpp = fb->format->cpp[1]; @@ -782,6 +832,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); VOP_WIN_SET(vop, win, uv_mst, dma_addr); + + for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) { + VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, + win_yuv2yuv, + y2r_coefficients[i], + bt601_yuv2rgb[i]); + } } if (win->phy->scl) @@ -820,10 +877,83 @@ static void vop_plane_atomic_update(struct drm_plane *plane, spin_unlock(&vop->reg_lock); } +static int vop_plane_atomic_async_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vop_win *vop_win = to_vop_win(plane); + const struct vop_win_data *win = vop_win->data; + int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : + DRM_PLANE_HELPER_NO_SCALING; + int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : + DRM_PLANE_HELPER_NO_SCALING; + struct drm_crtc_state *crtc_state; + + if (plane != state->crtc->cursor) + return -EINVAL; + + if (!plane->state) + return -EINVAL; + + if (!plane->state->fb) + return -EINVAL; + + if (state->state) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); + else /* Special case for asynchronous cursor updates. */ + crtc_state = plane->crtc->state; + + return drm_atomic_helper_check_plane_state(plane->state, crtc_state, + min_scale, max_scale, + true, true); +} + +static void vop_plane_atomic_async_update(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct vop *vop = to_vop(plane->state->crtc); + struct drm_plane_state *plane_state; + + plane_state = plane->funcs->atomic_duplicate_state(plane); + plane_state->crtc_x = new_state->crtc_x; + plane_state->crtc_y = new_state->crtc_y; + plane_state->crtc_h = new_state->crtc_h; + plane_state->crtc_w = new_state->crtc_w; + plane_state->src_x = new_state->src_x; + plane_state->src_y = new_state->src_y; + plane_state->src_h = new_state->src_h; + plane_state->src_w = new_state->src_w; + + if (plane_state->fb != new_state->fb) + drm_atomic_set_fb_for_plane(plane_state, new_state->fb); + + swap(plane_state, plane->state); + + if (plane->state->fb && plane->state->fb != new_state->fb) { + drm_framebuffer_get(plane->state->fb); + WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0); + drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb); + set_bit(VOP_PENDING_FB_UNREF, &vop->pending); + } + + if (vop->is_enabled) { + rockchip_drm_psr_inhibit_get_state(new_state->state); + vop_plane_atomic_update(plane, plane->state); + spin_lock(&vop->reg_lock); + vop_cfg_done(vop); + spin_unlock(&vop->reg_lock); + rockchip_drm_psr_inhibit_put_state(new_state->state); + } + + plane->funcs->atomic_destroy_state(plane, plane_state); +} + static const struct drm_plane_helper_funcs plane_helper_funcs = { .atomic_check = vop_plane_atomic_check, .atomic_update = vop_plane_atomic_update, .atomic_disable = vop_plane_atomic_disable, + .atomic_async_check = vop_plane_atomic_async_check, + .atomic_async_update = vop_plane_atomic_async_update, .prepare_fb = drm_gem_fb_prepare_fb, }; @@ -1274,6 +1404,18 @@ out: return ret; } +static void vop_plane_add_properties(struct drm_plane *plane, + const struct vop_win_data *win_data) +{ + unsigned int flags = 0; + + flags |= VOP_WIN_HAS_REG(win_data, x_mir_en) ? DRM_MODE_REFLECT_X : 0; + flags |= VOP_WIN_HAS_REG(win_data, y_mir_en) ? DRM_MODE_REFLECT_Y : 0; + if (flags) + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_0 | flags); +} + static int vop_create_crtc(struct vop *vop) { const struct vop_data *vop_data = vop->data; @@ -1311,6 +1453,7 @@ static int vop_create_crtc(struct vop *vop) plane = &vop_win->base; drm_plane_helper_add(plane, &plane_helper_funcs); + vop_plane_add_properties(plane, win_data); if (plane->type == DRM_PLANE_TYPE_PRIMARY) primary = plane; else if (plane->type == DRM_PLANE_TYPE_CURSOR) @@ -1348,6 +1491,7 @@ static int vop_create_crtc(struct vop *vop) goto err_cleanup_crtc; } drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); + vop_plane_add_properties(&vop_win->base, win_data); } port = of_get_child_by_name(dev->of_node, "port"); @@ -1531,6 +1675,7 @@ static void vop_win_init(struct vop *vop) vop_win->data = win_data; vop_win->vop = vop; + vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i]; } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 0fe40e1983d9..04ed401d2325 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -23,6 +23,8 @@ #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) +#define NUM_YUV2YUV_COEFFICIENTS 12 + enum vop_data_format { VOP_FMT_ARGB8888 = 0, VOP_FMT_RGB888, @@ -124,6 +126,10 @@ struct vop_scl_regs { struct vop_reg scale_cbcr_y; }; +struct vop_yuv2yuv_phy { + struct vop_reg y2r_coefficients[NUM_YUV2YUV_COEFFICIENTS]; +}; + struct vop_win_phy { const struct vop_scl_regs *scl; const uint32_t *data_formats; @@ -140,12 +146,20 @@ struct vop_win_phy { struct vop_reg uv_mst; struct vop_reg yrgb_vir; struct vop_reg uv_vir; + struct vop_reg y_mir_en; + struct vop_reg x_mir_en; struct vop_reg dst_alpha_ctl; struct vop_reg src_alpha_ctl; struct vop_reg channel; }; +struct vop_win_yuv2yuv_data { + uint32_t base; + const struct vop_yuv2yuv_phy *phy; + struct vop_reg y2r_en; +}; + struct vop_win_data { uint32_t base; const struct vop_win_phy *phy; @@ -159,6 +173,7 @@ struct vop_data { const struct vop_misc *misc; const struct vop_modeset *modeset; const struct vop_output *output; + const struct vop_win_yuv2yuv_data *win_yuv2yuv; const struct vop_win_data *win; unsigned int win_size; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 08fc40af52c8..bd76328c0fdb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -299,6 +299,114 @@ static const struct vop_data px30_vop_lit = { .win_size = ARRAY_SIZE(px30_vop_lit_win_data), }; +static const struct vop_scl_regs rk3066_win_scl = { + .scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3066_win0_data = { + .scl = &rk3066_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), + .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), +}; + +static const struct vop_win_phy rk3066_win1_data = { + .scl = &rk3066_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), + .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), +}; + +static const struct vop_win_phy rk3066_win2_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), + .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), +}; + +static const struct vop_modeset rk3066_modeset = { + .htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0), +}; + +static const struct vop_output rk3066_output = { + .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4), +}; + +static const struct vop_common rk3066_common = { + .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1), + .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0), + .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24), +}; + +static const struct vop_win_data rk3066_vop_win_data[] = { + { .base = 0x00, .phy = &rk3066_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3066_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3066_win2_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const int rk3066_vop_intrs[] = { + /* + * hs_start interrupt fires at frame-start, so serves + * the same purpose as dsp_hold in the driver. + */ + DSP_HOLD_VALID_INTR, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3066_intr = { + .intrs = rk3066_vop_intrs, + .nintrs = ARRAY_SIZE(rk3066_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3066_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4), + .clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8), +}; + +static const struct vop_data rk3066_vop = { + .version = VOP_VERSION(2, 1), + .intr = &rk3066_intr, + .common = &rk3066_common, + .modeset = &rk3066_modeset, + .output = &rk3066_output, + .win = rk3066_vop_win_data, + .win_size = ARRAY_SIZE(rk3066_vop_win_data), +}; + static const struct vop_scl_regs rk3188_win_scl = { .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), @@ -550,6 +658,27 @@ static const struct vop_intr rk3368_vop_intr = { .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0), }; +static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), + .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0), +}; + static const struct vop_win_phy rk3368_win23_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), @@ -557,6 +686,7 @@ static const struct vop_win_phy rk3368_win23_data = { .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20), + .y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15), .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0), .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0), @@ -566,9 +696,9 @@ static const struct vop_win_phy rk3368_win23_data = { }; static const struct vop_win_data rk3368_vop_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, + { .base = 0x00, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x40, .phy = &rk3288_win01_data, + { .base = 0x40, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_OVERLAY }, { .base = 0x00, .phy = &rk3368_win23_data, .type = DRM_PLANE_TYPE_OVERLAY }, @@ -637,6 +767,34 @@ static const struct vop_output rk3399_output = { .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), }; +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = { + .y2r_coefficients = { + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0), + }, +}; + +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { }; + +static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) }, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, + { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, + { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, +}; + static const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_RGB10, @@ -647,15 +805,22 @@ static const struct vop_data rk3399_vop_big = { .misc = &rk3368_misc, .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, + { .base = 0x00, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_PRIMARY }, { .base = 0x00, .phy = &rk3368_win23_data, .type = DRM_PLANE_TYPE_CURSOR}, }; +static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)}, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data }, +}; + static const struct vop_data rk3399_vop_lit = { .version = VOP_VERSION(3, 6), .intr = &rk3366_vop_intr, @@ -665,6 +830,7 @@ static const struct vop_data rk3399_vop_lit = { .misc = &rk3368_misc, .win = rk3399_vop_lit_win_data, .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), + .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data, }; static const struct vop_win_data rk3228_vop_win_data[] = { @@ -730,11 +896,11 @@ static const struct vop_intr rk3328_vop_intr = { }; static const struct vop_win_data rk3328_vop_win_data[] = { - { .base = 0xd0, .phy = &rk3288_win01_data, + { .base = 0xd0, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x1d0, .phy = &rk3288_win01_data, + { .base = 0x1d0, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_OVERLAY }, - { .base = 0x2d0, .phy = &rk3288_win01_data, + { .base = 0x2d0, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_CURSOR }, }; @@ -759,6 +925,8 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &px30_vop_big }, { .compatible = "rockchip,px30-vop-lit", .data = &px30_vop_lit }, + { .compatible = "rockchip,rk3066-vop", + .data = &rk3066_vop }, { .compatible = "rockchip,rk3188-vop", .data = &rk3188_vop }, { .compatible = "rockchip,rk3288-vop", diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 7348c68352ed..d837d4a7df4a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -983,4 +983,57 @@ #define RK3188_REG_CFG_DONE 0x90 /* rk3188 register definition end */ +/* rk3066 register definition */ +#define RK3066_SYS_CTRL0 0x00 +#define RK3066_SYS_CTRL1 0x04 +#define RK3066_DSP_CTRL0 0x08 +#define RK3066_DSP_CTRL1 0x0c +#define RK3066_INT_STATUS 0x10 +#define RK3066_MCU_CTRL 0x14 +#define RK3066_BLEND_CTRL 0x18 +#define RK3066_WIN0_COLOR_KEY_CTRL 0x1c +#define RK3066_WIN1_COLOR_KEY_CTRL 0x20 +#define RK3066_WIN2_COLOR_KEY_CTRL 0x24 +#define RK3066_WIN0_YRGB_MST0 0x28 +#define RK3066_WIN0_CBR_MST0 0x2c +#define RK3066_WIN0_YRGB_MST1 0x30 +#define RK3066_WIN0_CBR_MST1 0x34 +#define RK3066_WIN0_VIR 0x38 +#define RK3066_WIN0_ACT_INFO 0x3c +#define RK3066_WIN0_DSP_INFO 0x40 +#define RK3066_WIN0_DSP_ST 0x44 +#define RK3066_WIN0_SCL_FACTOR_YRGB 0x48 +#define RK3066_WIN0_SCL_FACTOR_CBR 0x4c +#define RK3066_WIN0_SCL_OFFSET 0x50 +#define RK3066_WIN1_YRGB_MST 0x54 +#define RK3066_WIN1_CBR_MST 0x58 +#define RK3066_WIN1_VIR 0x5c +#define RK3066_WIN1_ACT_INFO 0x60 +#define RK3066_WIN1_DSP_INFO 0x64 +#define RK3066_WIN1_DSP_ST 0x68 +#define RK3066_WIN1_SCL_FACTOR_YRGB 0x6c +#define RK3066_WIN1_SCL_FACTOR_CBR 0x70 +#define RK3066_WIN1_SCL_OFFSET 0x74 +#define RK3066_WIN2_MST 0x78 +#define RK3066_WIN2_VIR 0x7c +#define RK3066_WIN2_DSP_INFO 0x80 +#define RK3066_WIN2_DSP_ST 0x84 +#define RK3066_HWC_MST 0x88 +#define RK3066_HWC_DSP_ST 0x8c +#define RK3066_HWC_COLOR_LUT0 0x90 +#define RK3066_HWC_COLOR_LUT1 0x94 +#define RK3066_HWC_COLOR_LUT2 0x98 +#define RK3066_DSP_HTOTAL_HS_END 0x9c +#define RK3066_DSP_HACT_ST_END 0xa0 +#define RK3066_DSP_VTOTAL_VS_END 0xa4 +#define RK3066_DSP_VACT_ST_END 0xa8 +#define RK3066_DSP_VS_ST_END_F1 0xac +#define RK3066_DSP_VACT_ST_END_F1 0xb0 +#define RK3066_REG_CFG_DONE 0xc0 +#define RK3066_MCU_BYPASS_WPORT 0x100 +#define RK3066_MCU_BYPASS_RPORT 0x200 +#define RK3066_WIN2_LUT_ADDR 0x400 +#define RK3066_DSP_LUT_ADDR 0x800 +/* rk3066 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */ diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 8554102a6ead..f2cfd1698b78 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -229,8 +229,8 @@ static int shmob_drm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sdev->mmio = devm_ioremap_resource(&pdev->dev, res); - if (sdev->mmio == NULL) - return -ENOMEM; + if (IS_ERR(sdev->mmio)) + return PTR_ERR(sdev->mmio); ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); if (ret < 0) diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index ed76e52eb213..ec9f87483e39 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -53,18 +53,10 @@ sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) struct clk *compo_clk, *pix_clk; int rate = mode->clock * 1000; - DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - mode->base.id, mode->name); - - DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->vrefresh, mode->clock, - mode->hdisplay, - mode->hsync_start, mode->hsync_end, - mode->htotal, - mode->vdisplay, - mode->vsync_start, mode->vsync_end, - mode->vtotal, mode->type, mode->flags); + DRM_DEBUG_KMS("CRTC:%d (%s) mode: (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), mode->name); + + DRM_DEBUG_KMS(DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); if (mixer->id == STI_MIXER_MAIN) { compo_clk = compo->clk_compo_main; diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index b08376b7611b..6d33772f77eb 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -277,8 +277,8 @@ static void sti_dvo_pre_enable(struct drm_bridge *bridge) } static void sti_dvo_set_mode(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct sti_dvo *dvo = bridge->driver_private; struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc); diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 19b9b5ed1297..a63dd5eb7081 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -508,8 +508,8 @@ static void sti_hda_pre_enable(struct drm_bridge *bridge) } static void sti_hda_set_mode(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct sti_hda *hda = bridge->driver_private; u32 mode_idx; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index ccf718404a1c..458fcb5a93f2 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -434,7 +434,8 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) DRM_DEBUG_DRIVER("\n"); - ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, + hdmi->drm_connector, mode); if (ret < 0) { DRM_ERROR("failed to setup AVI infoframe: %d\n", ret); return ret; @@ -917,8 +918,8 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) } static void sti_hdmi_set_mode(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct sti_hdmi *hdmi = bridge->driver_private; int ret; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index a514b593f37c..a672b59a2226 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -215,7 +215,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) } static int -dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, +dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps) { diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 61dd661aa0ac..a91e04139595 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -691,7 +691,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - u32 src_x, src_y, src_w, src_h; + u32 src_w, src_h; DRM_DEBUG_DRIVER("\n"); @@ -699,8 +699,6 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, return 0; /* convert src_ from 16:16 format */ - src_x = state->src_x >> 16; - src_y = state->src_y >> 16; src_w = state->src_w >> 16; src_h = state->src_h >> 16; diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 9e9255ee59cd..892197f52557 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -45,28 +45,6 @@ static const u32 sunxi_rgb2yuv_coef[12] = { 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 }; -/* - * These coefficients are taken from the A33 BSP from Allwinner. - * - * The first three values of each row are coded as 13-bit signed fixed-point - * numbers, with 10 bits for the fractional part. The fourth value is a - * constant coded as a 14-bit signed fixed-point number with 4 bits for the - * fractional part. - * - * The values in table order give the following colorspace translation: - * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 - * R = 1.164 * Y + 1.596 * V - 222 - * B = 1.164 * Y + 2.018 * U + 276 - * - * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], - * following the BT601 spec. - */ -static const u32 sunxi_bt601_yuv2rgb_coef[12] = { - 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, - 0x000004a7, 0x00000000, 0x00000662, 0x00003211, - 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, -}; - static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -245,7 +223,8 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); /* TODO: Add support for the multi-planar YUV formats */ - if (format->num_planes == 1) + if (drm_format_info_is_yuv_packed(format) && + drm_format_info_is_yuv_sampling_422(format)) val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; else DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt); diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 9e4c375ccc96..93da837194cf 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -97,6 +97,7 @@ static int sun4i_drv_bind(struct device *dev) } drm_mode_config_init(drm); + drm->mode_config.allow_fb_modifiers = true; ret = component_bind_all(drm->dev, drm); if (ret) { diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index 1a7ebc45747e..e8239d4d4dd5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/component.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -48,10 +49,38 @@ static const u32 sun4i_frontend_horz_coef[64] = { 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42, }; +/* + * These coefficients are taken from the A33 BSP from Allwinner. + * + * The first three values of each row are coded as 13-bit signed fixed-point + * numbers, with 10 bits for the fractional part. The fourth value is a + * constant coded as a 14-bit signed fixed-point number with 4 bits for the + * fractional part. + * + * The values in table order give the following colorspace translation: + * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 + * R = 1.164 * Y + 1.596 * V - 222 + * B = 1.164 * Y + 2.018 * U + 276 + * + * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], + * following the BT601 spec. + */ +const u32 sunxi_bt601_yuv2rgb_coef[12] = { + 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, + 0x000004a7, 0x00000000, 0x00000662, 0x00003211, + 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, +}; +EXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef); + static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) { int i; + if (frontend->data->has_coef_access_ctrl) + regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, + SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, + SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); + for (i = 0; i < 32; i++) { regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i), sun4i_frontend_horz_coef[2 * i]); @@ -67,9 +96,11 @@ static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) sun4i_frontend_vert_coef[i]); } - regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, - SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, - SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); + if (frontend->data->has_coef_rdy) + regmap_write_bits(frontend->regs, + SUN4I_FRONTEND_FRM_CTRL_REG, + SUN4I_FRONTEND_FRM_CTRL_COEF_RDY, + SUN4I_FRONTEND_FRM_CTRL_COEF_RDY); } int sun4i_frontend_init(struct sun4i_frontend *frontend) @@ -84,59 +115,228 @@ void sun4i_frontend_exit(struct sun4i_frontend *frontend) } EXPORT_SYMBOL(sun4i_frontend_exit); +static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU444: + return true; + + default: + return false; + } +} + +static bool sun4i_frontend_format_supports_tiling(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU411: + return true; + + default: + return false; + } +} + void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; + unsigned int strides[3] = {}; + dma_addr_t paddr; + bool swap; + + if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) { + unsigned int width = state->src_w >> 16; + unsigned int offset; + + strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]); + + /* + * The X1 offset is the offset to the bottom-right point in the + * end tile, which is the final pixel (at offset width - 1) + * within the end tile (with a 32-byte mask). + */ + offset = (width - 1) & (32 - 1); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + + if (fb->format->num_planes > 1) { + strides[1] = + SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + } + + if (fb->format->num_planes > 2) { + strides[2] = + SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + } + } else { + strides[0] = fb->pitches[0]; + + if (fb->format->num_planes > 1) + strides[1] = fb->pitches[1]; + + if (fb->format->num_planes > 2) + strides[2] = fb->pitches[2]; + } /* Set the line width */ DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG, - fb->pitches[0]); + strides[0]); + + if (fb->format->num_planes > 1) + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG, + strides[1]); + + if (fb->format->num_planes > 2) + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG, + strides[2]); + + /* Some planar formats require chroma channel swapping by hand. */ + swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); /* Set the physical address of the buffer in memory */ paddr = drm_fb_cma_get_gem_addr(fb, state, 0); paddr -= PHYS_OFFSET; - DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); + DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr); regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); + + if (fb->format->num_planes > 1) { + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1); + paddr -= PHYS_OFFSET; + DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr); + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG, + paddr); + } + + if (fb->format->num_planes > 2) { + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2); + paddr -= PHYS_OFFSET; + DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr); + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG, + paddr); + } } EXPORT_SYMBOL(sun4i_frontend_update_buffer); -static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) +static int +sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format, + u32 *val) { - switch (fmt) { - case DRM_FORMAT_XRGB8888: + if (!format->is_yuv) *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; - return 0; - - default: + else if (drm_format_info_is_yuv_sampling_411(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411; + else if (drm_format_info_is_yuv_sampling_420(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420; + else if (drm_format_info_is_yuv_sampling_422(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422; + else if (drm_format_info_is_yuv_sampling_444(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444; + else return -EINVAL; - } + + return 0; } -static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val) +static int +sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format, + uint64_t modifier, u32 *val) { - if (drm_format_num_planes(fmt) == 1) + bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED); + + switch (format->num_planes) { + case 1: *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED; - else - return -EINVAL; + return 0; - return 0; + case 2: + *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR + : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR; + return 0; + + case 3: + *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR + : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR; + return 0; + + default: + return -EINVAL; + } } -static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val) +static int +sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format, + u32 *val) { - switch (fmt) { + /* Planar formats have an explicit input sequence. */ + if (drm_format_info_is_yuv_planar(format)) { + *val = 0; + return 0; + } + + switch (format->format) { case DRM_FORMAT_BGRX8888: *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; return 0; + case DRM_FORMAT_NV12: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; + return 0; + + case DRM_FORMAT_NV16: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; + return 0; + + case DRM_FORMAT_NV21: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; + return 0; + + case DRM_FORMAT_NV61: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; + return 0; + + case DRM_FORMAT_UYVY: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY; + return 0; + + case DRM_FORMAT_VYUY: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY; + return 0; + case DRM_FORMAT_XRGB8888: *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB; return 0; + case DRM_FORMAT_YUYV: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV; + return 0; + + case DRM_FORMAT_YVYU: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU; + return 0; + default: return -EINVAL; } @@ -160,14 +360,32 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) static const uint32_t sun4i_frontend_formats[] = { DRM_FORMAT_BGRX8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV21, + DRM_FORMAT_NV61, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, + DRM_FORMAT_YVYU, }; bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier) { unsigned int i; - if (modifier != DRM_FORMAT_MOD_LINEAR) + if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) + return sun4i_frontend_format_supports_tiling(fmt); + else if (modifier != DRM_FORMAT_MOD_LINEAR) return false; for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++) @@ -183,9 +401,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; - uint32_t format = fb->format->format; + const struct drm_format_info *format = fb->format; + uint64_t modifier = fb->modifier; u32 out_fmt_val; u32 in_fmt_val, in_mod_val, in_ps_val; + unsigned int i; + u32 bypass; int ret; ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val); @@ -194,7 +415,8 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, return ret; } - ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val); + ret = sun4i_frontend_drm_format_to_input_mode(format, modifier, + &in_mod_val); if (ret) { DRM_DEBUG_DRIVER("Invalid input mode\n"); return ret; @@ -216,16 +438,39 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, * I have no idea what this does exactly, but it seems to be * related to the scaler FIR filter phase parameters. */ - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, + frontend->data->ch_phase[0].horzphase); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, + frontend->data->ch_phase[1].horzphase); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, + frontend->data->ch_phase[0].vertphase[0]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, + frontend->data->ch_phase[1].vertphase[0]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, + frontend->data->ch_phase[0].vertphase[1]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, + frontend->data->ch_phase[1].vertphase[1]); + + /* + * Checking the input format is sufficient since we currently only + * support RGB output formats to the backend. If YUV output formats + * ever get supported, an YUV input and output would require bypassing + * the CSC engine too. + */ + if (format->is_yuv) { + /* Setup the CSC engine for YUV to RGB conversion. */ + bypass = 0; + + for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) + regmap_write(frontend->regs, + SUN4I_FRONTEND_CSC_COEF_REG(i), + sunxi_bt601_yuv2rgb_coef[i]); + } else { + bypass = SUN4I_FRONTEND_BYPASS_CSC_EN; + } regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, - SUN4I_FRONTEND_BYPASS_CSC_EN, - SUN4I_FRONTEND_BYPASS_CSC_EN); + SUN4I_FRONTEND_BYPASS_CSC_EN, bypass); regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, in_mod_val | in_fmt_val | in_ps_val); @@ -321,6 +566,10 @@ static int sun4i_frontend_bind(struct device *dev, struct device *master, frontend->dev = dev; frontend->node = dev->of_node; + frontend->data = of_device_get_match_data(dev); + if (!frontend->data) + return -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) @@ -433,8 +682,47 @@ static const struct dev_pm_ops sun4i_frontend_pm_ops = { .runtime_suspend = sun4i_frontend_runtime_suspend, }; +static const struct sun4i_frontend_data sun4i_a10_frontend = { + .ch_phase = { + { + .horzphase = 0, + .vertphase = { 0, 0 }, + }, + { + .horzphase = 0xfc000, + .vertphase = { 0xfc000, 0xfc000 }, + }, + }, + .has_coef_rdy = true, +}; + +static const struct sun4i_frontend_data sun8i_a33_frontend = { + .ch_phase = { + { + .horzphase = 0x400, + .vertphase = { 0x400, 0x400 }, + }, + { + .horzphase = 0x400, + .vertphase = { 0x400, 0x400 }, + }, + }, + .has_coef_access_ctrl = true, +}; + const struct of_device_id sun4i_frontend_of_table[] = { - { .compatible = "allwinner,sun8i-a33-display-frontend" }, + { + .compatible = "allwinner,sun4i-a10-display-frontend", + .data = &sun4i_a10_frontend + }, + { + .compatible = "allwinner,sun7i-a20-display-frontend", + .data = &sun4i_a10_frontend + }, + { + .compatible = "allwinner,sun8i-a33-display-frontend", + .data = &sun8i_a33_frontend + }, { } }; EXPORT_SYMBOL(sun4i_frontend_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h index ad146e8d8d70..0c382c1ddb0f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.h +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h @@ -22,12 +22,49 @@ #define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1) #define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020 +#define SUN4I_FRONTEND_BUF_ADDR1_REG 0x024 +#define SUN4I_FRONTEND_BUF_ADDR2_REG 0x028 + +#define SUN4I_FRONTEND_TB_OFF0_REG 0x030 +#define SUN4I_FRONTEND_TB_OFF1_REG 0x034 +#define SUN4I_FRONTEND_TB_OFF2_REG 0x038 +#define SUN4I_FRONTEND_TB_OFF_X1(x1) ((x1) << 16) +#define SUN4I_FRONTEND_TB_OFF_Y0(y0) ((y0) << 8) +#define SUN4I_FRONTEND_TB_OFF_X0(x0) (x0) #define SUN4I_FRONTEND_LINESTRD0_REG 0x040 +#define SUN4I_FRONTEND_LINESTRD1_REG 0x044 +#define SUN4I_FRONTEND_LINESTRD2_REG 0x048 + +/* + * In tiled mode, the stride is defined as the distance between the start of the + * end line of the current tile and the start of the first line in the next + * vertical tile. + * + * Tiles are represented in row-major order, thus the end line of current tile + * starts at: 31 * 32 (31 lines of 32 cols), the next vertical tile starts at: + * 32-bit-aligned-width * 32 and the distance is: + * 32 * (32-bit-aligned-width - 31). + */ +#define SUN4I_FRONTEND_LINESTRD_TILED(stride) (((stride) - 31) * 32) #define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR (0 << 8) #define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED (1 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR (2 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR (4 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR (6 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444 (0 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422 (1 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420 (2 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411 (3 << 4) #define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB (5 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY 0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV 1 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY 2 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU 3 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV 0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU 1 #define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX 0 #define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB 1 @@ -35,6 +72,8 @@ #define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888 1 #define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888 2 +#define SUN4I_FRONTEND_CSC_COEF_REG(c) (0x070 + (0x4 * (c))) + #define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100 #define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1))) @@ -73,6 +112,16 @@ struct drm_plane; struct regmap; struct reset_control; +struct sun4i_frontend_data { + bool has_coef_access_ctrl; + bool has_coef_rdy; + + struct { + u32 horzphase; + u32 vertphase[2]; + } ch_phase[2]; +}; + struct sun4i_frontend { struct list_head list; struct device *dev; @@ -83,9 +132,12 @@ struct sun4i_frontend { struct clk *ram_clk; struct regmap *regs; struct reset_control *reset; + + const struct sun4i_frontend_data *data; }; extern const struct of_device_id sun4i_frontend_of_table[]; +extern const u32 sunxi_bt601_yuv2rgb_coef[12]; int sun4i_frontend_init(struct sun4i_frontend *frontend); void sun4i_frontend_exit(struct sun4i_frontend *frontend); diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 061d2e0d9011..554a6f4561f3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -52,7 +52,8 @@ static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi, u8 buffer[17]; int i, ret; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &hdmi->connector, mode); if (ret < 0) { DRM_ERROR("Failed to get infoframes from mode\n"); return ret; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 29631e0efde3..c5a999ca1d72 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -114,6 +114,13 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, sun4i_backend_layer_enable(backend, layer->id, true); } +static bool sun4i_layer_format_mod_supported(struct drm_plane *plane, + uint32_t format, uint64_t modifier) +{ + return sun4i_backend_format_is_supported(format, modifier) || + sun4i_frontend_format_is_supported(format, modifier); +} + static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = { .prepare_fb = drm_gem_fb_prepare_fb, .atomic_disable = sun4i_backend_layer_atomic_disable, @@ -127,6 +134,7 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .reset = sun4i_backend_layer_reset, .update_plane = drm_atomic_helper_update_plane, + .format_mod_supported = sun4i_layer_format_mod_supported, }; static const uint32_t sun4i_layer_formats[] = { @@ -138,13 +146,31 @@ static const uint32_t sun4i_layer_formats[] = { DRM_FORMAT_RGBA4444, DRM_FORMAT_RGB888, DRM_FORMAT_RGB565, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV21, + DRM_FORMAT_NV61, DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, DRM_FORMAT_YVYU, }; +static const uint64_t sun4i_layer_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_ALLWINNER_TILED, + DRM_FORMAT_MOD_INVALID +}; + static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, struct sun4i_backend *backend, enum drm_plane_type type) @@ -161,7 +187,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, &sun4i_backend_layer_funcs, sun4i_layer_formats, ARRAY_SIZE(sun4i_layer_formats), - NULL, type, NULL); + sun4i_layer_modifiers, type, NULL); if (ret) { dev_err(drm->dev, "Couldn't initialize layer\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0082468f703c..a7566c67bfb0 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -741,7 +741,8 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, u8 buffer[17]; ssize_t err; - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &hdmi->output.connector, mode); if (err < 0) { dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); return; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index ef8692b7075a..44feac2a0359 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2116,7 +2116,8 @@ tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor, value &= ~INFOFRAME_CTRL_ENABLE; tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &sor->output.connector, mode); if (err < 0) { dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); return err; diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 01a6f2d42440..614f532ea89f 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -10,11 +10,14 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include <drm/tinydrm/tinydrm.h> #include <linux/device.h> #include <linux/dma-buf.h> +#include <linux/module.h> /** * DOC: overview @@ -36,31 +39,17 @@ * and registers the DRM device using devm_tinydrm_register(). */ -static struct drm_framebuffer * -tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct tinydrm_device *tdev = drm->dev_private; - - return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd, - tdev->fb_funcs); -} - static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = { - .fb_create = tinydrm_fb_create, + .fb_create = drm_gem_fb_create_with_dirty, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev, - const struct drm_framebuffer_funcs *fb_funcs, struct drm_driver *driver) { struct drm_device *drm; - mutex_init(&tdev->dirty_lock); - tdev->fb_funcs = fb_funcs; - /* * We don't embed drm_device, because that prevent us from using * devm_kzalloc() to allocate tinydrm_device in the driver since @@ -83,7 +72,6 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev, static void tinydrm_fini(struct tinydrm_device *tdev) { drm_mode_config_cleanup(tdev->drm); - mutex_destroy(&tdev->dirty_lock); tdev->drm->dev_private = NULL; drm_dev_put(tdev->drm); } @@ -97,7 +85,6 @@ static void devm_tinydrm_release(void *data) * devm_tinydrm_init - Initialize tinydrm device * @parent: Parent device object * @tdev: tinydrm device - * @fb_funcs: Framebuffer functions * @driver: DRM driver * * This function initializes @tdev, the underlying DRM device and it's @@ -108,12 +95,11 @@ static void devm_tinydrm_release(void *data) * Zero on success, negative error code on failure. */ int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev, - const struct drm_framebuffer_funcs *fb_funcs, struct drm_driver *driver) { int ret; - ret = tinydrm_init(parent, tdev, fb_funcs, driver); + ret = tinydrm_init(parent, tdev, driver); if (ret) return ret; diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c index bf6bfbc5d412..2737b6fdadc8 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c @@ -17,104 +17,16 @@ #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> #include <drm/drm_print.h> -#include <drm/tinydrm/tinydrm.h> +#include <drm/drm_rect.h> #include <drm/tinydrm/tinydrm-helpers.h> -#include <uapi/drm/drm.h> static unsigned int spi_max; module_param(spi_max, uint, 0400); MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size"); /** - * tinydrm_merge_clips - Merge clip rectangles - * @dst: Destination clip rectangle - * @src: Source clip rectangle(s) - * @num_clips: Number of @src clip rectangles - * @flags: Dirty fb ioctl flags - * @max_width: Maximum width of @dst - * @max_height: Maximum height of @dst - * - * This function merges @src clip rectangle(s) into @dst. If @src is NULL, - * @max_width and @min_width is used to set a full @dst clip rectangle. - * - * Returns: - * true if it's a full clip, false otherwise - */ -bool tinydrm_merge_clips(struct drm_clip_rect *dst, - struct drm_clip_rect *src, unsigned int num_clips, - unsigned int flags, u32 max_width, u32 max_height) -{ - unsigned int i; - - if (!src || !num_clips) { - dst->x1 = 0; - dst->x2 = max_width; - dst->y1 = 0; - dst->y2 = max_height; - return true; - } - - dst->x1 = ~0; - dst->y1 = ~0; - dst->x2 = 0; - dst->y2 = 0; - - for (i = 0; i < num_clips; i++) { - if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) - i++; - dst->x1 = min(dst->x1, src[i].x1); - dst->x2 = max(dst->x2, src[i].x2); - dst->y1 = min(dst->y1, src[i].y1); - dst->y2 = max(dst->y2, src[i].y2); - } - - if (dst->x2 > max_width || dst->y2 > max_height || - dst->x1 >= dst->x2 || dst->y1 >= dst->y2) { - DRM_DEBUG_KMS("Illegal clip: x1=%u, x2=%u, y1=%u, y2=%u\n", - dst->x1, dst->x2, dst->y1, dst->y2); - dst->x1 = 0; - dst->y1 = 0; - dst->x2 = max_width; - dst->y2 = max_height; - } - - return (dst->x2 - dst->x1) == max_width && - (dst->y2 - dst->y1) == max_height; -} -EXPORT_SYMBOL(tinydrm_merge_clips); - -int tinydrm_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips) -{ - struct tinydrm_device *tdev = fb->dev->dev_private; - struct drm_plane *plane = &tdev->pipe.plane; - int ret = 0; - - drm_modeset_lock(&plane->mutex, NULL); - - /* fbdev can flush even when we're not interested */ - if (plane->state->fb == fb) { - mutex_lock(&tdev->dirty_lock); - ret = tdev->fb_dirty(fb, file_priv, flags, - color, clips, num_clips); - mutex_unlock(&tdev->dirty_lock); - } - - drm_modeset_unlock(&plane->mutex); - - if (ret) - dev_err_once(fb->dev->dev, - "Failed to update display %d\n", ret); - - return ret; -} -EXPORT_SYMBOL(tinydrm_fb_dirty); - -/** * tinydrm_memcpy - Copy clip buffer * @dst: Destination buffer * @vaddr: Source buffer @@ -122,7 +34,7 @@ EXPORT_SYMBOL(tinydrm_fb_dirty); * @clip: Clip rectangle area to copy */ void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip) + struct drm_rect *clip) { unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); unsigned int pitch = fb->pitches[0]; @@ -146,7 +58,7 @@ EXPORT_SYMBOL(tinydrm_memcpy); * @clip: Clip rectangle area to copy */ void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip) + struct drm_rect *clip) { size_t len = (clip->x2 - clip->x1) * sizeof(u16); unsigned int x, y; @@ -186,7 +98,7 @@ EXPORT_SYMBOL(tinydrm_swab16); */ void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip, bool swap) + struct drm_rect *clip, bool swap) { size_t len = (clip->x2 - clip->x1) * sizeof(u32); unsigned int x, y; @@ -235,7 +147,7 @@ EXPORT_SYMBOL(tinydrm_xrgb8888_to_rgb565); * ITU BT.601 is used for the RGB -> luma (brightness) conversion. */ void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip) + struct drm_rect *clip) { unsigned int len = (clip->x2 - clip->x1) * sizeof(u32); unsigned int x, y; diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c index eacfc0ec8ff1..323564329535 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c @@ -9,8 +9,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modes.h> +#include <drm/drm_print.h> #include <drm/tinydrm/tinydrm.h> struct tinydrm_connector { @@ -108,36 +110,6 @@ tinydrm_connector_create(struct drm_device *drm, return connector; } -/** - * tinydrm_display_pipe_update - Display pipe update helper - * @pipe: Simple display pipe - * @old_state: Old plane state - * - * This function does a full framebuffer flush if the plane framebuffer - * has changed. It also handles vblank events. Drivers can use this as their - * &drm_simple_display_pipe_funcs->update callback. - */ -void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) -{ - struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); - struct drm_framebuffer *fb = pipe->plane.state->fb; - struct drm_crtc *crtc = &tdev->pipe.crtc; - - if (fb && (fb != old_state->fb)) { - if (tdev->fb_dirty) - tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0); - } - - if (crtc->state->event) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - spin_unlock_irq(&crtc->dev->event_lock); - crtc->state->event = NULL; - } -} -EXPORT_SYMBOL(tinydrm_display_pipe_update); - static int tinydrm_rotate_mode(struct drm_display_mode *mode, unsigned int rotation) { diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c index 81a2bbeb25d4..8bbd0beafc6a 100644 --- a/drivers/gpu/drm/tinydrm/hx8357d.c +++ b/drivers/gpu/drm/tinydrm/hx8357d.c @@ -16,6 +16,7 @@ #include <linux/property.h> #include <linux/spi/spi.h> +#include <drm/drm_drv.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> @@ -175,7 +176,7 @@ out_enable: static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = { .enable = yx240qv29_enable, .disable = mipi_dbi_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = mipi_dbi_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c index 78f7c2d1b449..43a3b68d90a2 100644 --- a/drivers/gpu/drm/tinydrm/ili9225.c +++ b/drivers/gpu/drm/tinydrm/ili9225.c @@ -20,9 +20,14 @@ #include <linux/spi/spi.h> #include <video/mipi_display.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_rect.h> +#include <drm/drm_vblank.h> #include <drm/tinydrm/mipi-dbi.h> #include <drm/tinydrm/tinydrm-helpers.h> @@ -73,16 +78,14 @@ static inline int ili9225_command(struct mipi_dbi *mipi, u8 cmd, u16 data) return mipi_dbi_command_buf(mipi, cmd, par, 2); } -static int ili9225_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, unsigned int flags, - unsigned int color, struct drm_clip_rect *clips, - unsigned int num_clips) +static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); struct tinydrm_device *tdev = fb->dev->dev_private; struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + unsigned int height = rect->y2 - rect->y1; + unsigned int width = rect->x2 - rect->x1; bool swap = mipi->swap_bytes; - struct drm_clip_rect clip; u16 x_start, y_start; u16 x1, x2, y1, y2; int ret = 0; @@ -90,54 +93,52 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb, void *tr; if (!mipi->enabled) - return 0; + return; - full = tinydrm_merge_clips(&clip, clips, num_clips, flags, - fb->width, fb->height); + full = width == fb->width && height == fb->height; - DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id, - clip.x1, clip.x2, clip.y1, clip.y2); + DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); if (!mipi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = mipi->tx_buf; - ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap); + ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap); if (ret) - return ret; + goto err_msg; } else { tr = cma_obj->vaddr; } switch (mipi->rotation) { default: - x1 = clip.x1; - x2 = clip.x2 - 1; - y1 = clip.y1; - y2 = clip.y2 - 1; + x1 = rect->x1; + x2 = rect->x2 - 1; + y1 = rect->y1; + y2 = rect->y2 - 1; x_start = x1; y_start = y1; break; case 90: - x1 = clip.y1; - x2 = clip.y2 - 1; - y1 = fb->width - clip.x2; - y2 = fb->width - clip.x1 - 1; + x1 = rect->y1; + x2 = rect->y2 - 1; + y1 = fb->width - rect->x2; + y2 = fb->width - rect->x1 - 1; x_start = x1; y_start = y2; break; case 180: - x1 = fb->width - clip.x2; - x2 = fb->width - clip.x1 - 1; - y1 = fb->height - clip.y2; - y2 = fb->height - clip.y1 - 1; + x1 = fb->width - rect->x2; + x2 = fb->width - rect->x1 - 1; + y1 = fb->height - rect->y2; + y2 = fb->height - rect->y1 - 1; x_start = x2; y_start = y2; break; case 270: - x1 = fb->height - clip.y2; - x2 = fb->height - clip.y1 - 1; - y1 = clip.x1; - y2 = clip.x2 - 1; + x1 = fb->height - rect->y2; + x2 = fb->height - rect->y1 - 1; + y1 = rect->x1; + y2 = rect->x2 - 1; x_start = x2; y_start = y1; break; @@ -152,16 +153,29 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb, ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, y_start); ret = mipi_dbi_command_buf(mipi, ILI9225_WRITE_DATA_TO_GRAM, tr, - (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2); - - return ret; + width * height * 2); +err_msg: + if (ret) + dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); } -static const struct drm_framebuffer_funcs ili9225_fb_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, - .dirty = tinydrm_fb_dirty, -}; +static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = pipe->plane.state; + struct drm_crtc *crtc = &pipe->crtc; + struct drm_rect rect; + + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + ili9225_fb_dirty(state->fb, &rect); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } +} static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, @@ -169,7 +183,14 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, { struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + struct drm_framebuffer *fb = plane_state->fb; struct device *dev = tdev->drm->dev; + struct drm_rect rect = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; int ret; u8 am_id; @@ -257,7 +278,8 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017); - mipi_dbi_enable_flush(mipi, crtc_state, plane_state); + mipi->enabled = true; + ili9225_fb_dirty(fb, &rect); } static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe) @@ -302,59 +324,10 @@ static int ili9225_dbi_command(struct mipi_dbi *mipi, u8 cmd, u8 *par, return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num); } -static const u32 ili9225_formats[] = { - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, -}; - -static int ili9225_init(struct device *dev, struct mipi_dbi *mipi, - const struct drm_simple_display_pipe_funcs *pipe_funcs, - struct drm_driver *driver, - const struct drm_display_mode *mode, - unsigned int rotation) -{ - size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16); - struct tinydrm_device *tdev = &mipi->tinydrm; - int ret; - - if (!mipi->command) - return -EINVAL; - - mutex_init(&mipi->cmdlock); - - mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL); - if (!mipi->tx_buf) - return -ENOMEM; - - ret = devm_tinydrm_init(dev, tdev, &ili9225_fb_funcs, driver); - if (ret) - return ret; - - tdev->fb_dirty = ili9225_fb_dirty; - - ret = tinydrm_display_pipe_init(tdev, pipe_funcs, - DRM_MODE_CONNECTOR_VIRTUAL, - ili9225_formats, - ARRAY_SIZE(ili9225_formats), mode, - rotation); - if (ret) - return ret; - - tdev->drm->mode_config.preferred_depth = 16; - mipi->rotation = rotation; - - drm_mode_config_reset(tdev->drm); - - DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n", - tdev->drm->mode_config.preferred_depth, rotation); - - return 0; -} - static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = { .enable = ili9225_pipe_enable, .disable = ili9225_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = ili9225_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; @@ -421,8 +394,8 @@ static int ili9225_probe(struct spi_device *spi) /* override the command function set in mipi_dbi_spi_init() */ mipi->command = ili9225_dbi_command; - ret = ili9225_init(&spi->dev, mipi, &ili9225_pipe_funcs, - &ili9225_driver, &ili9225_mode, rotation); + ret = mipi_dbi_init(&spi->dev, mipi, &ili9225_pipe_funcs, + &ili9225_driver, &ili9225_mode, rotation); if (ret) return ret; diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c index 51395bdc6ca2..713bb2dd7e04 100644 --- a/drivers/gpu/drm/tinydrm/ili9341.c +++ b/drivers/gpu/drm/tinydrm/ili9341.c @@ -15,6 +15,7 @@ #include <linux/property.h> #include <linux/spi/spi.h> +#include <drm/drm_drv.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> @@ -131,7 +132,7 @@ out_enable: static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = { .enable = yx240qv29_enable, .disable = mipi_dbi_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = mipi_dbi_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index 3fa62e77c30b..82a92ec9ae3c 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c @@ -17,6 +17,7 @@ #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <drm/drm_drv.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> @@ -139,7 +140,7 @@ out_enable: static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = { .enable = mi0283qt_enable, .disable = mipi_dbi_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = mipi_dbi_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 3a05e56f9b0d..918f77c7de34 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c @@ -10,18 +10,23 @@ */ #include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/dma-buf.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_vblank.h> +#include <drm/drm_rect.h> #include <drm/tinydrm/mipi-dbi.h> #include <drm/tinydrm/tinydrm-helpers.h> -#include <uapi/drm/drm.h> #include <video/mipi_display.h> #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */ @@ -169,7 +174,7 @@ EXPORT_SYMBOL(mipi_dbi_command_buf); * Zero on success, negative error code on failure. */ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, - struct drm_clip_rect *clip, bool swap) + struct drm_rect *clip, bool swap) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; @@ -208,58 +213,75 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, } EXPORT_SYMBOL(mipi_dbi_buf_copy); -static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips) +static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); struct tinydrm_device *tdev = fb->dev->dev_private; struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + unsigned int height = rect->y2 - rect->y1; + unsigned int width = rect->x2 - rect->x1; bool swap = mipi->swap_bytes; - struct drm_clip_rect clip; int ret = 0; bool full; void *tr; if (!mipi->enabled) - return 0; + return; - full = tinydrm_merge_clips(&clip, clips, num_clips, flags, - fb->width, fb->height); + full = width == fb->width && height == fb->height; - DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id, - clip.x1, clip.x2, clip.y1, clip.y2); + DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); if (!mipi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = mipi->tx_buf; - ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap); + ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, rect, swap); if (ret) - return ret; + goto err_msg; } else { tr = cma_obj->vaddr; } mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS, - (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF, - ((clip.x2 - 1) >> 8) & 0xFF, (clip.x2 - 1) & 0xFF); + (rect->x1 >> 8) & 0xff, rect->x1 & 0xff, + ((rect->x2 - 1) >> 8) & 0xff, (rect->x2 - 1) & 0xff); mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS, - (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF, - ((clip.y2 - 1) >> 8) & 0xFF, (clip.y2 - 1) & 0xFF); + (rect->y1 >> 8) & 0xff, rect->y1 & 0xff, + ((rect->y2 - 1) >> 8) & 0xff, (rect->y2 - 1) & 0xff); ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr, - (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2); - - return ret; + width * height * 2); +err_msg: + if (ret) + dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); } -static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, - .dirty = tinydrm_fb_dirty, -}; +/** + * mipi_dbi_pipe_update - Display pipe update helper + * @pipe: Simple display pipe + * @old_state: Old plane state + * + * This function handles framebuffer flushing and vblank events. Drivers can use + * this as their &drm_simple_display_pipe_funcs->update callback. + */ +void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = pipe->plane.state; + struct drm_crtc *crtc = &pipe->crtc; + struct drm_rect rect; + + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + mipi_dbi_fb_dirty(state->fb, &rect); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } +} +EXPORT_SYMBOL(mipi_dbi_pipe_update); /** * mipi_dbi_enable_flush - MIPI DBI enable helper @@ -270,18 +292,25 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = { * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and * enables the backlight. Drivers can use this in their * &drm_simple_display_pipe_funcs->enable callback. + * + * Note: Drivers which don't use mipi_dbi_pipe_update() because they have custom + * framebuffer flushing, can't use this function since they both use the same + * flushing code. */ void mipi_dbi_enable_flush(struct mipi_dbi *mipi, struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) { - struct tinydrm_device *tdev = &mipi->tinydrm; struct drm_framebuffer *fb = plane_state->fb; + struct drm_rect rect = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; mipi->enabled = true; - if (fb) - tdev->fb_dirty(fb, NULL, 0, 0, NULL, 0); - + mipi_dbi_fb_dirty(fb, &rect); backlight_enable(mipi->backlight); } EXPORT_SYMBOL(mipi_dbi_enable_flush); @@ -373,12 +402,10 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi, if (!mipi->tx_buf) return -ENOMEM; - ret = devm_tinydrm_init(dev, tdev, &mipi_dbi_fb_funcs, driver); + ret = devm_tinydrm_init(dev, tdev, driver); if (ret) return ret; - tdev->fb_dirty = mipi_dbi_fb_dirty; - /* TODO: Maybe add DRM_MODE_CONNECTOR_SPI */ ret = tinydrm_display_pipe_init(tdev, pipe_funcs, DRM_MODE_CONNECTOR_VIRTUAL, @@ -388,6 +415,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi, if (ret) return ret; + drm_plane_enable_fb_damage_clips(&tdev->pipe.plane); + tdev->drm->mode_config.preferred_depth = 16; mipi->rotation = rotation; diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 54d6fe0f37ce..b037c6540cf3 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c @@ -26,9 +26,13 @@ #include <linux/spi/spi.h> #include <linux/thermal.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_rect.h> +#include <drm/drm_vblank.h> #include <drm/tinydrm/tinydrm.h> #include <drm/tinydrm/tinydrm-helpers.h> @@ -521,17 +525,13 @@ static void repaper_gray8_to_mono_reversed(u8 *buf, u32 width, u32 height) } } -static int repaper_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips) +static int repaper_fb_dirty(struct drm_framebuffer *fb) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; struct tinydrm_device *tdev = fb->dev->dev_private; struct repaper_epd *epd = epd_from_tinydrm(tdev); - struct drm_clip_rect clip; + struct drm_rect clip; u8 *buf = NULL; int ret = 0; @@ -624,12 +624,6 @@ out_free: return ret; } -static const struct drm_framebuffer_funcs repaper_fb_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, - .dirty = tinydrm_fb_dirty, -}; - static void power_off(struct repaper_epd *epd) { /* Turn off power and all signals */ @@ -793,9 +787,7 @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) DRM_DEBUG_DRIVER("\n"); - mutex_lock(&tdev->dirty_lock); epd->enabled = false; - mutex_unlock(&tdev->dirty_lock); /* Nothing frame */ for (line = 0; line < epd->height; line++) @@ -838,10 +830,28 @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) power_off(epd); } +static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = pipe->plane.state; + struct drm_crtc *crtc = &pipe->crtc; + struct drm_rect rect; + + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + repaper_fb_dirty(state->fb); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } +} + static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { .enable = repaper_pipe_enable, .disable = repaper_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = repaper_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; @@ -1055,12 +1065,10 @@ static int repaper_probe(struct spi_device *spi) tdev = &epd->tinydrm; - ret = devm_tinydrm_init(dev, tdev, &repaper_fb_funcs, &repaper_driver); + ret = devm_tinydrm_init(dev, tdev, &repaper_driver); if (ret) return ret; - tdev->fb_dirty = repaper_fb_dirty; - ret = tinydrm_display_pipe_init(tdev, &repaper_pipe_funcs, DRM_MODE_CONNECTOR_VIRTUAL, repaper_formats, diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index a6a8a1081b73..01a8077954b3 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c @@ -17,9 +17,13 @@ #include <linux/spi/spi.h> #include <video/mipi_display.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_rect.h> +#include <drm/drm_vblank.h> #include <drm/tinydrm/mipi-dbi.h> #include <drm/tinydrm/tinydrm-helpers.h> @@ -61,7 +65,7 @@ static const u8 st7586_lookup[] = { 0x7, 0x4, 0x2, 0x0 }; static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip) + struct drm_rect *clip) { size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1); unsigned int x, y; @@ -87,7 +91,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, } static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb, - struct drm_clip_rect *clip) + struct drm_rect *clip) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; @@ -110,57 +114,62 @@ static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb, return ret; } -static int st7586_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, unsigned int flags, - unsigned int color, struct drm_clip_rect *clips, - unsigned int num_clips) +static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { struct tinydrm_device *tdev = fb->dev->dev_private; struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); - struct drm_clip_rect clip; int start, end; int ret = 0; if (!mipi->enabled) - return 0; - - tinydrm_merge_clips(&clip, clips, num_clips, flags, fb->width, - fb->height); + return; /* 3 pixels per byte, so grow clip to nearest multiple of 3 */ - clip.x1 = rounddown(clip.x1, 3); - clip.x2 = roundup(clip.x2, 3); + rect->x1 = rounddown(rect->x1, 3); + rect->x2 = roundup(rect->x2, 3); - DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id, - clip.x1, clip.x2, clip.y1, clip.y2); + DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); - ret = st7586_buf_copy(mipi->tx_buf, fb, &clip); + ret = st7586_buf_copy(mipi->tx_buf, fb, rect); if (ret) - return ret; + goto err_msg; /* Pixels are packed 3 per byte */ - start = clip.x1 / 3; - end = clip.x2 / 3; + start = rect->x1 / 3; + end = rect->x2 / 3; mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS, (start >> 8) & 0xFF, start & 0xFF, (end >> 8) & 0xFF, (end - 1) & 0xFF); mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS, - (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF, - (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF); + (rect->y1 >> 8) & 0xFF, rect->y1 & 0xFF, + (rect->y2 >> 8) & 0xFF, (rect->y2 - 1) & 0xFF); ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, (u8 *)mipi->tx_buf, - (end - start) * (clip.y2 - clip.y1)); - - return ret; + (end - start) * (rect->y2 - rect->y1)); +err_msg: + if (ret) + dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); } -static const struct drm_framebuffer_funcs st7586_fb_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, - .dirty = tinydrm_fb_dirty, -}; +static void st7586_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = pipe->plane.state; + struct drm_crtc *crtc = &pipe->crtc; + struct drm_rect rect; + + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + st7586_fb_dirty(state->fb, &rect); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } +} static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, @@ -168,6 +177,13 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, { struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_rect rect = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; int ret; u8 addr_mode; @@ -224,9 +240,10 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, msleep(100); - mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); + mipi->enabled = true; + st7586_fb_dirty(fb, &rect); - mipi_dbi_enable_flush(mipi, crtc_state, plane_state); + mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); } static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) @@ -262,12 +279,10 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi, if (!mipi->tx_buf) return -ENOMEM; - ret = devm_tinydrm_init(dev, tdev, &st7586_fb_funcs, driver); + ret = devm_tinydrm_init(dev, tdev, driver); if (ret) return ret; - tdev->fb_dirty = st7586_fb_dirty; - ret = tinydrm_display_pipe_init(tdev, pipe_funcs, DRM_MODE_CONNECTOR_VIRTUAL, st7586_formats, @@ -276,6 +291,8 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi, if (ret) return ret; + drm_plane_enable_fb_damage_clips(&tdev->pipe.plane); + tdev->drm->mode_config.preferred_depth = 32; mipi->rotation = rotation; @@ -290,7 +307,7 @@ static int st7586_init(struct device *dev, struct mipi_dbi *mipi, static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = { .enable = st7586_pipe_enable, .disable = st7586_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = st7586_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c index b39779e0dcd8..3bab9a9569a6 100644 --- a/drivers/gpu/drm/tinydrm/st7735r.c +++ b/drivers/gpu/drm/tinydrm/st7735r.c @@ -14,6 +14,7 @@ #include <linux/spi/spi.h> #include <video/mipi_display.h> +#include <drm/drm_drv.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/tinydrm/mipi-dbi.h> @@ -105,7 +106,7 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = { .enable = jd_t18003_t01_pipe_enable, .disable = mipi_dbi_pipe_disable, - .update = tinydrm_display_pipe_update, + .update = mipi_dbi_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index c24b078f0593..2c635f001c71 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -9,6 +9,7 @@ #include <linux/mm_types.h> #include <linux/reservation.h> #include <drm/drmP.h> +#include <drm/drm_util.h> #include <drm/drm_encoder.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 2f276222e30f..051b61b62541 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -109,7 +109,6 @@ struct vc4_hdmi_encoder { struct vc4_encoder base; bool hdmi_monitor; bool limited_rgb_range; - bool rgb_range_selectable; }; static inline struct vc4_hdmi_encoder * @@ -280,11 +279,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { - vc4_encoder->rgb_range_selectable = - drm_rgb_quant_range_selectable(edid); - } - drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -424,18 +418,18 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) union hdmi_infoframe frame; int ret; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + hdmi->connector, mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; } - drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode, + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + hdmi->connector, mode, vc4_encoder->limited_rgb_range ? HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL, - vc4_encoder->rgb_range_selectable, - false); + HDMI_QUANTIZATION_RANGE_FULL); frame.avi.right_bar = cstate->tv.margins.right; frame.avi.left_bar = cstate->tv.margins.left; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 2901ed0c5223..d098337c10e9 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -675,20 +675,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, uint32_t param = fourcc_mod_broadcom_param(fb->modifier); u32 tile_w, tile, x_off, pix_per_tile; - /* Column-based NV12 or RGBA. - */ - if (fb->format->num_planes > 1) { - if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) { - DRM_DEBUG_KMS("SAND format only valid for NV12/21"); - return -EINVAL; - } - hvs_format = HVS_PIXEL_FORMAT_H264; - } else { - if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) { - DRM_DEBUG_KMS("SAND256 format only valid for H.264"); - return -EINVAL; - } - } + hvs_format = HVS_PIXEL_FORMAT_H264; switch (base_format_mod) { case DRM_FORMAT_MOD_BROADCOM_SAND64: @@ -1151,8 +1138,6 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, switch (fourcc_mod_broadcom_mod(modifier)) { case DRM_FORMAT_MOD_LINEAR: case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: - case DRM_FORMAT_MOD_BROADCOM_SAND64: - case DRM_FORMAT_MOD_BROADCOM_SAND128: return true; default: return false; diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index f29deec83d1f..4e90cc8fa651 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -3,7 +3,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \ +virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ virtgpu_ioctl.o virtgpu_prime.o diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index e1c223e18d86..87d7c49cf057 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -243,12 +243,8 @@ static enum drm_connector_status virtio_gpu_conn_detect( static void virtio_gpu_conn_destroy(struct drm_connector *connector) { - struct virtio_gpu_output *virtio_gpu_output = - drm_connector_to_virtio_gpu_output(connector); - drm_connector_unregister(connector); drm_connector_cleanup(connector); - kfree(virtio_gpu_output); } static const struct drm_connector_funcs virtio_gpu_connector_funcs = { @@ -362,7 +358,7 @@ static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) +void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) { int i; @@ -381,7 +377,6 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) vgdev_output_init(vgdev, i); drm_mode_config_reset(vgdev->ddev); - return 0; } void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c deleted file mode 100644 index 0887e0b64b9c..000000000000 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2015 Red Hat, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <linux/pci.h> -#include <drm/drm_fb_helper.h> - -#include "virtgpu_drv.h" - -int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) -{ - struct drm_device *dev; - int ret; - - dev = drm_dev_alloc(driver, &vdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - vdev->priv = dev; - - if (strcmp(vdev->dev.parent->bus->name, "pci") == 0) { - struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); - const char *pname = dev_name(&pdev->dev); - bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; - char unique[20]; - - DRM_INFO("pci: %s detected at %s\n", - vga ? "virtio-vga" : "virtio-gpu-pci", - pname); - dev->pdev = pdev; - if (vga) - drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, - 0, - "virtiodrmfb"); - - /* - * Normally the drm_dev_set_unique() call is done by core DRM. - * The following comment covers, why virtio cannot rely on it. - * - * Unlike the other virtual GPU drivers, virtio abstracts the - * underlying bus type by using struct virtio_device. - * - * Hence the dev_is_pci() check, used in core DRM, will fail - * and the unique returned will be the virtio_device "virtio0", - * while a "pci:..." one is required. - * - * A few other ideas were considered: - * - Extend the dev_is_pci() check [in drm_set_busid] to - * consider virtio. - * Seems like a bigger hack than what we have already. - * - * - Point drm_device::dev to the parent of the virtio_device - * Semantic changes: - * * Using the wrong device for i2c, framebuffer_alloc and - * prime import. - * Visual changes: - * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, - * will print the wrong information. - * - * We could address the latter issues, by introducing - * drm_device::bus_dev, ... which would be used solely for this. - * - * So for the moment keep things as-is, with a bulky comment - * for the next person who feels like removing this - * drm_dev_set_unique() quirk. - */ - snprintf(unique, sizeof(unique), "pci:%s", pname); - ret = drm_dev_set_unique(dev, unique); - if (ret) - goto err_free; - - } - - ret = drm_dev_register(dev, 0); - if (ret) - goto err_free; - - return 0; - -err_free: - drm_dev_put(dev); - return ret; -} diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 7df50920c1e0..af92964b6889 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -40,8 +40,60 @@ static int virtio_gpu_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, virtio_gpu_modeset, int, 0400); +static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev) +{ + struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); + const char *pname = dev_name(&pdev->dev); + bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; + char unique[20]; + + DRM_INFO("pci: %s detected at %s\n", + vga ? "virtio-vga" : "virtio-gpu-pci", + pname); + dev->pdev = pdev; + if (vga) + drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, + 0, + "virtiodrmfb"); + + /* + * Normally the drm_dev_set_unique() call is done by core DRM. + * The following comment covers, why virtio cannot rely on it. + * + * Unlike the other virtual GPU drivers, virtio abstracts the + * underlying bus type by using struct virtio_device. + * + * Hence the dev_is_pci() check, used in core DRM, will fail + * and the unique returned will be the virtio_device "virtio0", + * while a "pci:..." one is required. + * + * A few other ideas were considered: + * - Extend the dev_is_pci() check [in drm_set_busid] to + * consider virtio. + * Seems like a bigger hack than what we have already. + * + * - Point drm_device::dev to the parent of the virtio_device + * Semantic changes: + * * Using the wrong device for i2c, framebuffer_alloc and + * prime import. + * Visual changes: + * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, + * will print the wrong information. + * + * We could address the latter issues, by introducing + * drm_device::bus_dev, ... which would be used solely for this. + * + * So for the moment keep things as-is, with a bulky comment + * for the next person who feels like removing this + * drm_dev_set_unique() quirk. + */ + snprintf(unique, sizeof(unique), "pci:%s", pname); + return drm_dev_set_unique(dev, unique); +} + static int virtio_gpu_probe(struct virtio_device *vdev) { + struct drm_device *dev; int ret; if (vgacon_text_force() && virtio_gpu_modeset == -1) @@ -50,18 +102,39 @@ static int virtio_gpu_probe(struct virtio_device *vdev) if (virtio_gpu_modeset == 0) return -EINVAL; - ret = drm_virtio_init(&driver, vdev); + dev = drm_dev_alloc(&driver, &vdev->dev); + if (IS_ERR(dev)) + return PTR_ERR(dev); + vdev->priv = dev; + + if (!strcmp(vdev->dev.parent->bus->name, "pci")) { + ret = virtio_gpu_pci_quirk(dev, vdev); + if (ret) + goto err_free; + } + + ret = virtio_gpu_init(dev); if (ret) - return ret; + goto err_free; + + ret = drm_dev_register(dev, 0); + if (ret) + goto err_free; drm_fbdev_generic_setup(vdev->priv, 32); return 0; + +err_free: + drm_dev_put(dev); + return ret; } static void virtio_gpu_remove(struct virtio_device *vdev) { struct drm_device *dev = vdev->priv; + drm_dev_unregister(dev); + virtio_gpu_deinit(dev); drm_put_dev(dev); } @@ -123,8 +196,6 @@ static const struct file_operations virtio_gpu_driver_fops = { static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, - .load = virtio_gpu_driver_load, - .unload = virtio_gpu_driver_unload, .open = virtio_gpu_driver_open, .postclose = virtio_gpu_driver_postclose, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 63704915f8ce..cf896d879382 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -50,9 +50,6 @@ #define DRIVER_MINOR 1 #define DRIVER_PATCHLEVEL 0 -/* virtgpu_drm_bus.c */ -int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); - struct virtio_gpu_object { struct drm_gem_object gem_base; uint32_t hw_res_handle; @@ -209,8 +206,8 @@ struct virtio_gpu_fpriv { extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; /* virtio_kms.c */ -int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags); -void virtio_gpu_driver_unload(struct drm_device *dev); +int virtio_gpu_init(struct drm_device *dev); +void virtio_gpu_deinit(struct drm_device *dev); int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file); @@ -320,7 +317,7 @@ int virtio_gpu_framebuffer_init(struct drm_device *dev, struct virtio_gpu_framebuffer *vgfb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); -int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); +void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); /* virtio_gpu_plane.c */ @@ -337,7 +334,6 @@ int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma); /* virtio_gpu_fence.c */ struct virtio_gpu_fence *virtio_gpu_fence_alloc( struct virtio_gpu_device *vgdev); -void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence); int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, struct virtio_gpu_fence *fence); diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 4d6826b27814..21bd4c4a32d1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -81,14 +81,6 @@ struct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev) return fence; } -void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence) -{ - if (!fence) - return; - - dma_fence_put(&fence->f); -} - int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, struct virtio_gpu_fence *fence) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 161b80fee492..14ce8188c052 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -351,7 +351,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d); ret = virtio_gpu_object_attach(vgdev, qobj, fence); if (ret) { - virtio_gpu_fence_cleanup(fence); + dma_fence_put(&fence->f); goto fail_backoff; } ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 1072064a0db2..84b6a6bf00c6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -106,7 +106,7 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, vgdev->num_capsets = num_capsets; } -int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) +int virtio_gpu_init(struct drm_device *dev) { static vq_callback_t *callbacks[] = { virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack @@ -193,9 +193,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) num_capsets, &num_capsets); DRM_INFO("number of cap sets: %d\n", num_capsets); - ret = virtio_gpu_modeset_init(vgdev); - if (ret) - goto err_modeset; + virtio_gpu_modeset_init(vgdev); virtio_device_ready(vgdev->vdev); vgdev->vqs_ready = true; @@ -209,7 +207,6 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) 5 * HZ); return 0; -err_modeset: err_scanouts: virtio_gpu_ttm_fini(vgdev); err_ttm: @@ -231,7 +228,7 @@ static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev) } } -void virtio_gpu_driver_unload(struct drm_device *dev) +void virtio_gpu_deinit(struct drm_device *dev) { struct virtio_gpu_device *vgdev = dev->dev_private; @@ -239,6 +236,7 @@ void virtio_gpu_driver_unload(struct drm_device *dev) flush_work(&vgdev->ctrlq.dequeue_work); flush_work(&vgdev->cursorq.dequeue_work); flush_work(&vgdev->config_changed_work); + vgdev->vdev->config->reset(vgdev->vdev); vgdev->vdev->config->del_vqs(vgdev->vdev); virtio_gpu_modeset_fini(vgdev); diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index ead5c53d4e21..024c2aa0c929 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -130,11 +130,12 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, plane->state->src_h >> 16, plane->state->src_x >> 16, plane->state->src_y >> 16); - virtio_gpu_cmd_resource_flush(vgdev, handle, - plane->state->src_x >> 16, - plane->state->src_y >> 16, - plane->state->src_w >> 16, - plane->state->src_h >> 16); + if (handle) + virtio_gpu_cmd_resource_flush(vgdev, handle, + plane->state->src_x >> 16, + plane->state->src_y >> 16, + plane->state->src_w >> 16, + plane->state->src_h >> 16); } static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, @@ -168,8 +169,10 @@ static void virtio_gpu_cursor_cleanup_fb(struct drm_plane *plane, return; vgfb = to_virtio_gpu_framebuffer(plane->state->fb); - if (vgfb->fence) - virtio_gpu_fence_cleanup(vgfb->fence); + if (vgfb->fence) { + dma_fence_put(&vgfb->fence->f); + vgfb->fence = NULL; + } } static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index e27c4aedb809..6bc2008b0d0d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -192,8 +192,16 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work) list_for_each_entry_safe(entry, tmp, &reclaim_list, list) { resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf; - if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) - DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type)); + if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) { + if (resp->type >= cpu_to_le32(VIRTIO_GPU_RESP_ERR_UNSPEC)) { + struct virtio_gpu_ctrl_hdr *cmd; + cmd = (struct virtio_gpu_ctrl_hdr *)entry->buf; + DRM_ERROR("response 0x%x (command 0x%x)\n", + le32_to_cpu(resp->type), + le32_to_cpu(cmd->type)); + } else + DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type)); + } if (resp->flags & cpu_to_le32(VIRTIO_GPU_FLAG_FENCE)) { u64 f = le64_to_cpu(resp->fence_id); diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index 78655269d843..9fc98bb4f3d9 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -125,7 +125,9 @@ static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi, union hdmi_infoframe frame; int ret; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + &hdmi->connector, + mode); if (ret) { DRM_DEV_ERROR(hdmi->dev, "failed to get avi infoframe: %d\n", ret); diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c index 6b7aa23dfc0a..397496cf0bdf 100644 --- a/drivers/staging/vboxvideo/vbox_fb.c +++ b/drivers/staging/vboxvideo/vbox_fb.c @@ -95,11 +95,6 @@ int vboxfb_create(struct drm_fb_helper *helper, strcpy(info->fix.id, "vboxdrmfb"); - /* - * The last flag forces a mode set on VT switches even if the kernel - * does not think it is needed. - */ - info->flags = FBINFO_DEFAULT | FBINFO_MISC_ALWAYS_SETPAR; info->fbops = &vboxfb_ops; /* diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 9c56412bb2cf..9f93895dde88 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -10,9 +10,11 @@ #ifndef __DW_HDMI__ #define __DW_HDMI__ -#include <drm/drmP.h> - +struct drm_connector; +struct drm_display_mode; +struct drm_encoder; struct dw_hdmi; +struct platform_device; /** * DOC: Supported input formats and encodings diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 48a671e782ca..7d3dd69a5caa 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -14,7 +14,8 @@ struct dw_mipi_dsi; struct dw_mipi_dsi_phy_ops { int (*init)(void *priv_data); - int (*get_lane_mbps)(void *priv_data, struct drm_display_mode *mode, + int (*get_lane_mbps)(void *priv_data, + const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps); }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index db94ef00940e..3f5c577c9dbd 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -94,23 +94,11 @@ struct dma_buf_attachment; struct pci_dev; struct pci_controller; -#define DRM_SWITCH_POWER_ON 0 -#define DRM_SWITCH_POWER_OFF 1 -#define DRM_SWITCH_POWER_CHANGING 2 -#define DRM_SWITCH_POWER_DYNAMIC_OFF 3 - -/* returns true if currently okay to sleep */ -static inline bool drm_can_sleep(void) -{ - if (in_atomic() || in_dbg_master() || irqs_disabled()) - return false; - return true; -} - -#if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) -#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) -#else -#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) -#endif +/* + * NOTE: drmP.h is obsolete - do NOT add anything to this file + * + * Do not include drmP.h in new files. + * Work is ongoing to remove drmP.h includes from existing files + */ #endif diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index cac4a1b6b0e8..811b4a92568f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -139,9 +139,9 @@ struct drm_crtc_commit { /** * @abort_completion: * - * A flag that's set after drm_atomic_helper_setup_commit takes a second - * reference for the completion of $drm_crtc_state.event. It's used by - * the free code to remove the second reference if commit fails. + * A flag that's set after drm_atomic_helper_setup_commit() takes a + * second reference for the completion of $drm_crtc_state.event. It's + * used by the free code to remove the second reference if commit fails. */ bool abort_completion; }; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index bd850747ce54..9da8c93f7976 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -196,8 +196,8 @@ struct drm_bridge_funcs { * the DRM framework will have to be extended with DRM bridge states. */ void (*mode_set)(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); /** * @pre_enable: * @@ -310,8 +310,8 @@ enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, void drm_bridge_disable(struct drm_bridge *bridge); void drm_bridge_post_disable(struct drm_bridge *bridge); void drm_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); void drm_bridge_pre_enable(struct drm_bridge *bridge); void drm_bridge_enable(struct drm_bridge *bridge); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f82701d49ea6..994161374a49 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -366,6 +366,12 @@ struct drm_display_info { bool has_hdmi_infoframe; /** + * @rgb_quant_range_selectable: Does the sink support selecting + * the RGB quantization range? + */ + bool rgb_quant_range_selectable; + + /** * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even * more stuff redundant with @bus_formats. */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 39c3900aab3c..85abd3fe9e83 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1149,9 +1149,6 @@ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -int drm_crtc_force_disable(struct drm_crtc *crtc); -int drm_crtc_force_disable_all(struct drm_device *dev); - int drm_mode_set_config_internal(struct drm_mode_set *set); struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index d65f034843ce..0ee9a96b70da 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -56,6 +56,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder); int drm_helper_connector_dpms(struct drm_connector *connector, int mode); void drm_helper_resume_force_mode(struct drm_device *dev); +int drm_helper_force_disable_all(struct drm_device *dev); /* drm_probe_helper.c */ int drm_helper_probe_single_connector_modes(struct drm_connector diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h index 4487660b26b8..40c34a5bf149 100644 --- a/include/drm/drm_damage_helper.h +++ b/include/drm/drm_damage_helper.h @@ -78,6 +78,9 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, bool drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, struct drm_rect *rect); +bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state, + struct drm_plane_state *state, + struct drm_rect *rect); /** * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect. diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 42411b3ea0c8..d5e092dccf3e 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -24,25 +24,79 @@ struct inode; struct pci_dev; struct pci_controller; + /** - * DRM device structure. This structure represent a complete card that + * enum drm_switch_power - power state of drm device + */ + +enum switch_power_state { + /** @DRM_SWITCH_POWER_ON: Power state is ON */ + DRM_SWITCH_POWER_ON = 0, + + /** @DRM_SWITCH_POWER_OFF: Power state is OFF */ + DRM_SWITCH_POWER_OFF = 1, + + /** @DRM_SWITCH_POWER_CHANGING: Power state is changing */ + DRM_SWITCH_POWER_CHANGING = 2, + + /** @DRM_SWITCH_POWER_DYNAMIC_OFF: Suspended */ + DRM_SWITCH_POWER_DYNAMIC_OFF = 3, +}; + +/** + * struct drm_device - DRM device structure + * + * This structure represent a complete card that * may contain multiple heads. */ struct drm_device { - struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */ - int if_version; /**< Highest interface version set */ - - /** \name Lifetime Management */ - /*@{ */ - struct kref ref; /**< Object ref-count */ - struct device *dev; /**< Device structure of bus-device */ - struct drm_driver *driver; /**< DRM driver managing the device */ - void *dev_private; /**< DRM driver private data */ - struct drm_minor *primary; /**< Primary node */ - struct drm_minor *render; /**< Render node */ + /** + * @legacy_dev_list: + * + * List of devices per driver for stealth attach cleanup + */ + struct list_head legacy_dev_list; + + /** @if_version: Highest interface version set */ + int if_version; + + /** @ref: Object ref-count */ + struct kref ref; + + /** @dev: Device structure of bus-device */ + struct device *dev; + + /** @driver: DRM driver managing the device */ + struct drm_driver *driver; + + /** + * @dev_private: + * + * DRM driver private data. Instead of using this pointer it is + * recommended that drivers use drm_dev_init() and embed struct + * &drm_device in their larger per-device structure. + */ + void *dev_private; + + /** @primary: Primary node */ + struct drm_minor *primary; + + /** @render: Render node */ + struct drm_minor *render; + + /** + * @registered: + * + * Internally used by drm_dev_register() and drm_connector_register(). + */ bool registered; - /* currently active master for this device. Protected by master_mutex */ + /** + * @master: + * + * Currently active master for this device. + * Protected by &master_mutex + */ struct drm_master *master; /** @@ -63,76 +117,65 @@ struct drm_device { */ bool unplugged; - struct inode *anon_inode; /**< inode for private address-space */ - char *unique; /**< unique name of the device */ - /*@} */ + /** @anon_inode: inode for private address-space */ + struct inode *anon_inode; + + /** @unique: Unique name of the device */ + char *unique; - /** \name Locks */ - /*@{ */ - struct mutex struct_mutex; /**< For others */ - struct mutex master_mutex; /**< For drm_minor::master and drm_file::is_master */ - /*@} */ + /** + * @struct_mutex: + * + * Lock for others (not &drm_minor.master and &drm_file.is_master) + */ + struct mutex struct_mutex; - /** \name Usage Counters */ - /*@{ */ - int open_count; /**< Outstanding files open, protected by drm_global_mutex. */ - spinlock_t buf_lock; /**< For drm_device::buf_use and a few other things. */ - int buf_use; /**< Buffers in use -- cannot alloc */ - atomic_t buf_alloc; /**< Buffer allocation in progress */ - /*@} */ + /** + * @master_mutex: + * + * Lock for &drm_minor.master and &drm_file.is_master + */ + struct mutex master_mutex; + + /** + * @open_count: + * + * Usage counter for outstanding files open, + * protected by drm_global_mutex + */ + int open_count; + /** @filelist_mutex: Protects @filelist. */ struct mutex filelist_mutex; + /** + * @filelist: + * + * List of userspace clients, linked through &drm_file.lhead. + */ struct list_head filelist; /** * @filelist_internal: * - * List of open DRM files for in-kernel clients. Protected by @filelist_mutex. + * List of open DRM files for in-kernel clients. + * Protected by &filelist_mutex. */ struct list_head filelist_internal; /** * @clientlist_mutex: * - * Protects @clientlist access. + * Protects &clientlist access. */ struct mutex clientlist_mutex; /** * @clientlist: * - * List of in-kernel clients. Protected by @clientlist_mutex. + * List of in-kernel clients. Protected by &clientlist_mutex. */ struct list_head clientlist; - /** \name Memory management */ - /*@{ */ - struct list_head maplist; /**< Linked list of regions */ - struct drm_open_hash map_hash; /**< User token hash table for maps */ - - /** \name Context handle management */ - /*@{ */ - struct list_head ctxlist; /**< Linked list of context handles */ - struct mutex ctxlist_mutex; /**< For ctxlist */ - - struct idr ctx_idr; - - struct list_head vmalist; /**< List of vmas (for debugging) */ - - /*@} */ - - /** \name DMA support */ - /*@{ */ - struct drm_device_dma *dma; /**< Optional pointer for DMA support */ - /*@} */ - - /** \name Context support */ - /*@{ */ - - __volatile__ long context_flag; /**< Context swapping flag */ - int last_context; /**< Last current context */ - /*@} */ - /** * @irq_enabled: * @@ -141,6 +184,10 @@ struct drm_device { * to true manually. */ bool irq_enabled; + + /** + * @irq: Used by the drm_irq_install() and drm_irq_unistall() helpers. + */ int irq; /** @@ -168,7 +215,16 @@ struct drm_device { */ struct drm_vblank_crtc *vblank; - spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ + /** + * @vblank_time_lock: + * + * Protects vblank count and time updates during vblank enable/disable + */ + spinlock_t vblank_time_lock; + /** + * @vbl_lock: Top-level vblank references lock, wraps the low-level + * @vblank_time_lock. + */ spinlock_t vbl_lock; /** @@ -184,45 +240,61 @@ struct drm_device { * races and imprecision over longer time periods, hence exposing a * hardware vblank counter is always recommended. * - * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set. + * This is the statically configured device wide maximum. The driver + * can instead choose to use a runtime configurable per-crtc value + * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count + * must be left at zero. See drm_crtc_set_max_vblank_count() on how + * to use the per-crtc value. + * + * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. */ - u32 max_vblank_count; /**< size of vblank counter register */ + u32 max_vblank_count; + + /** @vblank_event_list: List of vblank events */ + struct list_head vblank_event_list; /** - * List of events + * @event_lock: + * + * Protects @vblank_event_list and event delivery in + * general. See drm_send_event() and drm_send_event_locked(). */ - struct list_head vblank_event_list; spinlock_t event_lock; - /*@} */ + /** @agp: AGP data */ + struct drm_agp_head *agp; - struct drm_agp_head *agp; /**< AGP data */ + /** @pdev: PCI device structure */ + struct pci_dev *pdev; - struct pci_dev *pdev; /**< PCI device structure */ #ifdef __alpha__ + /** @hose: PCI hose, only used on ALPHA platforms. */ struct pci_controller *hose; #endif + /** @num_crtcs: Number of CRTCs on this device */ + unsigned int num_crtcs; - struct drm_sg_mem *sg; /**< Scatter gather memory */ - unsigned int num_crtcs; /**< Number of CRTCs on this device */ + /** @mode_config: Current mode config */ + struct drm_mode_config mode_config; - struct { - int context; - struct drm_hw_lock *lock; - } sigdata; - - struct drm_local_map *agp_buffer_map; - unsigned int agp_buffer_token; - - struct drm_mode_config mode_config; /**< Current mode config */ - - /** \name GEM information */ - /*@{ */ + /** @object_name_lock: GEM information */ struct mutex object_name_lock; + + /** @object_name_idr: GEM information */ struct idr object_name_idr; + + /** @vma_offset_manager: GEM information */ struct drm_vma_offset_manager *vma_offset_manager; - /*@} */ - int switch_power_state; + + /** + * @switch_power_state: + * + * Power state of the client. + * Used by drivers supporting the switcheroo driver. + * The state is maintained in the + * &vga_switcheroo_client_ops.set_gpu_state callback + */ + enum switch_power_state switch_power_state; /** * @fb_helper: @@ -231,6 +303,56 @@ struct drm_device { * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini(). */ struct drm_fb_helper *fb_helper; + + /* Everything below here is for legacy driver, never use! */ + /* private: */ + + /* Context handle management - linked list of context handles */ + struct list_head ctxlist; + + /* Context handle management - mutex for &ctxlist */ + struct mutex ctxlist_mutex; + + /* Context handle management */ + struct idr ctx_idr; + + /* Memory management - linked list of regions */ + struct list_head maplist; + + /* Memory management - user token hash table for maps */ + struct drm_open_hash map_hash; + + /* Context handle management - list of vmas (for debugging) */ + struct list_head vmalist; + + /* Optional pointer for DMA support */ + struct drm_device_dma *dma; + + /* Context swapping flag */ + __volatile__ long context_flag; + + /* Last current context */ + int last_context; + + /* Lock for &buf_use and a few other things. */ + spinlock_t buf_lock; + + /* Usage counter for buffers in use -- cannot alloc */ + int buf_use; + + /* Buffer allocation in progress */ + atomic_t buf_alloc; + + struct { + int context; + struct drm_hw_lock *lock; + } sigdata; + + struct drm_local_map *agp_buffer_map; + unsigned int agp_buffer_token; + + /* Scatter gather memory */ + struct drm_sg_mem *sg; }; #endif diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 5736c942c85b..c223c87ef119 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -314,6 +314,10 @@ # define DP_PSR_SETUP_TIME_SHIFT 1 # define DP_PSR2_SU_Y_COORDINATE_REQUIRED (1 << 4) /* eDP 1.4a */ # define DP_PSR2_SU_GRANULARITY_REQUIRED (1 << 5) /* eDP 1.4b */ + +#define DP_PSR2_SU_X_GRANULARITY 0x072 /* eDP 1.4b */ +#define DP_PSR2_SU_Y_GRANULARITY 0x074 /* eDP 1.4b */ + /* * 0x80-0x8f describe downstream port capabilities, but there are two layouts * based on whether DP_DETAILED_CAP_INFO_AVAILABLE was set. If it was not, @@ -1365,6 +1369,13 @@ enum drm_dp_quirk { * to 16 bits. So will give a constant value (0x8000) for compatability. */ DP_DPCD_QUIRK_CONSTANT_N, + /** + * @DP_DPCD_QUIRK_NO_PSR: + * + * The device does not support PSR even if reports that it supports or + * driver still need to implement proper handling for such device. + */ + DP_DPCD_QUIRK_NO_PSR, }; /** diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 371cc2816477..451d020f0137 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -44,7 +44,6 @@ struct drm_dp_vcpi { /** * struct drm_dp_mst_port - MST port - * @kref: reference count for this port. * @port_num: port number * @input: if this port is an input port. * @mcs: message capability status - DP 1.2 spec. @@ -67,7 +66,18 @@ struct drm_dp_vcpi { * in the MST topology. */ struct drm_dp_mst_port { - struct kref kref; + /** + * @topology_kref: refcount for this port's lifetime in the topology, + * only the DP MST helpers should need to touch this + */ + struct kref topology_kref; + + /** + * @malloc_kref: refcount for the memory allocation containing this + * structure. See drm_dp_mst_get_port_malloc() and + * drm_dp_mst_put_port_malloc(). + */ + struct kref malloc_kref; u8 port_num; bool input; @@ -102,7 +112,6 @@ struct drm_dp_mst_port { /** * struct drm_dp_mst_branch - MST branch device. - * @kref: reference count for this port. * @rad: Relative Address to talk to this branch device. * @lct: Link count total to talk to this branch device. * @num_ports: number of ports on the branch. @@ -121,7 +130,19 @@ struct drm_dp_mst_port { * to downstream port of parent branches. */ struct drm_dp_mst_branch { - struct kref kref; + /** + * @topology_kref: refcount for this branch device's lifetime in the + * topology, only the DP MST helpers should need to touch this + */ + struct kref topology_kref; + + /** + * @malloc_kref: refcount for the memory allocation containing this + * structure. See drm_dp_mst_get_mstb_malloc() and + * drm_dp_mst_put_mstb_malloc(). + */ + struct kref malloc_kref; + u8 rad[8]; u8 lct; int num_ports; @@ -404,9 +425,15 @@ struct drm_dp_payload { #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) +struct drm_dp_vcpi_allocation { + struct drm_dp_mst_port *port; + int vcpi; + struct list_head next; +}; + struct drm_dp_mst_topology_state { struct drm_private_state base; - int avail_slots; + struct list_head vcpis; struct drm_dp_mst_topology_mgr *mgr; }; @@ -617,13 +644,115 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_port *port, int pbn); -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - int slots); +int __must_check +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn); +int __must_check +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up); +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); + +void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); +void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); + +extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; + +/** + * __drm_dp_mst_state_iter_get - private atomic state iterator function for + * macro-internal use + * @state: &struct drm_atomic_state pointer + * @mgr: pointer to the &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: optional pointer to the old &struct drm_dp_mst_topology_state + * iteration cursor + * @new_state: optional pointer to the new &struct drm_dp_mst_topology_state + * iteration cursor + * @i: int iteration cursor, for macro-internal use + * + * Used by for_each_oldnew_mst_mgr_in_state(), + * for_each_old_mst_mgr_in_state(), and for_each_new_mst_mgr_in_state(). Don't + * call this directly. + * + * Returns: + * True if the current &struct drm_private_obj is a &struct + * drm_dp_mst_topology_mgr, false otherwise. + */ +static inline bool +__drm_dp_mst_state_iter_get(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr **mgr, + struct drm_dp_mst_topology_state **old_state, + struct drm_dp_mst_topology_state **new_state, + int i) +{ + struct __drm_private_objs_state *objs_state = &state->private_objs[i]; + + if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) + return false; + + *mgr = to_dp_mst_topology_mgr(objs_state->ptr); + if (old_state) + *old_state = to_dp_mst_topology_state(objs_state->old_state); + if (new_state) + *new_state = to_dp_mst_topology_state(objs_state->new_state); + + return true; +} + +/** + * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology + * managers in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking both old and new state. This is useful in places where the state + * delta needs to be considered, for example in atomic check functions. + */ +#define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) + +/** + * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the old state. This is useful in disable functions, where we + * need the old state the hardware is still in. + */ +#define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) + +/** + * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the new state. This is useful in enable functions, where we + * need the new state the hardware should be in when the atomic commit + * operation has completed. + */ +#define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) #endif diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index e3c404833115..8dc1a081fb36 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -352,18 +352,17 @@ drm_load_edid_firmware(struct drm_connector *connector) int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, - const struct drm_display_mode *mode, - bool is_hdmi2_sink); + struct drm_connector *connector, + const struct drm_display_mode *mode); int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, struct drm_connector *connector, const struct drm_display_mode *mode); void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, + struct drm_connector *connector, const struct drm_display_mode *mode, - enum hdmi_quantization_range rgb_quant_range, - bool rgb_quant_range_selectable, - bool is_hdmi2_sink); + enum hdmi_quantization_range rgb_quant_range); /** * drm_eld_mnl - Get ELD monitor name length in bytes. @@ -471,7 +470,6 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match); enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); bool drm_detect_hdmi_monitor(struct edid *edid); bool drm_detect_monitor_audio(struct edid *edid); -bool drm_rgb_quant_range_selectable(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, diff --git a/include/drm/drm_encoder_slave.h b/include/drm/drm_encoder_slave.h index 1107b4b1c599..a09864f6d684 100644 --- a/include/drm/drm_encoder_slave.h +++ b/include/drm/drm_encoder_slave.h @@ -27,7 +27,6 @@ #ifndef __DRM_ENCODER_SLAVE_H__ #define __DRM_ENCODER_SLAVE_H__ -#include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_encoder.h> diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index 8dbbe1eece1b..4becb09975a4 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -2,31 +2,9 @@ #ifndef __DRM_FB_CMA_HELPER_H__ #define __DRM_FB_CMA_HELPER_H__ -struct drm_fbdev_cma; -struct drm_gem_cma_object; - -struct drm_fb_helper_surface_size; -struct drm_framebuffer_funcs; -struct drm_fb_helper_funcs; struct drm_framebuffer; -struct drm_fb_helper; -struct drm_device; -struct drm_file; -struct drm_mode_fb_cmd2; -struct drm_plane; struct drm_plane_state; -int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp, - unsigned int max_conn_count); -void drm_fb_cma_fbdev_fini(struct drm_device *dev); - -struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count); -void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); - -void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); -void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); - struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index bcb389f04618..b3d9d88ab290 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -143,6 +143,123 @@ struct drm_format_name_buf { char str[32]; }; +/** + * drm_format_info_is_yuv_packed - check that the format info matches a YUV + * format with data laid in a single plane + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a packed YUV format. + */ +static inline bool +drm_format_info_is_yuv_packed(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 1; +} + +/** + * drm_format_info_is_yuv_semiplanar - check that the format info matches a YUV + * format with data laid in two planes (luminance and chrominance) + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a semiplanar YUV format. + */ +static inline bool +drm_format_info_is_yuv_semiplanar(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 2; +} + +/** + * drm_format_info_is_yuv_planar - check that the format info matches a YUV + * format with data laid in three planes (one for each YUV component) + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a planar YUV format. + */ +static inline bool +drm_format_info_is_yuv_planar(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 3; +} + +/** + * drm_format_info_is_yuv_sampling_410 - check that the format info matches a + * YUV format with 4:1:0 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:1:0 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_410(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 4 && info->vsub == 4; +} + +/** + * drm_format_info_is_yuv_sampling_411 - check that the format info matches a + * YUV format with 4:1:1 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:1:1 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_411(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 4 && info->vsub == 1; +} + +/** + * drm_format_info_is_yuv_sampling_420 - check that the format info matches a + * YUV format with 4:2:0 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:2:0 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_420(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 2 && info->vsub == 2; +} + +/** + * drm_format_info_is_yuv_sampling_422 - check that the format info matches a + * YUV format with 4:2:2 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:2:2 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_422(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 2 && info->vsub == 1; +} + +/** + * drm_format_info_is_yuv_sampling_444 - check that the format info matches a + * YUV format with 4:4:4 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:4:4 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_444(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 1 && info->vsub == 1; +} + const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); const struct drm_format_info * diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index c94acedfb08e..f0b34c977ec5 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -23,13 +23,17 @@ #ifndef __DRM_FRAMEBUFFER_H__ #define __DRM_FRAMEBUFFER_H__ -#include <linux/list.h> #include <linux/ctype.h> +#include <linux/list.h> +#include <linux/sched.h> + #include <drm/drm_mode_object.h> -struct drm_framebuffer; -struct drm_file; +struct drm_clip_rect; struct drm_device; +struct drm_file; +struct drm_framebuffer; +struct drm_gem_object; /** * struct drm_framebuffer_funcs - framebuffer hooks diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 07c504940ba1..947ac95eb24a 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -2,9 +2,12 @@ #ifndef __DRM_GEM_CMA_HELPER_H__ #define __DRM_GEM_CMA_HELPER_H__ -#include <drm/drmP.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> #include <drm/drm_gem.h> +struct drm_mode_create_dumb; + /** * struct drm_gem_cma_object - GEM object backed by CMA memory allocations * @base: base GEM object diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index a38de7eb55b4..7f307e834eef 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -25,6 +25,9 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, struct drm_framebuffer * drm_gem_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +struct drm_framebuffer * +drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, + const struct drm_mode_fb_cmd2 *mode_cmd); int drm_gem_fb_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index baded6514456..be4fed97e727 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -136,8 +136,7 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f), \ - .base.type = DRM_MODE_OBJECT_MODE + .vscan = (vs), .flags = (f) #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ @@ -214,20 +213,6 @@ struct drm_display_mode { struct list_head head; /** - * @base: - * - * A display mode is a normal modeset object, possibly including public - * userspace id. - * - * FIXME: - * - * This can probably be removed since the entire concept of userspace - * managing modes explicitly has never landed in upstream kernel mode - * setting support. - */ - struct drm_mode_object base; - - /** * @name: * * Human-readable name of the mode, filled out with drm_mode_set_name(). @@ -429,14 +414,14 @@ struct drm_display_mode { /** * DRM_MODE_FMT - printf string for &struct drm_display_mode */ -#define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" +#define DRM_MODE_FMT "\"%s\": %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" /** * DRM_MODE_ARG - printf arguments for &struct drm_display_mode * @m: display mode */ #define DRM_MODE_ARG(m) \ - (m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \ + (m)->name, (m)->vrefresh, (m)->clock, \ (m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \ (m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \ (m)->type, (m)->flags diff --git a/include/drm/drm_util.h b/include/drm/drm_util.h index 88abdca89baa..07b8e9f04599 100644 --- a/include/drm/drm_util.h +++ b/include/drm/drm_util.h @@ -26,7 +26,58 @@ #ifndef _DRM_UTIL_H_ #define _DRM_UTIL_H_ -/* helper for handling conditionals in various for_each macros */ +/** + * DOC: drm utils + * + * Macros and inline functions that does not naturally belong in other places + */ + +#include <linux/interrupt.h> +#include <linux/kgdb.h> +#include <linux/preempt.h> +#include <linux/smp.h> + +/* + * Use EXPORT_SYMBOL_FOR_TESTS_ONLY() for functions that shall + * only be visible for drmselftests. + */ +#if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) +#else +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) +#endif + +/** + * for_each_if - helper for handling conditionals in various for_each macros + * @condition: The condition to check + * + * Typical use:: + * + * #define for_each_foo_bar(x, y) \' + * list_for_each_entry(x, y->list, head) \' + * for_each_if(x->something == SOMETHING) + * + * The for_each_if() macro makes the use of for_each_foo_bar() less error + * prone. + */ #define for_each_if(condition) if (!(condition)) {} else +/** + * drm_can_sleep - returns true if currently okay to sleep + * + * This function shall not be used in new code. + * The check for running in atomic context may not work - see linux/preempt.h. + * + * FIXME: All users of drm_can_sleep should be removed (see todo.rst) + * + * Returns: + * False if kgdb is active, we are in atomic context or irqs are disabled. + */ +static inline bool drm_can_sleep(void) +{ + if (in_atomic() || in_dbg_master() || irqs_disabled()) + return false; + return true; +} + #endif diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 6ad9630d4f48..e528bb2f659d 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -129,6 +129,26 @@ struct drm_vblank_crtc { */ u32 last; /** + * @max_vblank_count: + * + * Maximum value of the vblank registers for this crtc. This value +1 + * will result in a wrap-around of the vblank register. It is used + * by the vblank core to handle wrap-arounds. + * + * If set to zero the vblank core will try to guess the elapsed vblanks + * between times when the vblank interrupt is disabled through + * high-precision timestamps. That approach is suffering from small + * races and imprecision over longer time periods, hence exposing a + * hardware vblank counter is always recommended. + * + * This is the runtime configurable per-crtc maximum set through + * drm_crtc_set_max_vblank_count(). If this is used the driver + * must leave the device wide &drm_device.max_vblank_count at zero. + * + * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. + */ + u32 max_vblank_count; + /** * @inmodeset: Tracks whether the vblank is disabled due to a modeset. * For legacy driver bit 2 additionally tracks whether an additional * temporary vblank reference has been acquired to paper over the @@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode); wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc); +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, + u32 max_vblank_count); #endif diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h index b8ba58861986..f4ec2834bc22 100644 --- a/include/drm/tinydrm/mipi-dbi.h +++ b/include/drm/tinydrm/mipi-dbi.h @@ -14,6 +14,7 @@ #include <drm/tinydrm/tinydrm.h> +struct drm_rect; struct spi_device; struct gpio_desc; struct regulator; @@ -67,6 +68,8 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi, const struct drm_simple_display_pipe_funcs *pipe_funcs, struct drm_driver *driver, const struct drm_display_mode *mode, unsigned int rotation); +void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state); void mipi_dbi_enable_flush(struct mipi_dbi *mipi, struct drm_crtc_state *crtc_state, struct drm_plane_state *plan_state); @@ -80,7 +83,7 @@ u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len); int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val); int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len); int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, - struct drm_clip_rect *clip, bool swap); + struct drm_rect *clip, bool swap); /** * mipi_dbi_command - MIPI DCS command with optional parameter(s) * @mipi: MIPI structure diff --git a/include/drm/tinydrm/tinydrm-helpers.h b/include/drm/tinydrm/tinydrm-helpers.h index 5b96f0b12c8c..f0d598789e4d 100644 --- a/include/drm/tinydrm/tinydrm-helpers.h +++ b/include/drm/tinydrm/tinydrm-helpers.h @@ -11,8 +11,8 @@ #define __LINUX_TINYDRM_HELPERS_H struct backlight_device; -struct tinydrm_device; -struct drm_clip_rect; +struct drm_framebuffer; +struct drm_rect; struct spi_transfer; struct spi_message; struct spi_device; @@ -33,23 +33,15 @@ static inline bool tinydrm_machine_little_endian(void) #endif } -bool tinydrm_merge_clips(struct drm_clip_rect *dst, - struct drm_clip_rect *src, unsigned int num_clips, - unsigned int flags, u32 max_width, u32 max_height); -int tinydrm_fb_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips); void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip); + struct drm_rect *clip); void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip); + struct drm_rect *clip); void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip, bool swap); + struct drm_rect *clip, bool swap); void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, - struct drm_clip_rect *clip); + struct drm_rect *clip); size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len); bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw); diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h index 448aa5ea4722..5621688edcc0 100644 --- a/include/drm/tinydrm/tinydrm.h +++ b/include/drm/tinydrm/tinydrm.h @@ -10,14 +10,9 @@ #ifndef __LINUX_TINYDRM_H #define __LINUX_TINYDRM_H -#include <linux/mutex.h> #include <drm/drm_simple_kms_helper.h> -struct drm_clip_rect; struct drm_driver; -struct drm_file; -struct drm_framebuffer; -struct drm_framebuffer_funcs; /** * struct tinydrm_device - tinydrm device @@ -32,24 +27,6 @@ struct tinydrm_device { * @pipe: Display pipe structure */ struct drm_simple_display_pipe pipe; - - /** - * @dirty_lock: Serializes framebuffer flushing - */ - struct mutex dirty_lock; - - /** - * @fb_funcs: Framebuffer functions used when creating framebuffers - */ - const struct drm_framebuffer_funcs *fb_funcs; - - /** - * @fb_dirty: Framebuffer dirty callback - */ - int (*fb_dirty)(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, unsigned flags, - unsigned color, struct drm_clip_rect *clips, - unsigned num_clips); }; static inline struct tinydrm_device * @@ -82,13 +59,10 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe) .clock = 1 /* pass validation */ int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev, - const struct drm_framebuffer_funcs *fb_funcs, struct drm_driver *driver); int devm_tinydrm_register(struct tinydrm_device *tdev); void tinydrm_shutdown(struct tinydrm_device *tdev); -void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state); int tinydrm_display_pipe_init(struct tinydrm_device *tdev, const struct drm_simple_display_pipe_funcs *funcs, diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h index bc8940ca280d..c0ff417b4770 100644 --- a/include/linux/dma-fence-array.h +++ b/include/linux/dma-fence-array.h @@ -40,6 +40,7 @@ struct dma_fence_array_cb { * @num_fences: number of fences in the array * @num_pending: fences in the array still pending * @fences: array of the fences + * @work: internal irq_work function */ struct dma_fence_array { struct dma_fence base; diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h index ed1dfba5e5f9..bfecd6bd4990 100644 --- a/include/linux/mfd/intel_soc_pmic.h +++ b/include/linux/mfd/intel_soc_pmic.h @@ -26,4 +26,7 @@ struct intel_soc_pmic { struct device *dev; }; +int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, + u32 value, u32 mask); + #endif /* __INTEL_SOC_PMIC_H__ */ diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 0b44260a5ee9..91d08a23f125 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -238,6 +238,8 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 +#define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 + /* add more to the end as needed */ #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) @@ -581,10 +583,18 @@ extern "C" { * Indicates the superblock size(s) used for the AFBC buffer. The buffer * size (in pixels) must be aligned to a multiple of the superblock size. * Four lowest significant bits(LSBs) are reserved for block size. + * + * Where one superblock size is specified, it applies to all planes of the + * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, + * the first applies to the Luma plane and the second applies to the Chroma + * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). + * Multiple superblock sizes are only valid for multi-plane YCbCr formats. */ #define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf #define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) /* * AFBC lossless colorspace transform @@ -644,6 +654,35 @@ extern "C" { */ #define AFBC_FORMAT_MOD_SC (1ULL << 9) +/* + * AFBC double-buffer + * + * Indicates that the buffer is allocated in a layout safe for front-buffer + * rendering. + */ +#define AFBC_FORMAT_MOD_DB (1ULL << 10) + +/* + * AFBC buffer content hints + * + * Indicates that the buffer includes per-superblock content hints. + */ +#define AFBC_FORMAT_MOD_BCH (1ULL << 11) + +/* + * Allwinner tiled modifier + * + * This tiling mode is implemented by the VPU found on all Allwinner platforms, + * codenamed sunxi. It is associated with a YUV format that uses either 2 or 3 + * planes. + * + * With this tiling, the luminance samples are disposed in tiles representing + * 32x32 pixels and the chrominance samples in tiles representing 32x64 pixels. + * The pixel order in each tile is linear and the tiles are disposed linearly, + * both in row-major order. + */ +#define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + #if defined(__cplusplus) } #endif |