diff options
391 files changed, 8867 insertions, 7902 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml b/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml index 984b90893583..bb6289c7d375 100644 --- a/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml +++ b/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml @@ -14,19 +14,6 @@ properties: compatible: const: chrontel,ch7033 - chrontel,byteswap: - $ref: /schemas/types.yaml#/definitions/uint8 - enum: - - 0 # BYTE_SWAP_RGB - - 1 # BYTE_SWAP_RBG - - 2 # BYTE_SWAP_GRB - - 3 # BYTE_SWAP_GBR - - 4 # BYTE_SWAP_BRG - - 5 # BYTE_SWAP_BGR - description: | - Set the byteswap value of the bridge. This is optional and if not - set value of BYTE_SWAP_BGR is used. - reg: maxItems: 1 description: I2C address of the device diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 94bc6e1b6451..f2515af8256f 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -24,6 +24,7 @@ properties: - qcom,sm8350-dp reg: + minItems: 4 items: - description: ahb register block - description: aux register block @@ -70,14 +71,28 @@ properties: operating-points-v2: maxItems: 1 + opp-table: true + power-domains: maxItems: 1 + aux-bus: + $ref: /schemas/display/dp-aux-bus.yaml# + + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + items: + maximum: 3 + "#sound-dai-cells": const: 0 - vdda-0p9-supply: true - vdda-1p2-supply: true + vdda-0p9-supply: + deprecated: true + vdda-1p2-supply: + deprecated: true ports: $ref: /schemas/graph.yaml#/properties/ports @@ -98,10 +113,33 @@ required: - clock-names - phys - phy-names - - "#sound-dai-cells" - power-domains - ports +allOf: + # AUX BUS does not exist on DP controllers + # Audio output also is present only on DP output + # p1 regions is present on DP, but not on eDP + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7280-edp + - qcom,sc8180x-edp + then: + properties: + "#sound-dai-cells": false + reg: + maxItems: 4 + else: + properties: + aux-bus: false + reg: + minItems: 5 + required: + - "#sound-dai-cells" + additionalProperties: false examples: @@ -140,9 +178,6 @@ examples: power-domains = <&rpmhpd SC7180_CX>; - vdda-0p9-supply = <&vdda_usb_ss_dp_core>; - vdda-1p2-supply = <&vdda_usb_ss_dp_1p2>; - ports { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml index 2df64afb76e6..253665c693e6 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml @@ -62,6 +62,7 @@ patternProperties: "^display-controller@[0-9a-f]+$": type: object description: Node containing the properties of DPU. + additionalProperties: false properties: compatible: @@ -105,6 +106,9 @@ patternProperties: maxItems: 1 operating-points-v2: true + opp-table: + type: object + ports: $ref: /schemas/graph.yaml#/properties/ports description: | diff --git a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml index 734d14de966d..c5824e1d2382 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml @@ -74,6 +74,7 @@ patternProperties: "^display-controller@[0-9a-f]+$": type: object description: Node containing the properties of DPU. + additionalProperties: false properties: compatible: @@ -113,6 +114,8 @@ patternProperties: maxItems: 1 operating-points-v2: true + opp-table: + type: object ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml index d3c3e4b07897..4890bc25f3fd 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml @@ -73,6 +73,7 @@ patternProperties: "^display-controller@[0-9a-f]+$": type: object description: Node containing the properties of DPU. + additionalProperties: false properties: compatible: @@ -114,6 +115,8 @@ patternProperties: maxItems: 1 operating-points-v2: true + opp-table: + type: object ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml index f427eec3d3a4..584d646021d5 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml @@ -72,6 +72,7 @@ patternProperties: "^display-controller@[0-9a-f]+$": type: object description: Node containing the properties of DPU. + additionalProperties: false properties: compatible: @@ -112,6 +113,8 @@ patternProperties: maxItems: 1 operating-points-v2: true + opp-table: + type: object ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml index 2bb8896beffc..7d1037373175 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml @@ -65,6 +65,7 @@ patternProperties: "^display-controller@[0-9a-f]+$": type: object description: Node containing the properties of DPU. + additionalProperties: false properties: compatible: @@ -102,6 +103,9 @@ patternProperties: maxItems: 1 operating-points-v2: true + opp-table: + type: object + ports: $ref: /schemas/graph.yaml#/properties/ports description: | diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml b/Documentation/devicetree/bindings/display/msm/gmu.yaml index fe55611d2603..67fdeeabae0c 100644 --- a/Documentation/devicetree/bindings/display/msm/gmu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml @@ -20,35 +20,24 @@ description: | properties: compatible: items: - - enum: - - qcom,adreno-gmu-630.2 + - pattern: '^qcom,adreno-gmu-6[0-9][0-9]\.[0-9]$' - const: qcom,adreno-gmu reg: - items: - - description: Core GMU registers - - description: GMU PDC registers - - description: GMU PDC sequence registers + minItems: 3 + maxItems: 4 reg-names: - items: - - const: gmu - - const: gmu_pdc - - const: gmu_pdc_seq + minItems: 3 + maxItems: 4 clocks: - items: - - description: GMU clock - - description: GPU CX clock - - description: GPU AXI clock - - description: GPU MEMNOC clock + minItems: 4 + maxItems: 7 clock-names: - items: - - const: gmu - - const: cxo - - const: axi - - const: memnoc + minItems: 4 + maxItems: 7 interrupts: items: @@ -76,6 +65,9 @@ properties: operating-points-v2: true + opp-table: + type: object + required: - compatible - reg @@ -91,6 +83,140 @@ required: additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-gmu-618.0 + - qcom,adreno-gmu-630.2 + then: + properties: + reg: + items: + - description: Core GMU registers + - description: GMU PDC registers + - description: GMU PDC sequence registers + reg-names: + items: + - const: gmu + - const: gmu_pdc + - const: gmu_pdc_seq + clocks: + items: + - description: GMU clock + - description: GPU CX clock + - description: GPU AXI clock + - description: GPU MEMNOC clock + clock-names: + items: + - const: gmu + - const: cxo + - const: axi + - const: memnoc + + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-gmu-635.0 + then: + properties: + reg: + items: + - description: Core GMU registers + - description: Resource controller registers + - description: GMU PDC registers + reg-names: + items: + - const: gmu + - const: rscc + - const: gmu_pdc + clocks: + items: + - description: GMU clock + - description: GPU CX clock + - description: GPU AXI clock + - description: GPU MEMNOC clock + - description: GPU AHB clock + - description: GPU HUB CX clock + - description: GPU SMMU vote clock + clock-names: + items: + - const: gmu + - const: cxo + - const: axi + - const: memnoc + - const: ahb + - const: hub + - const: smmu_vote + + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-gmu-640.1 + then: + properties: + reg: + items: + - description: Core GMU registers + - description: GMU PDC registers + - description: GMU PDC sequence registers + reg-names: + items: + - const: gmu + - const: gmu_pdc + - const: gmu_pdc_seq + + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-gmu-650.2 + then: + properties: + reg: + items: + - description: Core GMU registers + - description: Resource controller registers + - description: GMU PDC registers + - description: GMU PDC sequence registers + reg-names: + items: + - const: gmu + - const: rscc + - const: gmu_pdc + - const: gmu_pdc_seq + + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-gmu-640.1 + - qcom,adreno-gmu-650.2 + then: + properties: + clocks: + items: + - description: GPU AHB clock + - description: GMU clock + - description: GPU CX clock + - description: GPU AXI clock + - description: GPU MEMNOC clock + clock-names: + items: + - const: ahb + - const: gmu + - const: cxo + - const: axi + - const: memnoc + examples: - | #include <dt-bindings/clock/qcom,gpucc-sdm845.h> diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml index 3397bc31d087..346aabdccf7b 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -58,7 +58,8 @@ properties: - const: ocmem iommus: - maxItems: 1 + minItems: 1 + maxItems: 64 sram: $ref: /schemas/types.yaml#/definitions/phandle-array diff --git a/Documentation/devicetree/bindings/display/msm/mdp4.yaml b/Documentation/devicetree/bindings/display/msm/mdp4.yaml index f63f60fea27c..58c13f5277b6 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp4.yaml +++ b/Documentation/devicetree/bindings/display/msm/mdp4.yaml @@ -36,7 +36,7 @@ properties: maxItems: 1 iommus: - maxItems: 1 + maxItems: 4 ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 133f2bae04b5..18241f4051d2 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -234,6 +234,8 @@ properties: - mitsubishi,aa070mc01-ca1 # Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module - multi-inno,mi0700s4t-6 + # Multi-Inno Technology Co.,Ltd MI0800FT-9 8" 800x600 TFT Resistive Touch Module + - multi-inno,mi0800ft-9 # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. - multi-inno,mi1010ait-1cp # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 39792f051d2d..9a223df8530c 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -8,6 +8,7 @@ Required properties: "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi" "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi" "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi" + "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi" - reg: Represent the physical address range of the controller. - interrupts: Represent the controller's interrupt to the CPU(s). - clocks, clock-names: Phandles to the controller's pll reference diff --git a/Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml b/Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml index eea2e02678ed..83fe4b39b56f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,hdmi-phy-qmp.yaml @@ -28,12 +28,15 @@ properties: - const: hdmi_phy clocks: - maxItems: 2 + minItems: 2 + maxItems: 3 clock-names: + minItems: 2 items: - const: iface - const: ref + - const: xo power-domains: maxItems: 1 @@ -44,6 +47,9 @@ properties: vddio-supply: description: phandle to VDD I/O supply regulator + '#clock-cells': + const: 0 + '#phy-cells': const: 0 @@ -75,9 +81,12 @@ examples: "hdmi_phy"; clocks = <&mmcc 116>, - <&gcc 214>; + <&gcc 214>, + <&xo_board>; clock-names = "iface", - "ref"; + "ref", + "xo"; + #clock-cells = <0>; #phy-cells = <0>; vddio-supply = <&vreg_l12a_1p8>; diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 7634c27ac562..393d218e4a0c 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -679,6 +679,74 @@ Contact: Sam Ravnborg Level: Advanced +Brightness handling on devices with multiple internal panels +============================================================ + +On x86/ACPI devices there can be multiple backlight firmware interfaces: +(ACPI) video, vendor specific and others. As well as direct/native (PWM) +register programming by the KMS driver. + +To deal with this backlight drivers used on x86/ACPI call +acpi_video_get_backlight_type() which has heuristics (+quirks) to select +which backlight interface to use; and backlight drivers which do not match +the returned type will not register themselves, so that only one backlight +device gets registered (in a single GPU setup, see below). + +At the moment this more or less assumes that there will only +be 1 (internal) panel on a system. + +On systems with 2 panels this may be a problem, depending on +what interface acpi_video_get_backlight_type() selects: + +1. native: in this case the KMS driver is expected to know which backlight + device belongs to which output so everything should just work. +2. video: this does support controlling multiple backlights, but some work + will need to be done to get the output <-> backlight device mapping + +The above assumes both panels will require the same backlight interface type. +Things will break on systems with multiple panels where the 2 panels need +a different type of control. E.g. one panel needs ACPI video backlight control, +where as the other is using native backlight control. Currently in this case +only one of the 2 required backlight devices will get registered, based on +the acpi_video_get_backlight_type() return value. + +If this (theoretical) case ever shows up, then supporting this will need some +work. A possible solution here would be to pass a device and connector-name +to acpi_video_get_backlight_type() so that it can deal with this. + +Note in a way we already have a case where userspace sees 2 panels, +in dual GPU laptop setups with a mux. On those systems we may see +either 2 native backlight devices; or 2 native backlight devices. + +Userspace already has code to deal with this by detecting if the related +panel is active (iow which way the mux between the GPU and the panels +points) and then uses that backlight device. Userspace here very much +assumes a single panel though. It picks only 1 of the 2 backlight devices +and then only uses that one. + +Note that all userspace code (that I know off) is currently hardcoded +to assume a single panel. + +Before the recent changes to not register multiple (e.g. video + native) +/sys/class/backlight devices for a single panel (on a single GPU laptop), +userspace would see multiple backlight devices all controlling the same +backlight. + +To deal with this userspace had to always picks one preferred device under +/sys/class/backlight and will ignore the others. So to support brightness +control on multiple panels userspace will need to be updated too. + +There are plans to allow brightness control through the KMS API by adding +a "display brightness" property to drm_connector objects for panels. This +solves a number of issues with the /sys/class/backlight API, including not +being able to map a sysfs backlight device to a specific connector. Any +userspace changes to add support for brightness control on devices with +multiple panels really should build on top of this new KMS property. + +Contact: Hans de Goede + +Level: Advanced + Outside DRM =========== diff --git a/MAINTAINERS b/MAINTAINERS index 1e1581b90d9d..4f2fa9925116 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14532,6 +14532,7 @@ M: Daniel Dadap <ddadap@nvidia.com> L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/x86/nvidia-wmi-ec-backlight.c +F: include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h NVM EXPRESS DRIVER M: Keith Busch <kbusch@kernel.org> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7802d8846a8d..44ad4b6bd234 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -212,6 +212,7 @@ config ACPI_VIDEO tristate "Video" depends on BACKLIGHT_CLASS_DEVICE depends on INPUT + depends on ACPI_WMI || !X86 select THERMAL help This driver implements the ACPI Extensions For Display Adapters diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 5cbe2196176d..a7c3d11e0dac 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -73,6 +73,16 @@ module_param(device_id_scheme, bool, 0444); static int only_lcd = -1; module_param(only_lcd, int, 0444); +/* + * Display probing is known to take up to 5 seconds, so delay the fallback + * backlight registration by 5 seconds + 3 seconds for some extra margin. + */ +static int register_backlight_delay = 8; +module_param(register_backlight_delay, int, 0444); +MODULE_PARM_DESC(register_backlight_delay, + "Delay in seconds before doing fallback (non GPU driver triggered) " + "backlight registration, set to 0 to disable."); + static bool may_report_brightness_keys; static int register_count; static DEFINE_MUTEX(register_count_mutex); @@ -81,7 +91,9 @@ static LIST_HEAD(video_bus_head); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device); static void acpi_video_bus_notify(struct acpi_device *device, u32 event); -void acpi_video_detect_exit(void); +static void acpi_video_bus_register_backlight_work(struct work_struct *ignored); +static DECLARE_DELAYED_WORK(video_bus_register_backlight_work, + acpi_video_bus_register_backlight_work); /* * Indices in the _BCL method response: the first two items are special, @@ -1859,8 +1871,6 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) if (video->backlight_registered) return 0; - acpi_video_run_bcl_for_osi(video); - if (acpi_video_get_backlight_type() != acpi_backlight_video) return 0; @@ -2086,7 +2096,11 @@ static int acpi_video_bus_add(struct acpi_device *device) list_add_tail(&video->entry, &video_bus_head); mutex_unlock(&video_list_lock); - acpi_video_bus_register_backlight(video); + /* + * The userspace visible backlight_device gets registered separately + * from acpi_video_register_backlight(). + */ + acpi_video_run_bcl_for_osi(video); acpi_video_bus_add_notify_handler(video); return 0; @@ -2111,20 +2125,25 @@ static int acpi_video_bus_remove(struct acpi_device *device) video = acpi_driver_data(device); - acpi_video_bus_remove_notify_handler(video); - acpi_video_bus_unregister_backlight(video); - acpi_video_bus_put_devices(video); - mutex_lock(&video_list_lock); list_del(&video->entry); mutex_unlock(&video_list_lock); + acpi_video_bus_remove_notify_handler(video); + acpi_video_bus_unregister_backlight(video); + acpi_video_bus_put_devices(video); + kfree(video->attached_array); kfree(video); return 0; } +static void acpi_video_bus_register_backlight_work(struct work_struct *ignored) +{ + acpi_video_register_backlight(); +} + static int __init is_i740(struct pci_dev *dev) { if (dev->device == 0x00D1) @@ -2235,6 +2254,18 @@ int acpi_video_register(void) */ register_count = 1; + /* + * acpi_video_bus_add() skips registering the userspace visible + * backlight_device. The intend is for this to be registered by the + * drm/kms driver calling acpi_video_register_backlight() *after* it is + * done setting up its own native backlight device. The delayed work + * ensures that acpi_video_register_backlight() always gets called + * eventually, in case there is no drm/kms driver or it is disabled. + */ + if (register_backlight_delay) + schedule_delayed_work(&video_bus_register_backlight_work, + register_backlight_delay * HZ); + leave: mutex_unlock(®ister_count_mutex); return ret; @@ -2245,6 +2276,7 @@ void acpi_video_unregister(void) { mutex_lock(®ister_count_mutex); if (register_count) { + cancel_delayed_work_sync(&video_bus_register_backlight_work); acpi_bus_unregister_driver(&acpi_video_bus); register_count = 0; may_report_brightness_keys = false; @@ -2253,19 +2285,16 @@ void acpi_video_unregister(void) } EXPORT_SYMBOL(acpi_video_unregister); -void acpi_video_unregister_backlight(void) +void acpi_video_register_backlight(void) { struct acpi_video_bus *video; - mutex_lock(®ister_count_mutex); - if (register_count) { - mutex_lock(&video_list_lock); - list_for_each_entry(video, &video_bus_head, entry) - acpi_video_bus_unregister_backlight(video); - mutex_unlock(&video_list_lock); - } - mutex_unlock(®ister_count_mutex); + mutex_lock(&video_list_lock); + list_for_each_entry(video, &video_bus_head, entry) + acpi_video_bus_register_backlight(video); + mutex_unlock(&video_list_lock); } +EXPORT_SYMBOL(acpi_video_register_backlight); bool acpi_video_handles_brightness_key_presses(void) { @@ -2302,7 +2331,6 @@ static int __init acpi_video_init(void) static void __exit acpi_video_exit(void) { - acpi_video_detect_exit(); acpi_video_unregister(); } diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 5d7f38016a24..db2474fe58ac 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -17,8 +17,9 @@ * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop, * sony_acpi,... can take care about backlight brightness. * - * Backlight drivers can use acpi_video_get_backlight_type() to determine - * which driver should handle the backlight. + * Backlight drivers can use acpi_video_get_backlight_type() to determine which + * driver should handle the backlight. RAW/GPU-driver backlight drivers must + * use the acpi_video_backlight_use_native() helper for this. * * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) * this file will not be compiled and acpi_video_get_backlight_type() will @@ -27,20 +28,16 @@ #include <linux/export.h> #include <linux/acpi.h> +#include <linux/apple-gmux.h> #include <linux/backlight.h> #include <linux/dmi.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h> #include <linux/types.h> #include <linux/workqueue.h> #include <acpi/video.h> -void acpi_video_unregister_backlight(void); - -static bool backlight_notifier_registered; -static struct notifier_block backlight_nb; -static struct work_struct backlight_notify_work; - static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef; static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef; @@ -78,6 +75,36 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } +/* This depends on ACPI_WMI which is X86 only */ +#ifdef CONFIG_X86 +static bool nvidia_wmi_ec_supported(void) +{ + struct wmi_brightness_args args = { + .mode = WMI_BRIGHTNESS_MODE_GET, + .val = 0, + .ret = 0, + }; + struct acpi_buffer buf = { (acpi_size)sizeof(args), &args }; + acpi_status status; + + status = wmi_evaluate_method(WMI_BRIGHTNESS_GUID, 0, + WMI_BRIGHTNESS_METHOD_SOURCE, &buf, &buf); + if (ACPI_FAILURE(status)) + return false; + + /* + * If brightness is handled by the EC then nvidia-wmi-ec-backlight + * should be used, else the GPU driver(s) should be used. + */ + return args.ret == WMI_BRIGHTNESS_SOURCE_EC; +} +#else +static bool nvidia_wmi_ec_supported(void) +{ + return false; +} +#endif + /* Force to use vendor driver when the ACPI device is known to be * buggy */ static int video_detect_force_vendor(const struct dmi_system_id *d) @@ -105,63 +132,143 @@ static int video_detect_force_none(const struct dmi_system_id *d) } static const struct dmi_system_id video_detect_dmi_table[] = { - /* On Samsung X360, the BIOS will set a flag (VDRV) if generic - * ACPI backlight device is used. This flag will definitively break - * the backlight interface (even the vendor interface) until next - * reboot. It's why we should prevent video.ko from being used here - * and we can't rely on a later call to acpi_video_unregister(). - */ { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */ .callback = video_detect_force_vendor, - /* X360 */ + /* Acer KAV80 */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), }, }, { - .callback = video_detect_force_vendor, - /* Asus UL30VT */ - .matches = { + .callback = video_detect_force_vendor, + /* Asus UL30VT */ + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), }, }, { - .callback = video_detect_force_vendor, - /* Asus UL30A */ - .matches = { + .callback = video_detect_force_vendor, + /* Asus UL30A */ + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, { - .callback = video_detect_force_vendor, - /* GIGABYTE GB-BXBT-2807 */ - .matches = { + .callback = video_detect_force_vendor, + /* Asus X55U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X101CH */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X401U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X501U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus 1015CX */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), + }, + }, + { + .callback = video_detect_force_vendor, + /* GIGABYTE GB-BXBT-2807 */ + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"), }, }, { - .callback = video_detect_force_vendor, - /* Sony VPCEH3U1E */ - .matches = { + .callback = video_detect_force_vendor, + /* Samsung N150/N210/N220 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Samsung NF110/NF210/NF310 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), + DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Samsung NC210 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"), + DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Sony VPCEH3U1E */ + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"), }, }, { - .callback = video_detect_force_vendor, - /* Xiaomi Mi Pad 2 */ - .matches = { + .callback = video_detect_force_vendor, + /* Xiaomi Mi Pad 2 */ + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), }, }, /* + * Toshiba models with Transflective display, these need to use + * the toshiba_acpi vendor driver for proper Transflective handling. + */ + { + .callback = video_detect_force_vendor, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"), + }, + }, + { + .callback = video_detect_force_vendor, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"), + }, + }, + + /* * These models have a working acpi_video backlight control, and using * native backlight causes a regression where backlight does not work * when userspace is not handling brightness key events. Disable @@ -390,130 +497,119 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, }, { - /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */ + /* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */ .callback = video_detect_force_native, - /* Acer TravelMate 5735Z */ + /* Acer Aspire 5741 */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"), - DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), }, }, { - .callback = video_detect_force_native, - /* ASUSTeK COMPUTER INC. GA401 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401"), - }, - }, - { - .callback = video_detect_force_native, - /* ASUSTeK COMPUTER INC. GA502 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA502"), + /* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */ + .callback = video_detect_force_native, + /* Acer Aspire 5750 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), }, }, { - .callback = video_detect_force_native, - /* ASUSTeK COMPUTER INC. GA503 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), + /* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */ + .callback = video_detect_force_native, + /* Acer Extensa 5235 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), }, }, - /* - * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a - * working native and video interface. However the default detection - * mechanism first registers the video interface before unregistering - * it again and switching to the native interface during boot. This - * results in a dangling SBIOS request for backlight change for some - * reason, causing the backlight to switch to ~2% once per boot on the - * first power cord connect or disconnect event. Setting the native - * interface explicitly circumvents this buggy behaviour, by avoiding - * the unregistering process. - */ { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), + .callback = video_detect_force_native, + /* Acer TravelMate 4750 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), }, }, { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "AURA1501"), + /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */ + .callback = video_detect_force_native, + /* Acer TravelMate 5735Z */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"), + DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), }, }, { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"), + /* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */ + .callback = video_detect_force_native, + /* Acer TravelMate 5760 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), }, }, { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), + .callback = video_detect_force_native, + /* ASUSTeK COMPUTER INC. GA401 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA401"), }, }, - /* - * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10, - * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo - * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description - * above. - */ { - .callback = video_detect_force_native, - .ident = "TongFang PF5PU1G", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"), + .callback = video_detect_force_native, + /* ASUSTeK COMPUTER INC. GA502 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA502"), }, }, { - .callback = video_detect_force_native, - .ident = "TongFang PF4NU1F", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"), + .callback = video_detect_force_native, + /* ASUSTeK COMPUTER INC. GA503 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), }, }, { - .callback = video_detect_force_native, - .ident = "TongFang PF4NU1F", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"), + .callback = video_detect_force_native, + /* Asus UX303UB */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), }, }, { - .callback = video_detect_force_native, - .ident = "TongFang PF5NU1G", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"), + .callback = video_detect_force_native, + /* Samsung N150P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), + DMI_MATCH(DMI_BOARD_NAME, "N150P"), }, }, { - .callback = video_detect_force_native, - .ident = "TongFang PF5NU1G", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"), + .callback = video_detect_force_native, + /* Samsung N145P/N250P/N260P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), + DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), }, }, { - .callback = video_detect_force_native, - .ident = "TongFang PF5LUXG", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"), + .callback = video_detect_force_native, + /* Samsung N250P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), + DMI_MATCH(DMI_BOARD_NAME, "N250P"), }, }, + /* * Desktops which falsely report a backlight and which our heuristics * for this do not catch. @@ -537,43 +633,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { { }, }; -/* This uses a workqueue to avoid various locking ordering issues */ -static void acpi_video_backlight_notify_work(struct work_struct *work) -{ - if (acpi_video_get_backlight_type() != acpi_backlight_video) - acpi_video_unregister_backlight(); -} - -static int acpi_video_backlight_notify(struct notifier_block *nb, - unsigned long val, void *bd) -{ - struct backlight_device *backlight = bd; - - /* A raw bl registering may change video -> native */ - if (backlight->props.type == BACKLIGHT_RAW && - val == BACKLIGHT_REGISTERED) - schedule_work(&backlight_notify_work); - - return NOTIFY_OK; -} - /* * Determine which type of backlight interface to use on this system, * First check cmdline, then dmi quirks, then do autodetect. - * - * The autodetect order is: - * 1) Is the acpi-video backlight interface supported -> - * no, use a vendor interface - * 2) Is this a win8 "ready" BIOS and do we have a native interface -> - * yes, use a native interface - * 3) Else use the acpi-video interface - * - * Arguably the native on win8 check should be done first, but that would - * be a behavior change, which may causes issues. */ -enum acpi_backlight_type acpi_video_get_backlight_type(void) +static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) { static DEFINE_MUTEX(init_mutex); + static bool nvidia_wmi_ec_present; + static bool native_available; static bool init_done; static long video_caps; @@ -585,48 +653,60 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_video, NULL, &video_caps, NULL); - INIT_WORK(&backlight_notify_work, - acpi_video_backlight_notify_work); - backlight_nb.notifier_call = acpi_video_backlight_notify; - backlight_nb.priority = 0; - if (backlight_register_notifier(&backlight_nb) == 0) - backlight_notifier_registered = true; + nvidia_wmi_ec_present = nvidia_wmi_ec_supported(); init_done = true; } + if (native) + native_available = true; mutex_unlock(&init_mutex); + /* + * The below heuristics / detection steps are in order of descending + * presedence. The commandline takes presedence over anything else. + */ if (acpi_backlight_cmdline != acpi_backlight_undef) return acpi_backlight_cmdline; + /* DMI quirks override any autodetection. */ if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi; - if (!(video_caps & ACPI_VIDEO_BACKLIGHT)) - return acpi_backlight_vendor; + /* Special cases such as nvidia_wmi_ec and apple gmux. */ + if (nvidia_wmi_ec_present) + return acpi_backlight_nvidia_wmi_ec; - if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW)) - return acpi_backlight_native; + if (apple_gmux_present()) + return acpi_backlight_apple_gmux; + + /* On systems with ACPI video use either native or ACPI video. */ + if (video_caps & ACPI_VIDEO_BACKLIGHT) { + /* + * Windows 8 and newer no longer use the ACPI video interface, + * so it often does not work. If the ACPI tables are written + * for win8 and native brightness ctl is available, use that. + * + * The native check deliberately is inside the if acpi-video + * block on older devices without acpi-video support native + * is usually not the best choice. + */ + if (acpi_osi_is_win8() && native_available) + return acpi_backlight_native; + else + return acpi_backlight_video; + } - return acpi_backlight_video; + /* No ACPI video (old hw), use vendor specific fw methods. */ + return acpi_backlight_vendor; } -EXPORT_SYMBOL(acpi_video_get_backlight_type); -/* - * Set the preferred backlight interface type based on DMI info. - * This function allows DMI blacklists to be implemented by external - * platform drivers instead of putting a big blacklist in video_detect.c - */ -void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type) +enum acpi_backlight_type acpi_video_get_backlight_type(void) { - acpi_backlight_dmi = type; - /* Remove acpi-video backlight interface if it is no longer desired */ - if (acpi_video_get_backlight_type() != acpi_backlight_video) - acpi_video_unregister_backlight(); + return __acpi_video_get_backlight_type(false); } -EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type); +EXPORT_SYMBOL(acpi_video_get_backlight_type); -void __exit acpi_video_detect_exit(void) +bool acpi_video_backlight_use_native(void) { - if (backlight_notifier_registered) - backlight_unregister_notifier(&backlight_nb); + return __acpi_video_get_backlight_type(true) == acpi_backlight_native; } +EXPORT_SYMBOL(acpi_video_backlight_use_native); diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 066400ed8841..406b4e26f538 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -136,6 +136,10 @@ struct dma_fence *dma_fence_get_stub(void) &dma_fence_stub_ops, &dma_fence_stub_lock, 0, 0); + + set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, + &dma_fence_stub.flags); + dma_fence_signal_locked(&dma_fence_stub); } spin_unlock(&dma_fence_stub_lock); @@ -161,6 +165,10 @@ struct dma_fence *dma_fence_allocate_private_stub(void) &dma_fence_stub_ops, &dma_fence_stub_lock, 0, 0); + + set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, + &dma_fence_stub.flags); + dma_fence_signal(fence); return fence; @@ -500,6 +508,8 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) __dma_fence_might_wait(); + dma_fence_enable_sw_signaling(fence); + trace_dma_fence_wait_start(fence); if (fence->ops->wait) ret = fence->ops->wait(fence, intr, timeout); @@ -601,9 +611,6 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence) { unsigned long flags; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return; - spin_lock_irqsave(fence->lock, flags); __dma_fence_enable_signaling(fence); spin_unlock_irqrestore(fence->lock, flags); @@ -756,19 +763,16 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) unsigned long flags; signed long ret = timeout ? timeout : 1; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return ret; - spin_lock_irqsave(fence->lock, flags); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + goto out; + if (intr && signal_pending(current)) { ret = -ERESTARTSYS; goto out; } - if (!__dma_fence_enable_signaling(fence)) - goto out; - if (!timeout) { ret = 0; goto out; diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index 8ce1ea59d31b..0a9b099d0518 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -87,6 +87,8 @@ static int sanitycheck(void *arg) if (!chain) err = -ENOMEM; + dma_fence_enable_sw_signaling(chain); + dma_fence_signal(f); dma_fence_put(f); @@ -143,6 +145,8 @@ static int fence_chains_init(struct fence_chains *fc, unsigned int count, } fc->tail = fc->chains[i]; + + dma_fence_enable_sw_signaling(fc->chains[i]); } fc->chain_length = i; diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index 4105d5ea8dde..f0cee984b6c7 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -102,6 +102,8 @@ static int sanitycheck(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + array = mock_array(1, f); if (!array) return -ENOMEM; @@ -124,12 +126,16 @@ static int unwrap_array(void *arg) if (!f1) return -ENOMEM; + dma_fence_enable_sw_signaling(f1); + f2 = mock_fence(); if (!f2) { dma_fence_put(f1); return -ENOMEM; } + dma_fence_enable_sw_signaling(f2); + array = mock_array(2, f1, f2); if (!array) return -ENOMEM; @@ -164,12 +170,16 @@ static int unwrap_chain(void *arg) if (!f1) return -ENOMEM; + dma_fence_enable_sw_signaling(f1); + f2 = mock_fence(); if (!f2) { dma_fence_put(f1); return -ENOMEM; } + dma_fence_enable_sw_signaling(f2); + chain = mock_chain(f1, f2); if (!chain) return -ENOMEM; @@ -204,12 +214,16 @@ static int unwrap_chain_array(void *arg) if (!f1) return -ENOMEM; + dma_fence_enable_sw_signaling(f1); + f2 = mock_fence(); if (!f2) { dma_fence_put(f1); return -ENOMEM; } + dma_fence_enable_sw_signaling(f2); + array = mock_array(2, f1, f2); if (!array) return -ENOMEM; @@ -248,12 +262,16 @@ static int unwrap_merge(void *arg) if (!f1) return -ENOMEM; + dma_fence_enable_sw_signaling(f1); + f2 = mock_fence(); if (!f2) { err = -ENOMEM; goto error_put_f1; } + dma_fence_enable_sw_signaling(f2); + f3 = dma_fence_unwrap_merge(f1, f2); if (!f3) { err = -ENOMEM; @@ -296,10 +314,14 @@ static int unwrap_merge_complex(void *arg) if (!f1) return -ENOMEM; + dma_fence_enable_sw_signaling(f1); + f2 = mock_fence(); if (!f2) goto error_put_f1; + dma_fence_enable_sw_signaling(f2); + f3 = dma_fence_unwrap_merge(f1, f2); if (!f3) goto error_put_f2; diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c index c8a12d7ad71a..fb6e0a6ae2c9 100644 --- a/drivers/dma-buf/st-dma-fence.c +++ b/drivers/dma-buf/st-dma-fence.c @@ -102,6 +102,8 @@ static int sanitycheck(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_fence_signal(f); dma_fence_put(f); @@ -117,6 +119,8 @@ static int test_signaling(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + if (dma_fence_is_signaled(f)) { pr_err("Fence unexpectedly signaled on creation\n"); goto err_free; @@ -190,6 +194,8 @@ static int test_late_add_callback(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_fence_signal(f); if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) { @@ -282,6 +288,8 @@ static int test_status(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + if (dma_fence_get_status(f)) { pr_err("Fence unexpectedly has signaled status on creation\n"); goto err_free; @@ -308,6 +316,8 @@ static int test_error(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_fence_set_error(f, -EIO); if (dma_fence_get_status(f)) { @@ -337,6 +347,8 @@ static int test_wait(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + if (dma_fence_wait_timeout(f, false, 0) != -ETIME) { pr_err("Wait reported complete before being signaled\n"); goto err_free; @@ -379,6 +391,8 @@ static int test_wait_timeout(void *arg) if (!wt.f) return -ENOMEM; + dma_fence_enable_sw_signaling(wt.f); + if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) { pr_err("Wait reported complete before being signaled\n"); goto err_free; @@ -458,6 +472,8 @@ static int thread_signal_callback(void *arg) break; } + dma_fence_enable_sw_signaling(f1); + rcu_assign_pointer(t->fences[t->id], f1); smp_wmb(); diff --git a/drivers/dma-buf/st-dma-resv.c b/drivers/dma-buf/st-dma-resv.c index 813779e3c9be..15dbea1462ed 100644 --- a/drivers/dma-buf/st-dma-resv.c +++ b/drivers/dma-buf/st-dma-resv.c @@ -45,6 +45,8 @@ static int sanitycheck(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_fence_signal(f); dma_fence_put(f); @@ -69,6 +71,8 @@ static int test_signaling(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { @@ -114,6 +118,8 @@ static int test_for_each(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { @@ -173,6 +179,8 @@ static int test_for_each_unlocked(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { @@ -244,6 +252,8 @@ static int test_get_fences(void *arg) if (!f) return -ENOMEM; + dma_fence_enable_sw_signaling(f); + dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2f52e8941074..198ba846d34b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -235,6 +235,13 @@ config DRM_RADEON select HWMON select BACKLIGHT_CLASS_DEVICE select INTERVAL_TREE + # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work + # ACPI_VIDEO's dependencies must also be selected. + select INPUT if ACPI + select ACPI_VIDEO if ACPI + # On x86 ACPI_VIDEO also needs ACPI_WMI + select X86_PLATFORM_DEVICES if ACPI && X86 + select ACPI_WMI if ACPI && X86 help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to @@ -260,6 +267,13 @@ config DRM_AMDGPU select BACKLIGHT_CLASS_DEVICE select INTERVAL_TREE select DRM_BUDDY + # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work + # ACPI_VIDEO's dependencies must also be selected. + select INPUT if ACPI + select ACPI_VIDEO if ACPI + # On x86 ACPI_VIDEO also needs ACPI_WMI + select X86_PLATFORM_DEVICES if ACPI && X86 + select ACPI_WMI if ACPI && X86 help Choose this option if you have a recent AMD Radeon graphics card. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 79bb6fd83094..ae9371b172e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -885,6 +885,7 @@ struct amdgpu_device { u64 fence_context; unsigned num_rings; struct amdgpu_ring *rings[AMDGPU_MAX_RINGS]; + struct dma_fence __rcu *gang_submit; bool ib_pool_ready; struct amdgpu_sa_manager ib_pools[AMDGPU_IB_POOL_MAX]; struct amdgpu_sched gpu_sched[AMDGPU_HW_IP_NUM][AMDGPU_RING_PRIO_MAX]; @@ -1294,6 +1295,8 @@ u32 amdgpu_device_pcie_port_rreg(struct amdgpu_device *adev, u32 reg); void amdgpu_device_pcie_port_wreg(struct amdgpu_device *adev, u32 reg, u32 v); +struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, + struct dma_fence *gang); /* atpx handler */ #if defined(CONFIG_VGA_SWITCHEROO) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 3da27436922c..b14800ac179e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1053,6 +1053,10 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) { if (adev->flags & AMD_IS_APU) return false; + + if (amdgpu_sriov_vf(adev)) + return false; + return pm_suspend_target_state != PM_SUSPEND_TO_IDLE; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 4f5bd96000ec..9e98f3866edc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -686,6 +686,7 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, ib->length_dw = ib_len; /* This works for NO_HWS. TODO: need to handle without knowing VMID */ job->vmid = vmid; + job->num_ibs = 1; ret = amdgpu_ib_schedule(ring, 1, ib, job, &f); @@ -755,11 +756,7 @@ void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bo { struct ras_err_data err_data = {0, 0, 0, NULL}; - /* CPU MCA will handle page retirement if connected_to_cpu is 1 */ - if (!adev->gmc.xgmi.connected_to_cpu) - amdgpu_umc_poison_handler(adev, &err_data, reset); - else if (reset) - amdgpu_amdkfd_gpu_reset(adev); + amdgpu_umc_poison_handler(adev, &err_data, reset); } bool amdgpu_amdkfd_ras_query_utcl2_poison_status(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index b7933c2ce765..491d4846fc02 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -1674,10 +1674,12 @@ amdgpu_connector_add(struct amdgpu_device *adev, adev->mode_info.dither_property, AMDGPU_FMT_DITHER_DISABLE); - if (amdgpu_audio != 0) + if (amdgpu_audio != 0) { drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.audio_property, AMDGPU_AUDIO_AUTO); + amdgpu_connector->audio = AMDGPU_AUDIO_AUTO; + } subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = true; @@ -1799,6 +1801,7 @@ amdgpu_connector_add(struct amdgpu_device *adev, drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.audio_property, AMDGPU_AUDIO_AUTO); + amdgpu_connector->audio = AMDGPU_AUDIO_AUTO; } drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.dither_property, @@ -1852,6 +1855,7 @@ amdgpu_connector_add(struct amdgpu_device *adev, drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.audio_property, AMDGPU_AUDIO_AUTO); + amdgpu_connector->audio = AMDGPU_AUDIO_AUTO; } drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.dither_property, @@ -1902,6 +1906,7 @@ amdgpu_connector_add(struct amdgpu_device *adev, drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.audio_property, AMDGPU_AUDIO_AUTO); + amdgpu_connector->audio = AMDGPU_AUDIO_AUTO; } drm_object_attach_property(&amdgpu_connector->base.base, adev->mode_info.dither_property, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index e104d7ef3c3d..1bbd39b3b0fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -64,11 +64,51 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, return 0; } +static int amdgpu_cs_job_idx(struct amdgpu_cs_parser *p, + struct drm_amdgpu_cs_chunk_ib *chunk_ib) +{ + struct drm_sched_entity *entity; + unsigned int i; + int r; + + r = amdgpu_ctx_get_entity(p->ctx, chunk_ib->ip_type, + chunk_ib->ip_instance, + chunk_ib->ring, &entity); + if (r) + return r; + + /* + * Abort if there is no run queue associated with this entity. + * Possibly because of disabled HW IP. + */ + if (entity->rq == NULL) + return -EINVAL; + + /* Check if we can add this IB to some existing job */ + for (i = 0; i < p->gang_size; ++i) + if (p->entities[i] == entity) + return i; + + /* If not increase the gang size if possible */ + if (i == AMDGPU_CS_GANG_SIZE) + return -EINVAL; + + p->entities[i] = entity; + p->gang_size = i + 1; + return i; +} + static int amdgpu_cs_p1_ib(struct amdgpu_cs_parser *p, struct drm_amdgpu_cs_chunk_ib *chunk_ib, unsigned int *num_ibs) { - ++(*num_ibs); + int r; + + r = amdgpu_cs_job_idx(p, chunk_ib); + if (r < 0) + return r; + + ++(num_ibs[r]); return 0; } @@ -142,11 +182,12 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + unsigned int num_ibs[AMDGPU_CS_GANG_SIZE] = { }; struct amdgpu_vm *vm = &fpriv->vm; uint64_t *chunk_array_user; uint64_t *chunk_array; - unsigned size, num_ibs = 0; uint32_t uf_offset = 0; + unsigned int size; int ret; int i; @@ -209,7 +250,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, if (size < sizeof(struct drm_amdgpu_cs_chunk_ib)) goto free_partial_kdata; - ret = amdgpu_cs_p1_ib(p, p->chunks[i].kdata, &num_ibs); + ret = amdgpu_cs_p1_ib(p, p->chunks[i].kdata, num_ibs); if (ret) goto free_partial_kdata; break; @@ -246,17 +287,28 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, } } - ret = amdgpu_job_alloc(p->adev, num_ibs, &p->job, vm); - if (ret) - goto free_all_kdata; + if (!p->gang_size) + return -EINVAL; + + for (i = 0; i < p->gang_size; ++i) { + ret = amdgpu_job_alloc(p->adev, num_ibs[i], &p->jobs[i], vm); + if (ret) + goto free_all_kdata; + + ret = drm_sched_job_init(&p->jobs[i]->base, p->entities[i], + &fpriv->vm); + if (ret) + goto free_all_kdata; + } + p->gang_leader = p->jobs[p->gang_size - 1]; - if (p->ctx->vram_lost_counter != p->job->vram_lost_counter) { + if (p->ctx->vram_lost_counter != p->gang_leader->vram_lost_counter) { ret = -ECANCELED; goto free_all_kdata; } if (p->uf_entry.tv.bo) - p->job->uf_addr = uf_offset; + p->gang_leader->uf_addr = uf_offset; kvfree(chunk_array); /* Use this opportunity to fill in task info for the vm */ @@ -278,93 +330,69 @@ free_chunk: return ret; } -static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, - struct amdgpu_cs_parser *parser) +static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk, + unsigned int *ce_preempt, + unsigned int *de_preempt) { - struct amdgpu_fpriv *fpriv = parser->filp->driver_priv; + struct drm_amdgpu_cs_chunk_ib *chunk_ib = chunk->kdata; + struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - int r, ce_preempt = 0, de_preempt = 0; struct amdgpu_ring *ring; - int i, j; - - for (i = 0, j = 0; i < parser->nchunks && j < parser->job->num_ibs; i++) { - struct amdgpu_cs_chunk *chunk; - struct amdgpu_ib *ib; - struct drm_amdgpu_cs_chunk_ib *chunk_ib; - struct drm_sched_entity *entity; - - chunk = &parser->chunks[i]; - ib = &parser->job->ibs[j]; - chunk_ib = (struct drm_amdgpu_cs_chunk_ib *)chunk->kdata; - - if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB) - continue; - - if (chunk_ib->ip_type == AMDGPU_HW_IP_GFX && - chunk_ib->flags & AMDGPU_IB_FLAG_PREEMPT) { - if (chunk_ib->flags & AMDGPU_IB_FLAG_CE) - ce_preempt++; - else - de_preempt++; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + int r; - /* each GFX command submit allows 0 or 1 IB preemptible for CE & DE */ - if (ce_preempt > 1 || de_preempt > 1) - return -EINVAL; - } + r = amdgpu_cs_job_idx(p, chunk_ib); + if (r < 0) + return r; - r = amdgpu_ctx_get_entity(parser->ctx, chunk_ib->ip_type, - chunk_ib->ip_instance, chunk_ib->ring, - &entity); - if (r) - return r; + job = p->jobs[r]; + ring = amdgpu_job_ring(job); + ib = &job->ibs[job->num_ibs++]; - if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE) - parser->job->preamble_status |= - AMDGPU_PREAMBLE_IB_PRESENT; + /* MM engine doesn't support user fences */ + if (p->uf_entry.tv.bo && ring->funcs->no_user_fence) + return -EINVAL; - if (parser->entity && parser->entity != entity) - return -EINVAL; + if (chunk_ib->ip_type == AMDGPU_HW_IP_GFX && + chunk_ib->flags & AMDGPU_IB_FLAG_PREEMPT) { + if (chunk_ib->flags & AMDGPU_IB_FLAG_CE) + (*ce_preempt)++; + else + (*de_preempt)++; - /* Return if there is no run queue associated with this entity. - * Possibly because of disabled HW IP*/ - if (entity->rq == NULL) + /* Each GFX command submit allows only 1 IB max + * preemptible for CE & DE */ + if (*ce_preempt > 1 || *de_preempt > 1) return -EINVAL; + } - parser->entity = entity; - - ring = to_amdgpu_ring(entity->rq->sched); - r = amdgpu_ib_get(adev, vm, ring->funcs->parse_cs ? - chunk_ib->ib_bytes : 0, - AMDGPU_IB_POOL_DELAYED, ib); - if (r) { - DRM_ERROR("Failed to get ib !\n"); - return r; - } - - ib->gpu_addr = chunk_ib->va_start; - ib->length_dw = chunk_ib->ib_bytes / 4; - ib->flags = chunk_ib->flags; + if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE) + job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT; - j++; + r = amdgpu_ib_get(p->adev, vm, ring->funcs->parse_cs ? + chunk_ib->ib_bytes : 0, + AMDGPU_IB_POOL_DELAYED, ib); + if (r) { + DRM_ERROR("Failed to get ib !\n"); + return r; } - /* MM engine doesn't support user fences */ - ring = to_amdgpu_ring(parser->entity->rq->sched); - if (parser->job->uf_addr && ring->funcs->no_user_fence) - return -EINVAL; - + ib->gpu_addr = chunk_ib->va_start; + ib->length_dw = chunk_ib->ib_bytes / 4; + ib->flags = chunk_ib->flags; return 0; } -static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p, - struct amdgpu_cs_chunk *chunk) +static int amdgpu_cs_p2_dependencies(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk) { + struct drm_amdgpu_cs_chunk_dep *deps = chunk->kdata; struct amdgpu_fpriv *fpriv = p->filp->driver_priv; unsigned num_deps; int i, r; - struct drm_amdgpu_cs_chunk_dep *deps; - deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; num_deps = chunk->length_dw * 4 / sizeof(struct drm_amdgpu_cs_chunk_dep); @@ -402,7 +430,7 @@ static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p, dma_fence_put(old); } - r = amdgpu_sync_fence(&p->job->sync, fence); + r = amdgpu_sync_fence(&p->gang_leader->sync, fence); dma_fence_put(fence); if (r) return r; @@ -410,9 +438,9 @@ static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p, return 0; } -static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p, - uint32_t handle, u64 point, - u64 flags) +static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p, + uint32_t handle, u64 point, + u64 flags) { struct dma_fence *fence; int r; @@ -424,25 +452,23 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p, return r; } - r = amdgpu_sync_fence(&p->job->sync, fence); + r = amdgpu_sync_fence(&p->gang_leader->sync, fence); dma_fence_put(fence); return r; } -static int amdgpu_cs_process_syncobj_in_dep(struct amdgpu_cs_parser *p, - struct amdgpu_cs_chunk *chunk) +static int amdgpu_cs_p2_syncobj_in(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk) { - struct drm_amdgpu_cs_chunk_sem *deps; + struct drm_amdgpu_cs_chunk_sem *deps = chunk->kdata; unsigned num_deps; int i, r; - deps = (struct drm_amdgpu_cs_chunk_sem *)chunk->kdata; num_deps = chunk->length_dw * 4 / sizeof(struct drm_amdgpu_cs_chunk_sem); for (i = 0; i < num_deps; ++i) { - r = amdgpu_syncobj_lookup_and_add_to_sync(p, deps[i].handle, - 0, 0); + r = amdgpu_syncobj_lookup_and_add(p, deps[i].handle, 0, 0); if (r) return r; } @@ -450,21 +476,19 @@ static int amdgpu_cs_process_syncobj_in_dep(struct amdgpu_cs_parser *p, return 0; } -static int amdgpu_cs_process_syncobj_timeline_in_dep(struct amdgpu_cs_parser *p, - struct amdgpu_cs_chunk *chunk) +static int amdgpu_cs_p2_syncobj_timeline_wait(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk) { - struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps; + struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps = chunk->kdata; unsigned num_deps; int i, r; - syncobj_deps = (struct drm_amdgpu_cs_chunk_syncobj *)chunk->kdata; num_deps = chunk->length_dw * 4 / sizeof(struct drm_amdgpu_cs_chunk_syncobj); for (i = 0; i < num_deps; ++i) { - r = amdgpu_syncobj_lookup_and_add_to_sync(p, - syncobj_deps[i].handle, - syncobj_deps[i].point, - syncobj_deps[i].flags); + r = amdgpu_syncobj_lookup_and_add(p, syncobj_deps[i].handle, + syncobj_deps[i].point, + syncobj_deps[i].flags); if (r) return r; } @@ -472,14 +496,13 @@ static int amdgpu_cs_process_syncobj_timeline_in_dep(struct amdgpu_cs_parser *p, return 0; } -static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p, - struct amdgpu_cs_chunk *chunk) +static int amdgpu_cs_p2_syncobj_out(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk) { - struct drm_amdgpu_cs_chunk_sem *deps; + struct drm_amdgpu_cs_chunk_sem *deps = chunk->kdata; unsigned num_deps; int i; - deps = (struct drm_amdgpu_cs_chunk_sem *)chunk->kdata; num_deps = chunk->length_dw * 4 / sizeof(struct drm_amdgpu_cs_chunk_sem); @@ -507,15 +530,13 @@ static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p, return 0; } - -static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p, - struct amdgpu_cs_chunk *chunk) +static int amdgpu_cs_p2_syncobj_timeline_signal(struct amdgpu_cs_parser *p, + struct amdgpu_cs_chunk *chunk) { - struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps; + struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps = chunk->kdata; unsigned num_deps; int i; - syncobj_deps = (struct drm_amdgpu_cs_chunk_syncobj *)chunk->kdata; num_deps = chunk->length_dw * 4 / sizeof(struct drm_amdgpu_cs_chunk_syncobj); @@ -552,9 +573,9 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p return 0; } -static int amdgpu_cs_dependencies(struct amdgpu_device *adev, - struct amdgpu_cs_parser *p) +static int amdgpu_cs_pass2(struct amdgpu_cs_parser *p) { + unsigned int ce_preempt = 0, de_preempt = 0; int i, r; for (i = 0; i < p->nchunks; ++i) { @@ -563,29 +584,34 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev, chunk = &p->chunks[i]; switch (chunk->chunk_id) { + case AMDGPU_CHUNK_ID_IB: + r = amdgpu_cs_p2_ib(p, chunk, &ce_preempt, &de_preempt); + if (r) + return r; + break; case AMDGPU_CHUNK_ID_DEPENDENCIES: case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES: - r = amdgpu_cs_process_fence_dep(p, chunk); + r = amdgpu_cs_p2_dependencies(p, chunk); if (r) return r; break; case AMDGPU_CHUNK_ID_SYNCOBJ_IN: - r = amdgpu_cs_process_syncobj_in_dep(p, chunk); + r = amdgpu_cs_p2_syncobj_in(p, chunk); if (r) return r; break; case AMDGPU_CHUNK_ID_SYNCOBJ_OUT: - r = amdgpu_cs_process_syncobj_out_dep(p, chunk); + r = amdgpu_cs_p2_syncobj_out(p, chunk); if (r) return r; break; case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT: - r = amdgpu_cs_process_syncobj_timeline_in_dep(p, chunk); + r = amdgpu_cs_p2_syncobj_timeline_wait(p, chunk); if (r) return r; break; case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL: - r = amdgpu_cs_process_syncobj_timeline_out_dep(p, chunk); + r = amdgpu_cs_p2_syncobj_timeline_signal(p, chunk); if (r) return r; break; @@ -830,6 +856,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_list_entry *e; struct list_head duplicates; + unsigned int i; int r; INIT_LIST_HEAD(&p->validated); @@ -913,16 +940,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, e->bo_va = amdgpu_vm_bo_find(vm, bo); } - /* Move fence waiting after getting reservation lock of - * PD root. Then there is no need on a ctx mutex lock. - */ - r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entity); - if (unlikely(r != 0)) { - if (r != -ERESTARTSYS) - DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n"); - goto error_validate; - } - amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, &p->bytes_moved_vis_threshold); p->bytes_moved = 0; @@ -943,124 +960,138 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, if (r) goto error_validate; - amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved, - p->bytes_moved_vis); - - amdgpu_job_set_resources(p->job, p->bo_list->gds_obj, - p->bo_list->gws_obj, p->bo_list->oa_obj); - - if (!r && p->uf_entry.tv.bo) { + if (p->uf_entry.tv.bo) { struct amdgpu_bo *uf = ttm_to_amdgpu_bo(p->uf_entry.tv.bo); r = amdgpu_ttm_alloc_gart(&uf->tbo); - p->job->uf_addr += amdgpu_bo_gpu_offset(uf); + if (r) + goto error_validate; + + p->gang_leader->uf_addr += amdgpu_bo_gpu_offset(uf); } + amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved, + p->bytes_moved_vis); + + for (i = 0; i < p->gang_size; ++i) + amdgpu_job_set_resources(p->jobs[i], p->bo_list->gds_obj, + p->bo_list->gws_obj, + p->bo_list->oa_obj); + return 0; + error_validate: - if (r) - ttm_eu_backoff_reservation(&p->ticket, &p->validated); + ttm_eu_backoff_reservation(&p->ticket, &p->validated); out_free_user_pages: - if (r) { - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); - if (!e->user_pages) - continue; - amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm); - kvfree(e->user_pages); - e->user_pages = NULL; - } - mutex_unlock(&p->bo_list->bo_list_mutex); + if (!e->user_pages) + continue; + amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm); + kvfree(e->user_pages); + e->user_pages = NULL; } return r; } -static void trace_amdgpu_cs_ibs(struct amdgpu_cs_parser *parser) +static void trace_amdgpu_cs_ibs(struct amdgpu_cs_parser *p) { - int i; + int i, j; if (!trace_amdgpu_cs_enabled()) return; - for (i = 0; i < parser->job->num_ibs; i++) - trace_amdgpu_cs(parser, i); + for (i = 0; i < p->gang_size; ++i) { + struct amdgpu_job *job = p->jobs[i]; + + for (j = 0; j < job->num_ibs; ++j) + trace_amdgpu_cs(p, job, &job->ibs[j]); + } } -static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) +static int amdgpu_cs_patch_ibs(struct amdgpu_cs_parser *p, + struct amdgpu_job *job) { - struct amdgpu_ring *ring = to_amdgpu_ring(p->entity->rq->sched); - struct amdgpu_fpriv *fpriv = p->filp->driver_priv; - struct amdgpu_device *adev = p->adev; - struct amdgpu_vm *vm = &fpriv->vm; - struct amdgpu_bo_list_entry *e; - struct amdgpu_bo_va *bo_va; - struct amdgpu_bo *bo; + struct amdgpu_ring *ring = amdgpu_job_ring(job); + unsigned int i; int r; /* Only for UVD/VCE VM emulation */ - if (ring->funcs->parse_cs || ring->funcs->patch_cs_in_place) { - unsigned i, j; - - for (i = 0, j = 0; i < p->nchunks && j < p->job->num_ibs; i++) { - struct drm_amdgpu_cs_chunk_ib *chunk_ib; - struct amdgpu_bo_va_mapping *m; - struct amdgpu_bo *aobj = NULL; - struct amdgpu_cs_chunk *chunk; - uint64_t offset, va_start; - struct amdgpu_ib *ib; - uint8_t *kptr; - - chunk = &p->chunks[i]; - ib = &p->job->ibs[j]; - chunk_ib = chunk->kdata; - - if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB) - continue; + if (!ring->funcs->parse_cs && !ring->funcs->patch_cs_in_place) + return 0; - va_start = chunk_ib->va_start & AMDGPU_GMC_HOLE_MASK; - r = amdgpu_cs_find_mapping(p, va_start, &aobj, &m); - if (r) { - DRM_ERROR("IB va_start is invalid\n"); - return r; - } + for (i = 0; i < job->num_ibs; ++i) { + struct amdgpu_ib *ib = &job->ibs[i]; + struct amdgpu_bo_va_mapping *m; + struct amdgpu_bo *aobj; + uint64_t va_start; + uint8_t *kptr; - if ((va_start + chunk_ib->ib_bytes) > - (m->last + 1) * AMDGPU_GPU_PAGE_SIZE) { - DRM_ERROR("IB va_start+ib_bytes is invalid\n"); - return -EINVAL; - } + va_start = ib->gpu_addr & AMDGPU_GMC_HOLE_MASK; + r = amdgpu_cs_find_mapping(p, va_start, &aobj, &m); + if (r) { + DRM_ERROR("IB va_start is invalid\n"); + return r; + } - /* the IB should be reserved at this point */ - r = amdgpu_bo_kmap(aobj, (void **)&kptr); - if (r) { - return r; - } + if ((va_start + ib->length_dw * 4) > + (m->last + 1) * AMDGPU_GPU_PAGE_SIZE) { + DRM_ERROR("IB va_start+ib_bytes is invalid\n"); + return -EINVAL; + } - offset = m->start * AMDGPU_GPU_PAGE_SIZE; - kptr += va_start - offset; - - if (ring->funcs->parse_cs) { - memcpy(ib->ptr, kptr, chunk_ib->ib_bytes); - amdgpu_bo_kunmap(aobj); - - r = amdgpu_ring_parse_cs(ring, p, p->job, ib); - if (r) - return r; - } else { - ib->ptr = (uint32_t *)kptr; - r = amdgpu_ring_patch_cs_in_place(ring, p, p->job, ib); - amdgpu_bo_kunmap(aobj); - if (r) - return r; - } + /* the IB should be reserved at this point */ + r = amdgpu_bo_kmap(aobj, (void **)&kptr); + if (r) { + return r; + } + + kptr += va_start - (m->start * AMDGPU_GPU_PAGE_SIZE); - j++; + if (ring->funcs->parse_cs) { + memcpy(ib->ptr, kptr, ib->length_dw * 4); + amdgpu_bo_kunmap(aobj); + + r = amdgpu_ring_parse_cs(ring, p, job, ib); + if (r) + return r; + } else { + ib->ptr = (uint32_t *)kptr; + r = amdgpu_ring_patch_cs_in_place(ring, p, job, ib); + amdgpu_bo_kunmap(aobj); + if (r) + return r; } } - if (!p->job->vm) - return 0; + return 0; +} + +static int amdgpu_cs_patch_jobs(struct amdgpu_cs_parser *p) +{ + unsigned int i; + int r; + + for (i = 0; i < p->gang_size; ++i) { + r = amdgpu_cs_patch_ibs(p, p->jobs[i]); + if (r) + return r; + } + return 0; +} + +static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) +{ + struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + struct amdgpu_job *job = p->gang_leader; + struct amdgpu_device *adev = p->adev; + struct amdgpu_vm *vm = &fpriv->vm; + struct amdgpu_bo_list_entry *e; + struct amdgpu_bo_va *bo_va; + struct amdgpu_bo *bo; + unsigned int i; + int r; r = amdgpu_vm_clear_freed(adev, vm, NULL); if (r) @@ -1070,7 +1101,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&p->job->sync, fpriv->prt_va->last_pt_update); + r = amdgpu_sync_fence(&job->sync, fpriv->prt_va->last_pt_update); if (r) return r; @@ -1081,7 +1112,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update); + r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update); if (r) return r; } @@ -1100,7 +1131,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update); + r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update); if (r) return r; } @@ -1113,11 +1144,18 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&p->job->sync, vm->last_update); + r = amdgpu_sync_fence(&job->sync, vm->last_update); if (r) return r; - p->job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.bo); + for (i = 0; i < p->gang_size; ++i) { + job = p->jobs[i]; + + if (!job->vm) + continue; + + job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.bo); + } if (amdgpu_vm_debug) { /* Invalidate all BOs to test for userspace bugs */ @@ -1138,7 +1176,9 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + struct amdgpu_job *leader = p->gang_leader; struct amdgpu_bo_list_entry *e; + unsigned int i; int r; list_for_each_entry(e, &p->validated, tv.head) { @@ -1148,12 +1188,23 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) sync_mode = amdgpu_bo_explicit_sync(bo) ? AMDGPU_SYNC_EXPLICIT : AMDGPU_SYNC_NE_OWNER; - r = amdgpu_sync_resv(p->adev, &p->job->sync, resv, sync_mode, + r = amdgpu_sync_resv(p->adev, &leader->sync, resv, sync_mode, &fpriv->vm); if (r) return r; } - return 0; + + for (i = 0; i < p->gang_size - 1; ++i) { + r = amdgpu_sync_clone(&leader->sync, &p->jobs[i]->sync); + if (r) + return r; + } + + r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_size - 1]); + if (r && r != -ERESTARTSYS) + DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n"); + + return r; } static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p) @@ -1177,20 +1228,28 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; - struct drm_sched_entity *entity = p->entity; + struct amdgpu_job *leader = p->gang_leader; struct amdgpu_bo_list_entry *e; - struct amdgpu_job *job; + unsigned int i; uint64_t seq; int r; - job = p->job; - p->job = NULL; + for (i = 0; i < p->gang_size; ++i) + drm_sched_job_arm(&p->jobs[i]->base); - r = drm_sched_job_init(&job->base, entity, &fpriv->vm); - if (r) - goto error_unlock; + for (i = 0; i < (p->gang_size - 1); ++i) { + struct dma_fence *fence; - drm_sched_job_arm(&job->base); + fence = &p->jobs[i]->base.s_fence->scheduled; + r = amdgpu_sync_fence(&leader->sync, fence); + if (r) + goto error_cleanup; + } + + if (p->gang_size > 1) { + for (i = 0; i < p->gang_size; ++i) + amdgpu_job_set_gang_leader(p->jobs[i], leader); + } /* No memory allocation is allowed while holding the notifier lock. * The lock is held until amdgpu_cs_submit is finished and fence is @@ -1201,6 +1260,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, /* If userptr are invalidated after amdgpu_cs_parser_bos(), return * -EAGAIN, drmIoctl in libdrm will restart the amdgpu_cs_ioctl. */ + r = 0; amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); @@ -1208,62 +1268,65 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } if (r) { r = -EAGAIN; - goto error_abort; + goto error_unlock; } - p->fence = dma_fence_get(&job->base.s_fence->finished); + p->fence = dma_fence_get(&leader->base.s_fence->finished); + list_for_each_entry(e, &p->validated, tv.head) { - seq = amdgpu_ctx_add_fence(p->ctx, entity, p->fence); + /* Everybody except for the gang leader uses READ */ + for (i = 0; i < (p->gang_size - 1); ++i) { + dma_resv_add_fence(e->tv.bo->base.resv, + &p->jobs[i]->base.s_fence->finished, + DMA_RESV_USAGE_READ); + } + + /* The gang leader is remembered as writer */ + e->tv.num_shared = 0; + } + + seq = amdgpu_ctx_add_fence(p->ctx, p->entities[p->gang_size - 1], + p->fence); amdgpu_cs_post_dependencies(p); - if ((job->preamble_status & AMDGPU_PREAMBLE_IB_PRESENT) && + if ((leader->preamble_status & AMDGPU_PREAMBLE_IB_PRESENT) && !p->ctx->preamble_presented) { - job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT_FIRST; + leader->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT_FIRST; p->ctx->preamble_presented = true; } cs->out.handle = seq; - job->uf_sequence = seq; - - amdgpu_job_free_resources(job); + leader->uf_sequence = seq; - trace_amdgpu_cs_ioctl(job); amdgpu_vm_bo_trace_cs(&fpriv->vm, &p->ticket); - drm_sched_entity_push_job(&job->base); + for (i = 0; i < p->gang_size; ++i) { + amdgpu_job_free_resources(p->jobs[i]); + trace_amdgpu_cs_ioctl(p->jobs[i]); + drm_sched_entity_push_job(&p->jobs[i]->base); + p->jobs[i] = NULL; + } amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); - - /* Make sure all BOs are remembered as writers */ - amdgpu_bo_list_for_each_entry(e, p->bo_list) - e->tv.num_shared = 0; - ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence); + mutex_unlock(&p->adev->notifier_lock); mutex_unlock(&p->bo_list->bo_list_mutex); - return 0; -error_abort: - drm_sched_job_cleanup(&job->base); +error_unlock: mutex_unlock(&p->adev->notifier_lock); -error_unlock: - amdgpu_job_free(job); +error_cleanup: + for (i = 0; i < p->gang_size; ++i) + drm_sched_job_cleanup(&p->jobs[i]->base); return r; } /* Cleanup the parser structure */ -static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, - bool backoff) +static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser) { unsigned i; - if (error && backoff) { - ttm_eu_backoff_reservation(&parser->ticket, - &parser->validated); - mutex_unlock(&parser->bo_list->bo_list_mutex); - } - for (i = 0; i < parser->num_post_deps; i++) { drm_syncobj_put(parser->post_deps[i].syncobj); kfree(parser->post_deps[i].chain); @@ -1280,8 +1343,10 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, for (i = 0; i < parser->nchunks; i++) kvfree(parser->chunks[i].kdata); kvfree(parser->chunks); - if (parser->job) - amdgpu_job_free(parser->job); + for (i = 0; i < parser->gang_size; ++i) { + if (parser->jobs[i]) + amdgpu_job_free(parser->jobs[i]); + } if (parser->uf_entry.tv.bo) { struct amdgpu_bo *uf = ttm_to_amdgpu_bo(parser->uf_entry.tv.bo); @@ -1293,7 +1358,6 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_cs_parser parser; - bool reserved_buffers = false; int r; if (amdgpu_ras_intr_triggered()) @@ -1306,22 +1370,16 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r) { if (printk_ratelimit()) DRM_ERROR("Failed to initialize parser %d!\n", r); - goto out; + return r; } r = amdgpu_cs_pass1(&parser, data); if (r) - goto out; + goto error_fini; - r = amdgpu_cs_ib_fill(adev, &parser); + r = amdgpu_cs_pass2(&parser); if (r) - goto out; - - r = amdgpu_cs_dependencies(adev, &parser); - if (r) { - DRM_ERROR("Failed in the dependencies handling %d!\n", r); - goto out; - } + goto error_fini; r = amdgpu_cs_parser_bos(&parser, data); if (r) { @@ -1329,25 +1387,36 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_ERROR("Not enough memory for command submission!\n"); else if (r != -ERESTARTSYS && r != -EAGAIN) DRM_ERROR("Failed to process the buffer list %d!\n", r); - goto out; + goto error_fini; } - reserved_buffers = true; - - trace_amdgpu_cs_ibs(&parser); + r = amdgpu_cs_patch_jobs(&parser); + if (r) + goto error_backoff; r = amdgpu_cs_vm_handling(&parser); if (r) - goto out; + goto error_backoff; r = amdgpu_cs_sync_rings(&parser); if (r) - goto out; + goto error_backoff; + + trace_amdgpu_cs_ibs(&parser); r = amdgpu_cs_submit(&parser, data); -out: - amdgpu_cs_parser_fini(&parser, r, reserved_buffers); + if (r) + goto error_backoff; + + amdgpu_cs_parser_fini(&parser); + return 0; + +error_backoff: + ttm_eu_backoff_reservation(&parser.ticket, &parser.validated); + mutex_unlock(&parser.bo_list->bo_list_mutex); +error_fini: + amdgpu_cs_parser_fini(&parser); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h index 30ecc4917f81..cbaa19b2b8a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h @@ -27,6 +27,8 @@ #include "amdgpu_bo_list.h" #include "amdgpu_ring.h" +#define AMDGPU_CS_GANG_SIZE 4 + struct amdgpu_bo_va_mapping; struct amdgpu_cs_chunk { @@ -50,9 +52,11 @@ struct amdgpu_cs_parser { unsigned nchunks; struct amdgpu_cs_chunk *chunks; - /* scheduler job object */ - struct amdgpu_job *job; - struct drm_sched_entity *entity; + /* scheduler job objects */ + unsigned int gang_size; + struct drm_sched_entity *entities[AMDGPU_CS_GANG_SIZE]; + struct amdgpu_job *jobs[AMDGPU_CS_GANG_SIZE]; + struct amdgpu_job *gang_leader; /* buffer objects */ struct ww_acquire_ctx ticket; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 47aac179951a..ab8f970b2849 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3154,7 +3154,8 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { + adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || + (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP && amdgpu_sriov_vf(adev))) { r = adev->ip_blocks[i].version->funcs->resume(adev); if (r) { @@ -3511,6 +3512,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, adev->gmc.gart_size = 512 * 1024 * 1024; adev->accel_working = false; adev->num_rings = 0; + RCU_INIT_POINTER(adev->gang_submit, dma_fence_get_stub()); adev->mman.buffer_funcs = NULL; adev->mman.buffer_funcs_ring = NULL; adev->vm_manager.vm_pte_funcs = NULL; @@ -3992,6 +3994,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) release_firmware(adev->firmware.gpu_info_fw); adev->firmware.gpu_info_fw = NULL; adev->accel_working = false; + dma_fence_put(rcu_dereference_protected(adev->gang_submit, true)); amdgpu_reset_fini(adev); @@ -4067,12 +4070,20 @@ static void amdgpu_device_evict_resources(struct amdgpu_device *adev) int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) { struct amdgpu_device *adev = drm_to_adev(dev); + int r = 0; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; adev->in_suspend = true; + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_fini_data_exchange(adev); + r = amdgpu_virt_request_full_gpu(adev, false); + if (r) + return r; + } + if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3)) DRM_WARN("smart shift update failed\n"); @@ -4096,6 +4107,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) amdgpu_device_ip_suspend_phase2(adev); + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_release_full_gpu(adev, false); + return 0; } @@ -4114,6 +4128,12 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) struct amdgpu_device *adev = drm_to_adev(dev); int r = 0; + if (amdgpu_sriov_vf(adev)) { + r = amdgpu_virt_request_full_gpu(adev, true); + if (r) + return r; + } + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -4128,6 +4148,13 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) } r = amdgpu_device_ip_resume(adev); + + /* no matter what r is, always need to properly release full GPU */ + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_init_data_exchange(adev); + amdgpu_virt_release_full_gpu(adev, true); + } + if (r) { dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); return r; @@ -4749,6 +4776,7 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, struct amdgpu_device *tmp_adev = NULL; bool need_full_reset, skip_hw_reset, vram_lost = false; int r = 0; + bool gpu_reset_for_dev_remove = 0; /* Try reset handler method first */ tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, @@ -4768,6 +4796,10 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags); + gpu_reset_for_dev_remove = + test_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context->flags) && + test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); + /* * ASIC reset has to be done on all XGMI hive nodes ASAP * to allow proper links negotiation in FW (within 1 sec) @@ -4812,6 +4844,18 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, amdgpu_ras_intr_cleared(); } + /* Since the mode1 reset affects base ip blocks, the + * phase1 ip blocks need to be resumed. Otherwise there + * will be a BIOS signature error and the psp bootloader + * can't load kdb on the next amdgpu install. + */ + if (gpu_reset_for_dev_remove) { + list_for_each_entry(tmp_adev, device_list_handle, reset_list) + amdgpu_device_ip_resume_phase1(tmp_adev); + + goto end; + } + list_for_each_entry(tmp_adev, device_list_handle, reset_list) { if (need_full_reset) { /* post card */ @@ -5134,6 +5178,11 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, bool need_emergency_restart = false; bool audio_suspended = false; int tmp_vram_lost_counter; + bool gpu_reset_for_dev_remove = false; + + gpu_reset_for_dev_remove = + test_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context->flags) && + test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); /* * Special case: RAS triggered and full reset isn't supported @@ -5169,8 +5218,11 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, */ INIT_LIST_HEAD(&device_list); if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1)) { - list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { list_add_tail(&tmp_adev->reset_list, &device_list); + if (gpu_reset_for_dev_remove && adev->shutdown) + tmp_adev->shutdown = true; + } if (!list_is_first(&adev->reset_list, &device_list)) list_rotate_to_front(&adev->reset_list, &device_list); device_list_handle = &device_list; @@ -5253,6 +5305,10 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, retry: /* Rest of adevs pre asic reset from XGMI hive. */ list_for_each_entry(tmp_adev, device_list_handle, reset_list) { + if (gpu_reset_for_dev_remove) { + /* Workaroud for ASICs need to disable SMC first */ + amdgpu_device_smu_fini_early(tmp_adev); + } r = amdgpu_device_pre_asic_reset(tmp_adev, reset_context); /*TODO Should we stop ?*/ if (r) { @@ -5286,6 +5342,9 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ adev->asic_reset_res = 0; goto retry; } + + if (!r && gpu_reset_for_dev_remove) + goto recover_end; } skip_hw_reset: @@ -5359,6 +5418,7 @@ skip_sched_resume: amdgpu_device_unset_mp1_state(tmp_adev); } +recover_end: tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, reset_list); amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain); @@ -5541,9 +5601,9 @@ bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, ~*peer_adev->dev->dma_mask : ~((1ULL << 32) - 1); resource_size_t aper_limit = adev->gmc.aper_base + adev->gmc.aper_size - 1; - bool p2p_access = !adev->gmc.xgmi.connected_to_cpu && - !(pci_p2pdma_distance_many(adev->pdev, - &peer_adev->dev, 1, true) < 0); + bool p2p_access = + !adev->gmc.xgmi.connected_to_cpu && + !(pci_p2pdma_distance(adev->pdev, peer_adev->dev, false) < 0); return pcie_p2p && p2p_access && (adev->gmc.visible_vram_size && adev->gmc.real_vram_size == adev->gmc.visible_vram_size && @@ -5927,3 +5987,36 @@ void amdgpu_device_pcie_port_wreg(struct amdgpu_device *adev, (void)RREG32(data); spin_unlock_irqrestore(&adev->pcie_idx_lock, flags); } + +/** + * amdgpu_device_switch_gang - switch to a new gang + * @adev: amdgpu_device pointer + * @gang: the gang to switch to + * + * Try to switch to a new gang. + * Returns: NULL if we switched to the new gang or a reference to the current + * gang leader. + */ +struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, + struct dma_fence *gang) +{ + struct dma_fence *old = NULL; + + do { + dma_fence_put(old); + rcu_read_lock(); + old = dma_fence_get_rcu_safe(&adev->gang_submit); + rcu_read_unlock(); + + if (old == gang) + break; + + if (!dma_fence_is_signaled(old)) + return old; + + } while (cmpxchg((struct dma_fence __force **)&adev->gang_submit, + old, gang) != old); + + dma_fence_put(old); + return NULL; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 9fa2a5ceb77d..3993e6134914 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -229,7 +229,7 @@ static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev, ui return r; } - memcpy((u8 *)binary, (u8 *)fw->data, adev->mman.discovery_tmr_size); + memcpy((u8 *)binary, (u8 *)fw->data, fw->size); release_firmware(fw); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 5b09c8f4fe95..23998f727c7f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -39,6 +39,7 @@ #include <linux/pm_runtime.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_fb_helper.h> @@ -497,6 +498,11 @@ bool amdgpu_display_ddc_probe(struct amdgpu_connector *amdgpu_connector, static const struct drm_framebuffer_funcs amdgpu_fb_funcs = { .destroy = drm_gem_fb_destroy, .create_handle = drm_gem_fb_create_handle, +}; + +static const struct drm_framebuffer_funcs amdgpu_fb_funcs_atomic = { + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, .dirty = drm_atomic_helper_dirtyfb, }; @@ -1102,7 +1108,10 @@ static int amdgpu_display_gem_fb_verify_and_init(struct drm_device *dev, if (ret) goto err; - ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs); + if (drm_drv_uses_atomic_modeset(dev)) + ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs_atomic); + else + ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs); if (ret) goto err; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 782cbca37538..7bd8e33b14be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -58,7 +58,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); int r; - if (pci_p2pdma_distance_many(adev->pdev, &attach->dev, 1, true) < 0) + if (pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) attach->peer2peer = false; r = pm_runtime_get_sync(adev_to_drm(adev)->dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 728a0933ea6f..16f6a313335e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -102,9 +102,10 @@ * - 3.46.0 - To enable hot plug amdgpu tests in libdrm * - 3.47.0 - Add AMDGPU_GEM_CREATE_DISCARDABLE and AMDGPU_VM_NOALLOC flags * - 3.48.0 - Add IP discovery version info to HW INFO + * 3.49.0 - Add gang submit into CS IOCTL */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 48 +#define KMS_DRIVER_MINOR 49 #define KMS_DRIVER_PATCHLEVEL 0 int amdgpu_vram_limit; @@ -2186,6 +2187,37 @@ amdgpu_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(dev->dev); } + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 2)) { + bool need_to_reset_gpu = false; + + if (adev->gmc.xgmi.num_physical_nodes > 1) { + struct amdgpu_hive_info *hive; + + hive = amdgpu_get_xgmi_hive(adev); + if (hive->device_remove_count == 0) + need_to_reset_gpu = true; + hive->device_remove_count++; + amdgpu_put_xgmi_hive(hive); + } else { + need_to_reset_gpu = true; + } + + /* Workaround for ASICs need to reset SMU. + * Called only when the first device is removed. + */ + if (need_to_reset_gpu) { + struct amdgpu_reset_context reset_context; + + adev->shutdown = true; + memset(&reset_context, 0, sizeof(reset_context)); + reset_context.method = AMD_RESET_METHOD_NONE; + reset_context.reset_req_dev = adev; + set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); + set_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context.flags); + amdgpu_device_gpu_recover(adev, NULL, &reset_context); + } + } + amdgpu_driver_unload_kms(dev); drm_dev_unplug(dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 8adeb7469f1e..d0d99ed607dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -400,7 +400,6 @@ unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring) /* We are not protected by ring lock when reading the last sequence * but it's ok to report slightly wrong fence count here. */ - amdgpu_fence_process(ring); emitted = 0x100000000ull; emitted -= atomic_read(&ring->fence_drv.last_seq); emitted += READ_ONCE(ring->fence_drv.sync_seq); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index ceb91469958a..9546adc8a76f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -23,6 +23,7 @@ * */ +#include <linux/firmware.h> #include "amdgpu.h" #include "amdgpu_gfx.h" #include "amdgpu_rlc.h" @@ -865,3 +866,142 @@ int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev) } return amdgpu_num_kcq; } + +void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, + uint32_t ucode_id) +{ + const struct gfx_firmware_header_v1_0 *cp_hdr; + const struct gfx_firmware_header_v2_0 *cp_hdr_v2_0; + struct amdgpu_firmware_info *info = NULL; + const struct firmware *ucode_fw; + unsigned int fw_size; + + switch (ucode_id) { + case AMDGPU_UCODE_ID_CP_PFP: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.pfp_fw->data; + adev->gfx.pfp_fw_version = + le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.pfp_feature_version = + le32_to_cpu(cp_hdr->ucode_feature_version); + ucode_fw = adev->gfx.pfp_fw; + fw_size = le32_to_cpu(cp_hdr->header.ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_RS64_PFP: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.pfp_fw->data; + adev->gfx.pfp_fw_version = + le32_to_cpu(cp_hdr_v2_0->header.ucode_version); + adev->gfx.pfp_feature_version = + le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); + ucode_fw = adev->gfx.pfp_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_RS64_PFP_P0_STACK: + case AMDGPU_UCODE_ID_CP_RS64_PFP_P1_STACK: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.pfp_fw->data; + ucode_fw = adev->gfx.pfp_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->data_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_ME: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.me_fw->data; + adev->gfx.me_fw_version = + le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.me_feature_version = + le32_to_cpu(cp_hdr->ucode_feature_version); + ucode_fw = adev->gfx.me_fw; + fw_size = le32_to_cpu(cp_hdr->header.ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_RS64_ME: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.me_fw->data; + adev->gfx.me_fw_version = + le32_to_cpu(cp_hdr_v2_0->header.ucode_version); + adev->gfx.me_feature_version = + le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); + ucode_fw = adev->gfx.me_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_RS64_ME_P0_STACK: + case AMDGPU_UCODE_ID_CP_RS64_ME_P1_STACK: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.me_fw->data; + ucode_fw = adev->gfx.me_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->data_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_CE: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.ce_fw->data; + adev->gfx.ce_fw_version = + le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.ce_feature_version = + le32_to_cpu(cp_hdr->ucode_feature_version); + ucode_fw = adev->gfx.ce_fw; + fw_size = le32_to_cpu(cp_hdr->header.ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_MEC1: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec_fw->data; + adev->gfx.mec_fw_version = + le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.mec_feature_version = + le32_to_cpu(cp_hdr->ucode_feature_version); + ucode_fw = adev->gfx.mec_fw; + fw_size = le32_to_cpu(cp_hdr->header.ucode_size_bytes) - + le32_to_cpu(cp_hdr->jt_size) * 4; + break; + case AMDGPU_UCODE_ID_CP_MEC1_JT: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec_fw->data; + ucode_fw = adev->gfx.mec_fw; + fw_size = le32_to_cpu(cp_hdr->jt_size) * 4; + break; + case AMDGPU_UCODE_ID_CP_MEC2: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec2_fw->data; + adev->gfx.mec2_fw_version = + le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.mec2_feature_version = + le32_to_cpu(cp_hdr->ucode_feature_version); + ucode_fw = adev->gfx.mec2_fw; + fw_size = le32_to_cpu(cp_hdr->header.ucode_size_bytes) - + le32_to_cpu(cp_hdr->jt_size) * 4; + break; + case AMDGPU_UCODE_ID_CP_MEC2_JT: + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec2_fw->data; + ucode_fw = adev->gfx.mec2_fw; + fw_size = le32_to_cpu(cp_hdr->jt_size) * 4; + break; + case AMDGPU_UCODE_ID_CP_RS64_MEC: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.mec_fw->data; + adev->gfx.mec_fw_version = + le32_to_cpu(cp_hdr_v2_0->header.ucode_version); + adev->gfx.mec_feature_version = + le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); + ucode_fw = adev->gfx.mec_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes); + break; + case AMDGPU_UCODE_ID_CP_RS64_MEC_P0_STACK: + case AMDGPU_UCODE_ID_CP_RS64_MEC_P1_STACK: + case AMDGPU_UCODE_ID_CP_RS64_MEC_P2_STACK: + case AMDGPU_UCODE_ID_CP_RS64_MEC_P3_STACK: + cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *) + adev->gfx.mec_fw->data; + ucode_fw = adev->gfx.mec_fw; + fw_size = le32_to_cpu(cp_hdr_v2_0->data_size_bytes); + break; + default: + break; + } + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + info = &adev->firmware.ucode[ucode_id]; + info->ucode_id = ucode_id; + info->fw = ucode_fw; + adev->firmware.fw_size += ALIGN(fw_size, PAGE_SIZE); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 8abdf41d0f83..832b3807f1d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -304,6 +304,10 @@ struct amdgpu_gfx { uint32_t rlc_srlg_feature_version; uint32_t rlc_srls_fw_version; uint32_t rlc_srls_feature_version; + uint32_t rlcp_ucode_version; + uint32_t rlcp_ucode_feature_version; + uint32_t rlcv_ucode_version; + uint32_t rlcv_ucode_feature_version; uint32_t mec_feature_version; uint32_t mec2_feature_version; bool mec_fw_write_wait; @@ -422,4 +426,6 @@ int amdgpu_gfx_cp_ecc_error_irq(struct amdgpu_device *adev, uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg); void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v); int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev); +void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, uint32_t ucode_id); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index aebc384531ac..34233a74248c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -572,45 +572,15 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) void amdgpu_gmc_noretry_set(struct amdgpu_device *adev) { struct amdgpu_gmc *gmc = &adev->gmc; - - switch (adev->ip_versions[GC_HWIP][0]) { - case IP_VERSION(9, 0, 1): - case IP_VERSION(9, 3, 0): - case IP_VERSION(9, 4, 0): - case IP_VERSION(9, 4, 1): - case IP_VERSION(9, 4, 2): - case IP_VERSION(10, 3, 3): - case IP_VERSION(10, 3, 4): - case IP_VERSION(10, 3, 5): - case IP_VERSION(10, 3, 6): - case IP_VERSION(10, 3, 7): - /* - * noretry = 0 will cause kfd page fault tests fail - * for some ASICs, so set default to 1 for these ASICs. - */ - if (amdgpu_noretry == -1) - gmc->noretry = 1; - else - gmc->noretry = amdgpu_noretry; - break; - default: - /* Raven currently has issues with noretry - * regardless of what we decide for other - * asics, we should leave raven with - * noretry = 0 until we root cause the - * issues. - * - * default this to 0 for now, but we may want - * to change this in the future for certain - * GPUs as it can increase performance in - * certain cases. - */ - if (amdgpu_noretry == -1) - gmc->noretry = 0; - else - gmc->noretry = amdgpu_noretry; - break; - } + uint32_t gc_ver = adev->ip_versions[GC_HWIP][0]; + bool noretry_default = (gc_ver == IP_VERSION(9, 0, 1) || + gc_ver == IP_VERSION(9, 3, 0) || + gc_ver == IP_VERSION(9, 4, 0) || + gc_ver == IP_VERSION(9, 4, 1) || + gc_ver == IP_VERSION(9, 4, 2) || + gc_ver >= IP_VERSION(10, 3, 0)); + + gmc->noretry = (amdgpu_noretry == -1) ? noretry_default : amdgpu_noretry; } void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 877b3c22a8a8..46c99331d7f1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -105,7 +105,6 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, */ (*job)->base.sched = &adev->rings[0]->sched; (*job)->vm = vm; - (*job)->num_ibs = num_ibs; amdgpu_sync_create(&(*job)->sync); amdgpu_sync_create(&(*job)->sched_sync); @@ -125,6 +124,7 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, if (r) return r; + (*job)->num_ibs = 1; r = amdgpu_ib_get(adev, NULL, size, pool_type, &(*job)->ibs[0]); if (r) kfree(*job); @@ -173,11 +173,29 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job) dma_fence_put(&job->hw_fence); } +void amdgpu_job_set_gang_leader(struct amdgpu_job *job, + struct amdgpu_job *leader) +{ + struct dma_fence *fence = &leader->base.s_fence->scheduled; + + WARN_ON(job->gang_submit); + + /* + * Don't add a reference when we are the gang leader to avoid circle + * dependency. + */ + if (job != leader) + dma_fence_get(fence); + job->gang_submit = fence; +} + void amdgpu_job_free(struct amdgpu_job *job) { amdgpu_job_free_resources(job); amdgpu_sync_free(&job->sync); amdgpu_sync_free(&job->sched_sync); + if (job->gang_submit != &job->base.s_fence->scheduled) + dma_fence_put(job->gang_submit); if (!job->hw_fence.ops) kfree(job); @@ -247,12 +265,16 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, fence = amdgpu_sync_get_fence(&job->sync); } + if (!fence && job->gang_submit) + fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit); + return fence; } static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) { struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched); + struct amdgpu_device *adev = ring->adev; struct dma_fence *fence = NULL, *finished; struct amdgpu_job *job; int r = 0; @@ -264,8 +286,10 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) trace_amdgpu_sched_run_job(job); - if (job->vram_lost_counter != atomic_read(&ring->adev->vram_lost_counter)) - dma_fence_set_error(finished, -ECANCELED);/* skip IB as well if VRAM lost */ + /* Skip job if VRAM is lost and never resubmit gangs */ + if (job->vram_lost_counter != atomic_read(&adev->vram_lost_counter) || + (job->job_run_counter && job->gang_submit)) + dma_fence_set_error(finished, -ECANCELED); if (finished->error < 0) { DRM_INFO("Skip scheduling IBs!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index 2a1961bf1194..ab7b150e5d50 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -50,6 +50,7 @@ struct amdgpu_job { struct amdgpu_sync sync; struct amdgpu_sync sched_sync; struct dma_fence hw_fence; + struct dma_fence *gang_submit; uint32_t preamble_status; uint32_t preemption_status; bool vm_needs_flush; @@ -72,6 +73,11 @@ struct amdgpu_job { struct amdgpu_ib ibs[]; }; +static inline struct amdgpu_ring *amdgpu_job_ring(struct amdgpu_job *job) +{ + return to_amdgpu_ring(job->base.entity->rq->sched); +} + int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, struct amdgpu_job **job, struct amdgpu_vm *vm); int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, @@ -79,6 +85,8 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, void amdgpu_job_set_resources(struct amdgpu_job *job, struct amdgpu_bo *gds, struct amdgpu_bo *gws, struct amdgpu_bo *oa); void amdgpu_job_free_resources(struct amdgpu_job *job); +void amdgpu_job_set_gang_leader(struct amdgpu_job *job, + struct amdgpu_job *leader); void amdgpu_job_free(struct amdgpu_job *job); int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, void *owner, struct dma_fence **f); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 77668c3dae5b..fe23e09eec98 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -247,6 +247,14 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->ver = adev->gfx.rlc_srls_fw_version; fw_info->feature = adev->gfx.rlc_srls_feature_version; break; + case AMDGPU_INFO_FW_GFX_RLCP: + fw_info->ver = adev->gfx.rlcp_ucode_version; + fw_info->feature = adev->gfx.rlcp_ucode_feature_version; + break; + case AMDGPU_INFO_FW_GFX_RLCV: + fw_info->ver = adev->gfx.rlcv_ucode_version; + fw_info->feature = adev->gfx.rlcv_ucode_feature_version; + break; case AMDGPU_INFO_FW_GFX_MEC: if (query_fw->index == 0) { fw_info->ver = adev->gfx.mec_fw_version; @@ -328,6 +336,14 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->ver = adev->psp.cap_fw_version; fw_info->feature = adev->psp.cap_feature_version; break; + case AMDGPU_INFO_FW_MES_KIQ: + fw_info->ver = adev->mes.ucode_fw_version[0]; + fw_info->feature = 0; + break; + case AMDGPU_INFO_FW_MES: + fw_info->ver = adev->mes.ucode_fw_version[1]; + fw_info->feature = 0; + break; default: return -EINVAL; } @@ -1469,6 +1485,22 @@ static int amdgpu_debugfs_firmware_info_show(struct seq_file *m, void *unused) seq_printf(m, "RLC SRLS feature version: %u, firmware version: 0x%08x\n", fw_info.feature, fw_info.ver); + /* RLCP */ + query_fw.fw_type = AMDGPU_INFO_FW_GFX_RLCP; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "RLCP feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + + /* RLCV */ + query_fw.fw_type = AMDGPU_INFO_FW_GFX_RLCV; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "RLCV feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + /* MEC */ query_fw.fw_type = AMDGPU_INFO_FW_GFX_MEC; query_fw.index = 0; @@ -1581,6 +1613,22 @@ static int amdgpu_debugfs_firmware_info_show(struct seq_file *m, void *unused) fw_info.feature, fw_info.ver); } + /* MES_KIQ */ + query_fw.fw_type = AMDGPU_INFO_FW_MES_KIQ; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "MES_KIQ feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + + /* MES */ + query_fw.fw_type = AMDGPU_INFO_FW_MES; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "MES feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + seq_printf(m, "VBIOS version: %s\n", ctx->vbios_version); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 7b46f6bf4187..ad980f4b66e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -222,6 +222,8 @@ struct mes_add_queue_input { uint64_t tba_addr; uint64_t tma_addr; uint32_t is_kfd_process; + uint32_t is_aql_queue; + uint32_t queue_size; }; struct mes_remove_queue_input { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index c4848522be16..effa7df3ddbf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -511,6 +511,11 @@ static int psp_sw_fini(void *handle) kfree(cmd); cmd = NULL; + if (psp->km_ring.ring_mem) + amdgpu_bo_free_kernel(&adev->firmware.rbuf, + &psp->km_ring.ring_mem_mc_addr, + (void **)&psp->km_ring.ring_mem); + amdgpu_bo_free_kernel(&psp->fw_pri_bo, &psp->fw_pri_mc_addr, &psp->fw_pri_buf); amdgpu_bo_free_kernel(&psp->fence_buf_bo, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index e55f106621ef..ccebd8e2a2d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2720,7 +2720,8 @@ int amdgpu_ras_pre_fini(struct amdgpu_device *adev) /* Need disable ras on all IPs here before ip [hw/sw]fini */ - amdgpu_ras_disable_all_features(adev, 0); + if (con->features) + amdgpu_ras_disable_all_features(adev, 0); amdgpu_ras_recovery_fini(adev); return 0; } @@ -2833,11 +2834,8 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, struct mce *m = (struct mce *)data; struct amdgpu_device *adev = NULL; uint32_t gpu_id = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst, channel_index = 0; + uint32_t umc_inst = 0, ch_inst = 0; struct ras_err_data err_data = {0, 0, 0, NULL}; - struct eeprom_table_record err_rec; - uint64_t retired_page; /* * If the error was generated in UMC_V2, which belongs to GPU UMCs, @@ -2876,21 +2874,22 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, dev_info(adev->dev, "Uncorrectable error detected in UMC inst: %d, chan_idx: %d", umc_inst, ch_inst); + err_data.err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + if(!err_data.err_addr) { + dev_warn(adev->dev, "Failed to alloc memory for " + "umc error address record in mca notifier!\n"); + return NOTIFY_DONE; + } + /* * Translate UMC channel address to Physical address */ - channel_index = - adev->umc.channel_idx_tbl[umc_inst * adev->umc.channel_inst_num - + ch_inst]; - - retired_page = ADDR_OF_8KB_BLOCK(m->addr) | - ADDR_OF_256B_BLOCK(channel_index) | - OFFSET_IN_256B_BLOCK(m->addr); - - memset(&err_rec, 0x0, sizeof(struct eeprom_table_record)); - err_data.err_addr = &err_rec; - amdgpu_umc_fill_error_record(&err_data, m->addr, - retired_page, channel_index, umc_inst); + if (adev->umc.ras && + adev->umc.ras->convert_ras_error_address) + adev->umc.ras->convert_ras_error_address(adev, + &err_data, 0, ch_inst, umc_inst, m->addr); if (amdgpu_bad_page_threshold != 0) { amdgpu_ras_add_bad_pages(adev, err_data.err_addr, @@ -2898,6 +2897,7 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, amdgpu_ras_save_bad_pages(adev); } + kfree(err_data.err_addr); return NOTIFY_OK; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index f71b83c42590..f5318fedf2f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -31,6 +31,7 @@ enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET = 0, AMDGPU_SKIP_HW_RESET = 1, AMDGPU_SKIP_MODE2_RESET = 2, + AMDGPU_RESET_FOR_DEVICE_REMOVE = 3, }; struct amdgpu_reset_context { @@ -112,7 +113,8 @@ static inline bool amdgpu_reset_get_reset_domain(struct amdgpu_reset_domain *dom static inline void amdgpu_reset_put_reset_domain(struct amdgpu_reset_domain *domain) { - kref_put(&domain->refcount, amdgpu_reset_destroy_reset_domain); + if (domain) + kref_put(&domain->refcount, amdgpu_reset_destroy_reset_domain); } static inline bool amdgpu_reset_domain_schedule(struct amdgpu_reset_domain *domain, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c index 6373bfb47d55..012b72d00e04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c @@ -272,3 +272,275 @@ void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev) &adev->gfx.rlc.cp_table_gpu_addr, (void **)&adev->gfx.rlc.cp_table_ptr); } + +static int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev) +{ + const struct common_firmware_header *common_hdr; + const struct rlc_firmware_header_v2_0 *rlc_hdr; + struct amdgpu_firmware_info *info; + unsigned int *tmp; + unsigned int i; + + rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; + + adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); + adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); + adev->gfx.rlc.save_and_restore_offset = + le32_to_cpu(rlc_hdr->save_and_restore_offset); + adev->gfx.rlc.clear_state_descriptor_offset = + le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); + adev->gfx.rlc.avail_scratch_ram_locations = + le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); + adev->gfx.rlc.reg_restore_list_size = + le32_to_cpu(rlc_hdr->reg_restore_list_size); + adev->gfx.rlc.reg_list_format_start = + le32_to_cpu(rlc_hdr->reg_list_format_start); + adev->gfx.rlc.reg_list_format_separate_start = + le32_to_cpu(rlc_hdr->reg_list_format_separate_start); + adev->gfx.rlc.starting_offsets_start = + le32_to_cpu(rlc_hdr->starting_offsets_start); + adev->gfx.rlc.reg_list_format_size_bytes = + le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); + adev->gfx.rlc.reg_list_size_bytes = + le32_to_cpu(rlc_hdr->reg_list_size_bytes); + adev->gfx.rlc.register_list_format = + kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + + adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); + if (!adev->gfx.rlc.register_list_format) { + dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n"); + return -ENOMEM; + } + + tmp = (unsigned int *)((uintptr_t)rlc_hdr + + le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); + for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) + adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); + + adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; + + tmp = (unsigned int *)((uintptr_t)rlc_hdr + + le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); + for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) + adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_G; + info->fw = adev->gfx.rlc_fw; + if (info->fw) { + common_hdr = (const struct common_firmware_header *)info->fw->data; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE); + } + } + + return 0; +} + +static void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev) +{ + const struct rlc_firmware_header_v2_1 *rlc_hdr; + struct amdgpu_firmware_info *info; + + rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; + adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); + adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); + adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); + adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); + adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); + adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); + adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); + adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); + adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); + adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); + adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); + adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); + adev->gfx.rlc.reg_list_format_direct_reg_list_length = + le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + if (adev->gfx.rlc.save_restore_list_cntl_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.save_restore_list_srm_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); + } + } +} + +static void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev) +{ + const struct rlc_firmware_header_v2_2 *rlc_hdr; + struct amdgpu_firmware_info *info; + + rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; + adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); + adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); + adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); + adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); + } + } +} + +static void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev) +{ + const struct rlc_firmware_header_v2_3 *rlc_hdr; + struct amdgpu_firmware_info *info; + + rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data; + adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version); + adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version); + adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes); + adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes); + + adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version); + adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version); + adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes); + adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + if (adev->gfx.rlc.rlcp_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_P; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.rlcv_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V]; + info->ucode_id = AMDGPU_UCODE_ID_RLC_V; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE); + } + } +} + +static void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev) +{ + const struct rlc_firmware_header_v2_4 *rlc_hdr; + struct amdgpu_firmware_info *info; + + rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data; + adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes); + adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes); + adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes); + adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes); + adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes); + adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes); + adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes); + adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes); + adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes); + adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS]; + info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS]; + info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS]; + info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS]; + info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE); + } + + if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS]; + info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS; + info->fw = adev->gfx.rlc_fw; + adev->firmware.fw_size += + ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE); + } + } +} + +int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, + uint16_t version_major, + uint16_t version_minor) +{ + int err; + + if (version_major < 2) { + /* only support rlc_hdr v2.x and onwards */ + dev_err(adev->dev, "unsupported rlc fw hdr\n"); + return -EINVAL; + } + + /* is_rlc_v2_1 is still used in APU code path */ + if (version_major == 2 && version_minor == 1) + adev->gfx.rlc.is_rlc_v2_1 = true; + + if (version_minor >= 0) { + err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); + if (err) { + dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); + return err; + } + } + if (version_minor >= 1) + amdgpu_gfx_rlc_init_microcode_v2_1(adev); + if (version_minor >= 2) + amdgpu_gfx_rlc_init_microcode_v2_2(adev); + if (version_minor == 3) + amdgpu_gfx_rlc_init_microcode_v2_3(adev); + if (version_minor == 4) + amdgpu_gfx_rlc_init_microcode_v2_4(adev); + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h index 03ac36b2c2cf..23f060db9255 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h @@ -267,5 +267,7 @@ int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev); int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev); void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev); void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev); - +int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, + uint16_t version_major, + uint16_t version_minor); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c index 42c1f050542f..3949b7e3907f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c @@ -21,6 +21,7 @@ * */ +#include <linux/firmware.h> #include "amdgpu.h" #include "amdgpu_sdma.h" #include "amdgpu_ras.h" @@ -150,3 +151,135 @@ int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev, amdgpu_ras_interrupt_dispatch(adev, &ih_data); return 0; } + +static int amdgpu_sdma_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst) +{ + int err = 0; + uint16_t version_major; + const struct common_firmware_header *header = NULL; + const struct sdma_firmware_header_v1_0 *hdr; + const struct sdma_firmware_header_v2_0 *hdr_v2; + + err = amdgpu_ucode_validate(sdma_inst->fw); + if (err) + return err; + + header = (const struct common_firmware_header *) + sdma_inst->fw->data; + version_major = le16_to_cpu(header->header_version_major); + + switch (version_major) { + case 1: + hdr = (const struct sdma_firmware_header_v1_0 *)sdma_inst->fw->data; + sdma_inst->fw_version = le32_to_cpu(hdr->header.ucode_version); + sdma_inst->feature_version = le32_to_cpu(hdr->ucode_feature_version); + break; + case 2: + hdr_v2 = (const struct sdma_firmware_header_v2_0 *)sdma_inst->fw->data; + sdma_inst->fw_version = le32_to_cpu(hdr_v2->header.ucode_version); + sdma_inst->feature_version = le32_to_cpu(hdr_v2->ucode_feature_version); + break; + default: + return -EINVAL; + } + + if (sdma_inst->feature_version >= 20) + sdma_inst->burst_nop = true; + + return 0; +} + +void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, + bool duplicate) +{ + int i; + + for (i = 0; i < adev->sdma.num_instances; i++) { + release_firmware(adev->sdma.instance[i].fw); + if (duplicate) + break; + } + + memset((void *)adev->sdma.instance, 0, + sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES); +} + +int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, + char *fw_name, u32 instance, + bool duplicate) +{ + struct amdgpu_firmware_info *info = NULL; + const struct common_firmware_header *header = NULL; + int err = 0, i; + const struct sdma_firmware_header_v2_0 *sdma_hdr; + uint16_t version_major; + + err = request_firmware(&adev->sdma.instance[instance].fw, fw_name, adev->dev); + if (err) + goto out; + + header = (const struct common_firmware_header *) + adev->sdma.instance[instance].fw->data; + version_major = le16_to_cpu(header->header_version_major); + + if ((duplicate && instance) || (!duplicate && version_major > 1)) + return -EINVAL; + + err = amdgpu_sdma_init_inst_ctx(&adev->sdma.instance[instance]); + if (err) + goto out; + + if (duplicate) { + for (i = 1; i < adev->sdma.num_instances; i++) + memcpy((void *)&adev->sdma.instance[i], + (void *)&adev->sdma.instance[0], + sizeof(struct amdgpu_sdma_instance)); + } + + if (amdgpu_sriov_vf(adev)) + return 0; + + DRM_DEBUG("psp_load == '%s'\n", + adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + switch (version_major) { + case 1: + for (i = 0; i < adev->sdma.num_instances; i++) { + if (!duplicate && (instance != i)) + continue; + else { + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; + info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; + info->fw = adev->sdma.instance[i].fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); + } + } + break; + case 2: + sdma_hdr = (const struct sdma_firmware_header_v2_0 *) + adev->sdma.instance[0].fw->data; + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA_UCODE_TH0]; + info->ucode_id = AMDGPU_UCODE_ID_SDMA_UCODE_TH0; + info->fw = adev->sdma.instance[0].fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(sdma_hdr->ctx_ucode_size_bytes), PAGE_SIZE); + info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA_UCODE_TH1]; + info->ucode_id = AMDGPU_UCODE_ID_SDMA_UCODE_TH1; + info->fw = adev->sdma.instance[0].fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(sdma_hdr->ctl_ucode_size_bytes), PAGE_SIZE); + break; + default: + return -EINVAL; + } + } + +out: + if (err) { + DRM_ERROR("SDMA: Failed to init firmware \"%s\"\n", fw_name); + amdgpu_sdma_destroy_inst_ctx(adev, duplicate); + } + return err; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h index 53ac3ebae8d6..d2d88279fefb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h @@ -124,4 +124,8 @@ int amdgpu_sdma_process_ras_data_cb(struct amdgpu_device *adev, int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); +int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, + char *fw_name, u32 instance, bool duplicate); +void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, + bool duplicate); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 06dfcf297a8d..5e6ddc7e101c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -140,8 +140,10 @@ TRACE_EVENT(amdgpu_bo_create, ); TRACE_EVENT(amdgpu_cs, - TP_PROTO(struct amdgpu_cs_parser *p, int i), - TP_ARGS(p, i), + TP_PROTO(struct amdgpu_cs_parser *p, + struct amdgpu_job *job, + struct amdgpu_ib *ib), + TP_ARGS(p, job, ib), TP_STRUCT__entry( __field(struct amdgpu_bo_list *, bo_list) __field(u32, ring) @@ -151,10 +153,10 @@ TRACE_EVENT(amdgpu_cs, TP_fast_assign( __entry->bo_list = p->bo_list; - __entry->ring = to_amdgpu_ring(p->entity->rq->sched)->idx; - __entry->dw = p->job->ibs[i].length_dw; + __entry->ring = to_amdgpu_ring(job->base.sched)->idx; + __entry->dw = ib->length_dw; __entry->fences = amdgpu_fence_count_emitted( - to_amdgpu_ring(p->entity->rq->sched)); + to_amdgpu_ring(job->base.sched)); ), TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u", __entry->bo_list, __entry->ring, __entry->dw, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 939c8614f0e3..dd0bc649a57d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -164,70 +164,138 @@ void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr) } else if (version_major == 2) { const struct rlc_firmware_header_v2_0 *rlc_hdr = container_of(hdr, struct rlc_firmware_header_v2_0, header); + const struct rlc_firmware_header_v2_1 *rlc_hdr_v2_1 = + container_of(rlc_hdr, struct rlc_firmware_header_v2_1, v2_0); + const struct rlc_firmware_header_v2_2 *rlc_hdr_v2_2 = + container_of(rlc_hdr_v2_1, struct rlc_firmware_header_v2_2, v2_1); + const struct rlc_firmware_header_v2_3 *rlc_hdr_v2_3 = + container_of(rlc_hdr_v2_2, struct rlc_firmware_header_v2_3, v2_2); + const struct rlc_firmware_header_v2_4 *rlc_hdr_v2_4 = + container_of(rlc_hdr_v2_3, struct rlc_firmware_header_v2_4, v2_3); - DRM_DEBUG("ucode_feature_version: %u\n", - le32_to_cpu(rlc_hdr->ucode_feature_version)); - DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(rlc_hdr->jt_offset)); - DRM_DEBUG("jt_size: %u\n", le32_to_cpu(rlc_hdr->jt_size)); - DRM_DEBUG("save_and_restore_offset: %u\n", - le32_to_cpu(rlc_hdr->save_and_restore_offset)); - DRM_DEBUG("clear_state_descriptor_offset: %u\n", - le32_to_cpu(rlc_hdr->clear_state_descriptor_offset)); - DRM_DEBUG("avail_scratch_ram_locations: %u\n", - le32_to_cpu(rlc_hdr->avail_scratch_ram_locations)); - DRM_DEBUG("reg_restore_list_size: %u\n", - le32_to_cpu(rlc_hdr->reg_restore_list_size)); - DRM_DEBUG("reg_list_format_start: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_start)); - DRM_DEBUG("reg_list_format_separate_start: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_separate_start)); - DRM_DEBUG("starting_offsets_start: %u\n", - le32_to_cpu(rlc_hdr->starting_offsets_start)); - DRM_DEBUG("reg_list_format_size_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_size_bytes)); - DRM_DEBUG("reg_list_format_array_offset_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); - DRM_DEBUG("reg_list_size_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_size_bytes)); - DRM_DEBUG("reg_list_array_offset_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); - DRM_DEBUG("reg_list_format_separate_size_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_separate_size_bytes)); - DRM_DEBUG("reg_list_format_separate_array_offset_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_format_separate_array_offset_bytes)); - DRM_DEBUG("reg_list_separate_size_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_separate_size_bytes)); - DRM_DEBUG("reg_list_separate_array_offset_bytes: %u\n", - le32_to_cpu(rlc_hdr->reg_list_separate_array_offset_bytes)); - if (version_minor == 1) { - const struct rlc_firmware_header_v2_1 *v2_1 = - container_of(rlc_hdr, struct rlc_firmware_header_v2_1, v2_0); + switch (version_minor) { + case 0: + /* rlc_hdr v2_0 */ + DRM_DEBUG("ucode_feature_version: %u\n", + le32_to_cpu(rlc_hdr->ucode_feature_version)); + DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(rlc_hdr->jt_offset)); + DRM_DEBUG("jt_size: %u\n", le32_to_cpu(rlc_hdr->jt_size)); + DRM_DEBUG("save_and_restore_offset: %u\n", + le32_to_cpu(rlc_hdr->save_and_restore_offset)); + DRM_DEBUG("clear_state_descriptor_offset: %u\n", + le32_to_cpu(rlc_hdr->clear_state_descriptor_offset)); + DRM_DEBUG("avail_scratch_ram_locations: %u\n", + le32_to_cpu(rlc_hdr->avail_scratch_ram_locations)); + DRM_DEBUG("reg_restore_list_size: %u\n", + le32_to_cpu(rlc_hdr->reg_restore_list_size)); + DRM_DEBUG("reg_list_format_start: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_start)); + DRM_DEBUG("reg_list_format_separate_start: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_separate_start)); + DRM_DEBUG("starting_offsets_start: %u\n", + le32_to_cpu(rlc_hdr->starting_offsets_start)); + DRM_DEBUG("reg_list_format_size_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_size_bytes)); + DRM_DEBUG("reg_list_format_array_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); + DRM_DEBUG("reg_list_size_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_size_bytes)); + DRM_DEBUG("reg_list_array_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); + DRM_DEBUG("reg_list_format_separate_size_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_separate_size_bytes)); + DRM_DEBUG("reg_list_format_separate_array_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_format_separate_array_offset_bytes)); + DRM_DEBUG("reg_list_separate_size_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_separate_size_bytes)); + DRM_DEBUG("reg_list_separate_array_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr->reg_list_separate_array_offset_bytes)); + break; + case 1: + /* rlc_hdr v2_1 */ DRM_DEBUG("reg_list_format_direct_reg_list_length: %u\n", - le32_to_cpu(v2_1->reg_list_format_direct_reg_list_length)); + le32_to_cpu(rlc_hdr_v2_1->reg_list_format_direct_reg_list_length)); DRM_DEBUG("save_restore_list_cntl_ucode_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_cntl_ucode_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_cntl_ucode_ver)); DRM_DEBUG("save_restore_list_cntl_feature_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_cntl_feature_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_cntl_feature_ver)); DRM_DEBUG("save_restore_list_cntl_size_bytes %u\n", - le32_to_cpu(v2_1->save_restore_list_cntl_size_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_cntl_size_bytes)); DRM_DEBUG("save_restore_list_cntl_offset_bytes: %u\n", - le32_to_cpu(v2_1->save_restore_list_cntl_offset_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_cntl_offset_bytes)); DRM_DEBUG("save_restore_list_gpm_ucode_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_gpm_ucode_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_gpm_ucode_ver)); DRM_DEBUG("save_restore_list_gpm_feature_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_gpm_feature_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_gpm_feature_ver)); DRM_DEBUG("save_restore_list_gpm_size_bytes %u\n", - le32_to_cpu(v2_1->save_restore_list_gpm_size_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_gpm_size_bytes)); DRM_DEBUG("save_restore_list_gpm_offset_bytes: %u\n", - le32_to_cpu(v2_1->save_restore_list_gpm_offset_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_gpm_offset_bytes)); DRM_DEBUG("save_restore_list_srm_ucode_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_srm_ucode_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_srm_ucode_ver)); DRM_DEBUG("save_restore_list_srm_feature_ver: %u\n", - le32_to_cpu(v2_1->save_restore_list_srm_feature_ver)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_srm_feature_ver)); DRM_DEBUG("save_restore_list_srm_size_bytes %u\n", - le32_to_cpu(v2_1->save_restore_list_srm_size_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_srm_size_bytes)); DRM_DEBUG("save_restore_list_srm_offset_bytes: %u\n", - le32_to_cpu(v2_1->save_restore_list_srm_offset_bytes)); + le32_to_cpu(rlc_hdr_v2_1->save_restore_list_srm_offset_bytes)); + break; + case 2: + /* rlc_hdr v2_2 */ + DRM_DEBUG("rlc_iram_ucode_size_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_2->rlc_iram_ucode_size_bytes)); + DRM_DEBUG("rlc_iram_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_2->rlc_iram_ucode_offset_bytes)); + DRM_DEBUG("rlc_dram_ucode_size_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_2->rlc_dram_ucode_size_bytes)); + DRM_DEBUG("rlc_dram_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_2->rlc_dram_ucode_offset_bytes)); + break; + case 3: + /* rlc_hdr v2_3 */ + DRM_DEBUG("rlcp_ucode_version: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcp_ucode_version)); + DRM_DEBUG("rlcp_ucode_feature_version: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcp_ucode_feature_version)); + DRM_DEBUG("rlcp_ucode_size_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcp_ucode_size_bytes)); + DRM_DEBUG("rlcp_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcp_ucode_offset_bytes)); + DRM_DEBUG("rlcv_ucode_version: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcv_ucode_version)); + DRM_DEBUG("rlcv_ucode_feature_version: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcv_ucode_feature_version)); + DRM_DEBUG("rlcv_ucode_size_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcv_ucode_size_bytes)); + DRM_DEBUG("rlcv_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_3->rlcv_ucode_offset_bytes)); + break; + case 4: + /* rlc_hdr v2_4 */ + DRM_DEBUG("global_tap_delays_ucode_size_bytes :%u\n", + le32_to_cpu(rlc_hdr_v2_4->global_tap_delays_ucode_size_bytes)); + DRM_DEBUG("global_tap_delays_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_4->global_tap_delays_ucode_offset_bytes)); + DRM_DEBUG("se0_tap_delays_ucode_size_bytes :%u\n", + le32_to_cpu(rlc_hdr_v2_4->se0_tap_delays_ucode_size_bytes)); + DRM_DEBUG("se0_tap_delays_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_4->se0_tap_delays_ucode_offset_bytes)); + DRM_DEBUG("se1_tap_delays_ucode_size_bytes :%u\n", + le32_to_cpu(rlc_hdr_v2_4->se1_tap_delays_ucode_size_bytes)); + DRM_DEBUG("se1_tap_delays_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_4->se1_tap_delays_ucode_offset_bytes)); + DRM_DEBUG("se2_tap_delays_ucode_size_bytes :%u\n", + le32_to_cpu(rlc_hdr_v2_4->se2_tap_delays_ucode_size_bytes)); + DRM_DEBUG("se2_tap_delays_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_4->se2_tap_delays_ucode_offset_bytes)); + DRM_DEBUG("se3_tap_delays_ucode_size_bytes :%u\n", + le32_to_cpu(rlc_hdr_v2_4->se3_tap_delays_ucode_size_bytes)); + DRM_DEBUG("se3_tap_delays_ucode_offset_bytes: %u\n", + le32_to_cpu(rlc_hdr_v2_4->se3_tap_delays_ucode_offset_bytes)); + break; + default: + DRM_ERROR("Unknown RLC v2 ucode: v2.%u\n", version_minor); + break; } } else { DRM_ERROR("Unknown RLC ucode version: %u.%u\n", version_major, version_minor); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 3975bcaa2c89..1c36235b4539 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -261,8 +261,12 @@ struct rlc_firmware_header_v2_2 { /* version_major=2, version_minor=3 */ struct rlc_firmware_header_v2_3 { struct rlc_firmware_header_v2_2 v2_2; + uint32_t rlcp_ucode_version; + uint32_t rlcp_ucode_feature_version; uint32_t rlcp_ucode_size_bytes; uint32_t rlcp_ucode_offset_bytes; + uint32_t rlcv_ucode_version; + uint32_t rlcv_ucode_feature_version; uint32_t rlcv_ucode_size_bytes; uint32_t rlcv_ucode_offset_bytes; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 3629d8f292ef..2fb4951a6433 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -22,6 +22,8 @@ #define __AMDGPU_UMC_H__ #include "amdgpu_ras.h" +#define UMC_INVALID_ADDR 0x1ULL + /* * (addr / 256) * 4096, the higher 26 bits in ErrorAddr * is the index of 4KB block @@ -51,6 +53,10 @@ struct amdgpu_umc_ras { struct amdgpu_ras_block_object ras_block; void (*err_cnt_init)(struct amdgpu_device *adev); bool (*query_ras_poison_mode)(struct amdgpu_device *adev); + void (*convert_ras_error_address)(struct amdgpu_device *adev, + struct ras_err_data *err_data, + uint32_t umc_reg_offset, uint32_t ch_inst, + uint32_t umc_inst, uint64_t mca_addr); void (*ecc_info_query_ras_error_count)(struct amdgpu_device *adev, void *ras_error_status); void (*ecc_info_query_ras_error_address)(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index f36e4f08db6d..0b52af415b28 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -191,7 +191,7 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) fw_name = FIRMWARE_VCN4_0_2; if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = false; + adev->vcn.indirect_sram = true; break; case IP_VERSION(4, 0, 4): fw_name = FIRMWARE_VCN4_0_4; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 80b7a6cfd026..253ea6b159df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -161,7 +161,8 @@ #define AMDGPU_VCN_SW_RING_FLAG (1 << 9) #define AMDGPU_VCN_FW_LOGGING_FLAG (1 << 10) #define AMDGPU_VCN_SMU_VERSION_INFO_FLAG (1 << 11) -#define AMDGPU_VCN_VF_RB_SETUP_FLAG (1 << 12) +#define AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG (1 << 11) +#define AMDGPU_VCN_VF_RB_SETUP_FLAG (1 << 14) #define AMDGPU_VCN_IB_FLAG_DECODE_BUFFER 0x00000001 #define AMDGPU_VCN_CMD_FLAG_MSG_BUFFER 0x00000001 @@ -171,6 +172,9 @@ #define VCN_CODEC_DISABLE_MASK_HEVC (1 << 2) #define VCN_CODEC_DISABLE_MASK_H264 (1 << 3) +#define AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU (0) +#define AMDGPU_VCN_SMU_DPM_INTERFACE_APU (1) + enum fw_queue_mode { FW_QUEUE_RING_RESET = 1, FW_QUEUE_DPG_HOLD_OFF = 2, @@ -335,7 +339,9 @@ struct amdgpu_vcn4_fw_shared { struct amdgpu_fw_shared_unified_queue_struct sq; uint8_t pad1[8]; struct amdgpu_fw_shared_fw_logging fw_log; + uint8_t pad2[20]; struct amdgpu_fw_shared_rb_setup rb_setup; + struct amdgpu_fw_shared_smu_interface_info smu_dpm_interface; }; struct amdgpu_vcn_fwlog { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 59cac347baa3..83b0c5d86e48 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -183,10 +183,12 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo) struct amdgpu_bo *bo = vm_bo->bo; vm_bo->moved = true; + spin_lock(&vm_bo->vm->status_lock); if (bo->tbo.type == ttm_bo_type_kernel) list_move(&vm_bo->vm_status, &vm->evicted); else list_move_tail(&vm_bo->vm_status, &vm->evicted); + spin_unlock(&vm_bo->vm->status_lock); } /** * amdgpu_vm_bo_moved - vm_bo is moved @@ -198,7 +200,9 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) { + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->moved); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -211,7 +215,9 @@ static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo) { + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->idle); + spin_unlock(&vm_bo->vm->status_lock); vm_bo->moved = false; } @@ -225,9 +231,9 @@ static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo) { - spin_lock(&vm_bo->vm->invalidated_lock); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated); - spin_unlock(&vm_bo->vm->invalidated_lock); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -240,10 +246,13 @@ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo) { - if (vm_bo->bo->parent) + if (vm_bo->bo->parent) { + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->relocated); - else + spin_unlock(&vm_bo->vm->status_lock); + } else { amdgpu_vm_bo_idle(vm_bo); + } } /** @@ -256,9 +265,9 @@ static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo) { - spin_lock(&vm_bo->vm->invalidated_lock); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->done); - spin_unlock(&vm_bo->vm->invalidated_lock); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -363,12 +372,20 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, int (*validate)(void *p, struct amdgpu_bo *bo), void *param) { - struct amdgpu_vm_bo_base *bo_base, *tmp; + struct amdgpu_vm_bo_base *bo_base; + struct amdgpu_bo *shadow; + struct amdgpu_bo *bo; int r; - list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) { - struct amdgpu_bo *bo = bo_base->bo; - struct amdgpu_bo *shadow = amdgpu_bo_shadowed(bo); + spin_lock(&vm->status_lock); + while (!list_empty(&vm->evicted)) { + bo_base = list_first_entry(&vm->evicted, + struct amdgpu_vm_bo_base, + vm_status); + spin_unlock(&vm->status_lock); + + bo = bo_base->bo; + shadow = amdgpu_bo_shadowed(bo); r = validate(param, bo); if (r) @@ -385,7 +402,9 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->update_funcs->map_table(to_amdgpu_bo_vm(bo)); amdgpu_vm_bo_relocated(bo_base); } + spin_lock(&vm->status_lock); } + spin_unlock(&vm->status_lock); amdgpu_vm_eviction_lock(vm); vm->evicting = false; @@ -406,13 +425,18 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, */ bool amdgpu_vm_ready(struct amdgpu_vm *vm) { + bool empty; bool ret; amdgpu_vm_eviction_lock(vm); ret = !vm->evicting; amdgpu_vm_eviction_unlock(vm); - return ret && list_empty(&vm->evicted); + spin_lock(&vm->status_lock); + empty = list_empty(&vm->evicted); + spin_unlock(&vm->status_lock); + + return ret && empty; } /** @@ -680,9 +704,14 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, struct amdgpu_vm_update_params params; struct amdgpu_vm_bo_base *entry; bool flush_tlb_needed = false; + LIST_HEAD(relocated); int r, idx; - if (list_empty(&vm->relocated)) + spin_lock(&vm->status_lock); + list_splice_init(&vm->relocated, &relocated); + spin_unlock(&vm->status_lock); + + if (list_empty(&relocated)) return 0; if (!drm_dev_enter(adev_to_drm(adev), &idx)) @@ -697,7 +726,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (r) goto error; - list_for_each_entry(entry, &vm->relocated, vm_status) { + list_for_each_entry(entry, &relocated, vm_status) { /* vm_flush_needed after updating moved PDEs */ flush_tlb_needed |= entry->moved; @@ -713,9 +742,8 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (flush_tlb_needed) atomic64_inc(&vm->tlb_seq); - while (!list_empty(&vm->relocated)) { - entry = list_first_entry(&vm->relocated, - struct amdgpu_vm_bo_base, + while (!list_empty(&relocated)) { + entry = list_first_entry(&relocated, struct amdgpu_vm_bo_base, vm_status); amdgpu_vm_bo_idle(entry); } @@ -912,6 +940,7 @@ void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem, { struct amdgpu_bo_va *bo_va, *tmp; + spin_lock(&vm->status_lock); list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) { if (!bo_va->base.bo) continue; @@ -936,7 +965,6 @@ void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem, amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, gtt_mem, cpu_mem); } - spin_lock(&vm->invalidated_lock); list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) { if (!bo_va->base.bo) continue; @@ -949,7 +977,7 @@ void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem, amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, gtt_mem, cpu_mem); } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); } /** * amdgpu_vm_bo_update - update all BO mappings in the vm page table @@ -1278,24 +1306,29 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, int amdgpu_vm_handle_moved(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - struct amdgpu_bo_va *bo_va, *tmp; + struct amdgpu_bo_va *bo_va; struct dma_resv *resv; bool clear; int r; - list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) { + spin_lock(&vm->status_lock); + while (!list_empty(&vm->moved)) { + bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va, + base.vm_status); + spin_unlock(&vm->status_lock); + /* Per VM BOs never need to bo cleared in the page tables */ r = amdgpu_vm_bo_update(adev, bo_va, false); if (r) return r; + spin_lock(&vm->status_lock); } - spin_lock(&vm->invalidated_lock); while (!list_empty(&vm->invalidated)) { bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va, base.vm_status); resv = bo_va->base.bo->tbo.base.resv; - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); /* Try to reserve the BO to avoid clearing its ptes */ if (!amdgpu_vm_debug && dma_resv_trylock(resv)) @@ -1310,9 +1343,9 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, if (!clear) dma_resv_unlock(resv); - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); return 0; } @@ -1387,7 +1420,7 @@ static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev, if (bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv && !bo_va->base.moved) { - list_move(&bo_va->base.vm_status, &vm->moved); + amdgpu_vm_bo_moved(&bo_va->base); } trace_amdgpu_vm_bo_map(bo_va, mapping); } @@ -1763,9 +1796,9 @@ void amdgpu_vm_bo_del(struct amdgpu_device *adev, } } - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); list_del(&bo_va->base.vm_status); - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); list_for_each_entry_safe(mapping, next, &bo_va->valids, list) { list_del(&mapping->list); @@ -2019,9 +2052,11 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) INIT_LIST_HEAD(&vm->moved); INIT_LIST_HEAD(&vm->idle); INIT_LIST_HEAD(&vm->invalidated); - spin_lock_init(&vm->invalidated_lock); + spin_lock_init(&vm->status_lock); INIT_LIST_HEAD(&vm->freed); INIT_LIST_HEAD(&vm->done); + INIT_LIST_HEAD(&vm->pt_freed); + INIT_WORK(&vm->pt_free_work, amdgpu_vm_pt_free_work); /* create scheduler entities for page table updates */ r = drm_sched_entity_init(&vm->immediate, DRM_SCHED_PRIORITY_NORMAL, @@ -2223,6 +2258,8 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) amdgpu_amdkfd_gpuvm_destroy_cb(adev, vm); + flush_work(&vm->pt_free_work); + root = amdgpu_bo_ref(vm->root.bo); amdgpu_bo_reserve(root, true); amdgpu_vm_set_pasid(adev, vm, 0); @@ -2484,8 +2521,7 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, /* Intentionally setting invalid PTE flag * combination to force a no-retry-fault */ - flags = AMDGPU_PTE_EXECUTABLE | AMDGPU_PDE_PTE | - AMDGPU_PTE_TF; + flags = AMDGPU_PTE_SNOOPED | AMDGPU_PTE_PRT; value = 0; } else if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_NEVER) { /* Redirect the access to the dummy page */ @@ -2548,6 +2584,7 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) unsigned int total_done_objs = 0; unsigned int id = 0; + spin_lock(&vm->status_lock); seq_puts(m, "\tIdle BOs:\n"); list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) { if (!bo_va->base.bo) @@ -2585,7 +2622,6 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) id = 0; seq_puts(m, "\tInvalidated BOs:\n"); - spin_lock(&vm->invalidated_lock); list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) { if (!bo_va->base.bo) continue; @@ -2600,7 +2636,7 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) continue; total_done += amdgpu_bo_print_info(id++, bo_va->base.bo, m); } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); total_done_objs = id; seq_printf(m, "\tTotal idle size: %12lld\tobjs:\t%d\n", total_idle, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 9ecb7f663e19..83acb7bd80fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -254,6 +254,9 @@ struct amdgpu_vm { bool evicting; unsigned int saved_flags; + /* Lock to protect vm_bo add/del/move on all lists of vm */ + spinlock_t status_lock; + /* BOs who needs a validation */ struct list_head evicted; @@ -268,7 +271,6 @@ struct amdgpu_vm { /* regular invalidated BOs, but not yet updated in the PT */ struct list_head invalidated; - spinlock_t invalidated_lock; /* BO mappings freed, but not yet updated in the PT */ struct list_head freed; @@ -276,6 +278,10 @@ struct amdgpu_vm { /* BOs which are invalidated, has been updated in the PTs */ struct list_head done; + /* PT BOs scheduled to free and fill with zero if vm_resv is not hold */ + struct list_head pt_freed; + struct work_struct pt_free_work; + /* contains the page directory */ struct amdgpu_vm_bo_base root; struct dma_fence *last_update; @@ -471,6 +477,7 @@ int amdgpu_vm_pde_update(struct amdgpu_vm_update_params *params, int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, uint64_t start, uint64_t end, uint64_t dst, uint64_t flags); +void amdgpu_vm_pt_free_work(struct work_struct *work); #if defined(CONFIG_DEBUG_FS) void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index 88de9f0d4728..358b91243e37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -637,10 +637,34 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) } ttm_bo_set_bulk_move(&entry->bo->tbo, NULL); entry->bo->vm_bo = NULL; + + spin_lock(&entry->vm->status_lock); list_del(&entry->vm_status); + spin_unlock(&entry->vm->status_lock); amdgpu_bo_unref(&entry->bo); } +void amdgpu_vm_pt_free_work(struct work_struct *work) +{ + struct amdgpu_vm_bo_base *entry, *next; + struct amdgpu_vm *vm; + LIST_HEAD(pt_freed); + + vm = container_of(work, struct amdgpu_vm, pt_free_work); + + spin_lock(&vm->status_lock); + list_splice_init(&vm->pt_freed, &pt_freed); + spin_unlock(&vm->status_lock); + + /* flush_work in amdgpu_vm_fini ensure vm->root.bo is valid. */ + amdgpu_bo_reserve(vm->root.bo, true); + + list_for_each_entry_safe(entry, next, &pt_freed, vm_status) + amdgpu_vm_pt_free(entry); + + amdgpu_bo_unreserve(vm->root.bo); +} + /** * amdgpu_vm_pt_free_dfs - free PD/PT levels * @@ -652,11 +676,24 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) */ static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, struct amdgpu_vm *vm, - struct amdgpu_vm_pt_cursor *start) + struct amdgpu_vm_pt_cursor *start, + bool unlocked) { struct amdgpu_vm_pt_cursor cursor; struct amdgpu_vm_bo_base *entry; + if (unlocked) { + spin_lock(&vm->status_lock); + for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) + list_move(&entry->vm_status, &vm->pt_freed); + + if (start) + list_move(&start->entry->vm_status, &vm->pt_freed); + spin_unlock(&vm->status_lock); + schedule_work(&vm->pt_free_work); + return; + } + for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) amdgpu_vm_pt_free(entry); @@ -673,7 +710,7 @@ static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, */ void amdgpu_vm_pt_free_root(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - amdgpu_vm_pt_free_dfs(adev, vm, NULL); + amdgpu_vm_pt_free_dfs(adev, vm, NULL, false); } /** @@ -966,7 +1003,8 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, if (cursor.entry->bo) { params->table_freed = true; amdgpu_vm_pt_free_dfs(adev, params->vm, - &cursor); + &cursor, + params->unlocked); } amdgpu_vm_pt_next(adev, &cursor); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c index 03ec099d64e0..2b0669c464f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c @@ -212,12 +212,15 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, int r; /* Wait for PD/PT moves to be completed */ - dma_resv_for_each_fence(&cursor, bo->tbo.base.resv, - DMA_RESV_USAGE_KERNEL, fence) { + dma_resv_iter_begin(&cursor, bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL); + dma_resv_for_each_fence_unlocked(&cursor, fence) { r = amdgpu_sync_fence(&p->job->sync, fence); - if (r) + if (r) { + dma_resv_iter_end(&cursor); return r; + } } + dma_resv_iter_end(&cursor); do { ndw = p->num_dw_left; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index d1a2619fa89f..73a517bcf5c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -746,7 +746,7 @@ static bool amdgpu_vram_mgr_intersects(struct ttm_resource_manager *man, (amdgpu_vram_mgr_block_size(block) >> PAGE_SHIFT); if (place->fpfn < lpfn && - (place->lpfn && place->lpfn > fpfn)) + (!place->lpfn || place->lpfn > fpfn)) return true; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 10477ca52a41..47159e9a0884 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -406,14 +406,14 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) if (adev->reset_domain->type != XGMI_HIVE) { hive->reset_domain = amdgpu_reset_create_reset_domain(XGMI_HIVE, "amdgpu-reset-hive"); - if (!hive->reset_domain) { - dev_err(adev->dev, "XGMI: failed initializing reset domain for xgmi hive\n"); - ret = -ENOMEM; - kobject_put(&hive->kobj); - kfree(hive); - hive = NULL; - goto pro_end; - } + if (!hive->reset_domain) { + dev_err(adev->dev, "XGMI: failed initializing reset domain for xgmi hive\n"); + ret = -ENOMEM; + kobject_put(&hive->kobj); + kfree(hive); + hive = NULL; + goto pro_end; + } } else { amdgpu_reset_get_reset_domain(adev->reset_domain); hive->reset_domain = adev->reset_domain; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index 552e6fb55aa8..30dcc1681b4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -43,6 +43,7 @@ struct amdgpu_hive_info { } pstate; struct amdgpu_reset_domain *reset_domain; + uint32_t device_remove_count; }; struct amdgpu_pcs_ras_field { diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index fa7421afb9a6..6be9ac2b9c5b 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -26,6 +26,8 @@ #include <linux/pci.h> +#include <acpi/video.h> + #include <drm/drm_crtc_helper.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" @@ -182,7 +184,12 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode return; if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) - return; + goto register_acpi_backlight; + + if (!acpi_video_backlight_use_native()) { + drm_info(dev, "Skipping amdgpu atom DIG backlight registration\n"); + goto register_acpi_backlight; + } pdata = kmalloc(sizeof(struct amdgpu_backlight_privdata), GFP_KERNEL); if (!pdata) { @@ -218,6 +225,11 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode error: kfree(pdata); return; + +register_acpi_backlight: + /* Try registering an ACPI video backlight device instead. */ + acpi_video_register_backlight(); + return; } void diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index e4dde41f2f68..af94ac580d3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3943,56 +3943,6 @@ static void gfx_v10_0_check_fw_write_wait(struct amdgpu_device *adev) DRM_WARN_ONCE("CP firmware version too old, please update!"); } - -static void gfx_v10_0_init_rlc_ext_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_1 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); - adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); - adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); - adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); - adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); - adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); - adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); - adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); - adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); - adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); - adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); - adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); - adev->gfx.rlc.reg_list_format_direct_reg_list_length = - le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); -} - -static void gfx_v10_0_init_rlc_iram_dram_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_2 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); - adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); - adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); - adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); -} - -static void gfx_v10_0_init_tap_delays_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_4 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes); - adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes); - adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes); - adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes); - adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes); - adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes); - adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes); - adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes); - adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes); - adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes); -} - static bool gfx_v10_0_navi10_gfxoff_should_enable(struct amdgpu_device *adev) { bool ret = false; @@ -4028,12 +3978,7 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) char fw_name[40]; char *wks = ""; int err; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; - const struct gfx_firmware_header_v1_0 *cp_hdr; const struct rlc_firmware_header_v2_0 *rlc_hdr; - unsigned int *tmp = NULL; - unsigned int i = 0; uint16_t version_major; uint16_t version_minor; @@ -4091,9 +4036,7 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.pfp_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; - adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me%s.bin", chip_name, wks); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); @@ -4102,9 +4045,7 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.me_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; - adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce%s.bin", chip_name, wks); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); @@ -4113,69 +4054,27 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.ce_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; - adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE); if (!amdgpu_sriov_vf(adev)) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; + /* don't check this. There are apparently firmwares in the wild with + * incorrect size in the header + */ err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + if (err) + dev_dbg(adev->dev, + "gfx10: amdgpu_ucode_validate() failed \"%s\"\n", + fw_name); rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; version_major = le16_to_cpu(rlc_hdr->header.header_version_major); version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); - - adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); - adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); - adev->gfx.rlc.save_and_restore_offset = - le32_to_cpu(rlc_hdr->save_and_restore_offset); - adev->gfx.rlc.clear_state_descriptor_offset = - le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); - adev->gfx.rlc.avail_scratch_ram_locations = - le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); - adev->gfx.rlc.reg_restore_list_size = - le32_to_cpu(rlc_hdr->reg_restore_list_size); - adev->gfx.rlc.reg_list_format_start = - le32_to_cpu(rlc_hdr->reg_list_format_start); - adev->gfx.rlc.reg_list_format_separate_start = - le32_to_cpu(rlc_hdr->reg_list_format_separate_start); - adev->gfx.rlc.starting_offsets_start = - le32_to_cpu(rlc_hdr->starting_offsets_start); - adev->gfx.rlc.reg_list_format_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); - adev->gfx.rlc.reg_list_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_size_bytes); - adev->gfx.rlc.register_list_format = - kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + - adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); - if (!adev->gfx.rlc.register_list_format) { - err = -ENOMEM; + err = amdgpu_gfx_rlc_init_microcode(adev, version_major, version_minor); + if (err) goto out; - } - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); - for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) - adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); - - adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); - for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) - adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); - - if (version_major == 2) { - if (version_minor >= 1) - gfx_v10_0_init_rlc_ext_microcode(adev); - if (version_minor >= 2) - gfx_v10_0_init_rlc_iram_dram_microcode(adev); - if (version_minor == 4) { - gfx_v10_0_init_tap_delays_microcode(adev); - } - } } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec%s.bin", chip_name, wks); @@ -4185,9 +4084,8 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.mec_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; - adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2%s.bin", chip_name, wks); err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); @@ -4195,164 +4093,18 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.mec2_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *) - adev->gfx.mec2_fw->data; - adev->gfx.mec2_fw_version = - le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.mec2_feature_version = - le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); } else { err = 0; adev->gfx.mec2_fw = NULL; } - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_PFP]; - info->ucode_id = AMDGPU_UCODE_ID_CP_PFP; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_ME]; - info->ucode_id = AMDGPU_UCODE_ID_CP_ME; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_CE]; - info->ucode_id = AMDGPU_UCODE_ID_CP_CE; - info->fw = adev->gfx.ce_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_G; - info->fw = adev->gfx.rlc_fw; - if (info->fw) { - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - } - if (adev->gfx.rlc.save_restore_list_cntl_size_bytes && - adev->gfx.rlc.save_restore_list_gpm_size_bytes && - adev->gfx.rlc.save_restore_list_srm_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); - - if (adev->gfx.rlc.rlc_iram_ucode_size_bytes && - adev->gfx.rlc.rlc_dram_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); - } - - } - - if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS]; - info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS]; - info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS]; - info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS]; - info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS]; - info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE); - } - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes) - - le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1_JT]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1_JT; - info->fw = adev->gfx.mec_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - if (adev->gfx.mec2_fw) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC2]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - info->fw = adev->gfx.mec2_fw; - header = (const struct common_firmware_header *)info->fw->data; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes) - - le32_to_cpu(cp_hdr->jt_size) * 4, - PAGE_SIZE); - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC2_JT]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC2_JT; - info->fw = adev->gfx.mec2_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr->jt_size) * 4, - PAGE_SIZE); - } - } - gfx_v10_0_check_fw_write_wait(adev); out: if (err) { dev_err(adev->dev, - "gfx10: Failed to load firmware \"%s\"\n", + "gfx10: Failed to init firmware \"%s\"\n", fw_name); release_firmware(adev->gfx.pfp_fw); adev->gfx.pfp_fw = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index fa718318568e..251109723ab6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -438,61 +438,12 @@ static void gfx_v11_0_free_microcode(struct amdgpu_device *adev) kfree(adev->gfx.rlc.register_list_format); } -static void gfx_v11_0_init_rlc_ext_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_1 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); - adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); - adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); - adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); - adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); - adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); - adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); - adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); - adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); - adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); - adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); - adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); - adev->gfx.rlc.reg_list_format_direct_reg_list_length = - le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); -} - -static void gfx_v11_0_init_rlc_iram_dram_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_2 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes); - adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes); - adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes); - adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes); -} - -static void gfx_v11_0_init_rlcp_rlcv_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_3 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes); - adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes); - adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes); - adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes); -} - static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) { char fw_name[40]; char ucode_prefix[30]; int err; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; - const struct gfx_firmware_header_v1_0 *cp_hdr; - const struct gfx_firmware_header_v2_0 *cp_hdr_v2_0; const struct rlc_firmware_header_v2_0 *rlc_hdr; - unsigned int *tmp = NULL; - unsigned int i = 0; uint16_t version_major; uint16_t version_minor; @@ -513,14 +464,11 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) adev->gfx.pfp_fw->data, 2, 0); if (adev->gfx.rs64_enable) { dev_info(adev->dev, "CP RS64 enable\n"); - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.pfp_fw->data; - adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr_v2_0->header.ucode_version); - adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); - + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_PFP); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_PFP_P0_STACK); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_PFP_P1_STACK); } else { - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; - adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP); } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", ucode_prefix); @@ -531,14 +479,11 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; if (adev->gfx.rs64_enable) { - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.me_fw->data; - adev->gfx.me_fw_version = le32_to_cpu(cp_hdr_v2_0->header.ucode_version); - adev->gfx.me_feature_version = le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); - + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_ME); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_ME_P0_STACK); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_ME_P1_STACK); } else { - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; - adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME); } if (!amdgpu_sriov_vf(adev)) { @@ -547,58 +492,14 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + if (err) + goto out; rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; version_major = le16_to_cpu(rlc_hdr->header.header_version_major); version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); - - adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); - adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); - adev->gfx.rlc.save_and_restore_offset = - le32_to_cpu(rlc_hdr->save_and_restore_offset); - adev->gfx.rlc.clear_state_descriptor_offset = - le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); - adev->gfx.rlc.avail_scratch_ram_locations = - le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); - adev->gfx.rlc.reg_restore_list_size = - le32_to_cpu(rlc_hdr->reg_restore_list_size); - adev->gfx.rlc.reg_list_format_start = - le32_to_cpu(rlc_hdr->reg_list_format_start); - adev->gfx.rlc.reg_list_format_separate_start = - le32_to_cpu(rlc_hdr->reg_list_format_separate_start); - adev->gfx.rlc.starting_offsets_start = - le32_to_cpu(rlc_hdr->starting_offsets_start); - adev->gfx.rlc.reg_list_format_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); - adev->gfx.rlc.reg_list_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_size_bytes); - adev->gfx.rlc.register_list_format = - kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + - adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); - if (!adev->gfx.rlc.register_list_format) { - err = -ENOMEM; + err = amdgpu_gfx_rlc_init_microcode(adev, version_major, version_minor); + if (err) goto out; - } - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); - for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++) - adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); - - adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); - for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++) - adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); - - if (version_major == 2) { - if (version_minor >= 1) - gfx_v11_0_init_rlc_ext_microcode(adev); - if (version_minor >= 2) - gfx_v11_0_init_rlc_iram_dram_microcode(adev); - if (version_minor == 3) - gfx_v11_0_init_rlcp_rlcv_microcode(adev); - } } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", ucode_prefix); @@ -609,190 +510,23 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; if (adev->gfx.rs64_enable) { - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.mec_fw->data; - adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr_v2_0->header.ucode_version); - adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr_v2_0->ucode_feature_version); - + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_MEC); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_MEC_P0_STACK); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_MEC_P1_STACK); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_MEC_P2_STACK); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_MEC_P3_STACK); } else { - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; - adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT); } /* only one MEC for gfx 11.0.0. */ adev->gfx.mec2_fw = NULL; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - if (adev->gfx.rs64_enable) { - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.pfp_fw->data; - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_PFP]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_PFP; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_PFP_P0_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_PFP_P0_STACK; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_PFP_P1_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_PFP_P1_STACK; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.me_fw->data; - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_ME]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_ME; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_ME_P0_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_ME_P0_STACK; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_ME_P1_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_ME_P1_STACK; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - cp_hdr_v2_0 = (const struct gfx_firmware_header_v2_0 *)adev->gfx.mec_fw->data; - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_MEC]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_MEC; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_MEC_P0_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_MEC_P0_STACK; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_MEC_P1_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_MEC_P1_STACK; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_MEC_P2_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_MEC_P2_STACK; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_RS64_MEC_P3_STACK]; - info->ucode_id = AMDGPU_UCODE_ID_CP_RS64_MEC_P3_STACK; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr_v2_0->data_size_bytes), PAGE_SIZE); - } else { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_PFP]; - info->ucode_id = AMDGPU_UCODE_ID_CP_PFP; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_ME]; - info->ucode_id = AMDGPU_UCODE_ID_CP_ME; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes) - - le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1_JT]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1_JT; - info->fw = adev->gfx.mec_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - } - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_G; - info->fw = adev->gfx.rlc_fw; - if (info->fw) { - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - } - if (adev->gfx.rlc.save_restore_list_gpm_size_bytes && - adev->gfx.rlc.save_restore_list_srm_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.rlc_iram_ucode_size_bytes && - adev->gfx.rlc.rlc_dram_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.rlcp_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_P; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE); - } - - if (adev->gfx.rlc.rlcv_ucode_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_V; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE); - } - } - out: if (err) { dev_err(adev->dev, - "gfx11: Failed to load firmware \"%s\"\n", + "gfx11: Failed to init firmware \"%s\"\n", fw_name); release_firmware(adev->gfx.pfp_fw); adev->gfx.pfp_fw = NULL; @@ -5240,6 +4974,8 @@ static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) { u32 reg, data; + amdgpu_gfx_off_ctrl(adev, false); + reg = SOC15_REG_OFFSET(GC, 0, regRLC_SPM_MC_CNTL); if (amdgpu_sriov_is_pp_one_vf(adev)) data = RREG32_NO_KIQ(reg); @@ -5253,6 +4989,8 @@ static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) WREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL, data); else WREG32_SOC15(GC, 0, regRLC_SPM_MC_CNTL, data); + + amdgpu_gfx_off_ctrl(adev, true); } static const struct amdgpu_rlc_funcs gfx_v11_0_rlc_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 1d6d3a852a0b..0320be4a5fc6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1091,27 +1091,6 @@ static void gfx_v9_0_free_microcode(struct amdgpu_device *adev) kfree(adev->gfx.rlc.register_list_format); } -static void gfx_v9_0_init_rlc_ext_microcode(struct amdgpu_device *adev) -{ - const struct rlc_firmware_header_v2_1 *rlc_hdr; - - rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data; - adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver); - adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver); - adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes); - adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes); - adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver); - adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver); - adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes); - adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes); - adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver); - adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver); - adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes); - adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes); - adev->gfx.rlc.reg_list_format_direct_reg_list_length = - le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); -} - static void gfx_v9_0_check_fw_write_wait(struct amdgpu_device *adev) { adev->gfx.me_fw_write_wait = false; @@ -1273,9 +1252,6 @@ static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev, { char fw_name[30]; int err; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; - const struct gfx_firmware_header_v1_0 *cp_hdr; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); @@ -1284,9 +1260,7 @@ static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev, err = amdgpu_ucode_validate(adev->gfx.pfp_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; - adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); @@ -1295,9 +1269,7 @@ static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev, err = amdgpu_ucode_validate(adev->gfx.me_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; - adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); @@ -1306,37 +1278,12 @@ static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev, err = amdgpu_ucode_validate(adev->gfx.ce_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; - adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_PFP]; - info->ucode_id = AMDGPU_UCODE_ID_CP_PFP; - info->fw = adev->gfx.pfp_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_ME]; - info->ucode_id = AMDGPU_UCODE_ID_CP_ME; - info->fw = adev->gfx.me_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_CE]; - info->ucode_id = AMDGPU_UCODE_ID_CP_CE; - info->fw = adev->gfx.ce_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - } + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE); out: if (err) { dev_err(adev->dev, - "gfx9: Failed to load firmware \"%s\"\n", + "gfx9: Failed to init firmware \"%s\"\n", fw_name); release_firmware(adev->gfx.pfp_fw); adev->gfx.pfp_fw = NULL; @@ -1353,11 +1300,7 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev, { char fw_name[30]; int err; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; const struct rlc_firmware_header_v2_0 *rlc_hdr; - unsigned int *tmp = NULL; - unsigned int i = 0; uint16_t version_major; uint16_t version_minor; uint32_t smu_version; @@ -1386,92 +1329,17 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev, if (err) goto out; err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + if (err) + goto out; rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; version_major = le16_to_cpu(rlc_hdr->header.header_version_major); version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); - if (version_major == 2 && version_minor == 1) - adev->gfx.rlc.is_rlc_v2_1 = true; - - adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); - adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); - adev->gfx.rlc.save_and_restore_offset = - le32_to_cpu(rlc_hdr->save_and_restore_offset); - adev->gfx.rlc.clear_state_descriptor_offset = - le32_to_cpu(rlc_hdr->clear_state_descriptor_offset); - adev->gfx.rlc.avail_scratch_ram_locations = - le32_to_cpu(rlc_hdr->avail_scratch_ram_locations); - adev->gfx.rlc.reg_restore_list_size = - le32_to_cpu(rlc_hdr->reg_restore_list_size); - adev->gfx.rlc.reg_list_format_start = - le32_to_cpu(rlc_hdr->reg_list_format_start); - adev->gfx.rlc.reg_list_format_separate_start = - le32_to_cpu(rlc_hdr->reg_list_format_separate_start); - adev->gfx.rlc.starting_offsets_start = - le32_to_cpu(rlc_hdr->starting_offsets_start); - adev->gfx.rlc.reg_list_format_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_format_size_bytes); - adev->gfx.rlc.reg_list_size_bytes = - le32_to_cpu(rlc_hdr->reg_list_size_bytes); - adev->gfx.rlc.register_list_format = - kmalloc(adev->gfx.rlc.reg_list_format_size_bytes + - adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL); - if (!adev->gfx.rlc.register_list_format) { - err = -ENOMEM; - goto out; - } - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes)); - for (i = 0 ; i < (adev->gfx.rlc.reg_list_format_size_bytes >> 2); i++) - adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]); - - adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i; - - tmp = (unsigned int *)((uintptr_t)rlc_hdr + - le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes)); - for (i = 0 ; i < (adev->gfx.rlc.reg_list_size_bytes >> 2); i++) - adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]); - - if (adev->gfx.rlc.is_rlc_v2_1) - gfx_v9_0_init_rlc_ext_microcode(adev); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_G; - info->fw = adev->gfx.rlc_fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - - if (adev->gfx.rlc.is_rlc_v2_1 && - adev->gfx.rlc.save_restore_list_cntl_size_bytes && - adev->gfx.rlc.save_restore_list_gpm_size_bytes && - adev->gfx.rlc.save_restore_list_srm_size_bytes) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM]; - info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM; - info->fw = adev->gfx.rlc_fw; - adev->firmware.fw_size += - ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE); - } - } - + err = amdgpu_gfx_rlc_init_microcode(adev, version_major, version_minor); out: if (err) { dev_err(adev->dev, - "gfx9: Failed to load firmware \"%s\"\n", + "gfx9: Failed to init firmware \"%s\"\n", fw_name); release_firmware(adev->gfx.rlc_fw); adev->gfx.rlc_fw = NULL; @@ -1494,9 +1362,6 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, { char fw_name[30]; int err; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; - const struct gfx_firmware_header_v1_0 *cp_hdr; if (amdgpu_sriov_vf(adev) && (adev->asic_type == CHIP_ALDEBARAN)) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sjt_mec.bin", chip_name); @@ -1509,10 +1374,8 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, err = amdgpu_ucode_validate(adev->gfx.mec_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; - adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT); if (gfx_v9_0_load_mec2_fw_bin_support(adev)) { if (amdgpu_sriov_vf(adev) && (adev->asic_type == CHIP_ALDEBARAN)) @@ -1525,12 +1388,8 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, err = amdgpu_ucode_validate(adev->gfx.mec2_fw); if (err) goto out; - cp_hdr = (const struct gfx_firmware_header_v1_0 *) - adev->gfx.mec2_fw->data; - adev->gfx.mec2_fw_version = - le32_to_cpu(cp_hdr->header.ucode_version); - adev->gfx.mec2_feature_version = - le32_to_cpu(cp_hdr->ucode_feature_version); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); } else { err = 0; adev->gfx.mec2_fw = NULL; @@ -1540,49 +1399,12 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, adev->gfx.mec2_feature_version = adev->gfx.mec_feature_version; } - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1; - info->fw = adev->gfx.mec_fw; - header = (const struct common_firmware_header *)info->fw->data; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes) - le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1_JT]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC1_JT; - info->fw = adev->gfx.mec_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - if (adev->gfx.mec2_fw) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC2]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - info->fw = adev->gfx.mec2_fw; - header = (const struct common_firmware_header *)info->fw->data; - cp_hdr = (const struct gfx_firmware_header_v1_0 *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes) - le32_to_cpu(cp_hdr->jt_size) * 4, PAGE_SIZE); - - /* TODO: Determine if MEC2 JT FW loading can be removed - for all GFX V9 asic and above */ - if (gfx_v9_0_load_mec2_fw_bin_support(adev)) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC2_JT]; - info->ucode_id = AMDGPU_UCODE_ID_CP_MEC2_JT; - info->fw = adev->gfx.mec2_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(cp_hdr->jt_size) * 4, - PAGE_SIZE); - } - } - } - out: gfx_v9_0_check_if_need_gfxoff(adev); gfx_v9_0_check_fw_write_wait(adev); if (err) { dev_err(adev->dev, - "gfx9: Failed to load firmware \"%s\"\n", + "gfx9: Failed to init firmware \"%s\"\n", fw_name); release_firmware(adev->gfx.mec_fw); adev->gfx.mec_fw = NULL; @@ -5607,7 +5429,7 @@ static void gfx_v9_0_ring_emit_patch_cond_exec(struct amdgpu_ring *ring, unsigne BUG_ON(offset > ring->buf_mask); BUG_ON(ring->ring[offset] != 0x55aa55aa); - cur = (ring->wptr & ring->buf_mask) - 1; + cur = (ring->wptr - 1) & ring->buf_mask; if (likely(cur > offset)) ring->ring[offset] = cur - offset; else diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 4603653916f5..67ca16a8027c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1103,10 +1103,13 @@ static void gmc_v9_0_get_vm_pde(struct amdgpu_device *adev, int level, *flags |= AMDGPU_PDE_BFS(0x9); } else if (level == AMDGPU_VM_PDB0) { - if (*flags & AMDGPU_PDE_PTE) + if (*flags & AMDGPU_PDE_PTE) { *flags &= ~AMDGPU_PDE_PTE; - else + if (!(*flags & AMDGPU_PTE_VALID)) + *addr |= 1 << PAGE_SHIFT; + } else { *flags |= AMDGPU_PTE_TF; + } } } diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index b64cd46a159a..b48684db2832 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -185,7 +185,15 @@ static int mes_v11_0_add_hw_queue(struct amdgpu_mes *mes, mes_add_queue_pkt.trap_handler_addr = input->tba_addr; mes_add_queue_pkt.tma_addr = input->tma_addr; mes_add_queue_pkt.is_kfd_process = input->is_kfd_process; - mes_add_queue_pkt.trap_en = 1; + + if (!(((adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 4) && + (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) && + (adev->ip_versions[GC_HWIP][0] <= IP_VERSION(11, 0, 3)))) + mes_add_queue_pkt.trap_en = 1; + + /* For KFD, gds_size is re-used for queue size (needed in MES for AQL queues) */ + mes_add_queue_pkt.is_aql_queue = input->is_aql_queue; + mes_add_queue_pkt.gds_size = input->queue_size; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_add_queue_pkt, sizeof(mes_add_queue_pkt), diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 7fe8bf3417db..7241a9fb0121 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -561,44 +561,6 @@ static void sdma_v4_0_setup_ulv(struct amdgpu_device *adev) } } -static int sdma_v4_0_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst) -{ - int err = 0; - const struct sdma_firmware_header_v1_0 *hdr; - - err = amdgpu_ucode_validate(sdma_inst->fw); - if (err) - return err; - - hdr = (const struct sdma_firmware_header_v1_0 *)sdma_inst->fw->data; - sdma_inst->fw_version = le32_to_cpu(hdr->header.ucode_version); - sdma_inst->feature_version = le32_to_cpu(hdr->ucode_feature_version); - - if (sdma_inst->feature_version >= 20) - sdma_inst->burst_nop = true; - - return 0; -} - -static void sdma_v4_0_destroy_inst_ctx(struct amdgpu_device *adev) -{ - int i; - - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - - /* arcturus shares the same FW memory across - all SDMA isntances */ - if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) || - adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) - break; - } - - memset((void *)adev->sdma.instance, 0, - sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES); -} - /** * sdma_v4_0_init_microcode - load ucode images from disk * @@ -615,9 +577,7 @@ static int sdma_v4_0_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[30]; - int err = 0, i; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; + int ret, i; DRM_DEBUG("\n"); @@ -656,58 +616,25 @@ static int sdma_v4_0_init_microcode(struct amdgpu_device *adev) BUG(); } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); - - err = request_firmware(&adev->sdma.instance[0].fw, fw_name, adev->dev); - if (err) - goto out; - - err = sdma_v4_0_init_inst_ctx(&adev->sdma.instance[0]); - if (err) - goto out; - - for (i = 1; i < adev->sdma.num_instances; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { + if (i == 0) + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); + else + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma%d.bin", chip_name, i); if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) || adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) { /* Acturus & Aldebaran will leverage the same FW memory for every SDMA instance */ - memcpy((void *)&adev->sdma.instance[i], - (void *)&adev->sdma.instance[0], - sizeof(struct amdgpu_sdma_instance)); - } - else { - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma%d.bin", chip_name, i); - - err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); - if (err) - goto out; - - err = sdma_v4_0_init_inst_ctx(&adev->sdma.instance[i]); - if (err) - goto out; - } - } - - DRM_DEBUG("psp_load == '%s'\n", - adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - for (i = 0; i < adev->sdma.num_instances; i++) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; - info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; - info->fw = adev->sdma.instance[i].fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); + ret = amdgpu_sdma_init_microcode(adev, fw_name, 0, true); + break; + } else { + ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false); + if (ret) + return ret; } } -out: - if (err) { - DRM_ERROR("sdma_v4_0: Failed to load firmware \"%s\"\n", fw_name); - sdma_v4_0_destroy_inst_ctx(adev); - } - return err; + return ret; } /** @@ -2000,7 +1927,11 @@ static int sdma_v4_0_sw_fini(void *handle) amdgpu_ring_fini(&adev->sdma.instance[i].page); } - sdma_v4_0_destroy_inst_ctx(adev); + if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 0) || + adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) + amdgpu_sdma_destroy_inst_ctx(adev, true); + else + amdgpu_sdma_destroy_inst_ctx(adev, false); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index a019ac92edb7..c05c3eebde4c 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -240,10 +240,7 @@ static int sdma_v5_0_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[40]; - int err = 0, i; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; - const struct sdma_firmware_header_v1_0 *hdr; + int ret, i; if (amdgpu_sriov_vf(adev) && (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(5, 0, 5))) return 0; @@ -272,38 +269,12 @@ static int sdma_v5_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); - if (err) - goto out; - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; - adev->sdma.instance[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma.instance[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - if (adev->sdma.instance[i].feature_version >= 20) - adev->sdma.instance[i].burst_nop = true; - DRM_DEBUG("psp_load == '%s'\n", - adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; - info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; - info->fw = adev->sdma.instance[i].fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - } - } -out: - if (err) { - DRM_ERROR("sdma_v5_0: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false); + if (ret) + return ret; } - return err; + + return ret; } static unsigned sdma_v5_0_ring_init_cond_exec(struct amdgpu_ring *ring) @@ -1465,12 +1436,10 @@ static int sdma_v5_0_sw_fini(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int i; - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - + for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); - } + + amdgpu_sdma_destroy_inst_ctx(adev, false); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 95689ef4be10..f136fec7b4f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -89,33 +89,6 @@ static u32 sdma_v5_2_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3 return base + internal_offset; } -static int sdma_v5_2_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst) -{ - int err = 0; - const struct sdma_firmware_header_v1_0 *hdr; - - err = amdgpu_ucode_validate(sdma_inst->fw); - if (err) - return err; - - hdr = (const struct sdma_firmware_header_v1_0 *)sdma_inst->fw->data; - sdma_inst->fw_version = le32_to_cpu(hdr->header.ucode_version); - sdma_inst->feature_version = le32_to_cpu(hdr->ucode_feature_version); - - if (sdma_inst->feature_version >= 20) - sdma_inst->burst_nop = true; - - return 0; -} - -static void sdma_v5_2_destroy_inst_ctx(struct amdgpu_device *adev) -{ - release_firmware(adev->sdma.instance[0].fw); - - memset((void *)adev->sdma.instance, 0, - sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES); -} - /** * sdma_v5_2_init_microcode - load ucode images from disk * @@ -132,9 +105,6 @@ static int sdma_v5_2_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[40]; - int err = 0, i; - struct amdgpu_firmware_info *info = NULL; - const struct common_firmware_header *header = NULL; DRM_DEBUG("\n"); @@ -169,42 +139,7 @@ static int sdma_v5_2_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", chip_name); - err = request_firmware(&adev->sdma.instance[0].fw, fw_name, adev->dev); - if (err) - goto out; - - err = sdma_v5_2_init_inst_ctx(&adev->sdma.instance[0]); - if (err) - goto out; - - for (i = 1; i < adev->sdma.num_instances; i++) - memcpy((void *)&adev->sdma.instance[i], - (void *)&adev->sdma.instance[0], - sizeof(struct amdgpu_sdma_instance)); - - if (amdgpu_sriov_vf(adev) && (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(5, 2, 0))) - return 0; - - DRM_DEBUG("psp_load == '%s'\n", - adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - for (i = 0; i < adev->sdma.num_instances; i++) { - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; - info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; - info->fw = adev->sdma.instance[i].fw; - header = (const struct common_firmware_header *)info->fw->data; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - } - } - -out: - if (err) { - DRM_ERROR("sdma_v5_2: Failed to load firmware \"%s\"\n", fw_name); - sdma_v5_2_destroy_inst_ctx(adev); - } - return err; + return amdgpu_sdma_init_microcode(adev, fw_name, 0, true); } static unsigned sdma_v5_2_ring_init_cond_exec(struct amdgpu_ring *ring) @@ -1406,7 +1341,7 @@ static int sdma_v5_2_sw_fini(void *handle) for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); - sdma_v5_2_destroy_inst_ctx(adev); + amdgpu_sdma_destroy_inst_ctx(adev, true); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index 3a0b14be1a57..db51230163c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -78,33 +78,6 @@ static u32 sdma_v6_0_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3 return base + internal_offset; } -static int sdma_v6_0_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst) -{ - int err = 0; - const struct sdma_firmware_header_v2_0 *hdr; - - err = amdgpu_ucode_validate(sdma_inst->fw); - if (err) - return err; - - hdr = (const struct sdma_firmware_header_v2_0 *)sdma_inst->fw->data; - sdma_inst->fw_version = le32_to_cpu(hdr->header.ucode_version); - sdma_inst->feature_version = le32_to_cpu(hdr->ucode_feature_version); - - if (sdma_inst->feature_version >= 20) - sdma_inst->burst_nop = true; - - return 0; -} - -static void sdma_v6_0_destroy_inst_ctx(struct amdgpu_device *adev) -{ - release_firmware(adev->sdma.instance[0].fw); - - memset((void*)adev->sdma.instance, 0, - sizeof(struct amdgpu_sdma_instance) * AMDGPU_MAX_SDMA_INSTANCES); -} - /** * sdma_v6_0_init_microcode - load ucode images from disk * @@ -114,16 +87,10 @@ static void sdma_v6_0_destroy_inst_ctx(struct amdgpu_device *adev) * the driver (not loaded into hw). * Returns 0 on success, error on failure. */ - -// emulation only, won't work on real chip -// sdma 6.0.0 real chip need to use PSP to load firmware static int sdma_v6_0_init_microcode(struct amdgpu_device *adev) { char fw_name[30]; char ucode_prefix[30]; - int err = 0, i; - struct amdgpu_firmware_info *info = NULL; - const struct sdma_firmware_header_v2_0 *sdma_hdr; DRM_DEBUG("\n"); @@ -131,43 +98,7 @@ static int sdma_v6_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); - err = request_firmware(&adev->sdma.instance[0].fw, fw_name, adev->dev); - if (err) - goto out; - - err = sdma_v6_0_init_inst_ctx(&adev->sdma.instance[0]); - if (err) - goto out; - - for (i = 1; i < adev->sdma.num_instances; i++) { - memcpy((void*)&adev->sdma.instance[i], - (void*)&adev->sdma.instance[0], - sizeof(struct amdgpu_sdma_instance)); - } - - DRM_DEBUG("psp_load == '%s'\n", - adev->firmware.load_type == AMDGPU_FW_LOAD_PSP ? "true" : "false"); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - sdma_hdr = (const struct sdma_firmware_header_v2_0 *)adev->sdma.instance[0].fw->data; - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA_UCODE_TH0]; - info->ucode_id = AMDGPU_UCODE_ID_SDMA_UCODE_TH0; - info->fw = adev->sdma.instance[0].fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(sdma_hdr->ctx_ucode_size_bytes), PAGE_SIZE); - info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA_UCODE_TH1]; - info->ucode_id = AMDGPU_UCODE_ID_SDMA_UCODE_TH1; - info->fw = adev->sdma.instance[0].fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(sdma_hdr->ctl_ucode_size_bytes), PAGE_SIZE); - } - -out: - if (err) { - DRM_ERROR("sdma_v6_0: Failed to load firmware \"%s\"\n", fw_name); - sdma_v6_0_destroy_inst_ctx(adev); - } - return err; + return amdgpu_sdma_init_microcode(adev, fw_name, 0, true); } static unsigned sdma_v6_0_ring_init_cond_exec(struct amdgpu_ring *ring) @@ -1370,7 +1301,7 @@ static int sdma_v6_0_sw_fini(void *handle) for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); - sdma_v6_0_destroy_inst_ctx(adev); + amdgpu_sdma_destroy_inst_ctx(adev, true); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 5f0d6983714a..16b757664a35 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -629,6 +629,7 @@ static int soc21_common_early_init(void *handle) AMD_CG_SUPPORT_JPEG_MGCG; adev->pg_flags = AMD_PG_SUPPORT_GFX_PG | + AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_JPEG; adev->external_rev_id = adev->rev_id + 0x1; break; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c index bf7524f16b66..a0d19b768346 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c @@ -452,41 +452,47 @@ static void umc_v6_7_query_ras_error_count(struct amdgpu_device *adev, static void umc_v6_7_query_error_address(struct amdgpu_device *adev, struct ras_err_data *err_data, - uint32_t umc_reg_offset, - uint32_t ch_inst, - uint32_t umc_inst) + uint32_t umc_reg_offset, uint32_t ch_inst, + uint32_t umc_inst, uint64_t mca_addr) { uint32_t mc_umc_status_addr; uint32_t channel_index; - uint64_t mc_umc_status, mc_umc_addrt0; + uint64_t mc_umc_status = 0, mc_umc_addrt0; uint64_t err_addr, soc_pa, retired_page, column; - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); - mc_umc_addrt0 = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_ADDRT0); + if (mca_addr == UMC_INVALID_ADDR) { + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); + mc_umc_addrt0 = + SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_ADDRT0); - mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); + mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); - if (mc_umc_status == 0) - return; + if (mc_umc_status == 0) + return; - if (!err_data->err_addr) { - /* clear umc status */ - WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); - return; + if (!err_data->err_addr) { + /* clear umc status */ + WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); + return; + } } channel_index = adev->umc.channel_idx_tbl[umc_inst * adev->umc.channel_inst_num + ch_inst]; /* calculate error address if ue/ce error is detected */ - if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && + if ((REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) == 1 || - REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, CECC) == 1)) { - - err_addr = RREG64_PCIE((mc_umc_addrt0 + umc_reg_offset) * 4); - err_addr = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, CECC) == 1)) || + mca_addr != UMC_INVALID_ADDR) { + if (mca_addr == UMC_INVALID_ADDR) { + err_addr = RREG64_PCIE((mc_umc_addrt0 + umc_reg_offset) * 4); + err_addr = + REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); + } else { + err_addr = mca_addr; + } /* translate umc channel address to soc pa, 3 parts are included */ soc_pa = ADDR_OF_8KB_BLOCK(err_addr) | @@ -501,7 +507,8 @@ static void umc_v6_7_query_error_address(struct amdgpu_device *adev, /* we only save ue error information currently, ce is skipped */ if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) - == 1) { + == 1 || + mca_addr != UMC_INVALID_ADDR) { /* loop for all possibilities of [C4 C3 C2] */ for (column = 0; column < UMC_V6_7_NA_MAP_PA_NUM; column++) { retired_page = soc_pa | (column << UMC_V6_7_PA_C2_BIT); @@ -519,7 +526,8 @@ static void umc_v6_7_query_error_address(struct amdgpu_device *adev, } /* clear umc status */ - WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); + if (mca_addr == UMC_INVALID_ADDR) + WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); } static void umc_v6_7_query_ras_error_address(struct amdgpu_device *adev, @@ -540,9 +548,8 @@ static void umc_v6_7_query_ras_error_address(struct amdgpu_device *adev, ch_inst); umc_v6_7_query_error_address(adev, err_data, - umc_reg_offset, - ch_inst, - umc_inst); + umc_reg_offset, ch_inst, + umc_inst, UMC_INVALID_ADDR); } } @@ -583,4 +590,5 @@ struct amdgpu_umc_ras umc_v6_7_ras = { .query_ras_poison_mode = umc_v6_7_query_ras_poison_mode, .ecc_info_query_ras_error_count = umc_v6_7_ecc_info_query_ras_error_count, .ecc_info_query_ras_error_address = umc_v6_7_ecc_info_query_ras_error_address, + .convert_ras_error_address = umc_v6_7_query_error_address, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 39405f0db824..9c8b5fd99037 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -1761,21 +1761,23 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; -static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p) +static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p, + struct amdgpu_job *job) { struct drm_gpu_scheduler **scheds; /* The create msg must be in the first IB submitted */ - if (atomic_read(&p->entity->fence_seq)) + if (atomic_read(&job->base.entity->fence_seq)) return -EINVAL; scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_DEC] [AMDGPU_RING_PRIO_DEFAULT].sched; - drm_sched_entity_modify_sched(p->entity, scheds, 1); + drm_sched_entity_modify_sched(job->base.entity, scheds, 1); return 0; } -static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, uint64_t addr) +static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + uint64_t addr) { struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_bo_va_mapping *map; @@ -1846,7 +1848,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, uint64_t addr) if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11) continue; - r = vcn_v3_0_limit_sched(p); + r = vcn_v3_0_limit_sched(p, job); if (r) goto out; } @@ -1860,7 +1862,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_job *job, struct amdgpu_ib *ib) { - struct amdgpu_ring *ring = to_amdgpu_ring(p->entity->rq->sched); + struct amdgpu_ring *ring = amdgpu_job_ring(job); uint32_t msg_lo = 0, msg_hi = 0; unsigned i; int r; @@ -1879,7 +1881,8 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, msg_hi = val; } else if (reg == PACKET0(p->adev->vcn.internal.cmd, 0) && val == 0) { - r = vcn_v3_0_dec_msg(p, ((u64)msg_hi) << 32 | msg_lo); + r = vcn_v3_0_dec_msg(p, job, + ((u64)msg_hi) << 32 | msg_lo); if (r) return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 09c89faa8c27..897a5ce9c9da 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -150,6 +150,10 @@ static int vcn_v4_0_sw_init(void *handle) fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); fw_shared->sq.is_enabled = 1; + fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG); + fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ? + AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU; + if (amdgpu_sriov_vf(adev)) fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_VF_RB_SETUP_FLAG); @@ -1591,21 +1595,23 @@ static void vcn_v4_0_unified_ring_set_wptr(struct amdgpu_ring *ring) } } -static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p) +static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p, + struct amdgpu_job *job) { struct drm_gpu_scheduler **scheds; /* The create msg must be in the first IB submitted */ - if (atomic_read(&p->entity->fence_seq)) + if (atomic_read(&job->base.entity->fence_seq)) return -EINVAL; scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC] [AMDGPU_RING_PRIO_0].sched; - drm_sched_entity_modify_sched(p->entity, scheds, 1); + drm_sched_entity_modify_sched(job->base.entity, scheds, 1); return 0; } -static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, uint64_t addr) +static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + uint64_t addr) { struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_bo_va_mapping *map; @@ -1676,7 +1682,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, uint64_t addr) if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11) continue; - r = vcn_v4_0_limit_sched(p); + r = vcn_v4_0_limit_sched(p, job); if (r) goto out; } @@ -1689,32 +1695,34 @@ out: #define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003) static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, - struct amdgpu_job *job, - struct amdgpu_ib *ib) + struct amdgpu_job *job, + struct amdgpu_ib *ib) { - struct amdgpu_ring *ring = to_amdgpu_ring(p->entity->rq->sched); - struct amdgpu_vcn_decode_buffer *decode_buffer = NULL; + struct amdgpu_ring *ring = amdgpu_job_ring(job); + struct amdgpu_vcn_decode_buffer *decode_buffer; + uint64_t addr; uint32_t val; - int r = 0; /* The first instance can decode anything */ if (!ring->me) - return r; + return 0; /* unified queue ib header has 8 double words. */ if (ib->length_dw < 8) - return r; + return 0; val = amdgpu_ib_get_value(ib, 6); //RADEON_VCN_ENGINE_TYPE + if (val != RADEON_VCN_ENGINE_TYPE_DECODE) + return 0; - if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { - decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10]; + decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10]; - if (decode_buffer->valid_buf_flag & 0x1) - r = vcn_v4_0_dec_msg(p, ((u64)decode_buffer->msg_buffer_address_hi) << 32 | - decode_buffer->msg_buffer_address_lo); - } - return r; + if (!(decode_buffer->valid_buf_flag & 0x1)) + return 0; + + addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 | + decode_buffer->msg_buffer_address_lo; + return vcn_v4_0_dec_msg(p, job, addr); } static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 60a81649cf12..c7118843db05 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -742,7 +742,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0xbf88fffe, 0x877aff7f, 0x04000000, 0x8f7a857a, 0x886d7a6d, 0xb97b02dc, - 0x8f7b997b, 0xb97a2a05, + 0x8f7b997b, 0xb97a3a05, 0x807a817a, 0xbf0d997b, 0xbf850002, 0x8f7a897a, 0xbf820001, 0x8f7a8a7a, @@ -819,7 +819,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0xbefe037c, 0xbefc0370, 0xf4611c7a, 0xf8000000, 0x80708470, 0xbefc037e, - 0xb9702a05, 0x80708170, + 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, 0xb97a1e06, @@ -1069,7 +1069,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0xb9f9f816, 0x876f7bff, 0xfffff800, 0x906f8b6f, 0xb9efa2c3, 0xb9f3f801, - 0xb96e2a05, 0x806e816e, + 0xb96e3a05, 0x806e816e, 0xbf0d9972, 0xbf850002, 0x8f6e896e, 0xbf820001, 0x8f6e8a6e, 0xb96f1e06, @@ -2114,7 +2114,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0x007a0000, 0x7e000280, 0xbefe037a, 0xbeff037b, 0xb97b02dc, 0x8f7b997b, - 0xb97a2a05, 0x807a817a, + 0xb97a3a05, 0x807a817a, 0xbf0d997b, 0xbf850002, 0x8f7a897a, 0xbf820001, 0x8f7a8a7a, 0xb97b1e06, @@ -2157,7 +2157,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0x01000000, 0xe0704100, 0x705d0100, 0xe0704200, 0x705d0200, 0xe0704300, - 0x705d0300, 0xb9702a05, + 0x705d0300, 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, @@ -2189,7 +2189,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xbefe03ff, 0x0000ffff, 0xbeff0380, 0xe0704000, 0x705d0200, 0xbefe03c1, - 0xb9702a05, 0x80708170, + 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, 0xb97a1e06, @@ -2475,7 +2475,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xb9ef4803, 0x876f7bff, 0xfffff800, 0x906f8b6f, 0xb9efa2c3, 0xb9f3f801, - 0xb96e2a05, 0x806e816e, + 0xb96e3a05, 0x806e816e, 0xbf0d9972, 0xbf850002, 0x8f6e896e, 0xbf820001, 0x8f6e8a6e, 0xb96f1e06, @@ -2494,438 +2494,441 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0x00000000, }; - static const uint32_t cwsr_trap_gfx11_hex[] = { - 0xbfa00001, 0xbfa0021b, + 0xbfa00001, 0xbfa0021e, 0xb0804006, 0xb8f8f802, - 0x91788678, 0xb8fbf803, - 0x8b6eff78, 0x00002000, - 0xbfa10009, 0x8b6eff6d, - 0x00ff0000, 0xbfa2001e, - 0x8b6eff7b, 0x00000400, - 0xbfa20041, 0xbf830010, - 0xb8fbf803, 0xbfa0fffa, - 0x8b6eff7b, 0x00000900, - 0xbfa20015, 0x8b6eff7b, - 0x000071ff, 0xbfa10008, - 0x8b6fff7b, 0x00007080, - 0xbfa10001, 0xbeee1287, - 0xb8eff801, 0x846e8c6e, - 0x8b6e6f6e, 0xbfa2000a, + 0x9178ff78, 0x00020006, + 0xb8fbf803, 0xbf0d9f6d, + 0xbfa20006, 0x8b6eff78, + 0x00002000, 0xbfa10009, 0x8b6eff6d, 0x00ff0000, - 0xbfa20007, 0xb8eef801, - 0x8b6eff6e, 0x00000800, - 0xbfa20003, 0x8b6eff7b, - 0x00000400, 0xbfa20026, - 0xbefa4d82, 0xbf89fc07, - 0x84fa887a, 0xf4005bbd, - 0xf8000010, 0xbf89fc07, - 0x846e976e, 0x9177ff77, - 0x00800000, 0x8c776e77, - 0xf4045bbd, 0xf8000000, - 0xbf89fc07, 0xf4045ebd, - 0xf8000008, 0xbf89fc07, - 0x8bee6e6e, 0xbfa10001, - 0xbe80486e, 0x8b6eff6d, - 0x01ff0000, 0xbfa20005, - 0x8c78ff78, 0x00002000, - 0x80ec886c, 0x82ed806d, - 0xbfa00005, 0x8b6eff6d, - 0x01000000, 0xbfa20002, - 0x806c846c, 0x826d806d, - 0x8b6dff6d, 0x0000ffff, - 0x8bfe7e7e, 0x8bea6a6a, - 0xb978f802, 0xbe804a6c, - 0x8b6dff6d, 0x0000ffff, - 0xbefa0080, 0xb97a0283, - 0xbeee007e, 0xbeef007f, - 0xbefe0180, 0xbefe4d84, - 0xbf89fc07, 0x8b7aff7f, - 0x04000000, 0x847a857a, - 0x8c6d7a6d, 0xbefa007e, - 0x8b7bff7f, 0x0000ffff, - 0xbefe00c1, 0xbeff00c1, - 0xdca6c000, 0x007a0000, - 0x7e000280, 0xbefe007a, - 0xbeff007b, 0xb8fb02dc, - 0x847b997b, 0xb8fa3b05, - 0x807a817a, 0xbf0d997b, - 0xbfa20002, 0x847a897a, - 0xbfa00001, 0x847a8a7a, - 0xb8fb1e06, 0x847b8a7b, - 0x807a7b7a, 0x8b7bff7f, - 0x0000ffff, 0x807aff7a, - 0x00000200, 0x807a7e7a, - 0x827b807b, 0xd7610000, - 0x00010870, 0xd7610000, - 0x00010a71, 0xd7610000, - 0x00010c72, 0xd7610000, - 0x00010e73, 0xd7610000, - 0x00011074, 0xd7610000, - 0x00011275, 0xd7610000, - 0x00011476, 0xd7610000, - 0x00011677, 0xd7610000, - 0x00011a79, 0xd7610000, - 0x00011c7e, 0xd7610000, - 0x00011e7f, 0xbefe00ff, - 0x00003fff, 0xbeff0080, - 0xdca6c040, 0x007a0000, - 0xd760007a, 0x00011d00, - 0xd760007b, 0x00011f00, + 0xbfa2001e, 0x8b6eff7b, + 0x00000400, 0xbfa20041, + 0xbf830010, 0xb8fbf803, + 0xbfa0fffa, 0x8b6eff7b, + 0x00000900, 0xbfa20015, + 0x8b6eff7b, 0x000071ff, + 0xbfa10008, 0x8b6fff7b, + 0x00007080, 0xbfa10001, + 0xbeee1287, 0xb8eff801, + 0x846e8c6e, 0x8b6e6f6e, + 0xbfa2000a, 0x8b6eff6d, + 0x00ff0000, 0xbfa20007, + 0xb8eef801, 0x8b6eff6e, + 0x00000800, 0xbfa20003, + 0x8b6eff7b, 0x00000400, + 0xbfa20026, 0xbefa4d82, + 0xbf89fc07, 0x84fa887a, + 0xf4005bbd, 0xf8000010, + 0xbf89fc07, 0x846e976e, + 0x9177ff77, 0x00800000, + 0x8c776e77, 0xf4045bbd, + 0xf8000000, 0xbf89fc07, + 0xf4045ebd, 0xf8000008, + 0xbf89fc07, 0x8bee6e6e, + 0xbfa10001, 0xbe80486e, + 0x8b6eff6d, 0x01ff0000, + 0xbfa20005, 0x8c78ff78, + 0x00002000, 0x80ec886c, + 0x82ed806d, 0xbfa00005, + 0x8b6eff6d, 0x01000000, + 0xbfa20002, 0x806c846c, + 0x826d806d, 0x8b6dff6d, + 0x0000ffff, 0x8bfe7e7e, + 0x8bea6a6a, 0xb978f802, + 0xbe804a6c, 0x8b6dff6d, + 0x0000ffff, 0xbefa0080, + 0xb97a0283, 0xbeee007e, + 0xbeef007f, 0xbefe0180, + 0xbefe4d84, 0xbf89fc07, + 0x8b7aff7f, 0x04000000, + 0x847a857a, 0x8c6d7a6d, + 0xbefa007e, 0x8b7bff7f, + 0x0000ffff, 0xbefe00c1, + 0xbeff00c1, 0xdca6c000, + 0x007a0000, 0x7e000280, 0xbefe007a, 0xbeff007b, - 0xbef4007e, 0x8b75ff7f, - 0x0000ffff, 0x8c75ff75, - 0x00040000, 0xbef60080, - 0xbef700ff, 0x10807fac, - 0xbef1007d, 0xbef00080, - 0xb8f302dc, 0x84739973, - 0xbefe00c1, 0x857d9973, - 0x8b7d817d, 0xbf06817d, - 0xbfa20002, 0xbeff0080, - 0xbfa00002, 0xbeff00c1, - 0xbfa00009, 0xbef600ff, - 0x01000000, 0xe0685080, - 0x701d0100, 0xe0685100, - 0x701d0200, 0xe0685180, - 0x701d0300, 0xbfa00008, + 0xb8fb02dc, 0x847b997b, + 0xb8fa3b05, 0x807a817a, + 0xbf0d997b, 0xbfa20002, + 0x847a897a, 0xbfa00001, + 0x847a8a7a, 0xb8fb1e06, + 0x847b8a7b, 0x807a7b7a, + 0x8b7bff7f, 0x0000ffff, + 0x807aff7a, 0x00000200, + 0x807a7e7a, 0x827b807b, + 0xd7610000, 0x00010870, + 0xd7610000, 0x00010a71, + 0xd7610000, 0x00010c72, + 0xd7610000, 0x00010e73, + 0xd7610000, 0x00011074, + 0xd7610000, 0x00011275, + 0xd7610000, 0x00011476, + 0xd7610000, 0x00011677, + 0xd7610000, 0x00011a79, + 0xd7610000, 0x00011c7e, + 0xd7610000, 0x00011e7f, + 0xbefe00ff, 0x00003fff, + 0xbeff0080, 0xdca6c040, + 0x007a0000, 0xd760007a, + 0x00011d00, 0xd760007b, + 0x00011f00, 0xbefe007a, + 0xbeff007b, 0xbef4007e, + 0x8b75ff7f, 0x0000ffff, + 0x8c75ff75, 0x00040000, + 0xbef60080, 0xbef700ff, + 0x10807fac, 0xbef1007d, + 0xbef00080, 0xb8f302dc, + 0x84739973, 0xbefe00c1, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbfa20002, + 0xbeff0080, 0xbfa00002, + 0xbeff00c1, 0xbfa00009, 0xbef600ff, 0x01000000, - 0xe0685100, 0x701d0100, - 0xe0685200, 0x701d0200, - 0xe0685300, 0x701d0300, + 0xe0685080, 0x701d0100, + 0xe0685100, 0x701d0200, + 0xe0685180, 0x701d0300, + 0xbfa00008, 0xbef600ff, + 0x01000000, 0xe0685100, + 0x701d0100, 0xe0685200, + 0x701d0200, 0xe0685300, + 0x701d0300, 0xb8f03b05, + 0x80708170, 0xbf0d9973, + 0xbfa20002, 0x84708970, + 0xbfa00001, 0x84708a70, + 0xb8fa1e06, 0x847a8a7a, + 0x80707a70, 0x8070ff70, + 0x00000200, 0xbef600ff, + 0x01000000, 0x7e000280, + 0x7e020280, 0x7e040280, + 0xbefd0080, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xd7610002, 0x0000fa6c, + 0x807d817d, 0x917aff6d, + 0x80000000, 0xd7610002, + 0x0000fa7a, 0x807d817d, + 0xd7610002, 0x0000fa6e, + 0x807d817d, 0xd7610002, + 0x0000fa6f, 0x807d817d, + 0xd7610002, 0x0000fa78, + 0x807d817d, 0xb8faf803, + 0xd7610002, 0x0000fa7a, + 0x807d817d, 0xd7610002, + 0x0000fa7b, 0x807d817d, + 0xb8f1f801, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f814, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xb8f1f815, 0xd7610002, + 0x0000fa71, 0x807d817d, + 0xbefe00ff, 0x0000ffff, + 0xbeff0080, 0xe0685000, + 0x701d0200, 0xbefe00c1, 0xb8f03b05, 0x80708170, 0xbf0d9973, 0xbfa20002, 0x84708970, 0xbfa00001, 0x84708a70, 0xb8fa1e06, 0x847a8a7a, 0x80707a70, - 0x8070ff70, 0x00000200, 0xbef600ff, 0x01000000, - 0x7e000280, 0x7e020280, - 0x7e040280, 0xbefd0080, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xd7610002, - 0x0000fa6c, 0x807d817d, - 0x917aff6d, 0x80000000, - 0xd7610002, 0x0000fa7a, - 0x807d817d, 0xd7610002, - 0x0000fa6e, 0x807d817d, - 0xd7610002, 0x0000fa6f, - 0x807d817d, 0xd7610002, - 0x0000fa78, 0x807d817d, - 0xb8faf803, 0xd7610002, - 0x0000fa7a, 0x807d817d, - 0xd7610002, 0x0000fa7b, - 0x807d817d, 0xb8f1f801, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f814, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xb8f1f815, - 0xd7610002, 0x0000fa71, - 0x807d817d, 0xbefe00ff, - 0x0000ffff, 0xbeff0080, - 0xe0685000, 0x701d0200, - 0xbefe00c1, 0xb8f03b05, - 0x80708170, 0xbf0d9973, - 0xbfa20002, 0x84708970, - 0xbfa00001, 0x84708a70, - 0xb8fa1e06, 0x847a8a7a, - 0x80707a70, 0xbef600ff, - 0x01000000, 0xbef90080, - 0xbefd0080, 0xbf800000, - 0xbe804100, 0xbe824102, - 0xbe844104, 0xbe864106, - 0xbe884108, 0xbe8a410a, - 0xbe8c410c, 0xbe8e410e, - 0xd7610002, 0x0000f200, - 0x80798179, 0xd7610002, - 0x0000f201, 0x80798179, - 0xd7610002, 0x0000f202, - 0x80798179, 0xd7610002, - 0x0000f203, 0x80798179, - 0xd7610002, 0x0000f204, + 0xbef90080, 0xbefd0080, + 0xbf800000, 0xbe804100, + 0xbe824102, 0xbe844104, + 0xbe864106, 0xbe884108, + 0xbe8a410a, 0xbe8c410c, + 0xbe8e410e, 0xd7610002, + 0x0000f200, 0x80798179, + 0xd7610002, 0x0000f201, 0x80798179, 0xd7610002, - 0x0000f205, 0x80798179, - 0xd7610002, 0x0000f206, + 0x0000f202, 0x80798179, + 0xd7610002, 0x0000f203, 0x80798179, 0xd7610002, - 0x0000f207, 0x80798179, - 0xd7610002, 0x0000f208, + 0x0000f204, 0x80798179, + 0xd7610002, 0x0000f205, 0x80798179, 0xd7610002, - 0x0000f209, 0x80798179, - 0xd7610002, 0x0000f20a, + 0x0000f206, 0x80798179, + 0xd7610002, 0x0000f207, 0x80798179, 0xd7610002, - 0x0000f20b, 0x80798179, - 0xd7610002, 0x0000f20c, + 0x0000f208, 0x80798179, + 0xd7610002, 0x0000f209, 0x80798179, 0xd7610002, - 0x0000f20d, 0x80798179, - 0xd7610002, 0x0000f20e, + 0x0000f20a, 0x80798179, + 0xd7610002, 0x0000f20b, 0x80798179, 0xd7610002, - 0x0000f20f, 0x80798179, - 0xbf06a079, 0xbfa10006, - 0xe0685000, 0x701d0200, - 0x8070ff70, 0x00000080, - 0xbef90080, 0x7e040280, - 0x807d907d, 0xbf0aff7d, - 0x00000060, 0xbfa2ffbc, - 0xbe804100, 0xbe824102, - 0xbe844104, 0xbe864106, - 0xbe884108, 0xbe8a410a, - 0xd7610002, 0x0000f200, + 0x0000f20c, 0x80798179, + 0xd7610002, 0x0000f20d, 0x80798179, 0xd7610002, - 0x0000f201, 0x80798179, - 0xd7610002, 0x0000f202, + 0x0000f20e, 0x80798179, + 0xd7610002, 0x0000f20f, + 0x80798179, 0xbf06a079, + 0xbfa10006, 0xe0685000, + 0x701d0200, 0x8070ff70, + 0x00000080, 0xbef90080, + 0x7e040280, 0x807d907d, + 0xbf0aff7d, 0x00000060, + 0xbfa2ffbc, 0xbe804100, + 0xbe824102, 0xbe844104, + 0xbe864106, 0xbe884108, + 0xbe8a410a, 0xd7610002, + 0x0000f200, 0x80798179, + 0xd7610002, 0x0000f201, 0x80798179, 0xd7610002, - 0x0000f203, 0x80798179, - 0xd7610002, 0x0000f204, + 0x0000f202, 0x80798179, + 0xd7610002, 0x0000f203, 0x80798179, 0xd7610002, - 0x0000f205, 0x80798179, - 0xd7610002, 0x0000f206, + 0x0000f204, 0x80798179, + 0xd7610002, 0x0000f205, 0x80798179, 0xd7610002, - 0x0000f207, 0x80798179, - 0xd7610002, 0x0000f208, + 0x0000f206, 0x80798179, + 0xd7610002, 0x0000f207, 0x80798179, 0xd7610002, - 0x0000f209, 0x80798179, - 0xd7610002, 0x0000f20a, + 0x0000f208, 0x80798179, + 0xd7610002, 0x0000f209, 0x80798179, 0xd7610002, - 0x0000f20b, 0x80798179, - 0xe0685000, 0x701d0200, + 0x0000f20a, 0x80798179, + 0xd7610002, 0x0000f20b, + 0x80798179, 0xe0685000, + 0x701d0200, 0xbefe00c1, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbfa20002, + 0xbeff0080, 0xbfa00001, + 0xbeff00c1, 0xb8fb4306, + 0x8b7bc17b, 0xbfa10044, + 0xbfbd0000, 0x8b7aff6d, + 0x80000000, 0xbfa10040, + 0x847b867b, 0x847b827b, + 0xbef6007b, 0xb8f03b05, + 0x80708170, 0xbf0d9973, + 0xbfa20002, 0x84708970, + 0xbfa00001, 0x84708a70, + 0xb8fa1e06, 0x847a8a7a, + 0x80707a70, 0x8070ff70, + 0x00000200, 0x8070ff70, + 0x00000080, 0xbef600ff, + 0x01000000, 0xd71f0000, + 0x000100c1, 0xd7200000, + 0x000200c1, 0x16000084, + 0x857d9973, 0x8b7d817d, + 0xbf06817d, 0xbefd0080, + 0xbfa20012, 0xbe8300ff, + 0x00000080, 0xbf800000, + 0xbf800000, 0xbf800000, + 0xd8d80000, 0x01000000, + 0xbf890000, 0xe0685000, + 0x701d0100, 0x807d037d, + 0x80700370, 0xd5250000, + 0x0001ff00, 0x00000080, + 0xbf0a7b7d, 0xbfa2fff4, + 0xbfa00011, 0xbe8300ff, + 0x00000100, 0xbf800000, + 0xbf800000, 0xbf800000, + 0xd8d80000, 0x01000000, + 0xbf890000, 0xe0685000, + 0x701d0100, 0x807d037d, + 0x80700370, 0xd5250000, + 0x0001ff00, 0x00000100, + 0xbf0a7b7d, 0xbfa2fff4, 0xbefe00c1, 0x857d9973, 0x8b7d817d, 0xbf06817d, - 0xbfa20002, 0xbeff0080, - 0xbfa00001, 0xbeff00c1, - 0xb8fb4306, 0x8b7bc17b, - 0xbfa10044, 0xbfbd0000, - 0x8b7aff6d, 0x80000000, - 0xbfa10040, 0x847b867b, - 0x847b827b, 0xbef6007b, - 0xb8f03b05, 0x80708170, - 0xbf0d9973, 0xbfa20002, - 0x84708970, 0xbfa00001, - 0x84708a70, 0xb8fa1e06, - 0x847a8a7a, 0x80707a70, - 0x8070ff70, 0x00000200, - 0x8070ff70, 0x00000080, - 0xbef600ff, 0x01000000, - 0xd71f0000, 0x000100c1, - 0xd7200000, 0x000200c1, - 0x16000084, 0x857d9973, + 0xbfa20004, 0xbef000ff, + 0x00000200, 0xbeff0080, + 0xbfa00003, 0xbef000ff, + 0x00000400, 0xbeff00c1, + 0xb8fb3b05, 0x807b817b, + 0x847b827b, 0x857d9973, 0x8b7d817d, 0xbf06817d, - 0xbefd0080, 0xbfa20012, - 0xbe8300ff, 0x00000080, - 0xbf800000, 0xbf800000, - 0xbf800000, 0xd8d80000, - 0x01000000, 0xbf890000, - 0xe0685000, 0x701d0100, - 0x807d037d, 0x80700370, - 0xd5250000, 0x0001ff00, - 0x00000080, 0xbf0a7b7d, - 0xbfa2fff4, 0xbfa00011, - 0xbe8300ff, 0x00000100, - 0xbf800000, 0xbf800000, - 0xbf800000, 0xd8d80000, - 0x01000000, 0xbf890000, - 0xe0685000, 0x701d0100, - 0x807d037d, 0x80700370, - 0xd5250000, 0x0001ff00, - 0x00000100, 0xbf0a7b7d, - 0xbfa2fff4, 0xbefe00c1, - 0x857d9973, 0x8b7d817d, - 0xbf06817d, 0xbfa20004, - 0xbef000ff, 0x00000200, - 0xbeff0080, 0xbfa00003, - 0xbef000ff, 0x00000400, - 0xbeff00c1, 0xb8fb3b05, - 0x807b817b, 0x847b827b, - 0x857d9973, 0x8b7d817d, - 0xbf06817d, 0xbfa20017, + 0xbfa20017, 0xbef600ff, + 0x01000000, 0xbefd0084, + 0xbf0a7b7d, 0xbfa10037, + 0x7e008700, 0x7e028701, + 0x7e048702, 0x7e068703, + 0xe0685000, 0x701d0000, + 0xe0685080, 0x701d0100, + 0xe0685100, 0x701d0200, + 0xe0685180, 0x701d0300, + 0x807d847d, 0x8070ff70, + 0x00000200, 0xbf0a7b7d, + 0xbfa2ffef, 0xbfa00025, 0xbef600ff, 0x01000000, 0xbefd0084, 0xbf0a7b7d, - 0xbfa10037, 0x7e008700, + 0xbfa10011, 0x7e008700, 0x7e028701, 0x7e048702, 0x7e068703, 0xe0685000, - 0x701d0000, 0xe0685080, - 0x701d0100, 0xe0685100, - 0x701d0200, 0xe0685180, + 0x701d0000, 0xe0685100, + 0x701d0100, 0xe0685200, + 0x701d0200, 0xe0685300, 0x701d0300, 0x807d847d, - 0x8070ff70, 0x00000200, + 0x8070ff70, 0x00000400, 0xbf0a7b7d, 0xbfa2ffef, - 0xbfa00025, 0xbef600ff, - 0x01000000, 0xbefd0084, - 0xbf0a7b7d, 0xbfa10011, - 0x7e008700, 0x7e028701, - 0x7e048702, 0x7e068703, + 0xb8fb1e06, 0x8b7bc17b, + 0xbfa1000c, 0x847b837b, + 0x807b7d7b, 0xbefe00c1, + 0xbeff0080, 0x7e008700, 0xe0685000, 0x701d0000, - 0xe0685100, 0x701d0100, - 0xe0685200, 0x701d0200, - 0xe0685300, 0x701d0300, - 0x807d847d, 0x8070ff70, - 0x00000400, 0xbf0a7b7d, - 0xbfa2ffef, 0xb8fb1e06, - 0x8b7bc17b, 0xbfa1000c, - 0x847b837b, 0x807b7d7b, - 0xbefe00c1, 0xbeff0080, - 0x7e008700, 0xe0685000, - 0x701d0000, 0x807d817d, - 0x8070ff70, 0x00000080, - 0xbf0a7b7d, 0xbfa2fff8, - 0xbfa00141, 0xbef4007e, - 0x8b75ff7f, 0x0000ffff, - 0x8c75ff75, 0x00040000, - 0xbef60080, 0xbef700ff, - 0x10807fac, 0xb8f202dc, - 0x84729972, 0x8b6eff7f, - 0x04000000, 0xbfa1003a, + 0x807d817d, 0x8070ff70, + 0x00000080, 0xbf0a7b7d, + 0xbfa2fff8, 0xbfa00146, + 0xbef4007e, 0x8b75ff7f, + 0x0000ffff, 0x8c75ff75, + 0x00040000, 0xbef60080, + 0xbef700ff, 0x10807fac, + 0xb8f202dc, 0x84729972, + 0x8b6eff7f, 0x04000000, + 0xbfa1003a, 0xbefe00c1, + 0x857d9972, 0x8b7d817d, + 0xbf06817d, 0xbfa20002, + 0xbeff0080, 0xbfa00001, + 0xbeff00c1, 0xb8ef4306, + 0x8b6fc16f, 0xbfa1002f, + 0x846f866f, 0x846f826f, + 0xbef6006f, 0xb8f83b05, + 0x80788178, 0xbf0d9972, + 0xbfa20002, 0x84788978, + 0xbfa00001, 0x84788a78, + 0xb8ee1e06, 0x846e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0x8078ff78, + 0x00000080, 0xbef600ff, + 0x01000000, 0x857d9972, + 0x8b7d817d, 0xbf06817d, + 0xbefd0080, 0xbfa2000c, + 0xe0500000, 0x781d0000, + 0xbf8903f7, 0xdac00000, + 0x00000000, 0x807dff7d, + 0x00000080, 0x8078ff78, + 0x00000080, 0xbf0a6f7d, + 0xbfa2fff5, 0xbfa0000b, + 0xe0500000, 0x781d0000, + 0xbf8903f7, 0xdac00000, + 0x00000000, 0x807dff7d, + 0x00000100, 0x8078ff78, + 0x00000100, 0xbf0a6f7d, + 0xbfa2fff5, 0xbef80080, 0xbefe00c1, 0x857d9972, 0x8b7d817d, 0xbf06817d, 0xbfa20002, 0xbeff0080, 0xbfa00001, 0xbeff00c1, - 0xb8ef4306, 0x8b6fc16f, - 0xbfa1002f, 0x846f866f, - 0x846f826f, 0xbef6006f, - 0xb8f83b05, 0x80788178, - 0xbf0d9972, 0xbfa20002, - 0x84788978, 0xbfa00001, - 0x84788a78, 0xb8ee1e06, - 0x846e8a6e, 0x80786e78, + 0xb8ef3b05, 0x806f816f, + 0x846f826f, 0x857d9972, + 0x8b7d817d, 0xbf06817d, + 0xbfa20024, 0xbef600ff, + 0x01000000, 0xbeee0078, 0x8078ff78, 0x00000200, - 0x8078ff78, 0x00000080, - 0xbef600ff, 0x01000000, - 0x857d9972, 0x8b7d817d, - 0xbf06817d, 0xbefd0080, - 0xbfa2000c, 0xe0500000, - 0x781d0000, 0xbf8903f7, - 0xdac00000, 0x00000000, - 0x807dff7d, 0x00000080, - 0x8078ff78, 0x00000080, - 0xbf0a6f7d, 0xbfa2fff5, - 0xbfa0000b, 0xe0500000, - 0x781d0000, 0xbf8903f7, - 0xdac00000, 0x00000000, - 0x807dff7d, 0x00000100, - 0x8078ff78, 0x00000100, - 0xbf0a6f7d, 0xbfa2fff5, - 0xbef80080, 0xbefe00c1, - 0x857d9972, 0x8b7d817d, - 0xbf06817d, 0xbfa20002, - 0xbeff0080, 0xbfa00001, - 0xbeff00c1, 0xb8ef3b05, - 0x806f816f, 0x846f826f, - 0x857d9972, 0x8b7d817d, - 0xbf06817d, 0xbfa20024, - 0xbef600ff, 0x01000000, - 0xbeee0078, 0x8078ff78, - 0x00000200, 0xbefd0084, - 0xbf0a6f7d, 0xbfa10050, + 0xbefd0084, 0xbf0a6f7d, + 0xbfa10050, 0xe0505000, + 0x781d0000, 0xe0505080, + 0x781d0100, 0xe0505100, + 0x781d0200, 0xe0505180, + 0x781d0300, 0xbf8903f7, + 0x7e008500, 0x7e028501, + 0x7e048502, 0x7e068503, + 0x807d847d, 0x8078ff78, + 0x00000200, 0xbf0a6f7d, + 0xbfa2ffee, 0xe0505000, + 0x6e1d0000, 0xe0505080, + 0x6e1d0100, 0xe0505100, + 0x6e1d0200, 0xe0505180, + 0x6e1d0300, 0xbf8903f7, + 0xbfa00034, 0xbef600ff, + 0x01000000, 0xbeee0078, + 0x8078ff78, 0x00000400, + 0xbefd0084, 0xbf0a6f7d, + 0xbfa10012, 0xe0505000, + 0x781d0000, 0xe0505100, + 0x781d0100, 0xe0505200, + 0x781d0200, 0xe0505300, + 0x781d0300, 0xbf8903f7, + 0x7e008500, 0x7e028501, + 0x7e048502, 0x7e068503, + 0x807d847d, 0x8078ff78, + 0x00000400, 0xbf0a6f7d, + 0xbfa2ffee, 0xb8ef1e06, + 0x8b6fc16f, 0xbfa1000e, + 0x846f836f, 0x806f7d6f, + 0xbefe00c1, 0xbeff0080, 0xe0505000, 0x781d0000, - 0xe0505080, 0x781d0100, - 0xe0505100, 0x781d0200, - 0xe0505180, 0x781d0300, 0xbf8903f7, 0x7e008500, - 0x7e028501, 0x7e048502, - 0x7e068503, 0x807d847d, - 0x8078ff78, 0x00000200, - 0xbf0a6f7d, 0xbfa2ffee, + 0x807d817d, 0x8078ff78, + 0x00000080, 0xbf0a6f7d, + 0xbfa2fff7, 0xbeff00c1, 0xe0505000, 0x6e1d0000, - 0xe0505080, 0x6e1d0100, - 0xe0505100, 0x6e1d0200, - 0xe0505180, 0x6e1d0300, - 0xbf8903f7, 0xbfa00034, - 0xbef600ff, 0x01000000, - 0xbeee0078, 0x8078ff78, - 0x00000400, 0xbefd0084, - 0xbf0a6f7d, 0xbfa10012, - 0xe0505000, 0x781d0000, - 0xe0505100, 0x781d0100, - 0xe0505200, 0x781d0200, - 0xe0505300, 0x781d0300, - 0xbf8903f7, 0x7e008500, - 0x7e028501, 0x7e048502, - 0x7e068503, 0x807d847d, - 0x8078ff78, 0x00000400, - 0xbf0a6f7d, 0xbfa2ffee, - 0xb8ef1e06, 0x8b6fc16f, - 0xbfa1000e, 0x846f836f, - 0x806f7d6f, 0xbefe00c1, - 0xbeff0080, 0xe0505000, - 0x781d0000, 0xbf8903f7, - 0x7e008500, 0x807d817d, - 0x8078ff78, 0x00000080, - 0xbf0a6f7d, 0xbfa2fff7, - 0xbeff00c1, 0xe0505000, - 0x6e1d0000, 0xe0505100, - 0x6e1d0100, 0xe0505200, - 0x6e1d0200, 0xe0505300, - 0x6e1d0300, 0xbf8903f7, + 0xe0505100, 0x6e1d0100, + 0xe0505200, 0x6e1d0200, + 0xe0505300, 0x6e1d0300, + 0xbf8903f7, 0xb8f83b05, + 0x80788178, 0xbf0d9972, + 0xbfa20002, 0x84788978, + 0xbfa00001, 0x84788a78, + 0xb8ee1e06, 0x846e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0x80f8ff78, + 0x00000050, 0xbef600ff, + 0x01000000, 0xbefd00ff, + 0x0000006c, 0x80f89078, + 0xf428403a, 0xf0000000, + 0xbf89fc07, 0x80fd847d, + 0xbf800000, 0xbe804300, + 0xbe824302, 0x80f8a078, + 0xf42c403a, 0xf0000000, + 0xbf89fc07, 0x80fd887d, + 0xbf800000, 0xbe804300, + 0xbe824302, 0xbe844304, + 0xbe864306, 0x80f8c078, + 0xf430403a, 0xf0000000, + 0xbf89fc07, 0x80fd907d, + 0xbf800000, 0xbe804300, + 0xbe824302, 0xbe844304, + 0xbe864306, 0xbe884308, + 0xbe8a430a, 0xbe8c430c, + 0xbe8e430e, 0xbf06807d, + 0xbfa1fff0, 0xb980f801, + 0x00000000, 0xbfbd0000, 0xb8f83b05, 0x80788178, 0xbf0d9972, 0xbfa20002, 0x84788978, 0xbfa00001, 0x84788a78, 0xb8ee1e06, 0x846e8a6e, 0x80786e78, 0x8078ff78, 0x00000200, - 0x80f8ff78, 0x00000050, 0xbef600ff, 0x01000000, - 0xbefd00ff, 0x0000006c, - 0x80f89078, 0xf428403a, - 0xf0000000, 0xbf89fc07, - 0x80fd847d, 0xbf800000, - 0xbe804300, 0xbe824302, - 0x80f8a078, 0xf42c403a, - 0xf0000000, 0xbf89fc07, - 0x80fd887d, 0xbf800000, - 0xbe804300, 0xbe824302, - 0xbe844304, 0xbe864306, - 0x80f8c078, 0xf430403a, - 0xf0000000, 0xbf89fc07, - 0x80fd907d, 0xbf800000, - 0xbe804300, 0xbe824302, - 0xbe844304, 0xbe864306, - 0xbe884308, 0xbe8a430a, - 0xbe8c430c, 0xbe8e430e, - 0xbf06807d, 0xbfa1fff0, - 0xb980f801, 0x00000000, - 0xbfbd0000, 0xb8f83b05, - 0x80788178, 0xbf0d9972, - 0xbfa20002, 0x84788978, - 0xbfa00001, 0x84788a78, - 0xb8ee1e06, 0x846e8a6e, - 0x80786e78, 0x8078ff78, - 0x00000200, 0xbef600ff, - 0x01000000, 0xf4205bfa, + 0xf4205bfa, 0xf0000000, + 0x80788478, 0xf4205b3a, 0xf0000000, 0x80788478, - 0xf4205b3a, 0xf0000000, - 0x80788478, 0xf4205b7a, + 0xf4205b7a, 0xf0000000, + 0x80788478, 0xf4205c3a, 0xf0000000, 0x80788478, - 0xf4205c3a, 0xf0000000, - 0x80788478, 0xf4205c7a, + 0xf4205c7a, 0xf0000000, + 0x80788478, 0xf4205eba, 0xf0000000, 0x80788478, - 0xf4205eba, 0xf0000000, - 0x80788478, 0xf4205efa, + 0xf4205efa, 0xf0000000, + 0x80788478, 0xf4205e7a, 0xf0000000, 0x80788478, - 0xf4205e7a, 0xf0000000, - 0x80788478, 0xf4205cfa, + 0xf4205cfa, 0xf0000000, + 0x80788478, 0xf4205bba, 0xf0000000, 0x80788478, + 0xbf89fc07, 0xb96ef814, 0xf4205bba, 0xf0000000, 0x80788478, 0xbf89fc07, - 0xb96ef814, 0xf4205bba, - 0xf0000000, 0x80788478, - 0xbf89fc07, 0xb96ef815, - 0xbefd006f, 0xbefe0070, - 0xbeff0071, 0x8b6f7bff, - 0x000003ff, 0xb96f4803, - 0x8b6f7bff, 0xfffff800, - 0x856f8b6f, 0xb96fa2c3, - 0xb973f801, 0xb8ee3b05, - 0x806e816e, 0xbf0d9972, - 0xbfa20002, 0x846e896e, - 0xbfa00001, 0x846e8a6e, - 0xb8ef1e06, 0x846f8a6f, - 0x806e6f6e, 0x806eff6e, - 0x00000200, 0x806e746e, - 0x826f8075, 0x8b6fff6f, - 0x0000ffff, 0xf4085c37, - 0xf8000050, 0xf4085d37, - 0xf8000060, 0xf4005e77, - 0xf8000074, 0xbf89fc07, - 0x8b6dff6d, 0x0000ffff, - 0x8bfe7e7e, 0x8bea6a6a, + 0xb96ef815, 0xbefd006f, + 0xbefe0070, 0xbeff0071, + 0x8b6f7bff, 0x000003ff, + 0xb96f4803, 0x8b6f7bff, + 0xfffff800, 0x856f8b6f, + 0xb96fa2c3, 0xb973f801, + 0xb8ee3b05, 0x806e816e, + 0xbf0d9972, 0xbfa20002, + 0x846e896e, 0xbfa00001, + 0x846e8a6e, 0xb8ef1e06, + 0x846f8a6f, 0x806e6f6e, + 0x806eff6e, 0x00000200, + 0x806e746e, 0x826f8075, + 0x8b6fff6f, 0x0000ffff, + 0xf4085c37, 0xf8000050, + 0xf4085d37, 0xf8000060, + 0xf4005e77, 0xf8000074, + 0xbf89fc07, 0x8b6dff6d, + 0x0000ffff, 0x8bfe7e7e, + 0x8bea6a6a, 0xb8eef802, + 0xbf0d866e, 0xbfa20002, + 0xb97af802, 0xbe80486c, 0xb97af802, 0xbe804a6c, 0xbfb00000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm index 250ab007399b..0f81670f6f9c 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm @@ -43,12 +43,14 @@ #define HAVE_XNACK (ASIC_FAMILY < CHIP_SIENNA_CICHLID) #define HAVE_SENDMSG_RTN (ASIC_FAMILY >= CHIP_PLUM_BONITO) #define HAVE_BUFFER_LDS_LOAD (ASIC_FAMILY < CHIP_PLUM_BONITO) +#define SW_SA_TRAP (ASIC_FAMILY >= CHIP_PLUM_BONITO) var SINGLE_STEP_MISSED_WORKAROUND = 1 //workaround for lost MODE.DEBUG_EN exception when SAVECTX raised var SQ_WAVE_STATUS_SPI_PRIO_MASK = 0x00000006 var SQ_WAVE_STATUS_HALT_MASK = 0x2000 var SQ_WAVE_STATUS_ECC_ERR_MASK = 0x20000 +var SQ_WAVE_STATUS_TRAP_EN_SHIFT = 6 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SHIFT = 12 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SIZE = 9 @@ -183,6 +185,13 @@ L_SKIP_RESTORE: s_getreg_b32 s_save_trapsts, hwreg(HW_REG_TRAPSTS) +#if SW_SA_TRAP + // If ttmp1[31] is set then trap may occur early. + // Spin wait until SAVECTX exception is raised. + s_bitcmp1_b32 s_save_pc_hi, 31 + s_cbranch_scc1 L_CHECK_SAVE +#endif + s_and_b32 ttmp2, s_save_status, SQ_WAVE_STATUS_HALT_MASK s_cbranch_scc0 L_NOT_HALTED @@ -1061,8 +1070,20 @@ L_RESTORE_HWREG: s_and_b32 s_restore_pc_hi, s_restore_pc_hi, 0x0000ffff //pc[47:32] //Do it here in order not to affect STATUS s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 + +#if SW_SA_TRAP + // If traps are enabled then return to the shader with PRIV=0. + // Otherwise retain PRIV=1 for subsequent context save requests. + s_getreg_b32 s_restore_tmp, hwreg(HW_REG_STATUS) + s_bitcmp1_b32 s_restore_tmp, SQ_WAVE_STATUS_TRAP_EN_SHIFT + s_cbranch_scc1 L_RETURN_WITHOUT_PRIV + s_setreg_b32 hwreg(HW_REG_STATUS), s_restore_status // SCC is included, which is changed by previous salu + s_setpc_b64 [s_restore_pc_lo, s_restore_pc_hi] +L_RETURN_WITHOUT_PRIV: +#endif + s_setreg_b32 hwreg(HW_REG_STATUS), s_restore_status // SCC is included, which is changed by previous salu s_rfe_b64 s_restore_pc_lo //Return to the main shader program and resume execution L_END_PGM: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 56f7307c21d2..5feaba6a77de 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1584,6 +1584,8 @@ static int kfd_ioctl_smi_events(struct file *filep, return kfd_smi_event_open(pdd->dev, &args->anon_fd); } +#if IS_ENABLED(CONFIG_HSA_AMD_SVM) + static int kfd_ioctl_set_xnack_mode(struct file *filep, struct kfd_process *p, void *data) { @@ -1594,22 +1596,29 @@ static int kfd_ioctl_set_xnack_mode(struct file *filep, if (args->xnack_enabled >= 0) { if (!list_empty(&p->pqm.queues)) { pr_debug("Process has user queues running\n"); - mutex_unlock(&p->mutex); - return -EBUSY; + r = -EBUSY; + goto out_unlock; } - if (args->xnack_enabled && !kfd_process_xnack_mode(p, true)) + + if (p->xnack_enabled == args->xnack_enabled) + goto out_unlock; + + if (args->xnack_enabled && !kfd_process_xnack_mode(p, true)) { r = -EPERM; - else - p->xnack_enabled = args->xnack_enabled; + goto out_unlock; + } + + r = svm_range_switch_xnack_reserve_mem(p, args->xnack_enabled); } else { args->xnack_enabled = p->xnack_enabled; } + +out_unlock: mutex_unlock(&p->mutex); return r; } -#if IS_ENABLED(CONFIG_HSA_AMD_SVM) static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data) { struct kfd_ioctl_svm_args *args = data; @@ -1629,6 +1638,11 @@ static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data) return r; } #else +static int kfd_ioctl_set_xnack_mode(struct file *filep, + struct kfd_process *p, void *data) +{ + return -EPERM; +} static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data) { return -EPERM; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index e83725a28106..ecb4c3abc629 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -205,6 +205,8 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, } queue_input.is_kfd_process = 1; + queue_input.is_aql_queue = (q->properties.format == KFD_QUEUE_FORMAT_AQL); + queue_input.queue_size = q->properties.queue_size >> 2; queue_input.paging = false; queue_input.tba_addr = qpd->tba_addr; @@ -1240,6 +1242,24 @@ static void init_interrupts(struct device_queue_manager *dqm) dqm->dev->kfd2kgd->init_interrupts(dqm->dev->adev, i); } +static void init_sdma_bitmaps(struct device_queue_manager *dqm) +{ + unsigned int num_sdma_queues = + min_t(unsigned int, sizeof(dqm->sdma_bitmap)*8, + get_num_sdma_queues(dqm)); + unsigned int num_xgmi_sdma_queues = + min_t(unsigned int, sizeof(dqm->xgmi_sdma_bitmap)*8, + get_num_xgmi_sdma_queues(dqm)); + + if (num_sdma_queues) + dqm->sdma_bitmap = GENMASK_ULL(num_sdma_queues-1, 0); + if (num_xgmi_sdma_queues) + dqm->xgmi_sdma_bitmap = GENMASK_ULL(num_xgmi_sdma_queues-1, 0); + + dqm->sdma_bitmap &= ~get_reserved_sdma_queues_bitmap(dqm); + pr_info("sdma_bitmap: %llx\n", dqm->sdma_bitmap); +} + static int initialize_nocpsch(struct device_queue_manager *dqm) { int pipe, queue; @@ -1268,11 +1288,7 @@ static int initialize_nocpsch(struct device_queue_manager *dqm) memset(dqm->vmid_pasid, 0, sizeof(dqm->vmid_pasid)); - dqm->sdma_bitmap = ~0ULL >> (64 - get_num_sdma_queues(dqm)); - dqm->sdma_bitmap &= ~(get_reserved_sdma_queues_bitmap(dqm)); - pr_info("sdma_bitmap: %llx\n", dqm->sdma_bitmap); - - dqm->xgmi_sdma_bitmap = ~0ULL >> (64 - get_num_xgmi_sdma_queues(dqm)); + init_sdma_bitmaps(dqm); return 0; } @@ -1450,9 +1466,6 @@ static int set_sched_resources(struct device_queue_manager *dqm) static int initialize_cpsch(struct device_queue_manager *dqm) { - uint64_t num_sdma_queues; - uint64_t num_xgmi_sdma_queues; - pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm)); mutex_init(&dqm->lock_hidden); @@ -1461,24 +1474,10 @@ static int initialize_cpsch(struct device_queue_manager *dqm) dqm->active_cp_queue_count = 0; dqm->gws_queue_count = 0; dqm->active_runlist = false; - - num_sdma_queues = get_num_sdma_queues(dqm); - if (num_sdma_queues >= BITS_PER_TYPE(dqm->sdma_bitmap)) - dqm->sdma_bitmap = ULLONG_MAX; - else - dqm->sdma_bitmap = (BIT_ULL(num_sdma_queues) - 1); - - dqm->sdma_bitmap &= ~(get_reserved_sdma_queues_bitmap(dqm)); - pr_info("sdma_bitmap: %llx\n", dqm->sdma_bitmap); - - num_xgmi_sdma_queues = get_num_xgmi_sdma_queues(dqm); - if (num_xgmi_sdma_queues >= BITS_PER_TYPE(dqm->xgmi_sdma_bitmap)) - dqm->xgmi_sdma_bitmap = ULLONG_MAX; - else - dqm->xgmi_sdma_bitmap = (BIT_ULL(num_xgmi_sdma_queues) - 1); - INIT_WORK(&dqm->hw_exception_work, kfd_process_hw_exception); + init_sdma_bitmaps(dqm); + return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c index a6fcbeeb7428..0d53f6067422 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c @@ -350,11 +350,11 @@ static void event_interrupt_wq_v11(struct kfd_dev *dev, print_sq_intr_info_inst(context_id0, context_id1); sq_int_priv = REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, PRIV); - if (sq_int_priv /*&& (kfd_set_dbg_ev_from_interrupt(dev, pasid, + /*if (sq_int_priv && (kfd_set_dbg_ev_from_interrupt(dev, pasid, KFD_CTXID0_DOORBELL_ID(context_id0), KFD_CTXID0_TRAP_CODE(context_id0), - NULL, 0))*/) - return; + NULL, 0))) + return;*/ break; case SQ_INTERRUPT_WORD_ENCODING_ERROR: print_sq_intr_info_error(context_id0, context_id1); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 7522bf2d2f57..c70c026c9a93 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -898,7 +898,7 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } if (!mmget_not_zero(svm_bo->eviction_fence->mm)) { - pr_debug("addr 0x%lx of process mm is detroyed\n", addr); + pr_debug("addr 0x%lx of process mm is destroyed\n", addr); return VM_FAULT_SIGBUS; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index b8e14c2cc295..26b53b6d673e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -126,6 +126,10 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se4 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se5 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se6 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se7 = 0xFFFFFFFF; m->cp_hqd_persistent_state = CP_HQD_PERSISTENT_STATE__PRELOAD_REQ_MASK | 0x55 << CP_HQD_PERSISTENT_STATE__PRELOAD_SIZE__SHIFT; @@ -177,14 +181,6 @@ static int load_mqd(struct mqd_manager *mm, void *mqd, return r; } -static int hiq_load_mqd_kiq(struct mqd_manager *mm, void *mqd, - uint32_t pipe_id, uint32_t queue_id, - struct queue_properties *p, struct mm_struct *mms) -{ - return mm->dev->kfd2kgd->hiq_mqd_load(mm->dev->adev, mqd, pipe_id, - queue_id, p->doorbell_off); -} - static void update_mqd(struct mqd_manager *mm, void *mqd, struct queue_properties *q, struct mqd_update_info *minfo) @@ -256,31 +252,6 @@ static uint32_t read_doorbell_id(void *mqd) return m->queue_doorbell_id0; } -static int destroy_mqd(struct mqd_manager *mm, void *mqd, - enum kfd_preempt_type type, - unsigned int timeout, uint32_t pipe_id, - uint32_t queue_id) -{ - return mm->dev->kfd2kgd->hqd_destroy - (mm->dev->adev, mqd, type, timeout, - pipe_id, queue_id); -} - -static void free_mqd(struct mqd_manager *mm, void *mqd, - struct kfd_mem_obj *mqd_mem_obj) -{ - kfd_gtt_sa_free(mm->dev, mqd_mem_obj); -} - -static bool is_occupied(struct mqd_manager *mm, void *mqd, - uint64_t queue_address, uint32_t pipe_id, - uint32_t queue_id) -{ - return mm->dev->kfd2kgd->hqd_is_occupied( - mm->dev->adev, queue_address, - pipe_id, queue_id); -} - static int get_wave_state(struct mqd_manager *mm, void *mqd, void __user *ctl_stack, u32 *ctl_stack_used_size, @@ -349,15 +320,6 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, mm->update_mqd(mm, m, q, NULL); } -static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, - uint32_t pipe_id, uint32_t queue_id, - struct queue_properties *p, struct mm_struct *mms) -{ - return mm->dev->kfd2kgd->hqd_sdma_load(mm->dev->adev, mqd, - (uint32_t __user *)p->write_ptr, - mms); -} - #define SDMA_RLC_DUMMY_DEFAULT 0xf static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, @@ -389,25 +351,6 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, q->is_active = QUEUE_IS_ACTIVE(*q); } -/* - * * preempt type here is ignored because there is only one way - * * to preempt sdma queue - */ -static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd, - enum kfd_preempt_type type, - unsigned int timeout, uint32_t pipe_id, - uint32_t queue_id) -{ - return mm->dev->kfd2kgd->hqd_sdma_destroy(mm->dev->adev, mqd, timeout); -} - -static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd, - uint64_t queue_address, uint32_t pipe_id, - uint32_t queue_id) -{ - return mm->dev->kfd2kgd->hqd_sdma_is_occupied(mm->dev->adev, mqd); -} - #if defined(CONFIG_DEBUG_FS) static int debugfs_show_mqd(struct seq_file *m, void *data) @@ -445,11 +388,11 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, pr_debug("%s@%i\n", __func__, __LINE__); mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd; - mqd->free_mqd = free_mqd; + mqd->free_mqd = kfd_free_mqd_cp; mqd->load_mqd = load_mqd; mqd->update_mqd = update_mqd; - mqd->destroy_mqd = destroy_mqd; - mqd->is_occupied = is_occupied; + mqd->destroy_mqd = kfd_destroy_mqd_cp; + mqd->is_occupied = kfd_is_occupied_cp; mqd->mqd_size = sizeof(struct v11_compute_mqd); mqd->get_wave_state = get_wave_state; #if defined(CONFIG_DEBUG_FS) @@ -462,10 +405,10 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, mqd->allocate_mqd = allocate_hiq_mqd; mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd_hiq_sdma; - mqd->load_mqd = hiq_load_mqd_kiq; + mqd->load_mqd = kfd_hiq_load_mqd_kiq; mqd->update_mqd = update_mqd; - mqd->destroy_mqd = destroy_mqd; - mqd->is_occupied = is_occupied; + mqd->destroy_mqd = kfd_destroy_mqd_cp; + mqd->is_occupied = kfd_is_occupied_cp; mqd->mqd_size = sizeof(struct v11_compute_mqd); #if defined(CONFIG_DEBUG_FS) mqd->debugfs_show_mqd = debugfs_show_mqd; @@ -476,11 +419,11 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, case KFD_MQD_TYPE_DIQ: mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd_hiq; - mqd->free_mqd = free_mqd; + mqd->free_mqd = kfd_free_mqd_cp; mqd->load_mqd = load_mqd; mqd->update_mqd = update_mqd; - mqd->destroy_mqd = destroy_mqd; - mqd->is_occupied = is_occupied; + mqd->destroy_mqd = kfd_destroy_mqd_cp; + mqd->is_occupied = kfd_is_occupied_cp; mqd->mqd_size = sizeof(struct v11_compute_mqd); #if defined(CONFIG_DEBUG_FS) mqd->debugfs_show_mqd = debugfs_show_mqd; @@ -491,10 +434,10 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, mqd->allocate_mqd = allocate_sdma_mqd; mqd->init_mqd = init_mqd_sdma; mqd->free_mqd = free_mqd_hiq_sdma; - mqd->load_mqd = load_mqd_sdma; + mqd->load_mqd = kfd_load_mqd_sdma; mqd->update_mqd = update_mqd_sdma; - mqd->destroy_mqd = destroy_mqd_sdma; - mqd->is_occupied = is_occupied_sdma; + mqd->destroy_mqd = kfd_destroy_mqd_sdma; + mqd->is_occupied = kfd_is_occupied_sdma; mqd->mqd_size = sizeof(struct v11_sdma_mqd); #if defined(CONFIG_DEBUG_FS) mqd->debugfs_show_mqd = debugfs_show_mqd_sdma; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index cf5b4005534c..f5913ba22174 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -278,7 +278,7 @@ static void svm_range_free(struct svm_range *prange, bool update_mem_usage) svm_range_free_dma_mappings(prange); if (update_mem_usage && !p->xnack_enabled) { - pr_debug("unreserve mem limit: %lld\n", size); + pr_debug("unreserve prange 0x%p size: 0x%llx\n", prange, size); amdgpu_amdkfd_unreserve_mem_limit(NULL, size, KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); } @@ -2956,6 +2956,64 @@ out: return r; } +int +svm_range_switch_xnack_reserve_mem(struct kfd_process *p, bool xnack_enabled) +{ + struct svm_range *prange, *pchild; + uint64_t reserved_size = 0; + uint64_t size; + int r = 0; + + pr_debug("switching xnack from %d to %d\n", p->xnack_enabled, xnack_enabled); + + mutex_lock(&p->svms.lock); + + list_for_each_entry(prange, &p->svms.list, list) { + svm_range_lock(prange); + list_for_each_entry(pchild, &prange->child_list, child_list) { + size = (pchild->last - pchild->start + 1) << PAGE_SHIFT; + if (xnack_enabled) { + amdgpu_amdkfd_unreserve_mem_limit(NULL, size, + KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); + } else { + r = amdgpu_amdkfd_reserve_mem_limit(NULL, size, + KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); + if (r) + goto out_unlock; + reserved_size += size; + } + } + + size = (prange->last - prange->start + 1) << PAGE_SHIFT; + if (xnack_enabled) { + amdgpu_amdkfd_unreserve_mem_limit(NULL, size, + KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); + } else { + r = amdgpu_amdkfd_reserve_mem_limit(NULL, size, + KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); + if (r) + goto out_unlock; + reserved_size += size; + } +out_unlock: + svm_range_unlock(prange); + if (r) + break; + } + + if (r) + amdgpu_amdkfd_unreserve_mem_limit(NULL, reserved_size, + KFD_IOC_ALLOC_MEM_FLAGS_USERPTR); + else + /* Change xnack mode must be inside svms lock, to avoid race with + * svm_range_deferred_list_work unreserve memory in parallel. + */ + p->xnack_enabled = xnack_enabled; + + mutex_unlock(&p->svms.lock); + return r; +} + void svm_range_list_fini(struct kfd_process *p) { struct svm_range *prange; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 012c53729516..7a33b93f9df6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -203,6 +203,7 @@ void svm_range_list_lock_and_flush_work(struct svm_range_list *svms, struct mm_s void svm_range_bo_unref_async(struct svm_range_bo *svm_bo); void svm_range_set_max_pages(struct amdgpu_device *adev); +int svm_range_switch_xnack_reserve_mem(struct kfd_process *p, bool xnack_enabled); #else diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5da2a1d97b81..4c73727e0b7d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -90,6 +90,8 @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_plane_helper.h> +#include <acpi/video.h> + #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" @@ -4038,6 +4040,13 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) amdgpu_dm_update_backlight_caps(dm, dm->num_of_edps); dm->brightness[dm->num_of_edps] = AMDGPU_MAX_BL_LEVEL; + if (!acpi_video_backlight_use_native()) { + drm_info(adev_to_drm(dm->adev), "Skipping amdgpu DM backlight registration\n"); + /* Try registering an ACPI video backlight device instead. */ + acpi_video_register_backlight(); + return; + } + props.max_brightness = AMDGPU_MAX_BL_LEVEL; props.brightness = AMDGPU_MAX_BL_LEVEL; props.type = BACKLIGHT_RAW; @@ -4739,7 +4748,7 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev, plane_info->visible = true; plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE; - plane_info->layer_index = 0; + plane_info->layer_index = plane_state->normalized_zpos; ret = fill_plane_color_attributes(plane_state, plane_info->format, &plane_info->color_space); @@ -4807,7 +4816,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, dc_plane_state->global_alpha = plane_info.global_alpha; dc_plane_state->global_alpha_value = plane_info.global_alpha_value; dc_plane_state->dcc = plane_info.dcc; - dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0 + dc_plane_state->layer_index = plane_info.layer_index; dc_plane_state->flip_int_enabled = true; /* @@ -9460,6 +9469,14 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } } + /* + * DC consults the zpos (layer_index in DC terminology) to determine the + * hw plane on which to enable the hw cursor (see + * `dcn10_can_pipe_disable_cursor`). By now, all modified planes are in + * atomic state, so call drm helper to normalize zpos. + */ + drm_atomic_normalize_zpos(dev, state); + /* Remove exiting planes if they are modified */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ret = dm_update_plane_state(dc, state, plane, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index b8077fcd4651..f0b01c8dc4a6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -880,8 +880,17 @@ void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigne void dm_helpers_init_panel_settings( struct dc_context *ctx, - struct dc_panel_config *panel_config) -{ + struct dc_panel_config *panel_config, + struct dc_sink *sink) +{ + // Extra Panel Power Sequence + panel_config->pps.extra_t3_ms = sink->edid_caps.panel_patch.extra_t3_ms; + panel_config->pps.extra_t7_ms = sink->edid_caps.panel_patch.extra_t7_ms; + panel_config->pps.extra_delay_backlight_off = sink->edid_caps.panel_patch.extra_delay_backlight_off; + panel_config->pps.extra_post_t7_ms = 0; + panel_config->pps.extra_pre_t11_ms = 0; + panel_config->pps.extra_t12_ms = sink->edid_caps.panel_patch.extra_t12_ms; + panel_config->pps.extra_post_OUI_ms = 0; // Feature DSC panel_config->dsc.disable_dsc_edp = false; panel_config->dsc.force_dsc_edp_policy = 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index c8da18e45b0e..8ca10ab3dfc1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -170,7 +170,13 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) &stream, 1, ¶ms); - power_opt |= psr_power_opt_z10_static_screen; + /* + * Only enable static-screen optimizations for PSR1. For PSR SU, this + * causes vstartup interrupt issues, used by amdgpu_dm to send vblank + * events. + */ + if (link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) + power_opt |= psr_power_opt_z10_static_screen; return dc_link_set_psr_allow_active(link, &psr_enable, false, false, &power_opt); } diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 85ed0afb74a9..53b077b40d72 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -24,6 +24,7 @@ */ #include "dm_services.h" +#include "core_types.h" #include "ObjectID.h" #include "atomfirmware.h" @@ -850,7 +851,7 @@ static enum bp_result get_ss_info_v4_1( if (disp_cntl_tbl->dvi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_HDMI: ss_info->spread_spectrum_percentage = @@ -860,7 +861,7 @@ static enum bp_result get_ss_info_v4_1( if (disp_cntl_tbl->hdmi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; /* TODO LVDS not support anymore? */ case AS_SIGNAL_TYPE_DISPLAY_PORT: @@ -871,7 +872,7 @@ static enum bp_result get_ss_info_v4_1( if (disp_cntl_tbl->dp_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_GPU_PLL: /* atom_firmware: DAL only get data from dce_info table. @@ -885,7 +886,7 @@ static enum bp_result get_ss_info_v4_1( DATA_TABLES(smu_info)); if (!smu_info) return BP_RESULT_BADBIOSTABLE; - + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info->gpuclk_ss_percentage); ss_info->spread_spectrum_percentage = smu_info->waflclk_ss_percentage; ss_info->spread_spectrum_range = @@ -893,7 +894,7 @@ static enum bp_result get_ss_info_v4_1( if (smu_info->waflclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_XGMI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_XGMI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; default: result = BP_RESULT_UNSUPPORTED; @@ -930,6 +931,7 @@ static enum bp_result get_ss_info_v4_2( if (!smu_info) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info->gpuclk_ss_percentage); ss_info->type.STEP_AND_DELAY_INFO = false; ss_info->spread_percentage_divider = 1000; /* BIOS no longer uses target clock. Always enable for now */ @@ -944,7 +946,7 @@ static enum bp_result get_ss_info_v4_2( if (disp_cntl_tbl->dvi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_HDMI: ss_info->spread_spectrum_percentage = @@ -954,7 +956,7 @@ static enum bp_result get_ss_info_v4_2( if (disp_cntl_tbl->hdmi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; /* TODO LVDS not support anymore? */ case AS_SIGNAL_TYPE_DISPLAY_PORT: @@ -965,7 +967,7 @@ static enum bp_result get_ss_info_v4_2( if (smu_info->gpuclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_GPU_PLL: /* atom_firmware: DAL only get data from dce_info table. @@ -1015,7 +1017,7 @@ static enum bp_result get_ss_info_v4_5( if (disp_cntl_tbl->dvi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DVI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_HDMI: ss_info->spread_spectrum_percentage = @@ -1025,7 +1027,7 @@ static enum bp_result get_ss_info_v4_5( if (disp_cntl_tbl->hdmi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_DISPLAY_PORT: ss_info->spread_spectrum_percentage = @@ -1035,7 +1037,7 @@ static enum bp_result get_ss_info_v4_5( if (disp_cntl_tbl->dp_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ss_info->type.CENTER_MODE = true; - DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT: %d\n", ss_info->spread_spectrum_percentage); + DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT ss_percentage: %d\n", ss_info->spread_spectrum_percentage); break; case AS_SIGNAL_TYPE_GPU_PLL: /* atom_smu_info_v4_0 does not have fields for SS for SMU Display PLL anymore. @@ -1373,7 +1375,7 @@ static enum bp_result bios_parser_get_lttpr_interop( default: break; } - + DC_LOG_BIOS("DCE_INFO_CAPS_VBIOS_LTTPR_TRANSPARENT_ENABLE: %d tbl_revision.major = %d tbl_revision.minor = %d\n", *dce_caps, tbl_revision.major, tbl_revision.minor); return result; } @@ -1389,6 +1391,7 @@ static enum bp_result bios_parser_get_lttpr_caps( if (!DATA_TABLES(dce_info)) return BP_RESULT_UNSUPPORTED; + *dce_caps = 0; header = GET_IMAGE(struct atom_common_table_header, DATA_TABLES(dce_info)); get_atom_data_table_revision(header, &tbl_revision); @@ -1422,7 +1425,11 @@ static enum bp_result bios_parser_get_lttpr_caps( default: break; } - + DC_LOG_BIOS("DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE: %d tbl_revision.major = %d tbl_revision.minor = %d\n", *dce_caps, tbl_revision.major, tbl_revision.minor); + if (dcb->ctx->dc->config.force_bios_enable_lttpr && *dce_caps == 0) { + *dce_caps = 1; + DC_LOG_BIOS("DCE_INFO_CAPS_VBIOS_LTTPR_TRANSPARENT_ENABLE: forced enabled"); + } return result; } @@ -1860,7 +1867,7 @@ static enum bp_result get_firmware_info_v3_2( /* Vega12 */ smu_info_v3_2 = GET_IMAGE(struct atom_smu_info_v3_2, DATA_TABLES(smu_info)); - + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage); if (!smu_info_v3_2) return BP_RESULT_BADBIOSTABLE; @@ -1869,7 +1876,7 @@ static enum bp_result get_firmware_info_v3_2( /* Vega20 */ smu_info_v3_3 = GET_IMAGE(struct atom_smu_info_v3_3, DATA_TABLES(smu_info)); - + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage); if (!smu_info_v3_3) return BP_RESULT_BADBIOSTABLE; @@ -2011,7 +2018,7 @@ static enum bp_result get_firmware_info_v3_4( if (!smu_info_v3_5) return BP_RESULT_BADBIOSTABLE; - + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_5->gpuclk_ss_percentage); info->default_engine_clk = smu_info_v3_5->bootup_dcefclk_10khz * 10; break; @@ -2417,6 +2424,7 @@ static enum bp_result get_integrated_info_v11( info_v11 = GET_IMAGE(struct atom_integrated_system_info_v1_11, DATA_TABLES(integratedsysteminfo)); + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage); if (info_v11 == NULL) return BP_RESULT_BADBIOSTABLE; @@ -2631,6 +2639,7 @@ static enum bp_result get_integrated_info_v2_1( info_v2_1 = GET_IMAGE(struct atom_integrated_system_info_v2_1, DATA_TABLES(integratedsysteminfo)); + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage); if (info_v2_1 == NULL) return BP_RESULT_BADBIOSTABLE; @@ -2792,6 +2801,8 @@ static enum bp_result get_integrated_info_v2_2( info_v2_2 = GET_IMAGE(struct atom_integrated_system_info_v2_2, DATA_TABLES(integratedsysteminfo)); + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage); + if (info_v2_2 == NULL) return BP_RESULT_BADBIOSTABLE; @@ -2943,6 +2954,27 @@ static enum bp_result construct_integrated_info( default: return result; } + if (result == BP_RESULT_OK) { + + DC_LOG_BIOS("edp1:\n" + "\tedp_pwr_on_off_delay = %d\n" + "\tedp_pwr_on_vary_bl_to_blon = %d\n" + "\tedp_pwr_down_bloff_to_vary_bloff = %d\n" + "\tedp_bootup_bl_level = %d\n", + info->edp1_info.edp_pwr_on_off_delay, + info->edp1_info.edp_pwr_on_vary_bl_to_blon, + info->edp1_info.edp_pwr_down_bloff_to_vary_bloff, + info->edp1_info.edp_bootup_bl_level); + DC_LOG_BIOS("edp2:\n" + "\tedp_pwr_on_off_delayv = %d\n" + "\tedp_pwr_on_vary_bl_to_blon = %d\n" + "\tedp_pwr_down_bloff_to_vary_bloff = %d\n" + "\tedp_bootup_bl_level = %d\n", + info->edp2_info.edp_pwr_on_off_delay, + info->edp2_info.edp_pwr_on_vary_bl_to_blon, + info->edp2_info.edp_pwr_down_bloff_to_vary_bloff, + info->edp2_info.edp_bootup_bl_level); + } } if (result != BP_RESULT_OK) @@ -2968,13 +3000,22 @@ static enum bp_result construct_integrated_info( info->ext_disp_conn_info.path[i].ext_encoder_obj_id.id, info->ext_disp_conn_info.path[i].caps ); + if (info->ext_disp_conn_info.path[i].caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) + DC_LOG_BIOS("BIOS EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN on path %d\n", i); + else if (bp->base.ctx->dc->config.force_bios_fixed_vs) { + info->ext_disp_conn_info.path[i].caps |= EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN; + DC_LOG_BIOS("driver forced EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN on path %d\n", i); + } } - // Log the Checksum and Voltage Swing DC_LOG_BIOS("Integrated info table CHECKSUM: %d\n" "Integrated info table FIX_DP_VOLTAGE_SWING: %d\n", info->ext_disp_conn_info.checksum, info->ext_disp_conn_info.fixdpvoltageswing); + if (bp->base.ctx->dc->config.force_bios_fixed_vs && info->ext_disp_conn_info.fixdpvoltageswing == 0) { + info->ext_disp_conn_info.fixdpvoltageswing = bp->base.ctx->dc->config.force_bios_fixed_vs & 0xF; + DC_LOG_BIOS("driver forced fixdpvoltageswing = %d\n", info->ext_disp_conn_info.fixdpvoltageswing); + } } /* Sort voltage table from low to high*/ for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { @@ -3320,6 +3361,7 @@ static enum bp_result bios_get_board_layout_info( struct bios_parser *bp; static enum bp_result record_result; + unsigned int max_slots; const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, @@ -3336,8 +3378,14 @@ static enum bp_result bios_get_board_layout_info( } board_layout_info->num_of_slots = 0; + max_slots = MAX_BOARD_SLOTS; + + // Assume single slot on v1_5 + if (bp->object_info_tbl.revision.minor == 5) { + max_slots = 1; + } - for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + for (i = 0; i < max_slots; ++i) { record_result = get_bracket_layout_record(dcb, slot_index_to_vbios_id[i], &board_layout_info->slots[i]); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index d43258e3cd4f..c1eaf571407a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -104,7 +104,7 @@ static int dcn31_get_active_display_cnt_wa( return display_count; } -static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) +static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; int i; @@ -115,9 +115,10 @@ static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) if (pipe->top_pipe || pipe->prev_odm_pipe) continue; if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { - if (disable) + if (disable) { pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); - else + reset_sync_context_for_pipe(dc, context, i); + } else pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); } } @@ -216,11 +217,11 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { - dcn31_disable_otg_wa(clk_mgr_base, true); + dcn31_disable_otg_wa(clk_mgr_base, context, true); clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; dcn31_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn31_disable_otg_wa(clk_mgr_base, false); + dcn31_disable_otg_wa(clk_mgr_base, context, false); update_dispclk = true; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c index cd86aa912e3c..1131c6d73f6c 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c @@ -126,7 +126,7 @@ static int dcn314_get_active_display_cnt_wa( return display_count; } -static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) +static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; int i; @@ -136,12 +136,21 @@ static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) if (pipe->top_pipe || pipe->prev_odm_pipe) continue; - if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || - dc_is_virtual_signal(pipe->stream->signal))) { - if (disable) + if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { + struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; + + if (disable) { + if (stream_enc && stream_enc->funcs->disable_fifo) + pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); + pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); - else + reset_sync_context_for_pipe(dc, context, i); + } else { pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); + + if (stream_enc && stream_enc->funcs->enable_fifo) + pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); + } } } } @@ -240,11 +249,11 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { - dcn314_disable_otg_wa(clk_mgr_base, true); + dcn314_disable_otg_wa(clk_mgr_base, context, true); clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn314_disable_otg_wa(clk_mgr_base, false); + dcn314_disable_otg_wa(clk_mgr_base, context, false); update_dispclk = true; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c index 14071aef5eab..893991a0eb97 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c @@ -51,6 +51,9 @@ #define TO_CLK_MGR_DCN315(clk_mgr)\ container_of(clk_mgr, struct clk_mgr_dcn315, base) +#define UNSUPPORTED_DCFCLK 10000000 +#define MIN_DPP_DISP_CLK 100000 + static int dcn315_get_active_display_cnt_wa( struct dc *dc, struct dc_state *context) @@ -84,7 +87,7 @@ static int dcn315_get_active_display_cnt_wa( return display_count; } -static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) +static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; int i; @@ -96,9 +99,10 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) continue; if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || dc_is_virtual_signal(pipe->stream->signal))) { - if (disable) + if (disable) { pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); - else + reset_sync_context_for_pipe(dc, context, i); + } else pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); } } @@ -151,6 +155,9 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, } } + /* Lock pstate by requesting unsupported dcfclk if change is unsupported */ + if (!new_clocks->p_state_change_support) + new_clocks->dcfclk_khz = UNSUPPORTED_DCFCLK; if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; dcn315_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); @@ -164,10 +171,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. if (!IS_DIAG_DC(dc->ctx->dce_environment)) { - if (new_clocks->dppclk_khz < 100000) - new_clocks->dppclk_khz = 100000; - if (new_clocks->dispclk_khz < 100000) - new_clocks->dispclk_khz = 100000; + if (new_clocks->dppclk_khz < MIN_DPP_DISP_CLK) + new_clocks->dppclk_khz = MIN_DPP_DISP_CLK; + if (new_clocks->dispclk_khz < MIN_DPP_DISP_CLK) + new_clocks->dispclk_khz = MIN_DPP_DISP_CLK; } if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { @@ -180,12 +187,12 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { /* No need to apply the w/a if we haven't taken over from bios yet */ if (clk_mgr_base->clks.dispclk_khz) - dcn315_disable_otg_wa(clk_mgr_base, true); + dcn315_disable_otg_wa(clk_mgr_base, context, true); clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); if (clk_mgr_base->clks.dispclk_khz) - dcn315_disable_otg_wa(clk_mgr_base, false); + dcn315_disable_otg_wa(clk_mgr_base, context, false); update_dispclk = true; } @@ -280,7 +287,7 @@ static struct wm_table ddr5_wm_table = { { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 64.0, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -288,7 +295,7 @@ static struct wm_table ddr5_wm_table = { { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 64.0, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -296,7 +303,7 @@ static struct wm_table ddr5_wm_table = { { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 64.0, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -304,7 +311,7 @@ static struct wm_table ddr5_wm_table = { { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 64.0, + .pstate_latency_us = 129.0, .sr_exit_time_us = 11.5, .sr_enter_plus_exit_time_us = 14.5, .valid = true, @@ -561,8 +568,7 @@ static void dcn315_clk_mgr_helper_populate_bw_params( ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); bw_params->vram_type = bios_info->memory_type; bw_params->num_channels = bios_info->ma_channel_number; - if (!bw_params->num_channels) - bw_params->num_channels = 2; + bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4; for (i = 0; i < WM_SET_COUNT; i++) { bw_params->wm_table.entries[i].wm_inst = i; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c index 0cd3d2eb7ac7..187f5b27fdc8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c @@ -112,7 +112,7 @@ static int dcn316_get_active_display_cnt_wa( return display_count; } -static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) +static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; int i; @@ -124,9 +124,10 @@ static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) continue; if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || dc_is_virtual_signal(pipe->stream->signal))) { - if (disable) + if (disable) { pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); - else + reset_sync_context_for_pipe(dc, context, i); + } else pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); } } @@ -221,11 +222,11 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { - dcn316_disable_otg_wa(clk_mgr_base, true); + dcn316_disable_otg_wa(clk_mgr_base, context, true); clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn316_disable_otg_wa(clk_mgr_base, false); + dcn316_disable_otg_wa(clk_mgr_base, context, false); update_dispclk = true; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index c6785969eb1a..f0f3f66629cc 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -156,12 +156,14 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) { struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); unsigned int num_levels; + unsigned int num_dcfclk_levels, num_dtbclk_levels, num_dispclk_levels; memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks)); clk_mgr_base->clks.p_state_change_support = true; clk_mgr_base->clks.prev_p_state_change_support = true; clk_mgr_base->clks.fclk_prev_p_state_change_support = true; clk_mgr->smu_present = false; + clk_mgr->dpm_present = false; if (!clk_mgr_base->bw_params) return; @@ -179,6 +181,7 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) dcn32_init_single_clock(clk_mgr, PPCLK_DCFCLK, &clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, &num_levels); + num_dcfclk_levels = num_levels; /* SOCCLK */ dcn32_init_single_clock(clk_mgr, PPCLK_SOCCLK, @@ -189,11 +192,16 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) dcn32_init_single_clock(clk_mgr, PPCLK_DTBCLK, &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz, &num_levels); + num_dtbclk_levels = num_levels; /* DISPCLK */ dcn32_init_single_clock(clk_mgr, PPCLK_DISPCLK, &clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, &num_levels); + num_dispclk_levels = num_levels; + + if (num_dcfclk_levels && num_dtbclk_levels && num_dispclk_levels) + clk_mgr->dpm_present = true; if (clk_mgr_base->ctx->dc->debug.min_disp_clk_khz) { unsigned int i; @@ -658,6 +666,12 @@ static void dcn32_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base) &num_levels); clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1; + if (clk_mgr->dpm_present && !num_levels) + clk_mgr->dpm_present = false; + + if (!clk_mgr->dpm_present) + dcn32_patch_dpm_table(clk_mgr_base->bw_params); + DC_FP_START(); /* Refresh bounding box */ clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box( diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index bc7325831c91..258ba5a872b1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1184,11 +1184,7 @@ static void disable_vbios_mode_if_required( pipe->stream_res.pix_clk_params.requested_pix_clk_100hz; if (pix_clk_100hz != requested_pix_clk_100hz) { - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(dc->current_state, - pipe, TX_OFF_SYMCLK_OFF); - else - core_link_disable_stream(pipe); + core_link_disable_stream(pipe); pipe->stream->dpms_off = false; } } @@ -1205,7 +1201,7 @@ static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context) int count = 0; struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->plane_state) + if (!pipe->plane_state || pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) continue; /* Timeout 100 ms */ @@ -1754,6 +1750,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c context->stream_count == 0) dc->hwss.prepare_bandwidth(dc, context); + if (dc->debug.enable_double_buffered_dsc_pg_support) + dc->hwss.update_dsc_pg(dc, context, false); + disable_dangling_plane(dc, context); /* re-program planes for existing stream, in case we need to * free up plane resource for later use @@ -1844,6 +1843,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc->hwss.optimize_bandwidth(dc, context); } + if (dc->debug.enable_double_buffered_dsc_pg_support) + dc->hwss.update_dsc_pg(dc, context, true); + if (dc->ctx->dce_version >= DCE_VERSION_MAX) TRACE_DCN_CLOCK_STATE(&context->bw_ctx.bw.dcn.clk); else @@ -2007,6 +2009,9 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) dc->hwss.optimize_bandwidth(dc, context); + if (dc->debug.enable_double_buffered_dsc_pg_support) + dc->hwss.update_dsc_pg(dc, context, true); + dc->optimized_required = false; dc->wm_optimized_required = false; } @@ -2326,9 +2331,13 @@ static enum surface_update_type det_surface_update(const struct dc *dc, type = get_scaling_info_update_type(u); elevate_update_type(&overall_type, type); - if (u->flip_addr) + if (u->flip_addr) { update_flags->bits.addr_update = 1; - + if (u->flip_addr->address.tmz_surface != u->surface->address.tmz_surface) { + update_flags->bits.tmz_changed = 1; + elevate_update_type(&overall_type, UPDATE_TYPE_FULL); + } + } if (u->in_transfer_func) update_flags->bits.in_transfer_func_change = 1; @@ -2763,11 +2772,8 @@ static void copy_stream_update_to_stream(struct dc *dc, if (update->abm_level) stream->abm_level = *update->abm_level; - if (update->periodic_interrupt0) - stream->periodic_interrupt0 = *update->periodic_interrupt0; - - if (update->periodic_interrupt1) - stream->periodic_interrupt1 = *update->periodic_interrupt1; + if (update->periodic_interrupt) + stream->periodic_interrupt = *update->periodic_interrupt; if (update->gamut_remap) stream->gamut_remap_matrix = *update->gamut_remap; @@ -2987,13 +2993,8 @@ static void commit_planes_do_stream_update(struct dc *dc, if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) { - if (stream_update->periodic_interrupt0 && - dc->hwss.setup_periodic_interrupt) - dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE0); - - if (stream_update->periodic_interrupt1 && - dc->hwss.setup_periodic_interrupt) - dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE1); + if (stream_update->periodic_interrupt && dc->hwss.setup_periodic_interrupt) + dc->hwss.setup_periodic_interrupt(dc, pipe_ctx); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || @@ -3061,11 +3062,7 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->dpms_off) { if (*stream_update->dpms_off) { - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(dc->current_state, - pipe_ctx, TX_OFF_SYMCLK_ON); - else - core_link_disable_stream(pipe_ctx); + core_link_disable_stream(pipe_ctx); /* for dpms, keep acquired resources*/ if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only) pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); @@ -3075,12 +3072,7 @@ static void commit_planes_do_stream_update(struct dc *dc, } else { if (get_seamless_boot_stream_count(context) == 0) dc->hwss.prepare_bandwidth(dc, dc->current_state); - - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(dc->current_state, - pipe_ctx, TX_ON_SYMCLK_ON); - else - core_link_enable_stream(dc->current_state, pipe_ctx); + core_link_enable_stream(dc->current_state, pipe_ctx); } } @@ -3211,6 +3203,9 @@ static void commit_planes_for_stream(struct dc *dc, if (get_seamless_boot_stream_count(context) == 0) dc->hwss.prepare_bandwidth(dc, context); + if (dc->debug.enable_double_buffered_dsc_pg_support) + dc->hwss.update_dsc_pg(dc, context, false); + context_clock_trace(dc, context); } @@ -3534,11 +3529,59 @@ static void commit_planes_for_stream(struct dc *dc, } } +/* Determines if the incoming context requires a applying transition state with unnecessary + * pipe splitting and ODM disabled, due to hardware limitations. In a case where + * the OPP associated with an MPCC might change due to plane additions, this function + * returns true. + */ +static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc, + struct dc_stream_state *stream, + int surface_count, + bool *is_plane_addition) +{ + + struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream); + bool force_minimal_pipe_splitting = false; + + *is_plane_addition = false; + + if (cur_stream_status && + dc->current_state->stream_count > 0 && + dc->debug.pipe_split_policy != MPC_SPLIT_AVOID) { + /* determine if minimal transition is required due to MPC*/ + if (surface_count > 0) { + if (cur_stream_status->plane_count > surface_count) { + force_minimal_pipe_splitting = true; + } else if (cur_stream_status->plane_count < surface_count) { + force_minimal_pipe_splitting = true; + *is_plane_addition = true; + } + } + } + + if (cur_stream_status && + dc->current_state->stream_count == 1 && + dc->debug.enable_single_display_2to1_odm_policy) { + /* determine if minimal transition is required due to dynamic ODM*/ + if (surface_count > 0) { + if (cur_stream_status->plane_count > 2 && cur_stream_status->plane_count > surface_count) { + force_minimal_pipe_splitting = true; + } else if (surface_count > 2 && cur_stream_status->plane_count < surface_count) { + force_minimal_pipe_splitting = true; + *is_plane_addition = true; + } + } + } + + return force_minimal_pipe_splitting; +} + static bool commit_minimal_transition_state(struct dc *dc, struct dc_state *transition_base_context) { struct dc_state *transition_context = dc_create_state(dc); - enum pipe_split_policy tmp_policy; + enum pipe_split_policy tmp_mpc_policy; + bool temp_dynamic_odm_policy; enum dc_status ret = DC_ERROR_UNEXPECTED; unsigned int i, j; @@ -3546,10 +3589,13 @@ static bool commit_minimal_transition_state(struct dc *dc, return false; if (!dc->config.is_vmin_only_asic) { - tmp_policy = dc->debug.pipe_split_policy; + tmp_mpc_policy = dc->debug.pipe_split_policy; dc->debug.pipe_split_policy = MPC_SPLIT_AVOID; } + temp_dynamic_odm_policy = dc->debug.enable_single_display_2to1_odm_policy; + dc->debug.enable_single_display_2to1_odm_policy = false; + dc_resource_state_copy_construct(transition_base_context, transition_context); //commit minimal state @@ -3570,20 +3616,22 @@ static bool commit_minimal_transition_state(struct dc *dc, ret = dc_commit_state_no_check(dc, transition_context); } - //always release as dc_commit_state_no_check retains in good case + /*always release as dc_commit_state_no_check retains in good case*/ dc_release_state(transition_context); - //restore previous pipe split policy + /*restore previous pipe split and odm policy*/ if (!dc->config.is_vmin_only_asic) - dc->debug.pipe_split_policy = tmp_policy; + dc->debug.pipe_split_policy = tmp_mpc_policy; + + dc->debug.enable_single_display_2to1_odm_policy = temp_dynamic_odm_policy; if (ret != DC_OK) { - //this should never happen + /*this should never happen*/ BREAK_TO_DEBUGGER(); return false; } - //force full surface update + /*force full surface update*/ for (i = 0; i < dc->current_state->stream_count; i++) { for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF; @@ -3606,24 +3654,14 @@ bool dc_update_planes_and_stream(struct dc *dc, * cause underflow. Apply stream configuration with minimal pipe * split first to avoid unsupported transitions for active pipes. */ - bool force_minimal_pipe_splitting = false; - bool is_plane_addition = false; - - struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream); + bool force_minimal_pipe_splitting; + bool is_plane_addition; - if (cur_stream_status && - dc->current_state->stream_count > 0 && - dc->debug.pipe_split_policy != MPC_SPLIT_AVOID) { - /* determine if minimal transition is required */ - if (surface_count > 0) { - if (cur_stream_status->plane_count > surface_count) { - force_minimal_pipe_splitting = true; - } else if (cur_stream_status->plane_count < surface_count) { - force_minimal_pipe_splitting = true; - is_plane_addition = true; - } - } - } + force_minimal_pipe_splitting = could_mpcc_tree_change_for_active_pipes( + dc, + stream, + surface_count, + &is_plane_addition); /* on plane addition, minimal state is the current one */ if (force_minimal_pipe_splitting && is_plane_addition && @@ -3640,7 +3678,7 @@ bool dc_update_planes_and_stream(struct dc *dc, &context)) return false; - /* on plane addition, minimal state is the new one */ + /* on plane removal, minimal state is the new one */ if (force_minimal_pipe_splitting && !is_plane_addition) { if (!commit_minimal_transition_state(dc, context)) { dc_release_state(context); @@ -4027,7 +4065,7 @@ struct dc_sink *dc_link_add_remote_sink( * Treat device as no EDID device if EDID * parsing fails */ - if (edid_status != EDID_OK) { + if (edid_status != EDID_OK && edid_status != EDID_PARTIAL_VALID) { dc_sink->dc_edid.length = 0; dm_error("Bad EDID, status%d!\n", edid_status); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 4bb78e356ebd..3d19fb92333b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -848,20 +848,13 @@ static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason bool reset_cur_dp_mst_topology(struct dc_link *link) { - bool result = false; DC_LOGGER_INIT(link->ctx->logger); LINK_INFO("link=%d, mst branch is now Disconnected\n", link->link_index); revert_dpia_mst_dsc_always_on_wa(link); - result = dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); - - link->mst_stream_alloc_table.stream_count = 0; - memset(link->mst_stream_alloc_table.stream_allocations, - 0, - sizeof(link->mst_stream_alloc_table.stream_allocations)); - return result; + return dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); } static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc, @@ -1315,7 +1308,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, if (link->connector_signal == SIGNAL_TYPE_EDP) { // Init dc_panel_config - dm_helpers_init_panel_settings(dc_ctx, &link->panel_config); + dm_helpers_init_panel_settings(dc_ctx, &link->panel_config, sink); // Override dc_panel_config if system has specific settings dm_helpers_override_panel_settings(dc_ctx, &link->panel_config); } @@ -1984,7 +1977,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, int i; bool apply_seamless_boot_optimization = false; uint32_t bl_oled_enable_delay = 50; // in ms - const uint32_t post_oui_delay = 30; // 30ms + uint32_t post_oui_delay = 30; // 30ms /* Reduce link bandwidth between failed link training attempts. */ bool do_fallback = false; @@ -2031,8 +2024,10 @@ static enum dc_status enable_link_dp(struct dc_state *state, // during mode switch we do DP_SET_POWER off then on, and OUI is lost dpcd_set_source_specific_data(link); - if (link->dpcd_sink_ext_caps.raw != 0) + if (link->dpcd_sink_ext_caps.raw != 0) { + post_oui_delay += link->panel_config.pps.extra_post_OUI_ms; msleep(post_oui_delay); + } // similarly, mode switch can cause loss of cable ID dpcd_write_cable_id_to_dprx(link); @@ -2644,9 +2639,8 @@ static void disable_link(struct dc_link *link, const struct link_resource *link_ dp_set_fec_ready(link, link_res, false); } } - } else { - if (signal != SIGNAL_TYPE_VIRTUAL) - link->link_enc->funcs->disable_output(link->link_enc, signal); + } else if (signal != SIGNAL_TYPE_VIRTUAL) { + link->dc->hwss.disable_link_output(link, link_res, signal); } if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { @@ -2668,6 +2662,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) bool is_over_340mhz = false; bool is_vga_mode = (stream->timing.h_addressable == 640) && (stream->timing.v_addressable == 480); + struct dc *dc = pipe_ctx->stream->ctx->dc; if (stream->phy_pix_clk == 0) stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10; @@ -2707,11 +2702,12 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) display_color_depth = COLOR_DEPTH_888; - link->link_enc->funcs->enable_tmds_output( - link->link_enc, + dc->hwss.enable_tmds_link_output( + link, + &pipe_ctx->link_res, + pipe_ctx->stream->signal, pipe_ctx->clock_source->id, display_color_depth, - pipe_ctx->stream->signal, stream->phy_pix_clk); if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) @@ -2722,15 +2718,16 @@ static void enable_link_lvds(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dc *dc = stream->ctx->dc; if (stream->phy_pix_clk == 0) stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10; memset(&stream->link->cur_link_settings, 0, sizeof(struct dc_link_settings)); - - link->link_enc->funcs->enable_lvds_output( - link->link_enc, + dc->hwss.enable_lvds_link_output( + link, + &pipe_ctx->link_res, pipe_ctx->clock_source->id, stream->phy_pix_clk); @@ -3568,6 +3565,35 @@ static void update_mst_stream_alloc_table( work_table[i]; } +static void remove_stream_from_alloc_table( + struct dc_link *link, + struct stream_encoder *dio_stream_enc, + struct hpo_dp_stream_encoder *hpo_dp_stream_enc) +{ + int i = 0; + struct link_mst_stream_allocation_table *table = + &link->mst_stream_alloc_table; + + if (hpo_dp_stream_enc) { + for (; i < table->stream_count; i++) + if (hpo_dp_stream_enc == table->stream_allocations[i].hpo_dp_stream_enc) + break; + } else { + for (; i < table->stream_count; i++) + if (dio_stream_enc == table->stream_allocations[i].stream_enc) + break; + } + + if (i < table->stream_count) { + i++; + for (; i < table->stream_count; i++) + table->stream_allocations[i-1] = table->stream_allocations[i]; + memset(&table->stream_allocations[table->stream_count-1], 0, + sizeof(struct link_mst_stream_allocation)); + table->stream_count--; + } +} + static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp) { const uint32_t VCP_Y_PRECISION = 1000; @@ -3985,26 +4011,32 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) &empty_link_settings, avg_time_slots_per_mtp); - /* TODO: which component is responsible for remove payload table? */ if (mst_mode) { + /* when link is in mst mode, reply on mst manager to remove + * payload + */ if (dm_helpers_dp_mst_write_payload_allocation_table( stream->ctx, stream, &proposed_table, - false)) { + false)) update_mst_stream_alloc_table( - link, - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.hpo_dp_stream_enc, - &proposed_table); - } - else { - DC_LOG_WARNING("Failed to update" - "MST allocation table for" - "pipe idx:%d\n", - pipe_ctx->pipe_idx); - } + link, + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc, + &proposed_table); + else + DC_LOG_WARNING("Failed to update" + "MST allocation table for" + "pipe idx:%d\n", + pipe_ctx->pipe_idx); + } else { + /* when link is no longer in mst mode (mst hub unplugged), + * remove payload with default dc logic + */ + remove_stream_from_alloc_table(link, pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc); } DC_LOG_MST("%s" diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index d01d2eeed813..651231387043 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -35,6 +35,8 @@ #include "dc_link_ddc.h" #include "dce/dce_aux.h" #include "dmub/inc/dmub_cmd.h" +#include "link_dpcd.h" +#include "include/dal_asic_id.h" #define DC_LOGGER_INIT(logger) @@ -683,6 +685,21 @@ bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, bool result = false; struct ddc *ddc_pin = ddc->ddc_pin; + if ((ddc->link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + !ddc->link->dc->debug.disable_fixed_vs_aux_timeout_wa && + ASICREV_IS_YELLOW_CARP(ddc->ctx->asic_id.hw_internal_rev)) { + /* Fixed VS workaround for AUX timeout */ + const uint32_t fixed_vs_address = 0xF004F; + const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc}; + + core_link_write_dpcd(ddc->link, + fixed_vs_address, + fixed_vs_data, + sizeof(fixed_vs_data)); + + timeout = 3072; + } + /* Do not try to access nonexistent DDC pin. */ if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY) return true; @@ -691,6 +708,7 @@ bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout); result = true; } + return result; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index e2413d2908c9..c57df45e83ff 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -526,9 +526,9 @@ uint8_t dc_dp_initialize_scrambling_data_symbols( return disable_scrabled_data_symbols; } -static inline bool is_repeater(struct dc_link *link, uint32_t offset) +static inline bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset) { - return (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); + return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); } static void dpcd_set_lt_pattern_and_lane_settings( @@ -545,7 +545,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( bool edp_workaround = false; /* TODO link_prop.INTERNAL */ dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; - if (is_repeater(link, offset)) + if (is_repeater(lt_settings, offset)) dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); @@ -561,7 +561,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET] = dpcd_pattern.raw; - if (is_repeater(link, offset)) { + if (is_repeater(lt_settings, offset)) { DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", __func__, offset, @@ -584,7 +584,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( lt_settings->dpcd_lane_settings, size_in_bytes); - if (is_repeater(link, offset)) { + if (is_repeater(lt_settings, offset)) { if (dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" @@ -873,7 +873,7 @@ enum dc_status dp_get_lane_status_and_lane_adjust( uint32_t lane; enum dc_status status; - if (is_repeater(link, offset)) { + if (is_repeater(link_training_setting, offset)) { lane01_status_address = DP_LANE0_1_STATUS_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); @@ -906,7 +906,7 @@ enum dc_status dp_get_lane_status_and_lane_adjust( ln_align->raw = dpcd_buf[2]; - if (is_repeater(link, offset)) { + if (is_repeater(link_training_setting, offset)) { DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", __func__, @@ -954,7 +954,7 @@ enum dc_status dpcd_set_lane_settings( lane0_set_address = DP_TRAINING_LANE0_SET; - if (is_repeater(link, offset)) + if (is_repeater(link_training_setting, offset)) lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); @@ -963,7 +963,7 @@ enum dc_status dpcd_set_lane_settings( (uint8_t *)(link_training_setting->dpcd_lane_settings), link_training_setting->link_settings.lane_count); - if (is_repeater(link, offset)) { + if (is_repeater(link_training_setting, offset)) { if (dp_get_link_encoding_format(&link_training_setting->link_settings) == DP_128b_132b_ENCODING) DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" @@ -1172,7 +1172,7 @@ static enum link_training_result perform_channel_equalization_sequence( /* Note: also check that TPS4 is a supported feature*/ tr_pattern = lt_settings->pattern_for_eq; - if (is_repeater(link, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) + if (is_repeater(lt_settings, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; dp_set_hw_training_pattern(link, link_res, tr_pattern, offset); @@ -1198,7 +1198,7 @@ static enum link_training_result perform_channel_equalization_sequence( /* 3. wait for receiver to lock-on*/ wait_time_microsec = lt_settings->eq_pattern_time; - if (is_repeater(link, offset)) + if (is_repeater(lt_settings, offset)) wait_time_microsec = dp_translate_training_aux_read_interval( link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); @@ -1469,7 +1469,6 @@ static inline void decide_8b_10b_training_settings( */ lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; - lt_settings->lttpr_mode = link->lttpr_mode; lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); @@ -1478,6 +1477,7 @@ static inline void decide_8b_10b_training_settings( lt_settings->should_set_fec_ready = true; lt_settings->disallow_per_lane_settings = true; lt_settings->always_match_dpcd_with_hw_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } @@ -1501,9 +1501,8 @@ static inline void decide_128b_132b_training_settings(struct dc_link *link, lt_settings->cds_pattern_time = 2500; lt_settings->cds_wait_time_limit = (dp_convert_to_count( link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; - lt_settings->lttpr_mode = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ? - LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_TRANSPARENT; lt_settings->disallow_per_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link); dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } @@ -1543,7 +1542,7 @@ static void override_training_settings( lt_settings->ffe_preset = overrides->ffe_preset; /* Override HW lane settings with BIOS forced values if present */ if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; lt_settings->always_match_dpcd_with_hw_lane_settings = false; @@ -1584,6 +1583,15 @@ static void override_training_settings( if (link->preferred_training_settings.fec_enable != NULL) lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; + + #if defined(CONFIG_DRM_AMD_DC_DCN) + /* Check DP tunnel LTTPR mode debug option. */ + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) + lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; + +#endif + dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); + } uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count) @@ -1649,7 +1657,7 @@ static enum dc_status configure_lttpr_mode_non_transparent( link->dpcd_caps.lttpr_caps.mode = repeater_mode; } - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__); @@ -2099,7 +2107,7 @@ static enum link_training_result dp_perform_8b_10b_link_training( /* 1. set link rate, lane count and spread. */ dpcd_set_link_settings(link, lt_settings); - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { /* 2. perform link training (set link training done * to false is done as well) @@ -2216,7 +2224,7 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq link->vendor_specific_lttpr_link_rate_wa = target_rate; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { /* 2. perform link training (set link training done * to false is done as well) @@ -2288,7 +2296,7 @@ static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( ASSERT(dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING); - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); return status; } @@ -2635,6 +2643,7 @@ enum link_training_result dc_link_dp_perform_link_training( link, link_settings, <_settings); + override_training_settings( link, &link->preferred_training_settings, @@ -2652,7 +2661,7 @@ enum link_training_result dc_link_dp_perform_link_training( * Per DP specs starting from here, DPTX device shall not issue * Non-LT AUX transactions inside training mode. */ - if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) + if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && encoding == DP_8b_10b_ENCODING) status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); else if (encoding == DP_8b_10b_ENCODING) status = dp_perform_8b_10b_link_training(link, link_res, <_settings); @@ -2758,8 +2767,14 @@ bool perform_link_training_with_retries( skip_video_pattern); /* Transmit idle pattern once training successful. */ - if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) + if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) { dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + /* Update verified link settings to current one + * Because DPIA LT might fallback to lower link setting. + */ + link->verified_link_cap.link_rate = link->cur_link_settings.link_rate; + link->verified_link_cap.lane_count = link->cur_link_settings.lane_count; + } } else { status = dc_link_dp_perform_link_training(link, &pipe_ctx->link_res, @@ -3080,7 +3095,7 @@ struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) * account for lttpr repeaters cap * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). */ - if (link->lttpr_mode != LTTPR_MODE_NON_LTTPR) { + if (dp_is_lttpr_present(link)) { if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; lttpr_max_link_rate = get_lttpr_max_link_rate(link); @@ -3234,7 +3249,7 @@ static bool dp_verify_link_cap( cur_link_settings = max_link_settings; /* Grant extended timeout request */ - if ((link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (link->dpcd_caps.lttpr_caps.max_ext_timeout > 0)) { + if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) { uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80; core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant)); @@ -4095,8 +4110,13 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) &dpcd_lane_adjustment[0].raw, sizeof(dpcd_lane_adjustment)); + /* prepare link training settings */ + link_training_settings.link_settings = link->cur_link_settings; + + link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link->cur_link_settings); + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) + link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) dp_fixed_vs_pe_read_lane_adjust( link, link_training_settings.dpcd_lane_settings); @@ -4203,9 +4223,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) test_pattern_size); } - /* prepare link training settings */ - link_training_settings.link_settings = link->cur_link_settings; - for (lane = 0; lane < (unsigned int)(link->cur_link_settings.lane_count); lane++) { @@ -4518,25 +4535,15 @@ void dc_link_dp_handle_link_loss(struct dc_link *link) for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && - pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) { - if (link->dc->hwss.update_phy_state) - link->dc->hwss.update_phy_state(link->dc->current_state, - pipe_ctx, TX_OFF_SYMCLK_OFF); - else - core_link_disable_stream(pipe_ctx); - } + pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) + core_link_disable_stream(pipe_ctx); } for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && - pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) { - if (link->dc->hwss.update_phy_state) - link->dc->hwss.update_phy_state(link->dc->current_state, - pipe_ctx, TX_ON_SYMCLK_ON); - else - core_link_enable_stream(link->dc->current_state, pipe_ctx); - } + pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) + core_link_enable_stream(link->dc->current_state, pipe_ctx); } } @@ -5025,125 +5032,136 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } -/* Logic to determine LTTPR mode */ -static void determine_lttpr_mode(struct dc_link *link) +bool dp_retrieve_lttpr_cap(struct dc_link *link) { - bool allow_lttpr_non_transparent_mode = 0; - bool vbios_lttpr_enable = link->dc->caps.vbios_lttpr_enable; + uint8_t lttpr_dpcd_data[8]; + enum dc_status status = DC_ERROR_UNEXPECTED; + bool is_lttpr_present = false; + + /* Logic to determine LTTPR support*/ bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; - if (link->ctx->dc->debug.lttpr_mode_override != 0) { - link->lttpr_mode = link->ctx->dc->debug.lttpr_mode_override; - return; - } + if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support) + return false; - if ((link->dc->config.allow_lttpr_non_transparent_mode.bits.DP2_0 && - link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)) { - allow_lttpr_non_transparent_mode = 1; - } else if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A && - !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { - allow_lttpr_non_transparent_mode = 1; + /* By reading LTTPR capability, RX assumes that we will enable + * LTTPR extended aux timeout if LTTPR is present. + */ + status = core_link_read_dpcd(link, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + lttpr_dpcd_data, + sizeof(lttpr_dpcd_data)); + + link->dpcd_caps.lttpr_caps.revision.raw = + lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_link_rate = + lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.phy_repeater_cnt = + lttpr_dpcd_data[DP_PHY_REPEATER_CNT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_lane_count = + lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.mode = + lttpr_dpcd_data[DP_PHY_REPEATER_MODE - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_ext_timeout = + lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw = + lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw = + lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + /* If this chip cap is set, at least one retimer must exist in the chain + * Override count to 1 if we receive a known bad count (0 or an invalid value) + */ + if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && + (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) { + ASSERT(0); + link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80; } - link->lttpr_mode = LTTPR_MODE_NON_LTTPR; - if (vbios_lttpr_enable && vbios_lttpr_interop) - link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT; - else if (!vbios_lttpr_enable && vbios_lttpr_interop) { - if (allow_lttpr_non_transparent_mode) - link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT; - else - link->lttpr_mode = LTTPR_MODE_TRANSPARENT; - } else if (!vbios_lttpr_enable && !vbios_lttpr_interop) { - if (!allow_lttpr_non_transparent_mode || !link->dc->caps.extended_aux_timeout_support) - link->lttpr_mode = LTTPR_MODE_NON_LTTPR; - else - link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT; - } + /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ + is_lttpr_present = dp_is_lttpr_present(link); -#if defined(CONFIG_DRM_AMD_DC_DCN) - /* Check DP tunnel LTTPR mode debug option. */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && - link->dc->debug.dpia_debug.bits.force_non_lttpr) - link->lttpr_mode = LTTPR_MODE_NON_LTTPR; -#endif + if (is_lttpr_present) + CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); + + return is_lttpr_present; } -bool dp_retrieve_lttpr_cap(struct dc_link *link) +bool dp_is_lttpr_present(struct dc_link *link) { - uint8_t lttpr_dpcd_data[8]; - enum dc_status status = DC_ERROR_UNEXPECTED; - bool is_lttpr_present = false; + return (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 && + link->dpcd_caps.lttpr_caps.max_lane_count > 0 && + link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && + link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); +} - memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data)); +enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting) +{ + enum dp_link_encoding encoding = dp_get_link_encoding_format(link_setting); - /* Logic to determine LTTPR mode*/ - determine_lttpr_mode(link); + if (encoding == DP_8b_10b_ENCODING) + return dp_decide_8b_10b_lttpr_mode(link); + else if (encoding == DP_128b_132b_ENCODING) + return dp_decide_128b_132b_lttpr_mode(link); - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT || link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - !link->dc->debug.disable_fixed_vs_aux_timeout_wa) { - /* Fixed VS workaround for AUX timeout */ - const uint32_t fixed_vs_address = 0xF004F; - const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc}; + ASSERT(0); + return LTTPR_MODE_NON_LTTPR; +} - core_link_write_dpcd( - link, - fixed_vs_address, - fixed_vs_data, - sizeof(fixed_vs_data)); - } +void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override) +{ + if (!dp_is_lttpr_present(link)) + return; - /* By reading LTTPR capability, RX assumes that we will enable - * LTTPR extended aux timeout if LTTPR is present. - */ - status = core_link_read_dpcd( - link, - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, - lttpr_dpcd_data, - sizeof(lttpr_dpcd_data)); - - link->dpcd_caps.lttpr_caps.revision.raw = - lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_link_rate = - lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.phy_repeater_cnt = - lttpr_dpcd_data[DP_PHY_REPEATER_CNT - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_lane_count = - lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.mode = - lttpr_dpcd_data[DP_PHY_REPEATER_MODE - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_ext_timeout = - lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw = - lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw = - lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ - is_lttpr_present = (link->dpcd_caps.lttpr_caps.max_lane_count > 0 && - link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && - link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); - if (is_lttpr_present) { - CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); - configure_lttpr_mode_transparent(link); - } else - link->lttpr_mode = LTTPR_MODE_NON_LTTPR; + if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) { + *override = LTTPR_MODE_TRANSPARENT; + } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) { + *override = LTTPR_MODE_NON_TRANSPARENT; + } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) { + *override = LTTPR_MODE_NON_LTTPR; } - return is_lttpr_present; +} + +enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link) +{ + bool is_lttpr_present = dp_is_lttpr_present(link); + bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable; + bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware; + + if (!is_lttpr_present) + return LTTPR_MODE_NON_LTTPR; + + if (vbios_lttpr_aware) { + if (vbios_lttpr_force_non_transparent) + return LTTPR_MODE_NON_TRANSPARENT; + else + return LTTPR_MODE_TRANSPARENT; + } + + if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A && + link->dc->caps.extended_aux_timeout_support) + return LTTPR_MODE_NON_TRANSPARENT; + + return LTTPR_MODE_NON_LTTPR; +} + +enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link) +{ + return dp_is_lttpr_present(link) ? LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_NON_LTTPR; } static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id) @@ -5205,13 +5223,16 @@ static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout uint64_t current_ts = 0; uint64_t time_taken_ms = 0; enum dc_connection_type type = dc_connection_none; + bool lttpr_present; + bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; - determine_lttpr_mode(link); + lttpr_present = dp_is_lttpr_present(link) || + (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support); /* Issue an AUX read to test DPRX responsiveness. If LTTPR is supported the first read is expected to * be to determine LTTPR capabilities. Otherwise trying to read power state should be an innocuous AUX read. */ - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT || link->lttpr_mode == LTTPR_MODE_TRANSPARENT) + if (lttpr_present) status = core_link_read_dpcd( link, DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, @@ -5341,6 +5362,10 @@ static bool retrieve_link_cap(struct dc_link *link) } is_lttpr_present = dp_retrieve_lttpr_cap(link); + + if (is_lttpr_present) + configure_lttpr_mode_transparent(link); + /* Read DP tunneling information. */ status = dpcd_get_tunneling_device_data(link); @@ -6092,7 +6117,7 @@ bool dc_link_dp_set_test_pattern( /* Set DPCD Lane Settings before running test pattern */ if (p_link_settings != NULL) { if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { dp_fixed_vs_pe_set_retimer_lane_settings( link, p_link_settings->dpcd_lane_settings, @@ -7069,68 +7094,16 @@ void dp_enable_link_phy( enum clock_source_id clock_source, const struct dc_link_settings *link_settings) { - struct dc *dc = link->ctx->dc; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct pipe_ctx *pipes = - link->dc->current_state->res_ctx.pipe_ctx; - struct clock_source *dp_cs = - link->dc->res_pool->dp_clock_source; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - unsigned int i; - - if (link->connector_signal == SIGNAL_TYPE_EDP) { - if (!link->dc->config.edp_no_power_sequencing) - link->dc->hwss.edp_power_control(link, true); - link->dc->hwss.edp_wait_for_hpd_ready(link, true); - } - - /* If the current pixel clock source is not DTO(happens after - * switching from HDMI passive dongle to DP on the same connector), - * switch the pixel clock source to DTO. - */ - for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream != NULL && - pipes[i].stream->link == link) { - if (pipes[i].clock_source != NULL && - pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { - pipes[i].clock_source = dp_cs; - pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz = - pipes[i].stream->timing.pix_clk_100hz; - pipes[i].clock_source->funcs->program_pix_clk( - pipes[i].clock_source, - &pipes[i].stream_res.pix_clk_params, - dp_get_link_encoding_format(link_settings), - &pipes[i].pll_settings); - } - } - } - link->cur_link_settings = *link_settings; - - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { - if (dc->clk_mgr->funcs->notify_link_rate_change) - dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); - } - - if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - - if (link_hwss->ext.enable_dp_link_output) - link_hwss->ext.enable_dp_link_output(link, link_res, signal, - clock_source, link_settings); - - if (dmcu != NULL && dmcu->funcs->unlock_phy) - dmcu->funcs->unlock_phy(dmcu); - - dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); + link->dc->hwss.enable_dp_link_output(link, link_res, signal, + clock_source, link_settings); dp_receiver_power_ctrl(link, true); } void edp_add_delay_for_T9(struct dc_link *link) { - if (link->local_sink && - link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0) - udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000); + if (link && link->panel_config.pps.extra_delay_backlight_off > 0) + udelay(link->panel_config.pps.extra_delay_backlight_off * 1000); } bool edp_receiver_ready_T9(struct dc_link *link) @@ -7186,9 +7159,8 @@ bool edp_receiver_ready_T7(struct dc_link *link) } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms } - if (link->local_sink && - link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0) - udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000); + if (link && link->panel_config.pps.extra_t7_ms > 0) + udelay(link->panel_config.pps.extra_t7_ms * 1000); return result; } @@ -7197,29 +7169,11 @@ void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_ enum signal_type signal) { struct dc *dc = link->ctx->dc; - struct dmcu *dmcu = dc->res_pool->dmcu; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); if (!link->wa_flags.dp_keep_receiver_powered) dp_receiver_power_ctrl(link, false); - if (signal == SIGNAL_TYPE_EDP) { - if (link->dc->hwss.edp_backlight_control) - link->dc->hwss.edp_backlight_control(link, false); - if (link_hwss->ext.disable_dp_link_output) - link_hwss->ext.disable_dp_link_output(link, link_res, signal); - link->dc->hwss.edp_power_control(link, false); - } else { - if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - if (link_hwss->ext.disable_dp_link_output) - link_hwss->ext.disable_dp_link_output(link, link_res, signal); - if (dmcu != NULL && dmcu->funcs->unlock_phy) - dmcu->funcs->unlock_phy(dmcu); - } - - dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); - + dc->hwss.disable_link_output(link, link_res, signal); /* Clear current link setting.*/ memset(&link->cur_link_settings, 0, sizeof(link->cur_link_settings)); @@ -7285,7 +7239,7 @@ void dp_set_hw_lane_settings( { const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - if ((link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset)) + if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset)) return; if (link_hwss->ext.set_dp_lane_settings) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c index 468e39589ed8..74e36b34d3f7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c @@ -115,12 +115,14 @@ static enum link_training_result dpia_configure_link( DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n", __func__, link->link_id.enum_id - ENUM_ID_1, - link->lttpr_mode); + lt_settings->lttpr_mode); dp_decide_training_settings(link, link_setting, lt_settings); + dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); + status = dpcd_configure_channel_coding(link, lt_settings); if (status != DC_OK && link->is_hpd_pending) return LINK_TRAINING_ABORT; @@ -178,7 +180,7 @@ static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type, switch (type) { case DPIA_SET_CFG_SET_LINK: - data.set_link.mode = link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0; + data.set_link.mode = lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0; break; case DPIA_SET_CFG_SET_PHY_TEST_MODE: break; @@ -553,7 +555,7 @@ static enum link_training_result dpia_training_cr_phase( { enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop); else result = dpia_training_cr_transparent(link, link_res, lt_settings); @@ -830,7 +832,7 @@ static enum link_training_result dpia_training_eq_phase( { enum link_training_result result; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop); else result = dpia_training_eq_transparent(link, link_res, lt_settings); @@ -870,13 +872,14 @@ static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop) * @param hop The Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_end(struct dc_link *link, + struct link_training_settings *lt_settings, uint32_t hop) { enum link_training_result result = LINK_TRAINING_SUCCESS; uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */ enum dc_status status; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); if (hop == repeater_cnt) { /* DPTX-to-DPIA */ @@ -916,7 +919,7 @@ static enum link_training_result dpia_training_end(struct dc_link *link, link->link_id.enum_id - ENUM_ID_1, hop, result, - link->lttpr_mode); + lt_settings->lttpr_mode); return result; } @@ -928,7 +931,9 @@ static enum link_training_result dpia_training_end(struct dc_link *link, * @param link DPIA link being trained. * @param hop The Hop in display path. DPRX = 0. */ -static void dpia_training_abort(struct dc_link *link, uint32_t hop) +static void dpia_training_abort(struct dc_link *link, + struct link_training_settings *lt_settings, + uint32_t hop) { uint8_t data = 0; uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET; @@ -936,7 +941,7 @@ static void dpia_training_abort(struct dc_link *link, uint32_t hop) DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n", __func__, link->link_id.enum_id - ENUM_ID_1, - link->lttpr_mode, + lt_settings->lttpr_mode, link->is_hpd_pending); /* Abandon clean-up if sink unplugged. */ @@ -964,12 +969,16 @@ enum link_training_result dc_link_dpia_perform_link_training( uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */ int8_t repeater_id; /* Current hop. */ + struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in + + lt_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link_settings); + /* Configure link as prescribed in link_setting and set LTTPR mode. */ result = dpia_configure_link(link, link_res, link_setting, <_settings); if (result != LINK_TRAINING_SUCCESS) return result; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) + if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); /* Train each hop in turn starting with the one closest to DPTX. @@ -987,7 +996,7 @@ enum link_training_result dc_link_dpia_perform_link_training( break; /* Stop training hop. */ - result = dpia_training_end(link, repeater_id); + result = dpia_training_end(link, <_settings, repeater_id); if (result != LINK_TRAINING_SUCCESS) break; } @@ -1001,9 +1010,9 @@ enum link_training_result dc_link_dpia_perform_link_training( msleep(5); result = dp_check_link_loss_status(link, <_settings); } else if (result == LINK_TRAINING_ABORT) { - dpia_training_abort(link, repeater_id); + dpia_training_abort(link, <_settings, repeater_id); } else { - dpia_training_end(link, repeater_id); + dpia_training_end(link, <_settings, repeater_id); } return result; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 29f27e3fe3ac..8ee0d946bb2f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -3581,6 +3581,23 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, } } +void reset_sync_context_for_pipe(const struct dc *dc, + struct dc_state *context, + uint8_t pipe_idx) +{ + int i; + struct pipe_ctx *pipe_ctx_reset; + + /* reset the otg sync context for the pipe and its slave pipes if any */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe_ctx_reset = &context->res_ctx.pipe_ctx[i]; + + if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) && + IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx)) + SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i); + } +} + uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) { /* TODO - get transmitter to phy idx mapping from DMUB */ @@ -3645,3 +3662,25 @@ const struct link_hwss *get_link_hwss(const struct dc_link *link, else return get_virtual_link_hwss(); } + +bool is_h_timing_divisible_by_2(struct dc_stream_state *stream) +{ + bool divisible = false; + uint16_t h_blank_start = 0; + uint16_t h_blank_end = 0; + + if (stream) { + h_blank_start = stream->timing.h_total - stream->timing.h_front_porch; + h_blank_end = h_blank_start - stream->timing.h_addressable; + + /* HTOTAL, Hblank start/end, and Hsync start/end all must be + * divisible by 2 in order for the horizontal timing params + * to be considered divisible by 2. Hsync start is always 0. + */ + divisible = (stream->timing.h_total % 2 == 0) && + (h_blank_start % 2 == 0) && + (h_blank_end % 2 == 0) && + (stream->timing.h_sync_width % 2 == 0); + } + return divisible; +}
\ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 0c85ab5933b4..ae13887756bf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -30,6 +30,7 @@ #include "resource.h" #include "ipp.h" #include "timing_generator.h" +#include "dc_dmub_srv.h" #define DC_LOGGER dc->ctx->logger @@ -519,7 +520,7 @@ bool dc_stream_remove_writeback(struct dc *dc, } /* remove writeback info for disabled writeback pipes from stream */ - for (i = 0, j = 0; i < stream->num_wb_info; i++) { + for (i = 0, j = 0; i < stream->num_wb_info && j < MAX_DWB_PIPES; i++) { if (stream->writeback_info[i].wb_enabled) { if (i != j) /* trim the array */ diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 53b13beff0b2..2ecf36e6329b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.202" +#define DC_VER "3.2.205" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -406,6 +406,9 @@ struct dc_config { bool ignore_dpref_ss; bool enable_mipi_converter_optimization; bool use_default_clock_table; + bool force_bios_enable_lttpr; + uint8_t force_bios_fixed_vs; + }; enum visual_confirm { @@ -832,6 +835,8 @@ struct dc_debug_options { bool force_subvp_mclk_switch; bool allow_sw_cursor_fallback; unsigned int force_subvp_num_ways; + unsigned int force_mall_ss_num_ways; + bool alloc_extra_way_for_cursor; bool force_usr_allow; /* uses value at boot and disables switch */ bool disable_dtb_ref_clk_switch; @@ -845,6 +850,7 @@ struct dc_debug_options { bool use_legacy_soc_bb_mechanism; bool exit_idle_opt_for_cursor_updates; bool enable_single_display_2to1_odm_policy; + bool enable_double_buffered_dsc_pg_support; bool enable_dp_dig_pixel_rate_div_policy; enum lttpr_mode lttpr_mode_override; }; @@ -1116,6 +1122,7 @@ union surface_update_flags { uint32_t clock_change:1; uint32_t stereo_format_change:1; uint32_t lut_3d:1; + uint32_t tmz_changed:1; uint32_t full_update:1; } bits; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index df5ad02fc4b3..89d7d3fd3321 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -674,12 +674,28 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc, pipe_data->pipe_config.subvp_data.processing_delay_lines = div64_u64(((uint64_t)(dc->caps.subvp_fw_processing_delay_us) * ((uint64_t)phantom_timing->pix_clk_100hz * 100) + ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000)); + + if (subvp_pipe->bottom_pipe) { + pipe_data->pipe_config.subvp_data.main_split_pipe_index = subvp_pipe->bottom_pipe->pipe_idx; + } else if (subvp_pipe->next_odm_pipe) { + pipe_data->pipe_config.subvp_data.main_split_pipe_index = subvp_pipe->next_odm_pipe->pipe_idx; + } else { + pipe_data->pipe_config.subvp_data.main_split_pipe_index = 0; + } + // Find phantom pipe index based on phantom stream for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j]; if (phantom_pipe->stream == subvp_pipe->stream->mall_stream_config.paired_stream) { pipe_data->pipe_config.subvp_data.phantom_pipe_index = phantom_pipe->pipe_idx; + if (phantom_pipe->bottom_pipe) { + pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = phantom_pipe->bottom_pipe->pipe_idx; + } else if (phantom_pipe->next_odm_pipe) { + pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = phantom_pipe->next_odm_pipe->pipe_idx; + } else { + pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = 0; + } break; } } @@ -724,7 +740,9 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, if (!pipe->stream) continue; - if (pipe->plane_state && !pipe->top_pipe && + /* For SubVP pipe count, only count the top most (ODM / MPC) pipe + */ + if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) subvp_pipes[subvp_count++] = pipe; } @@ -737,7 +755,12 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, if (!pipe->stream) continue; + /* When populating subvp cmd info, only pass in the top most (ODM / MPC) pipe. + * Any ODM or MPC splits being used in SubVP will be handled internally in + * populate_subvp_cmd_pipe_info + */ if (pipe->plane_state && pipe->stream->mall_stream_config.paired_stream && + !pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE) { diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 9f5b47b9a83d..7e438345b1a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -85,6 +85,7 @@ void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, union dmub_inbox0 bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *dmub_oca); +void dc_dmub_setup_subvp_dmub_command(struct dc *dc, struct dc_state *context, bool enable); void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv); #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 3f64b3092692..bf5f9e2773bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -117,6 +117,22 @@ struct psr_settings { * Add a struct dc_panel_config under dc_link */ struct dc_panel_config { + // extra panel power sequence parameters + struct pps { + unsigned int extra_t3_ms; + unsigned int extra_t7_ms; + unsigned int extra_delay_backlight_off; + unsigned int extra_post_t7_ms; + unsigned int extra_pre_t11_ms; + unsigned int extra_t12_ms; + unsigned int extra_post_OUI_ms; + } pps; + // ABM + struct varib { + unsigned int varibright_feature_enable; + unsigned int def_varibright_level; + unsigned int abm_config_setting; + } varib; // edp DSC struct dsc { bool disable_dsc_edp; @@ -141,7 +157,6 @@ struct dc_link { bool link_state_valid; bool aux_access_disabled; bool sync_lt_in_progress; - enum lttpr_mode lttpr_mode; bool is_internal_display; /* TODO: Rename. Flag an endpoint as having a programmable mapping to a @@ -244,7 +259,7 @@ struct dc_link { struct gpio *hpd_gpio; enum dc_link_fec_state fec_state; struct dc_panel_config panel_config; - enum phy_state phy_state; + struct phy_state phy_state; }; const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 9fcf9dc5bce4..9e6025c98db9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -212,8 +212,7 @@ struct dc_stream_state { /* DMCU info */ unsigned int abm_level; - struct periodic_interrupt_config periodic_interrupt0; - struct periodic_interrupt_config periodic_interrupt1; + struct periodic_interrupt_config periodic_interrupt; /* from core_stream struct */ struct dc_context *ctx; @@ -281,8 +280,7 @@ struct dc_stream_update { struct dc_info_packet *hdr_static_metadata; unsigned int *abm_level; - struct periodic_interrupt_config *periodic_interrupt0; - struct periodic_interrupt_config *periodic_interrupt1; + struct periodic_interrupt_config *periodic_interrupt; struct dc_info_packet *vrr_infopacket; struct dc_info_packet *vsc_infopacket; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index 0df06740ec39..bec5e9f787fc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -393,17 +393,18 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, if (copy_settings_data->dsc_enable_status && link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, - sizeof(link->dpcd_caps.sink_dev_id_str))) + sizeof(DP_SINK_DEVICE_STR_ID_1))) link->psr_settings.force_ffu_mode = 1; else link->psr_settings.force_ffu_mode = 0; copy_settings_data->force_ffu_mode = link->psr_settings.force_ffu_mode; if (link->fec_state == dc_link_fec_enabled && + link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, - sizeof(link->dpcd_caps.sink_dev_id_str)) || + sizeof(DP_SINK_DEVICE_STR_ID_1)) || !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2, - sizeof(link->dpcd_caps.sink_dev_id_str)))) + sizeof(DP_SINK_DEVICE_STR_ID_2)))) copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 1; else copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 801206aed63a..d260eaa1509e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -722,7 +722,6 @@ void dce110_edp_wait_for_hpd_ready( struct dc_context *ctx = link->ctx; struct graphics_object_id connector = link->link_enc->connector; struct gpio *hpd; - struct dc_sink *sink = link->local_sink; bool edp_hpd_high = false; uint32_t time_elapsed = 0; uint32_t timeout = power_up ? @@ -755,9 +754,9 @@ void dce110_edp_wait_for_hpd_ready( return; } - if (sink != NULL) { - if (sink->edid_caps.panel_patch.extra_t3_ms > 0) { - int extra_t3_in_ms = sink->edid_caps.panel_patch.extra_t3_ms; + if (link != NULL) { + if (link->panel_config.pps.extra_t3_ms > 0) { + int extra_t3_in_ms = link->panel_config.pps.extra_t3_ms; msleep(extra_t3_in_ms); } @@ -842,7 +841,7 @@ void dce110_edp_power_control( /* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */ if (link->local_sink != NULL) remaining_min_edp_poweroff_time_ms += - link->local_sink->edid_caps.panel_patch.extra_t12_ms; + link->panel_config.pps.extra_t12_ms; /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */ if (dp_trace_get_edp_poweroff_timestamp(link) != 0) { @@ -946,7 +945,7 @@ void dce110_edp_wait_for_T12( current_ts, dp_trace_get_edp_poweroff_timestamp(link)), 1000000); - t12_duration += link->local_sink->edid_caps.panel_patch.extra_t12_ms; // Add extra T12 + t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12 if (time_since_edp_poweroff_ms < t12_duration) msleep(t12_duration - time_since_edp_poweroff_ms); @@ -965,6 +964,8 @@ void dce110_edp_backlight_control( struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; uint8_t panel_instance; + unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; + unsigned int post_T7_delay = OLED_POST_T7_DELAY; if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) != CONNECTOR_ID_EDP) { @@ -1043,8 +1044,10 @@ void dce110_edp_backlight_control( link_transmitter_control(ctx->dc_bios, &cntl); - if (enable && link->dpcd_sink_ext_caps.bits.oled) - msleep(OLED_POST_T7_DELAY); + if (enable && link->dpcd_sink_ext_caps.bits.oled) { + post_T7_delay += link->panel_config.pps.extra_post_t7_ms; + msleep(post_T7_delay); + } if (link->dpcd_sink_ext_caps.bits.oled || link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || @@ -1066,8 +1069,10 @@ void dce110_edp_backlight_control( DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); } - if (!enable && link->dpcd_sink_ext_caps.bits.oled) - msleep(OLED_PRE_T11_DELAY); + if (!enable && link->dpcd_sink_ext_caps.bits.oled) { + pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; + msleep(pre_T11_delay); + } } void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) @@ -1441,6 +1446,14 @@ static enum dc_status dce110_enable_stream_timing( return DC_ERROR_UNEXPECTED; } + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + pipe_ctx->stream_res.tg->funcs->program_timing( pipe_ctx->stream_res.tg, &stream->timing, @@ -1577,12 +1590,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( if (dc_is_dp_signal(pipe_ctx->stream->signal)) dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG); - if (!stream->dpms_off) { - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(context, pipe_ctx, TX_ON_SYMCLK_ON); - else - core_link_enable_stream(context, pipe_ctx); - } + if (!stream->dpms_off) + core_link_enable_stream(context, pipe_ctx); /* DCN3.1 FPGA Workaround * Need to enable HPO DP Stream Encoder before setting OTG master enable. @@ -2118,6 +2127,7 @@ static void dce110_reset_hw_ctx_wrap( BREAK_TO_DEBUGGER(); } pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); + pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; pipe_ctx_old->plane_res.mi->funcs->free_mem_input( pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); @@ -2996,6 +3006,124 @@ void dce110_set_pipe(struct pipe_ctx *pipe_ctx) abm->funcs->set_pipe(abm, otg_inst, panel_cntl->inst); } +void dce110_enable_lvds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock) +{ + link->link_enc->funcs->enable_lvds_output( + link->link_enc, + clock_source, + pixel_clock); + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; +} + +void dce110_enable_tmds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock) +{ + link->link_enc->funcs->enable_tmds_output( + link->link_enc, + clock_source, + color_depth, + signal, + pixel_clock); + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; +} + +void dce110_enable_dp_link_output( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings) +{ + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct pipe_ctx *pipes = + link->dc->current_state->res_ctx.pipe_ctx; + struct clock_source *dp_cs = + link->dc->res_pool->dp_clock_source; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + unsigned int i; + + + if (link->connector_signal == SIGNAL_TYPE_EDP) { + if (!link->dc->config.edp_no_power_sequencing) + link->dc->hwss.edp_power_control(link, true); + link->dc->hwss.edp_wait_for_hpd_ready(link, true); + } + + /* If the current pixel clock source is not DTO(happens after + * switching from HDMI passive dongle to DP on the same connector), + * switch the pixel clock source to DTO. + */ + + for (i = 0; i < MAX_PIPES; i++) { + if (pipes[i].stream != NULL && + pipes[i].stream->link == link) { + if (pipes[i].clock_source != NULL && + pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { + pipes[i].clock_source = dp_cs; + pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz = + pipes[i].stream->timing.pix_clk_100hz; + pipes[i].clock_source->funcs->program_pix_clk( + pipes[i].clock_source, + &pipes[i].stream_res.pix_clk_params, + dp_get_link_encoding_format(link_settings), + &pipes[i].pll_settings); + } + } + } + + if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { + if (dc->clk_mgr->funcs->notify_link_rate_change) + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); + } + + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + if (link_hwss->ext.enable_dp_link_output) + link_hwss->ext.enable_dp_link_output(link, link_res, signal, + clock_source, link_settings); + + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + + if (dmcu != NULL && dmcu->funcs->unlock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); +} + +void dce110_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_power_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); +} + static const struct hw_sequencer_funcs dce110_funcs = { .program_gamut_remap = program_gamut_remap, .program_output_csc = program_output_csc, @@ -3035,6 +3163,10 @@ static const struct hw_sequencer_funcs dce110_funcs = { .set_backlight_level = dce110_set_backlight_level, .set_abm_immediate_disable = dce110_set_abm_immediate_disable, .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, }; static const struct hwseq_private_funcs dce110_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index b6f3843d3d05..758f4b3b0087 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -90,6 +90,24 @@ bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, uint32_t frame_ramp); void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); void dce110_set_pipe(struct pipe_ctx *pipe_ctx); - +void dce110_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); +void dce110_enable_lvds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock); +void dce110_enable_tmds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock); +void dce110_enable_dp_link_output( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings); #endif /* __DC_HWSS_DCE110_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index f26e08032da0..72521749c01d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -899,6 +899,14 @@ enum dc_status dcn10_enable_stream_timing( return DC_ERROR_UNEXPECTED; } + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + pipe_ctx->stream_res.tg->funcs->program_timing( pipe_ctx->stream_res.tg, &stream->timing, @@ -1017,6 +1025,7 @@ static void dcn10_reset_back_end_for_pipe( if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, NULL); + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; } for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -3803,7 +3812,7 @@ void dcn10_calc_vupdate_position( { const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; int vline_int_offset_from_vupdate = - pipe_ctx->stream->periodic_interrupt0.lines_offset; + pipe_ctx->stream->periodic_interrupt.lines_offset; int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); int start_position; @@ -3828,18 +3837,10 @@ void dcn10_calc_vupdate_position( static void dcn10_cal_vline_position( struct dc *dc, struct pipe_ctx *pipe_ctx, - enum vline_select vline, uint32_t *start_line, uint32_t *end_line) { - enum vertical_interrupt_ref_point ref_point = INVALID_POINT; - - if (vline == VLINE0) - ref_point = pipe_ctx->stream->periodic_interrupt0.ref_point; - else if (vline == VLINE1) - ref_point = pipe_ctx->stream->periodic_interrupt1.ref_point; - - switch (ref_point) { + switch (pipe_ctx->stream->periodic_interrupt.ref_point) { case START_V_UPDATE: dcn10_calc_vupdate_position( dc, @@ -3848,7 +3849,9 @@ static void dcn10_cal_vline_position( end_line); break; case START_V_SYNC: - // Suppose to do nothing because vsync is 0; + // vsync is line 0 so start_line is just the requested line offset + *start_line = pipe_ctx->stream->periodic_interrupt.lines_offset; + *end_line = *start_line + 2; break; default: ASSERT(0); @@ -3858,24 +3861,15 @@ static void dcn10_cal_vline_position( void dcn10_setup_periodic_interrupt( struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum vline_select vline) + struct pipe_ctx *pipe_ctx) { struct timing_generator *tg = pipe_ctx->stream_res.tg; + uint32_t start_line = 0; + uint32_t end_line = 0; - if (vline == VLINE0) { - uint32_t start_line = 0; - uint32_t end_line = 0; - - dcn10_cal_vline_position(dc, pipe_ctx, vline, &start_line, &end_line); + dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); - tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); - - } else if (vline == VLINE1) { - pipe_ctx->stream_res.tg->funcs->setup_vertical_interrupt1( - tg, - pipe_ctx->stream->periodic_interrupt1.lines_offset); - } + tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); } void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 9ae07c77fdc0..0ef7bf7ddb75 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -175,8 +175,7 @@ void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); void dcn10_setup_periodic_interrupt( struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum vline_select vline); + struct pipe_ctx *pipe_ctx); enum dc_status dcn10_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index 10e613ec7d24..f2371c948822 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -82,6 +82,10 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .set_backlight_level = dce110_set_backlight_level, .set_abm_immediate_disable = dce110_set_abm_immediate_disable, .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .update_visual_confirm_color = dcn10_update_visual_confirm_color, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 294827906c69..ea7739255119 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -1393,6 +1393,12 @@ void optc1_read_otg_state(struct optc *optc1, REG_GET(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); + REG_GET(OTG_VERTICAL_INTERRUPT1_CONTROL, + OTG_VERTICAL_INTERRUPT1_INT_ENABLE, &s->vertical_interrupt1_en); + + REG_GET(OTG_VERTICAL_INTERRUPT1_POSITION, + OTG_VERTICAL_INTERRUPT1_LINE_START, &s->vertical_interrupt1_line); + REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 3fe5882ed018..6323ca6dc3b3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -583,6 +583,8 @@ struct dcn_otg_state { uint32_t underflow_occurred_status; uint32_t otg_enabled; uint32_t blank_enabled; + uint32_t vertical_interrupt1_en; + uint32_t vertical_interrupt1_line; uint32_t vertical_interrupt2_en; uint32_t vertical_interrupt2_line; }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 2b9d3e63191b..915a20461c77 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -274,6 +274,7 @@ struct dccg_registers { uint32_t DSCCLK2_DTO_PARAM; uint32_t DPSTREAMCLK_ROOT_GATE_DISABLE; uint32_t DPSTREAMCLK_GATE_DISABLE; + uint32_t DCCG_GATE_DISABLE_CNTL; uint32_t DCCG_GATE_DISABLE_CNTL2; uint32_t DCCG_GATE_DISABLE_CNTL3; uint32_t HDMISTREAMCLK0_DTO_PARAM; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h index cd2671161ef1..7ce64a3c1b02 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -445,226 +445,6 @@ type DSCRM_DSC_FORWARD_EN; \ type DSCRM_DSC_OPP_PIPE_SOURCE -#define DSC_REG_LIST_DCN314(id) \ - SRI(DSC_TOP_CONTROL, DSC_TOP, id),\ - SRI(DSC_DEBUG_CONTROL, DSC_TOP, id),\ - SRI(DSCC_CONFIG0, DSCC, id),\ - SRI(DSCC_CONFIG1, DSCC, id),\ - SRI(DSCC_STATUS, DSCC, id),\ - SRI(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id),\ - SRI(DSCC_PPS_CONFIG0, DSCC, id),\ - SRI(DSCC_PPS_CONFIG1, DSCC, id),\ - SRI(DSCC_PPS_CONFIG2, DSCC, id),\ - SRI(DSCC_PPS_CONFIG3, DSCC, id),\ - SRI(DSCC_PPS_CONFIG4, DSCC, id),\ - SRI(DSCC_PPS_CONFIG5, DSCC, id),\ - SRI(DSCC_PPS_CONFIG6, DSCC, id),\ - SRI(DSCC_PPS_CONFIG7, DSCC, id),\ - SRI(DSCC_PPS_CONFIG8, DSCC, id),\ - SRI(DSCC_PPS_CONFIG9, DSCC, id),\ - SRI(DSCC_PPS_CONFIG10, DSCC, id),\ - SRI(DSCC_PPS_CONFIG11, DSCC, id),\ - SRI(DSCC_PPS_CONFIG12, DSCC, id),\ - SRI(DSCC_PPS_CONFIG13, DSCC, id),\ - SRI(DSCC_PPS_CONFIG14, DSCC, id),\ - SRI(DSCC_PPS_CONFIG15, DSCC, id),\ - SRI(DSCC_PPS_CONFIG16, DSCC, id),\ - SRI(DSCC_PPS_CONFIG17, DSCC, id),\ - SRI(DSCC_PPS_CONFIG18, DSCC, id),\ - SRI(DSCC_PPS_CONFIG19, DSCC, id),\ - SRI(DSCC_PPS_CONFIG20, DSCC, id),\ - SRI(DSCC_PPS_CONFIG21, DSCC, id),\ - SRI(DSCC_PPS_CONFIG22, DSCC, id),\ - SRI(DSCC_MEM_POWER_CONTROL, DSCC, id),\ - SRI(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_MAX_ABS_ERROR0, DSCC, id),\ - SRI(DSCC_MAX_ABS_ERROR1, DSCC, id),\ - SRI(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCCIF_CONFIG0, DSCCIF, id),\ - SRI(DSCCIF_CONFIG1, DSCCIF, id),\ - SRI(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) - -#define DSC_REG_LIST_SH_MASK_DCN314(mask_sh)\ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_TEST_CLOCK_MUX_SEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \ - /*DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh),*/ \ - DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \ - DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_FORCE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_DIS, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_FORCE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_DIS, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC_R_Y_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC_R_Y_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC_G_CB_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC_G_CB_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC_B_CR_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC_B_CR_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_R_Y_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_G_CB_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR1, DSCC_B_CR_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_PIXEL_FORMAT, mask_sh), \ - DSC2_SF(DSCCIF0, DSCCIF_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_WIDTH, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_HEIGHT, mask_sh), \ - DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \ - DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh) - - struct dcn20_dsc_registers { uint32_t DSC_TOP_CONTROL; uint32_t DSC_DEBUG_CONTROL; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 6f8c344e321d..e1d271fe9e64 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -706,6 +706,14 @@ enum dc_status dcn20_enable_stream_timing( return DC_ERROR_UNEXPECTED; } + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); @@ -1565,6 +1573,7 @@ static void dcn20_update_dchubp_dpp( /* Any updates are handled in dc interface, just need * to apply existing for plane enable / opp change */ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed + || pipe_ctx->update_flags.bits.plane_changed || pipe_ctx->stream->update_flags.bits.gamut_remap || pipe_ctx->stream->update_flags.bits.out_csc) { /* dpp/cm gamut remap*/ @@ -1898,10 +1907,13 @@ void dcn20_post_unlock_program_front_end( * can underflow due to HUBP_VTG_SEL programming if done in the regular front end * programming sequence). */ - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (dc->hwss.update_phantom_vp_position) - dc->hwss.update_phantom_vp_position(dc, context, pipe); - dcn20_program_pipe(dc, pipe, context); + while (pipe) { + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (dc->hwss.update_phantom_vp_position) + dc->hwss.update_phantom_vp_position(dc, context, pipe); + dcn20_program_pipe(dc, pipe, context); + } + pipe = pipe->bottom_pipe; } } } @@ -2349,7 +2361,9 @@ static void dcn20_reset_back_end_for_pipe( struct dc_state *context) { int i; - struct dc_link *link; + struct dc_link *link = pipe_ctx->stream->link; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + DC_LOGGER_INIT(dc->ctx->logger); if (pipe_ctx->stream_res.stream_enc == NULL) { pipe_ctx->stream = NULL; @@ -2357,19 +2371,15 @@ static void dcn20_reset_back_end_for_pipe( } if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - link = pipe_ctx->stream->link; /* DPMS may already disable or */ /* dpms_off status is incorrect due to fastboot * feature. When system resume from S4 with second * screen only, the dpms_off would be true but * VBIOS lit up eDP, so check link status too. */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) { - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(dc->current_state, pipe_ctx, TX_OFF_SYMCLK_OFF); - else - core_link_disable_stream(pipe_ctx); - } else if (pipe_ctx->stream_res.audio) + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) dc->hwss.disable_audio_stream(pipe_ctx); /* free acquired resources */ @@ -2409,6 +2419,16 @@ static void dcn20_reset_back_end_for_pipe( if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, NULL); + /* TODO - convert symclk_ref_cnts for otg to a bit map to solve + * the case where the same symclk is shared across multiple otg + * instances + */ + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, + &pipe_ctx->link_res, pipe_ctx->stream->signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + } } for (i = 0; i < dc->res_pool->pipe_count; i++) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index 91e4885b743e..7c5817c426fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -96,6 +96,10 @@ static const struct hw_sequencer_funcs dcn20_funcs = { #ifndef TRIM_FSFT .optimize_timing_for_fsft = dcn20_optimize_timing_for_fsft, #endif + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .update_visual_confirm_color = dcn20_update_visual_confirm_color diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c index 05b3fba9ccce..61bcfa03c4e7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c @@ -82,7 +82,7 @@ static bool patch_address_for_sbs_tb_stereo( return false; } -static void gpu_addr_to_uma(struct dce_hwseq *hwseq, +static bool gpu_addr_to_uma(struct dce_hwseq *hwseq, PHYSICAL_ADDRESS_LOC *addr) { bool is_in_uma; @@ -98,6 +98,7 @@ static void gpu_addr_to_uma(struct dce_hwseq *hwseq, } else { is_in_uma = false; } + return is_in_uma; } static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq, diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c index 1826dd7f3da1..9c16633e473a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c @@ -86,6 +86,10 @@ static const struct hw_sequencer_funcs dcn201_funcs = { .set_backlight_level = dce110_set_backlight_level, .set_abm_immediate_disable = dce110_set_abm_immediate_disable, .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, .update_visual_confirm_color = dcn20_update_visual_confirm_color, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index b270f0b194dc..fe1a8e2e08ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -99,6 +99,10 @@ static const struct hw_sequencer_funcs dcn21_funcs = { #ifndef TRIM_FSFT .optimize_timing_for_fsft = dcn20_optimize_timing_for_fsft, #endif + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .is_abm_supported = dcn21_is_abm_supported, .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index fb59fed8f425..8c5045711264 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -939,13 +939,32 @@ bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, s void dcn30_hardware_release(struct dc *dc) { + bool subvp_in_use = false; + uint32_t i; + dc_dmub_srv_p_state_delegate(dc, false, NULL); + dc_dmub_setup_subvp_dmub_command(dc, dc->current_state, false); + + /* SubVP treated the same way as FPO. If driver disable and + * we are using a SubVP config, disable and force on DCN side + * to prevent P-State hang on driver enable. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (!pipe->stream) + continue; + + if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + subvp_in_use = true; + break; + } + } /* If pstate unsupported, or still supported * by firmware, force it supported by dcn */ if (dc->current_state) - if ((!dc->clk_mgr->clks.p_state_change_support || + if ((!dc->clk_mgr->clks.p_state_change_support || subvp_in_use || dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) && dc->res_pool->hubbub->funcs->force_pstate_change_control) dc->res_pool->hubbub->funcs->force_pstate_change_control( diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c index 4c06e6e1ba4a..3216d10c58ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c @@ -100,6 +100,10 @@ static const struct hw_sequencer_funcs dcn30_funcs = { .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .hardware_release = dcn30_hardware_release, .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .update_visual_confirm_color = dcn20_update_visual_confirm_color, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index f6f3878c99b8..3a3b2ac791c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -724,7 +724,8 @@ static const struct dc_debug_options debug_defaults_drv = { .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, .disable_psr = false, - .use_max_lb = true + .use_max_lb = true, + .exit_idle_opt_for_cursor_updates = true }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c index 3d42a1a337ec..6192851c59ed 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c @@ -99,6 +99,10 @@ static const struct hw_sequencer_funcs dcn301_funcs = { .set_backlight_level = dcn21_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .optimize_pwr_state = dcn21_optimize_pwr_state, diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index db172677d613..559e563d5bc1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -634,7 +634,7 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; -static const struct resource_caps res_cap_dcn301 = { +static struct resource_caps res_cap_dcn301 = { .num_timing_generator = 4, .num_opp = 4, .num_video_plane = 4, @@ -700,6 +700,7 @@ static const struct dc_debug_options debug_defaults_drv = { .dwb_fi_phase = -1, // -1 = disable .dmub_command_table = true, .use_max_lb = false, + .exit_idle_opt_for_cursor_updates = true }; static const struct dc_debug_options debug_defaults_diags = { @@ -1429,6 +1430,8 @@ static bool dcn301_resource_construct( ctx->dc_bios->regs = &bios_regs; + if (dc->ctx->asic_id.chip_id == DEVICE_ID_VGH_1435) + res_cap_dcn301.num_pll = 2; pool->base.res_cap = &res_cap_dcn301; pool->base.funcs = &dcn301_res_pool_funcs; diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index 4fab537e822f..b925b6ddde5a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -93,7 +93,8 @@ static const struct dc_debug_options debug_defaults_drv = { .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, - .use_max_lb = true + .use_max_lb = true, + .exit_idle_opt_for_cursor_updates = true }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index d97076648acb..527d5c902878 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -77,6 +77,7 @@ static const struct dc_debug_options debug_defaults_drv = { .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, + .exit_idle_opt_for_cursor_updates = true, .disable_idle_power_optimizations = false, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c index 23621ff08c90..52fb2bf3d578 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c @@ -150,9 +150,9 @@ static void dcn31_hpo_dp_stream_enc_dp_blank( * 10us*5000=50ms. This covers 41.7ms of minimum 24 Hz mode + * a little more because we may not trust delay accuracy. */ - //REG_WAIT(DP_SYM32_ENC_VID_STREAM_CONTROL, - // VID_STREAM_STATUS, 0, - // 10, 5000); + REG_WAIT(DP_SYM32_ENC_VID_STREAM_CONTROL, + VID_STREAM_STATUS, 0, + 10, 5000); /* Disable SDP tranmission */ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 51c5f3685470..6360dc9502e7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -876,7 +876,7 @@ static bool hubbub31_get_dcc_compression_cap(struct hubbub *hubbub, return true; } -static int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, +int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, struct dcn_hubbub_phys_addr_config *pa_config) { struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h index e3a654bf04e8..70c60de448ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h @@ -122,6 +122,8 @@ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh) +int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config); void hubbub31_construct(struct dcn20_hubbub *hubbub3, struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 8d83b611507a..bdf101547484 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -535,11 +535,11 @@ static void dcn31_reset_back_end_for_pipe( pipe_ctx->stream_res.tg, OPTC_DSC_DISABLED, 0, 0); pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( @@ -553,12 +553,9 @@ static void dcn31_reset_back_end_for_pipe( * screen only, the dpms_off would be true but * VBIOS lit up eDP, so check link status too. */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) { - if (dc->hwss.update_phy_state) - dc->hwss.update_phy_state(dc->current_state, pipe_ctx, TX_OFF_SYMCLK_OFF); - else - core_link_disable_stream(pipe_ctx); - } else if (pipe_ctx->stream_res.audio) + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) dc->hwss.disable_audio_stream(pipe_ctx); /* free acquired resources */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c index e708f07fe75a..3a32810bbe38 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -100,6 +100,10 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .set_backlight_level = dcn21_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .z10_restore = dcn31_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 8745132d6374..8c1a6fb36306 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -890,7 +890,7 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = true, .optimize_edp_link_rate = true, .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ - .dml_hostvm_override = DML_HOSTVM_OVERRIDE_FALSE, + .dml_hostvm_override = DML_HOSTVM_NO_OVERRIDE, }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c index 36630d532c18..1bd7e0f327d8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c @@ -45,6 +45,48 @@ #define DC_LOGGER \ dccg->ctx->logger +static void dccg314_get_pixel_rate_div( + struct dccg *dccg, + uint32_t otg_inst, + enum pixel_rate_div *k1, + enum pixel_rate_div *k2) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA; + + *k1 = PIXEL_RATE_DIV_NA; + *k2 = PIXEL_RATE_DIV_NA; + + switch (otg_inst) { + case 0: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG0_PIXEL_RATE_DIVK1, &val_k1, + OTG0_PIXEL_RATE_DIVK2, &val_k2); + break; + case 1: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG1_PIXEL_RATE_DIVK1, &val_k1, + OTG1_PIXEL_RATE_DIVK2, &val_k2); + break; + case 2: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG2_PIXEL_RATE_DIVK1, &val_k1, + OTG2_PIXEL_RATE_DIVK2, &val_k2); + break; + case 3: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG3_PIXEL_RATE_DIVK1, &val_k1, + OTG3_PIXEL_RATE_DIVK2, &val_k2); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } + + *k1 = (enum pixel_rate_div)val_k1; + *k2 = (enum pixel_rate_div)val_k2; +} + static void dccg314_set_pixel_rate_div( struct dccg *dccg, uint32_t otg_inst, @@ -52,6 +94,11 @@ static void dccg314_set_pixel_rate_div( enum pixel_rate_div k2) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA; + + dccg314_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2); + if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA || (k1 == cur_k1 && k2 == cur_k2)) + return; switch (otg_inst) { case 0: diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h index 9a4a9efc0203..6a35986307af 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h @@ -63,34 +63,28 @@ DCCG_SRII(PHASE, DTBCLK_DTO, 3),\ SR(DCCG_AUDIO_DTBCLK_DTO_MODULO),\ SR(DCCG_AUDIO_DTBCLK_DTO_PHASE),\ + SR(DCCG_AUDIO_DTO_SOURCE),\ + SR(DENTIST_DISPCLK_CNTL),\ + SR(DSCCLK0_DTO_PARAM),\ + SR(DSCCLK1_DTO_PARAM),\ + SR(DSCCLK2_DTO_PARAM),\ + SR(DSCCLK_DTO_CTRL),\ + SR(DCCG_GATE_DISABLE_CNTL2),\ + SR(DCCG_GATE_DISABLE_CNTL3),\ + SR(HDMISTREAMCLK0_DTO_PARAM),\ SR(OTG_PIXEL_RATE_DIV),\ SR(DTBCLK_P_CNTL),\ SR(DCCG_AUDIO_DTO_SOURCE) - -#define DCCG_MASK_SH_LIST_DCN314(mask_sh) \ - DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ +#define DCCG_MASK_SH_LIST_DCN314_COMMON(mask_sh) \ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\ - DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 1, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\ - DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 2, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\ - DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 3, mask_sh),\ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_EN, mask_sh),\ DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_SRC_SEL, mask_sh),\ - DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_SRC_SEL, mask_sh),\ - DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_SRC_SEL, mask_sh),\ - DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh),\ - DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_SRC_SEL, mask_sh),\ - DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_EN, mask_sh),\ - DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_SRC_SEL, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_EN, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN, mask_sh),\ @@ -100,7 +94,6 @@ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_SRC_SEL, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_SRC_SEL, mask_sh),\ DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN, mask_sh),\ - DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_DTO_FORCE_DIS, mask_sh),\ DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, mask_sh),\ @@ -148,7 +141,48 @@ DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_SRC_SEL, mask_sh),\ DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_EN, mask_sh),\ DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\ - DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh) + DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\ + DCCG_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE, mask_sh),\ + DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh) + +#define DCCG_MASK_SH_LIST_DCN314(mask_sh) \ + DCCG_MASK_SH_LIST_DCN314_COMMON(mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 1, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 2, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 3, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_EN, mask_sh),\ + DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_FORCE_SRC_SEL, mask_sh),\ + DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_DTO_FORCE_DIS, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_ENABLE, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_ENABLE, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_GATE_DISABLE, mask_sh) struct dccg *dccg314_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c index 914c5da737ed..0d2ffb692957 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c @@ -56,7 +56,8 @@ static void enc314_enable_fifo(struct stream_encoder *enc) /* TODO: Confirm if we need to wait for DIG_SYMCLK_FE_ON */ REG_WAIT(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, 1, 10, 5000); - REG_UPDATE_2(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 1, DIG_FIFO_READ_START_LEVEL, 0x7); + REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7); + REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 1); REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, 1, 10, 5000); REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, 0); REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, 0, 10, 5000); @@ -261,6 +262,16 @@ static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing) return two_pix; } +void enc314_stream_encoder_dp_blank( + struct dc_link *link, + struct stream_encoder *enc) +{ + /* New to DCN314 - disable the FIFO before VID stream disable. */ + enc314_disable_fifo(enc); + + enc1_stream_encoder_dp_blank(link, enc); +} + static void enc314_stream_encoder_dp_unblank( struct dc_link *link, struct stream_encoder *enc, @@ -316,15 +327,11 @@ static void enc314_stream_encoder_dp_unblank( /* switch DP encoder to CRTC data, but reset it the fifo first. It may happen * that it overflows during mode transition, and sometimes doesn't recover. */ - REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7); REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 1); udelay(10); REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 0); - /* DIG Resync FIFO now needs to be explicitly enabled. */ - enc314_enable_fifo(enc); - /* wait 100us for DIG/DP logic to prime * (i.e. a few video lines) */ @@ -340,6 +347,12 @@ static void enc314_stream_encoder_dp_unblank( REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true); + /* + * DIG Resync FIFO now needs to be explicitly enabled. + * This should come after DP_VID_STREAM_ENABLE per HW docs. + */ + enc314_enable_fifo(enc); + dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM); } @@ -408,7 +421,7 @@ static const struct stream_encoder_funcs dcn314_str_enc_funcs = { .stop_dp_info_packets = enc1_stream_encoder_stop_dp_info_packets, .dp_blank = - enc1_stream_encoder_dp_blank, + enc314_stream_encoder_dp_blank, .dp_unblank = enc314_stream_encoder_dp_unblank, .audio_mute_control = enc3_audio_mute_control, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index 39931d48f385..588c1c71241f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -343,12 +343,14 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig { struct dc_stream_state *stream = pipe_ctx->stream; unsigned int odm_combine_factor = 0; - struct dc *dc = pipe_ctx->stream->ctx->dc; bool two_pix_per_container = false; two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); odm_combine_factor = get_odm_config(pipe_ctx, NULL); + if (pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) + return odm_combine_factor; + if (is_dp_128b_132b_signal(pipe_ctx)) { *k2_div = PIXEL_RATE_DIV_BY_1; } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { @@ -364,7 +366,7 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig } else { *k1_div = PIXEL_RATE_DIV_BY_1; *k2_div = PIXEL_RATE_DIV_BY_4; - if ((odm_combine_factor == 2) || dc->debug.enable_dp_dig_pixel_rate_div_policy) + if (odm_combine_factor == 2) *k2_div = PIXEL_RATE_DIV_BY_2; } } @@ -384,21 +386,10 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) return; odm_combine_factor = get_odm_config(pipe_ctx, NULL); - if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1 - || dcn314_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) + if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1) pix_per_cycle = 2; if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, pix_per_cycle); } - -bool dcn314_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) -{ - struct dc *dc = pipe_ctx->stream->ctx->dc; - - if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) && - dc->debug.enable_dp_dig_pixel_rate_div_policy) - return true; - return false; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h index d014580592ac..244280298212 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h @@ -41,6 +41,4 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); -bool dcn314_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx); - #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index fcf67eb3478f..5b6c2d94ec71 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -102,6 +102,10 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .set_backlight_level = dcn21_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, .z10_restore = dcn31_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, @@ -146,7 +150,6 @@ static const struct hwseq_private_funcs dcn314_private_funcs = { .setup_hpo_hw_control = dcn31_setup_hpo_hw_control, .calculate_dccg_k1_k2_values = dcn314_calculate_dccg_k1_k2_values, .set_pixels_per_cycle = dcn314_set_pixels_per_cycle, - .is_dp_dig_pixel_rate_div_policy = dcn314_is_dp_dig_pixel_rate_div_policy, }; void dcn314_hw_sequencer_construct(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 49b7e256d4ea..24ec71cbd3e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -87,6 +87,9 @@ #define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 #define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE__SHIFT 0x0 +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE_MASK 0x0000000FL + #include "reg_helper.h" #include "dce/dmub_abm.h" #include "dce/dmub_psr.h" @@ -579,7 +582,7 @@ static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { #define dsc_regsDCN314(id)\ [id] = {\ - DSC_REG_LIST_DCN314(id)\ + DSC_REG_LIST_DCN20(id)\ } static const struct dcn20_dsc_registers dsc_regs[] = { @@ -590,11 +593,11 @@ static const struct dcn20_dsc_registers dsc_regs[] = { }; static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN314(__SHIFT) + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) }; static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN314(_MASK) + DSC_REG_LIST_SH_MASK_DCN20(_MASK) }; static const struct dcn30_mpc_registers mpc_regs = { @@ -844,7 +847,7 @@ static const struct resource_caps res_cap_dcn314 = { .num_ddc = 5, .num_vmid = 16, .num_mpc_3dlut = 2, - .num_dsc = 4, + .num_dsc = 3, }; static const struct dc_plane_cap plane_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c index 26eb04ea472c..e4daed44ef5f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c @@ -42,6 +42,48 @@ #define DC_LOGGER \ dccg->ctx->logger +static void dccg32_get_pixel_rate_div( + struct dccg *dccg, + uint32_t otg_inst, + enum pixel_rate_div *k1, + enum pixel_rate_div *k2) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA; + + *k1 = PIXEL_RATE_DIV_NA; + *k2 = PIXEL_RATE_DIV_NA; + + switch (otg_inst) { + case 0: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG0_PIXEL_RATE_DIVK1, &val_k1, + OTG0_PIXEL_RATE_DIVK2, &val_k2); + break; + case 1: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG1_PIXEL_RATE_DIVK1, &val_k1, + OTG1_PIXEL_RATE_DIVK2, &val_k2); + break; + case 2: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG2_PIXEL_RATE_DIVK1, &val_k1, + OTG2_PIXEL_RATE_DIVK2, &val_k2); + break; + case 3: + REG_GET_2(OTG_PIXEL_RATE_DIV, + OTG3_PIXEL_RATE_DIVK1, &val_k1, + OTG3_PIXEL_RATE_DIVK2, &val_k2); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } + + *k1 = (enum pixel_rate_div)val_k1; + *k2 = (enum pixel_rate_div)val_k2; +} + static void dccg32_set_pixel_rate_div( struct dccg *dccg, uint32_t otg_inst, @@ -50,6 +92,17 @@ static void dccg32_set_pixel_rate_div( { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA; + + // Don't program 0xF into the register field. Not valid since + // K1 / K2 field is only 1 / 2 bits wide + if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) + return; + + dccg32_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2); + if (k1 == cur_k1 && k2 == cur_k2) + return; + switch (otg_inst) { case 0: REG_UPDATE_2(OTG_PIXEL_RATE_DIV, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c index d4963959426c..f6d3da475835 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c @@ -68,7 +68,7 @@ static void dcn32_init_crb(struct hubbub *hubbub) REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x47F); } -static void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte) +void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte) { struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); @@ -98,9 +98,13 @@ static void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigne default: break; } - /* Should never be hit, if it is we have an erroneous hw config*/ - ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size - + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs); + if (hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size + + hubbub2->det3_size + hubbub2->compbuf_size_segments > hubbub2->crb_size_segs) { + /* This may happen during seamless transition from ODM 2:1 to ODM4:1 */ + DC_LOG_WARNING("CRB Config Warning: DET size (%d,%d,%d,%d) + Compbuf size (%d) > CRB segments (%d)\n", + hubbub2->det0_size, hubbub2->det1_size, hubbub2->det2_size, hubbub2->det3_size, + hubbub2->compbuf_size_segments, hubbub2->crb_size_segs); + } } static void dcn32_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase) @@ -140,7 +144,7 @@ static uint32_t convert_and_clamp( return ret_val; } -static bool hubbub32_program_urgent_watermarks( +bool hubbub32_program_urgent_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, @@ -330,7 +334,7 @@ static bool hubbub32_program_urgent_watermarks( return wm_pending; } -static bool hubbub32_program_stutter_watermarks( +bool hubbub32_program_stutter_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, @@ -476,7 +480,7 @@ static bool hubbub32_program_stutter_watermarks( } -static bool hubbub32_program_pstate_watermarks( +bool hubbub32_program_pstate_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, @@ -629,7 +633,7 @@ static bool hubbub32_program_pstate_watermarks( } -static bool hubbub32_program_usr_watermarks( +bool hubbub32_program_usr_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, @@ -709,7 +713,7 @@ static bool hubbub32_program_usr_watermarks( return wm_pending; } -static void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow) +void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow) { struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); @@ -909,7 +913,7 @@ static void hubbub32_wm_read_state(struct hubbub *hubbub, DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, &s->fclk_pstate_change); } -static void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub) +void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub) { struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); uint32_t refclk_mhz = hubbub->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h index 3bae6e558971..cda94e0e31bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h @@ -161,6 +161,35 @@ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh) +bool hubbub32_program_urgent_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +bool hubbub32_program_stutter_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +bool hubbub32_program_pstate_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +bool hubbub32_program_usr_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow); + +void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub); + +void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte); void hubbub32_construct(struct dcn20_hubbub *hubbub2, struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index 449459ca5a72..a750343ca521 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -49,6 +49,7 @@ #include "dcn20/dcn20_optc.h" #include "dmub_subvp_state.h" #include "dce/dmub_hw_lock_mgr.h" +#include "dcn32_resource.h" #include "dc_link_dp.h" #include "dmub/inc/dmub_subvp_state.h" @@ -198,42 +199,6 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) return false; } -/* This function takes in the start address and surface size to be cached in CAB - * and calculates the total number of cache lines required to store the surface. - * The number of cache lines used for each surface is calculated independently of - * one another. For example, if there is a primary surface(1), meta surface(2), and - * cursor(3), this function should be called 3 times to calculate the number of cache - * lines used for each of those surfaces. - */ -static uint32_t dcn32_cache_lines_for_surface(struct dc *dc, uint32_t surface_size, uint64_t start_address) -{ - uint32_t lines_used = 1; - uint32_t num_cached_bytes = 0; - uint32_t remaining_size = 0; - uint32_t cache_line_size = dc->caps.cache_line_size; - uint32_t remainder = 0; - - /* 1. Calculate surface size minus the number of bytes stored - * in the first cache line (all bytes in first cache line might - * not be fully used). - */ - div_u64_rem(start_address, cache_line_size, &remainder); - num_cached_bytes = cache_line_size - remainder; - remaining_size = surface_size - num_cached_bytes; - - /* 2. Calculate number of cache lines that will be fully used with - * the remaining number of bytes to be stored. - */ - lines_used += (remaining_size / cache_line_size); - - /* 3. Check if we need an extra line due to the remaining size not being - * a multiple of CACHE_LINE_SIZE. - */ - if (remaining_size % cache_line_size > 0) - lines_used++; - - return lines_used; -} /* This function loops through every surface that needs to be cached in CAB for SS, * and calculates the total number of ways required to store all surfaces (primary, @@ -241,94 +206,116 @@ static uint32_t dcn32_cache_lines_for_surface(struct dc *dc, uint32_t surface_si */ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) { - uint8_t i, j; + uint8_t i; + int j; struct dc_stream_state *stream = NULL; struct dc_plane_state *plane = NULL; - uint32_t surface_size = 0; uint32_t cursor_size = 0; - uint32_t cache_lines_used = 0; uint32_t total_lines = 0; uint32_t lines_per_way = 0; - uint32_t num_ways = 0; - uint32_t prev_addr_low = 0; + uint8_t num_ways = 0; + uint8_t bytes_per_pixel = 0; + uint8_t cursor_bpp = 0; + uint16_t mblk_width = 0; + uint16_t mblk_height = 0; + uint16_t mall_alloc_width_blk_aligned = 0; + uint16_t mall_alloc_height_blk_aligned = 0; + uint16_t num_mblks = 0; + uint32_t bytes_in_mall = 0; + uint32_t cache_lines_used = 0; + uint32_t cache_lines_per_plane = 0; - for (i = 0; i < ctx->stream_count; i++) { - stream = ctx->streams[i]; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - // Don't include PSR surface in the total surface size for CAB allocation - if (stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) + if (!pipe->stream || !pipe->plane_state || + pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED || + pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) continue; - if (ctx->stream_status[i].plane_count == 0) - continue; + bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; + mblk_width = DCN3_2_MBLK_WIDTH; + mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE; - // For each stream, loop through each plane to calculate the number of cache - // lines required to store the surface in CAB - for (j = 0; j < ctx->stream_status[i].plane_count; j++) { - plane = ctx->stream_status[i].plane_states[j]; + /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) - + * FLOOR(vp_x_start, blk_width) + * + * mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c + */ + mall_alloc_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x + + pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) - + (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width); + + /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) - + * FLOOR(vp_y_start, blk_height) + * + * mall_alloc_height_blk_aligned_l/c = full_vp_height_blk_aligned_l/c + */ + mall_alloc_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y + + pipe->plane_res.scl_data.viewport.height + mblk_height - 1) / mblk_height * mblk_height) - + (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height); - // Calculate total surface size - if (prev_addr_low != plane->address.grph.addr.u.low_part) { - /* if plane address are different from prev FB, then userspace allocated separate FBs*/ - surface_size += plane->plane_size.surface_pitch * - plane->plane_size.surface_size.height * - (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4); + num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) * + ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height); - prev_addr_low = plane->address.grph.addr.u.low_part; - } else { - /* We have the same fb for all the planes. - * Xorg always creates one giant fb that holds all surfaces, - * so allocating it once is sufficient. - * */ - continue; - } - // Convert surface size + starting address to number of cache lines required - // (alignment accounted for) - cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size, - plane->address.grph.addr.quad_part); - - if (plane->address.grph.meta_addr.quad_part) { - // Meta surface - cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size, - plane->address.grph.meta_addr.quad_part); - } - } + /* For DCC: + * meta_num_mblk = CEILING(full_mblk_width_ub_l*full_mblk_height_ub_l*Bpe/256/mblk_bytes, 1) + */ + if (pipe->plane_state->dcc.enable) + num_mblks += (mall_alloc_width_blk_aligned * mall_alloc_width_blk_aligned * bytes_per_pixel + + (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES); - // Include cursor size for CAB allocation - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j]; - struct hubp *hubp = pipe->plane_res.hubp; + bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES; - if (pipe->stream && pipe->plane_state && hubp) - /* Find the cursor plane and use the exact size instead of - * using the max for calculation - */ - if (hubp->curs_attr.width > 0) { - cursor_size = hubp->curs_attr.width * hubp->curs_attr.height; - break; - } - } + /* (cache lines used is total bytes / cache_line size. Add +2 for worst case alignment + * (MALL is 64-byte aligned) + */ + cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2; + cache_lines_used += cache_lines_per_plane; + } - switch (stream->cursor_attributes.color_format) { - case CURSOR_MODE_MONO: - cursor_size /= 2; - break; - case CURSOR_MODE_COLOR_1BIT_AND: - case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: - case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: - cursor_size *= 4; - break; + // Include cursor size for CAB allocation + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j]; + struct hubp *hubp = pipe->plane_res.hubp; - case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: - case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: - cursor_size *= 8; - break; - } + if (pipe->stream && pipe->plane_state && hubp) + /* Find the cursor plane and use the exact size instead of + using the max for calculation */ - if (stream->cursor_position.enable && plane->address.grph.cursor_cache_addr.quad_part) { - cache_lines_used += dcn32_cache_lines_for_surface(dc, cursor_size, - plane->address.grph.cursor_cache_addr.quad_part); - } + if (hubp->curs_attr.width > 0) { + // Round cursor width to next multiple of 64 + cursor_size = (((hubp->curs_attr.width + 63) / 64) * 64) * hubp->curs_attr.height; + + switch (pipe->stream->cursor_attributes.color_format) { + case CURSOR_MODE_MONO: + cursor_size /= 2; + cursor_bpp = 4; + break; + case CURSOR_MODE_COLOR_1BIT_AND: + case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: + case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: + cursor_size *= 4; + cursor_bpp = 4; + break; + + case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: + case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: + cursor_size *= 8; + cursor_bpp = 8; + break; + } + + if (pipe->stream->cursor_position.enable && !dc->debug.alloc_extra_way_for_cursor && + cursor_size > 16384) { + /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1) + */ + cache_lines_used += (((hubp->curs_attr.width * hubp->curs_attr.height * cursor_bpp + + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) / DCN3_2_MALL_MBLK_SIZE_BYTES) * + DCN3_2_MALL_MBLK_SIZE_BYTES) / dc->caps.cache_line_size + 2; + } + break; + } } // Convert number of cache lines required to number of ways @@ -345,8 +332,8 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c plane = ctx->stream_status[i].plane_states[j]; if (stream->cursor_position.enable && plane && - !plane->address.grph.cursor_cache_addr.quad_part && - cursor_size > 16384) { + dc->debug.alloc_extra_way_for_cursor && + cursor_size > 16384) { /* Cursor caching is not supported since it won't be on the same line. * So we need an extra line to accommodate it. With large cursors and a single 4k monitor * this case triggers corruption. If we're at the edge, then dont trigger display refresh @@ -358,7 +345,9 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c } } } - + if (dc->debug.force_mall_ss_num_ways > 0) { + num_ways = dc->debug.force_mall_ss_num_ways; + } return num_ways; } @@ -367,7 +356,7 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) union dmub_rb_cmd cmd; uint8_t ways, i; int j; - bool stereo_in_use = false; + bool mall_ss_unsupported = false; struct dc_plane_state *plane = NULL; if (!dc->ctx->dmub_srv) @@ -398,22 +387,23 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) */ ways = dcn32_calculate_cab_allocation(dc, dc->current_state); - /* MALL not supported with Stereo3D. If any plane is using stereo, - * don't try to enter MALL. + /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, + * or TMZ surface, don't try to enter MALL. */ for (i = 0; i < dc->current_state->stream_count; i++) { for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { plane = dc->current_state->stream_status[i].plane_states[j]; - if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO) { - stereo_in_use = true; + if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO || + plane->address.tmz_surface) { + mall_ss_unsupported = true; break; } } - if (stereo_in_use) + if (mall_ss_unsupported) break; } - if (ways <= dc->caps.cache_num_ways && !stereo_in_use) { + if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) { memset(&cmd, 0, sizeof(cmd)); cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; @@ -451,7 +441,6 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) */ void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) { -/* int i; bool enable_subvp = false; @@ -469,7 +458,6 @@ void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) } } dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp); -*/ } /* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and: @@ -773,7 +761,8 @@ void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context) hubp->funcs->hubp_update_mall_sel(hubp, num_ways <= dc->caps.cache_num_ways && pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && - pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO ? 2 : 0, + pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO && + !pipe->plane_state->address.tmz_surface ? 2 : 0, cache_cursor); } } @@ -883,6 +872,7 @@ void dcn32_init_hw(struct dc *dc) if (link->link_enc->funcs->is_dig_enabled && link->link_enc->funcs->is_dig_enabled(link->link_enc)) { link->link_status.link_active = true; + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; if (link->link_enc->funcs->fec_is_active && link->link_enc->funcs->fec_is_active(link->link_enc)) link->fec_state = dc_link_fec_enabled; @@ -1181,6 +1171,9 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); odm_combine_factor = get_odm_config(pipe_ctx, NULL); + if (pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) + return odm_combine_factor; + if (is_dp_128b_132b_signal(pipe_ctx)) { *k2_div = PIXEL_RATE_DIV_BY_1; } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { @@ -1275,31 +1268,69 @@ bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) return false; } -void dcn32_update_phy_state(struct dc_state *state, struct pipe_ctx *pipe_ctx, - enum phy_state target_state) +static void apply_symclk_on_tx_off_wa(struct dc_link *link) { - enum phy_state current_state = pipe_ctx->stream->link->phy_state; - - if (target_state == TX_OFF_SYMCLK_OFF) { - core_link_disable_stream(pipe_ctx); - pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF; - } else if (target_state == TX_ON_SYMCLK_ON) { - core_link_enable_stream(state, pipe_ctx); - pipe_ctx->stream->link->phy_state = TX_ON_SYMCLK_ON; - } else if (target_state == TX_OFF_SYMCLK_ON) { - if (current_state == TX_ON_SYMCLK_ON) { - core_link_disable_stream(pipe_ctx); - pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF; + /* There are use cases where SYMCLK is referenced by OTG. For instance + * for TMDS signal, OTG relies SYMCLK even if TX video output is off. + * However current link interface will power off PHY when disabling link + * output. This will turn off SYMCLK generated by PHY. The workaround is + * to identify such case where SYMCLK is still in use by OTG when we + * power off PHY. When this is detected, we will temporarily power PHY + * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling + * program_pix_clk interface. When OTG is disabled, we will then power + * off PHY by calling disable link output again. + * + * In future dcn generations, we plan to rework transmitter control + * interface so that we could have an option to set SYMCLK ON TX OFF + * state in one step without this workaround + */ + + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + if (link->phy_state.symclk_ref_cnts.otg > 0) { + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + break; + } } + } +} - pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings); - pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_ON; - } else - BREAK_TO_DEBUGGER(); +void dcn32_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_power_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + + apply_symclk_on_tx_off_wa(link); } /* For SubVP the main pipe can have a viewport position change @@ -1310,7 +1341,7 @@ void dcn32_update_phantom_vp_position(struct dc *dc, struct dc_state *context, struct pipe_ctx *phantom_pipe) { - uint8_t i; + uint32_t i; struct dc_plane_state *phantom_plane = phantom_pipe->plane_state; for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -1333,3 +1364,58 @@ void dcn32_update_phantom_vp_position(struct dc *dc, } } } + +bool dcn32_dsc_pg_status( + struct dce_hwseq *hws, + unsigned int dsc_inst) +{ + uint32_t pwr_status = 0; + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_GET(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 1: /* DSC1 */ + + REG_GET(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 2: /* DSC2 */ + REG_GET(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 3: /* DSC3 */ + REG_GET(DOMAIN19_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + return pwr_status == 0 ? true : false; +} + +void dcn32_update_dsc_pg(struct dc *dc, + struct dc_state *context, + bool safe_to_disable) +{ + struct dce_hwseq *hws = dc->hwseq; + int i; + + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { + struct display_stream_compressor *dsc = dc->res_pool->dscs[i]; + bool is_dsc_ungated = hws->funcs.dsc_pg_status(hws, dsc->inst); + + if (context->res_ctx.is_dsc_acquired[i]) { + if (!is_dsc_ungated) { + hws->funcs.dsc_pg_control(hws, dsc->inst, true); + } + } else if (safe_to_disable) { + if (is_dsc_ungated) { + hws->funcs.dsc_pg_control(hws, dsc->inst, false); + } + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h index 150d541f35b4..ac3657a5b9ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h @@ -84,11 +84,20 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx); -void dcn32_update_phy_state(struct dc_state *state, struct pipe_ctx *pipe_ctx, - enum phy_state target_state); +void dcn32_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); void dcn32_update_phantom_vp_position(struct dc *dc, struct dc_state *context, struct pipe_ctx *phantom_pipe); +bool dcn32_dsc_pg_status( + struct dce_hwseq *hws, + unsigned int dsc_inst); + +void dcn32_update_dsc_pg(struct dc *dc, + struct dc_state *context, + bool safe_to_disable); + #endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index c554929471af..45a949ba6f3f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -99,13 +99,17 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .hardware_release = dcn30_hardware_release, .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dcn32_disable_link_output, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .commit_subvp_config = dcn32_commit_subvp_config, .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock, .update_visual_confirm_color = dcn20_update_visual_confirm_color, - .update_phy_state = dcn32_update_phy_state, .update_phantom_vp_position = dcn32_update_phantom_vp_position, + .update_dsc_pg = dcn32_update_dsc_pg, }; static const struct hwseq_private_funcs dcn32_private_funcs = { @@ -135,6 +139,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = { .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn32_update_odm, .dsc_pg_control = dcn32_dsc_pg_control, + .dsc_pg_status = dcn32_dsc_pg_status, .set_hdr_multiplier = dcn10_set_hdr_multiplier, .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, .wait_for_blank_complete = dcn20_wait_for_blank_complete, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 11f1435b8c07..05de97ea855f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -90,29 +90,6 @@ #include "dcn20/dcn20_vmid.h" #include "dml/dcn32/dcn32_fpu.h" -#define DCN_BASE__INST0_SEG1 0x000000C0 -#define DCN_BASE__INST0_SEG2 0x000034C0 -#define DCN_BASE__INST0_SEG3 0x00009000 -#define NBIO_BASE__INST0_SEG1 0x00000014 - -#define MAX_INSTANCE 6 -#define MAX_SEGMENT 6 - -struct IP_BASE_INSTANCE { - unsigned int segment[MAX_SEGMENT]; -}; - -struct IP_BASE { - struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; -}; - -static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0x00009000, 0x02403C00, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } } } }; - #define DC_LOGGER_INIT(logger) enum dcn32_clk_src_array_id { @@ -741,8 +718,12 @@ static const struct dc_debug_options debug_defaults_drv = { .force_disable_subvp = false, .exit_idle_opt_for_cursor_updates = true, .enable_single_display_2to1_odm_policy = true, + + /* Must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ + .enable_double_buffered_dsc_pg_support = true, .enable_dp_dig_pixel_rate_div_policy = 1, .allow_sw_cursor_fallback = false, + .alloc_extra_way_for_cursor = true, }; static const struct dc_debug_options debug_defaults_diags = { @@ -919,10 +900,10 @@ static struct hubp *dcn32_hubp_create( #undef REG_STRUCT #define REG_STRUCT hubp_regs - hubp_regs_init(0), - hubp_regs_init(1), - hubp_regs_init(2), - hubp_regs_init(3); + hubp_regs_init(0), + hubp_regs_init(1), + hubp_regs_init(2), + hubp_regs_init(3); if (hubp32_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) @@ -1859,12 +1840,6 @@ validate_out: return out; } - -static bool is_dual_plane(enum surface_pixel_format format) -{ - return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; -} - int dcn32_populate_dml_pipes_from_context( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, @@ -1873,12 +1848,37 @@ int dcn32_populate_dml_pipes_from_context( int i, pipe_cnt; struct resource_context *res_ctx = &context->res_ctx; struct pipe_ctx *pipe; - bool subvp_in_use = false, is_pipe_split_expected[MAX_PIPES]; - int plane_count = 0; + bool subvp_in_use = false; + uint8_t is_pipe_split_expected[MAX_PIPES] = {0}; struct dc_crtc_timing *timing; dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + /* Determine whether we will apply ODM 2to1 policy: + * Applies to single display and where the number of planes is less than 3. + * For 3 plane case ( 2 MPO planes ), we will not set the policy for the MPO pipes. + * + * Apply pipe split policy first so we can predict the pipe split correctly + * (dcn32_predict_pipe_split). + */ + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + if (context->stream_count == 1 && + context->stream_status[0].plane_count <= 1 && + !dc_is_hdmi_signal(res_ctx->pipe_ctx[i].stream->signal) && + is_h_timing_divisible_by_2(res_ctx->pipe_ctx[i].stream) && + pipe->stream->timing.pix_clk_100hz * 100 > DCN3_2_VMIN_DISPCLK_HZ && + dc->debug.enable_single_display_2to1_odm_policy) { + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; + } + pipe_cnt++; + } + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { if (!res_ctx->pipe_ctx[i].stream) @@ -1931,57 +1931,18 @@ int dcn32_populate_dml_pipes_from_context( } } - /* Calculate the number of planes we have so we can determine - * whether to apply ODM 2to1 policy or not - */ - if (pipe->stream && !pipe->prev_odm_pipe && - (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) - ++plane_count; - DC_FP_START(); - is_pipe_split_expected[i] = dcn32_predict_pipe_split(context, pipes[i].pipe, i); + is_pipe_split_expected[i] = dcn32_predict_pipe_split(context, &pipes[pipe_cnt]); DC_FP_END(); pipe_cnt++; } - /* Determine whether we will apply ODM 2to1 policy - * Applies to single display and where the number of planes is less than 3 - * For 3 plane case ( 2 MPO planes ), we will not set the policy for the MPO pipes - */ - for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { - if (!res_ctx->pipe_ctx[i].stream) - continue; - pipe = &res_ctx->pipe_ctx[i]; - timing = &pipe->stream->timing; - - pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; - if (context->stream_count == 1 && !dc_is_hdmi_signal(res_ctx->pipe_ctx[i].stream->signal)) { - if (dc->debug.enable_single_display_2to1_odm_policy) { - if (!((plane_count > 2) && pipe->top_pipe)) - pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; - } - } - pipe_cnt++; - } - /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all * the DET available for each pipe). Use the DET override input to maintain our driver * policy. */ - if (pipe_cnt == 1 && !is_pipe_split_expected[0]) { - pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; - if (pipe->plane_state && !dc->debug.disable_z9_mpc) { - if (!is_dual_plane(pipe->plane_state->format)) { - pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; - pipes[0].pipe.src.unbounded_req_mode = true; - if (pipe->plane_state->src_rect.width >= 5120 && - pipe->plane_state->src_rect.height >= 2880) - pipes[0].pipe.src.det_size_override = 320; // 5K or higher - } - } - } else - dcn32_determine_det_override(context, pipes, is_pipe_split_expected, dc->res_pool->pipe_count); + dcn32_set_det_allocations(dc, context, pipes); // In general cases we want to keep the dram clock change requirement // (prefer configs that support MCLK switch). Only override to false diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 95f3517724d1..55945cca2260 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -28,11 +28,16 @@ #include "core_types.h" +#define DCN3_2_DEFAULT_DET_SIZE 256 +#define DCN3_2_MAX_DET_SIZE 1152 +#define DCN3_2_MIN_DET_SIZE 128 +#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 #define DCN3_2_DET_SEG_SIZE 64 #define DCN3_2_MALL_MBLK_SIZE_BYTES 65536 // 64 * 1024 #define DCN3_2_MBLK_WIDTH 128 #define DCN3_2_MBLK_HEIGHT_4BPE 128 #define DCN3_2_MBLK_HEIGHT_8BPE 64 +#define DCN3_2_VMIN_DISPCLK_HZ 717000000 #define TO_DCN32_RES_POOL(pool)\ container_of(pool, struct dcn32_resource_pool, base) @@ -109,9 +114,12 @@ struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( struct dc_stream_state *stream, struct pipe_ctx *head_pipe); -void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes, - bool *is_pipe_split_expected, int pipe_cnt); +void dcn32_determine_det_override(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes); +void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes); /* definitions for run time init of reg offsets */ /* CLK SRC */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 417dfdcf9596..a2a70a1572b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -28,6 +28,11 @@ #include "dcn20/dcn20_resource.h" #include "dml/dcn32/display_mode_vba_util_32.h" +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + /** * ******************************************************************************************** * dcn32_helper_calculate_num_ways_for_subvp: Calculate number of ways needed for SubVP @@ -66,8 +71,11 @@ uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_stat for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - // Find the phantom pipes - if (pipe->stream && pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && + /* Find the phantom pipes. + * - For pipe split case we need to loop through the bottom and next ODM + * pipes or only half the viewport size is counted + */ + if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { struct pipe_ctx *main_pipe = NULL; @@ -118,9 +126,9 @@ uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_stat // (MALL is 64-byte aligned) cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2; - // For DCC we must cache the meat surface, so double cache lines required + /* For DCC divide by 256 */ if (pipe->plane_state->dcc.enable) - cache_lines_per_plane *= 2; + cache_lines_per_plane = cache_lines_per_plane + (cache_lines_per_plane / 256) + 1; cache_lines_used += cache_lines_per_plane; } } @@ -225,36 +233,133 @@ bool dcn32_mpo_in_use(struct dc_state *context) return false; } -void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes, - bool *is_pipe_split_expected, int pipe_cnt) +/** + * ******************************************************************************************* + * dcn32_determine_det_override: Determine DET allocation for each pipe + * + * This function determines how much DET to allocate for each pipe. The total number of + * DET segments will be split equally among each of the streams, and after that the DET + * segments per stream will be split equally among the planes for the given stream. + * + * If there is a plane that's driven by more than 1 pipe (i.e. pipe split), then the + * number of DET for that given plane will be split among the pipes driving that plane. + * + * + * High level algorithm: + * 1. Split total DET among number of streams + * 2. For each stream, split DET among the planes + * 3. For each plane, check if there is a pipe split. If yes, split the DET allocation + * among those pipes. + * 4. Assign the DET override to the DML pipes. + * + * @param [in]: dc: Current DC state + * @param [in]: context: New DC state to be programmed + * @param [in]: pipes: Array of DML pipes + * + * @return: void + * + * ******************************************************************************************* + */ +void dcn32_determine_det_override(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes) { - int i, j, count, stream_segments, pipe_segments[MAX_PIPES]; + uint32_t i, j, k; + uint8_t pipe_plane_count, stream_segments, plane_segments, pipe_segments[MAX_PIPES] = {0}; + uint8_t pipe_counted[MAX_PIPES] = {0}; + uint8_t pipe_cnt = 0; + struct dc_plane_state *current_plane = NULL; + uint8_t stream_count = 0; + + for (i = 0; i < context->stream_count; i++) { + /* Don't count SubVP streams for DET allocation */ + if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM) { + stream_count++; + } + } - if (context->stream_count > 0) { - stream_segments = 18 / context->stream_count; + if (stream_count > 0) { + stream_segments = 18 / stream_count; for (i = 0; i < context->stream_count; i++) { - count = 0; - for (j = 0; j < pipe_cnt; j++) { - if (context->res_ctx.pipe_ctx[j].stream == context->streams[i]) { - count++; - if (is_pipe_split_expected[j]) - count++; + if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM) + continue; + if (context->stream_status[i].plane_count > 0) + plane_segments = stream_segments / context->stream_status[i].plane_count; + else + plane_segments = stream_segments; + for (j = 0; j < dc->res_pool->pipe_count; j++) { + pipe_plane_count = 0; + if (context->res_ctx.pipe_ctx[j].stream == context->streams[i] && + pipe_counted[j] != 1) { + /* Note: pipe_plane_count indicates the number of pipes to be used for a + * given plane. e.g. pipe_plane_count = 1 means single pipe (i.e. not split), + * pipe_plane_count = 2 means 2:1 split, etc. + */ + pipe_plane_count++; + pipe_counted[j] = 1; + current_plane = context->res_ctx.pipe_ctx[j].plane_state; + for (k = 0; k < dc->res_pool->pipe_count; k++) { + if (k != j && context->res_ctx.pipe_ctx[k].stream == context->streams[i] && + context->res_ctx.pipe_ctx[k].plane_state == current_plane) { + pipe_plane_count++; + pipe_counted[k] = 1; + } + } + + pipe_segments[j] = plane_segments / pipe_plane_count; + for (k = 0; k < dc->res_pool->pipe_count; k++) { + if (k != j && context->res_ctx.pipe_ctx[k].stream == context->streams[i] && + context->res_ctx.pipe_ctx[k].plane_state == current_plane) { + pipe_segments[k] = plane_segments / pipe_plane_count; + } + } } } - pipe_segments[i] = stream_segments / count; } - for (i = 0; i < pipe_cnt; i++) { - pipes[i].pipe.src.det_size_override = 0; - for (j = 0; j < context->stream_count; j++) { - if (context->res_ctx.pipe_ctx[i].stream == context->streams[j]) { - pipes[i].pipe.src.det_size_override = pipe_segments[j] * DCN3_2_DET_SEG_SIZE; - break; - } - } + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + pipes[pipe_cnt].pipe.src.det_size_override = pipe_segments[i] * DCN3_2_DET_SEG_SIZE; + pipe_cnt++; } } else { - for (i = 0; i < pipe_cnt; i++) + for (i = 0; i < dc->res_pool->pipe_count; i++) pipes[i].pipe.src.det_size_override = 4 * DCN3_2_DET_SEG_SIZE; //DCN3_2_DEFAULT_DET_SIZE } } + +void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe; + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + + if (!res_ctx->pipe_ctx[i].stream) + continue; + + pipe = &res_ctx->pipe_ctx[i]; + pipe_cnt++; + } + + /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all + * the DET available for each pipe). Use the DET override input to maintain our driver + * policy. + */ + if (pipe_cnt == 1) { + pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; + if (pipe->plane_state && !dc->debug.disable_z9_mpc && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { + if (!is_dual_plane(pipe->plane_state->format)) { + pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; + pipes[0].pipe.src.unbounded_req_mode = true; + if (pipe->plane_state->src_rect.width >= 5120 && + pipe->plane_state->src_rect.height >= 2880) + pipes[0].pipe.src.det_size_override = 320; // 5K or higher + } + } + } else + dcn32_determine_det_override(dc, context, pipes); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index 1bbc0bdf5dc3..aed0f689cbbf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -93,31 +93,6 @@ #include "vm_helper.h" #include "dcn20/dcn20_vmid.h" -#define DCN_BASE__INST0_SEG1 0x000000C0 -#define DCN_BASE__INST0_SEG2 0x000034C0 -#define DCN_BASE__INST0_SEG3 0x00009000 -#define NBIO_BASE__INST0_SEG1 0x00000014 - -#define MAX_INSTANCE 8 -#define MAX_SEGMENT 6 - -struct IP_BASE_INSTANCE { - unsigned int segment[MAX_SEGMENT]; -}; - -struct IP_BASE { - struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; -}; - -static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0x00009000, 0x02403C00, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } } } }; - #define DC_LOGGER_INIT(logger) #define fixed16_to_double(x) (((double)x) / ((double) (1 << 16))) #define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) @@ -743,8 +718,12 @@ static const struct dc_debug_options debug_defaults_drv = { .force_disable_subvp = false, .exit_idle_opt_for_cursor_updates = true, .enable_single_display_2to1_odm_policy = true, + + /*must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ + .enable_double_buffered_dsc_pg_support = true, .enable_dp_dig_pixel_rate_div_policy = 1, .allow_sw_cursor_fallback = false, + .alloc_extra_way_for_cursor = true, }; static const struct dc_debug_options debug_defaults_diags = { @@ -820,11 +799,11 @@ static struct dce_i2c_hw *dcn321_i2c_hw_create( #undef REG_STRUCT #define REG_STRUCT i2c_hw_regs - i2c_inst_regs_init(1), - i2c_inst_regs_init(2), - i2c_inst_regs_init(3), - i2c_inst_regs_init(4), - i2c_inst_regs_init(5); + i2c_inst_regs_init(1), + i2c_inst_regs_init(2), + i2c_inst_regs_init(3), + i2c_inst_regs_init(4), + i2c_inst_regs_init(5); dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); @@ -922,10 +901,10 @@ static struct hubp *dcn321_hubp_create( #undef REG_STRUCT #define REG_STRUCT hubp_regs - hubp_regs_init(0), - hubp_regs_init(1), - hubp_regs_init(2), - hubp_regs_init(3); + hubp_regs_init(0), + hubp_regs_init(1), + hubp_regs_init(2), + hubp_regs_init(3); if (hubp32_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) @@ -1670,10 +1649,10 @@ static bool dcn321_resource_construct( #undef REG_STRUCT #define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); #undef REG_STRUCT #define REG_STRUCT dccg_regs diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index e93187c06648..e3e5c39895a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -173,7 +173,8 @@ void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigne (result == 0x0) void dm_helpers_init_panel_settings( struct dc_context *ctx, - struct dc_panel_config *config); + struct dc_panel_config *config, + struct dc_sink *sink); void dm_helpers_override_panel_settings( struct dc_context *ctx, struct dc_panel_config *config); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c index d40d32e380f4..1d84ae50311d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c @@ -2636,7 +2636,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman &mode_lib->vba.SrcActiveDrainRate, &mode_lib->vba.TInitXFill, &mode_lib->vba.TslvChk); - locals->XFCRemoteSurfaceFlipLatency[k] = + locals->XFCRemoteSurfaceFlipLatency[k] = dml_floor( mode_lib->vba.XFCRemoteSurfaceFlipDelay / (mode_lib->vba.HTotal[k] diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c index 241d28d0b7fb..422f17aefd4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c @@ -379,6 +379,11 @@ void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param dcn3_01_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + if ((int)(dcn3_01_soc.dram_clock_change_latency_us * 1000) + != dc->debug.dram_clock_change_latency_ns + && dc->debug.dram_clock_change_latency_ns) { + dcn3_01_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000.0; + } dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c index 0e62eb823e34..b6e99eefe869 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c @@ -291,6 +291,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = { .do_urgent_latency_adjustment = false, .urgent_latency_adjustment_fabric_clock_component_us = 0, .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, + .num_chans = 4, }; struct _vcs_dpi_ip_params_st dcn3_16_ip = { @@ -667,6 +668,12 @@ void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params dcn3_1_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + if ((int)(dcn3_1_soc.dram_clock_change_latency_us * 1000) + != dc->debug.dram_clock_change_latency_ns + && dc->debug.dram_clock_change_latency_ns) { + dcn3_1_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000; + } + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31); else @@ -682,7 +689,11 @@ void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param dcn3_15_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator; dcn3_15_ip.max_num_dpp = dc->res_pool->pipe_count; - dcn3_15_soc.num_chans = bw_params->num_channels; + + if (bw_params->num_channels > 0) + dcn3_15_soc.num_chans = bw_params->num_channels; + if (bw_params->dram_channel_width_bytes > 0) + dcn3_15_soc.dram_channel_width_bytes = bw_params->dram_channel_width_bytes; ASSERT(clk_table->num_entries); @@ -721,6 +732,12 @@ void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param */ dcn3_15_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2; + if ((int)(dcn3_15_soc.dram_clock_change_latency_us * 1000) + != dc->debug.dram_clock_change_latency_ns + && dc->debug.dram_clock_change_latency_ns) { + dcn3_15_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000; + } + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) dml_init_instance(&dc->dml, &dcn3_15_soc, &dcn3_15_ip, DML_PROJECT_DCN31); else @@ -813,6 +830,11 @@ void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param dcn3_16_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2; dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2; } + if ((int)(dcn3_16_soc.dram_clock_change_latency_us * 1000) + != dc->debug.dram_clock_change_latency_ns + && dc->debug.dram_clock_change_latency_ns) { + dcn3_16_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000; + } if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) dml_init_instance(&dc->dml, &dcn3_16_soc, &dcn3_16_ip, DML_PROJECT_DCN31); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index 4e3356d12147..8dfe639b6508 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -1051,10 +1051,10 @@ static bool CalculatePrefetchSchedule( bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC; /*rev 99*/ prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane); - max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; + max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC; prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime)); - prefetch_bw_oto = dml_max(prefetch_bw_pr, prefetch_sw_bytes / max_Tsw); + prefetch_bw_oto = dml_max(prefetch_bw_pr, prefetch_sw_bytes / max_Tsw); min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre); Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index 4bb3b31ea7e0..cf420ad2b8dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -264,6 +264,11 @@ void dcn314_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2; } + if ((int)(dcn3_14_soc.dram_clock_change_latency_us * 1000) + != dc->debug.dram_clock_change_latency_ns + && dc->debug.dram_clock_change_latency_ns) { + dcn3_14_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000; + } if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) dml_init_instance(&dc->dml, &dcn3_14_soc, &dcn3_14_ip, DML_PROJECT_DCN314); else @@ -318,6 +323,8 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.dest.vblank_nom = + dcn3_14_ip.VBlankNomDefaultUS / (timing->h_total / (timing->pix_clk_100hz / 10000.0)); pipes[pipe_cnt].pipe.src.dcc_rate = 3; pipes[pipe_cnt].dout.dsc_input_bpc = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index 2829f179f982..0d12fd079cd6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -265,33 +265,13 @@ static void CalculateRowBandwidth( static void CalculateFlipSchedule( struct display_mode_lib *mode_lib, + unsigned int k, double HostVMInefficiencyFactor, double UrgentExtraLatency, double UrgentLatency, - unsigned int GPUVMMaxPageTableLevels, - bool HostVMEnable, - unsigned int HostVMMaxNonCachedPageTableLevels, - bool GPUVMEnable, - double HostVMMinPageSize, double PDEAndMetaPTEBytesPerFrame, double MetaRowBytes, - double DPTEBytesPerRow, - double BandwidthAvailableForImmediateFlip, - unsigned int TotImmediateFlipBytes, - enum source_format_class SourcePixelFormat, - double LineTime, - double VRatio, - double VRatioChroma, - double Tno_bw, - bool DCCEnable, - unsigned int dpte_row_height, - unsigned int meta_row_height, - unsigned int dpte_row_height_chroma, - unsigned int meta_row_height_chroma, - double *DestinationLinesToRequestVMInImmediateFlip, - double *DestinationLinesToRequestRowInImmediateFlip, - double *final_flip_bw, - bool *ImmediateFlipSupportedForPipe); + double DPTEBytesPerRow); static double CalculateWriteBackDelay( enum source_format_class WritebackPixelFormat, double WritebackHRatio, @@ -325,64 +305,28 @@ static void CalculateVupdateAndDynamicMetadataParameters( static void CalculateWatermarksAndDRAMSpeedChangeSupport( struct display_mode_lib *mode_lib, unsigned int PrefetchMode, - unsigned int NumberOfActivePlanes, - unsigned int MaxLineBufferLines, - unsigned int LineBufferSize, - unsigned int WritebackInterfaceBufferSize, double DCFCLK, double ReturnBW, - bool SynchronizedVBlank, - unsigned int dpte_group_bytes[], - unsigned int MetaChunkSize, double UrgentLatency, double ExtraLatency, - double WritebackLatency, - double WritebackChunkSize, double SOCCLK, - double DRAMClockChangeLatency, - double SRExitTime, - double SREnterPlusExitTime, - double SRExitZ8Time, - double SREnterPlusExitZ8Time, double DCFCLKDeepSleep, unsigned int DETBufferSizeY[], unsigned int DETBufferSizeC[], unsigned int SwathHeightY[], unsigned int SwathHeightC[], - unsigned int LBBitPerPixel[], double SwathWidthY[], double SwathWidthC[], - double HRatio[], - double HRatioChroma[], - unsigned int vtaps[], - unsigned int VTAPsChroma[], - double VRatio[], - double VRatioChroma[], - unsigned int HTotal[], - double PixelClock[], - unsigned int BlendingAndTiming[], unsigned int DPPPerPlane[], double BytePerPixelDETY[], double BytePerPixelDETC[], - double DSTXAfterScaler[], - double DSTYAfterScaler[], - bool WritebackEnable[], - enum source_format_class WritebackPixelFormat[], - double WritebackDestinationWidth[], - double WritebackDestinationHeight[], - double WritebackSourceHeight[], bool UnboundedRequestEnabled, unsigned int CompressedBufferSizeInkByte, enum clock_change_support *DRAMClockChangeSupport, - double *UrgentWatermark, - double *WritebackUrgentWatermark, - double *DRAMClockChangeWatermark, - double *WritebackDRAMClockChangeWatermark, double *StutterExitWatermark, double *StutterEnterPlusExitWatermark, double *Z8StutterExitWatermark, - double *Z8StutterEnterPlusExitWatermark, - double *MinActiveDRAMClockChangeLatencySupported); + double *Z8StutterEnterPlusExitWatermark); static void CalculateDCFCLKDeepSleep( struct display_mode_lib *mode_lib, @@ -1362,7 +1306,7 @@ static bool CalculatePrefetchSchedule( // - ((NumberOfCursors > 0 || GPUVMEnable || DCCEnable) ? - ((GPUVMEnable || myPipe->DCCEnable) ? (*DestinationLinesToRequestVMInVBlank + 2 * *DestinationLinesToRequestRowInVBlank) : 0.0); // TODO: Did someone else add this?? #else - LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch - *DestinationLinesToRequestVMInVBlank - 2 * *DestinationLinesToRequestRowInVBlank; + LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch - *DestinationLinesToRequestVMInVBlank - 2 * *DestinationLinesToRequestRowInVBlank; #endif #ifdef __DML_VBA_DEBUG__ @@ -2928,33 +2872,13 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman for (k = 0; k < v->NumberOfActivePlanes; ++k) { CalculateFlipSchedule( mode_lib, + k, HostVMInefficiencyFactor, v->UrgentExtraLatency, v->UrgentLatency, - v->GPUVMMaxPageTableLevels, - v->HostVMEnable, - v->HostVMMaxNonCachedPageTableLevels, - v->GPUVMEnable, - v->HostVMMinPageSize, v->PDEAndMetaPTEBytesFrame[k], v->MetaRowByte[k], - v->PixelPTEBytesPerRow[k], - v->BandwidthAvailableForImmediateFlip, - v->TotImmediateFlipBytes, - v->SourcePixelFormat[k], - v->HTotal[k] / v->PixelClock[k], - v->VRatio[k], - v->VRatioChroma[k], - v->Tno_bw[k], - v->DCCEnable[k], - v->dpte_row_height[k], - v->meta_row_height[k], - v->dpte_row_height_chroma[k], - v->meta_row_height_chroma[k], - &v->DestinationLinesToRequestVMInImmediateFlip[k], - &v->DestinationLinesToRequestRowInImmediateFlip[k], - &v->final_flip_bw[k], - &v->ImmediateFlipSupportedForPipe[k]); + v->PixelPTEBytesPerRow[k]); } v->total_dcn_read_bw_with_flip = 0.0; @@ -3041,64 +2965,28 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman CalculateWatermarksAndDRAMSpeedChangeSupport( mode_lib, PrefetchMode, - v->NumberOfActivePlanes, - v->MaxLineBufferLines, - v->LineBufferSize, - v->WritebackInterfaceBufferSize, v->DCFCLK, v->ReturnBW, - v->SynchronizedVBlank, - v->dpte_group_bytes, - v->MetaChunkSize, v->UrgentLatency, v->UrgentExtraLatency, - v->WritebackLatency, - v->WritebackChunkSize, v->SOCCLK, - v->DRAMClockChangeLatency, - v->SRExitTime, - v->SREnterPlusExitTime, - v->SRExitZ8Time, - v->SREnterPlusExitZ8Time, v->DCFCLKDeepSleep, v->DETBufferSizeY, v->DETBufferSizeC, v->SwathHeightY, v->SwathHeightC, - v->LBBitPerPixel, v->SwathWidthY, v->SwathWidthC, - v->HRatio, - v->HRatioChroma, - v->vtaps, - v->VTAPsChroma, - v->VRatio, - v->VRatioChroma, - v->HTotal, - v->PixelClock, - v->BlendingAndTiming, v->DPPPerPlane, v->BytePerPixelDETY, v->BytePerPixelDETC, - v->DSTXAfterScaler, - v->DSTYAfterScaler, - v->WritebackEnable, - v->WritebackPixelFormat, - v->WritebackDestinationWidth, - v->WritebackDestinationHeight, - v->WritebackSourceHeight, v->UnboundedRequestEnabled, v->CompressedBufferSizeInkByte, &DRAMClockChangeSupport, - &v->UrgentWatermark, - &v->WritebackUrgentWatermark, - &v->DRAMClockChangeWatermark, - &v->WritebackDRAMClockChangeWatermark, &v->StutterExitWatermark, &v->StutterEnterPlusExitWatermark, &v->Z8StutterExitWatermark, - &v->Z8StutterEnterPlusExitWatermark, - &v->MinActiveDRAMClockChangeLatencySupported); + &v->Z8StutterEnterPlusExitWatermark); for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (v->WritebackEnable[k] == true) { @@ -3710,61 +3598,43 @@ static void CalculateRowBandwidth( static void CalculateFlipSchedule( struct display_mode_lib *mode_lib, + unsigned int k, double HostVMInefficiencyFactor, double UrgentExtraLatency, double UrgentLatency, - unsigned int GPUVMMaxPageTableLevels, - bool HostVMEnable, - unsigned int HostVMMaxNonCachedPageTableLevels, - bool GPUVMEnable, - double HostVMMinPageSize, double PDEAndMetaPTEBytesPerFrame, double MetaRowBytes, - double DPTEBytesPerRow, - double BandwidthAvailableForImmediateFlip, - unsigned int TotImmediateFlipBytes, - enum source_format_class SourcePixelFormat, - double LineTime, - double VRatio, - double VRatioChroma, - double Tno_bw, - bool DCCEnable, - unsigned int dpte_row_height, - unsigned int meta_row_height, - unsigned int dpte_row_height_chroma, - unsigned int meta_row_height_chroma, - double *DestinationLinesToRequestVMInImmediateFlip, - double *DestinationLinesToRequestRowInImmediateFlip, - double *final_flip_bw, - bool *ImmediateFlipSupportedForPipe) + double DPTEBytesPerRow) { + struct vba_vars_st *v = &mode_lib->vba; double min_row_time = 0.0; unsigned int HostVMDynamicLevelsTrips; double TimeForFetchingMetaPTEImmediateFlip; double TimeForFetchingRowInVBlankImmediateFlip; double ImmediateFlipBW; + double LineTime = v->HTotal[k] / v->PixelClock[k]; - if (GPUVMEnable == true && HostVMEnable == true) { - HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels; + if (v->GPUVMEnable == true && v->HostVMEnable == true) { + HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels; } else { HostVMDynamicLevelsTrips = 0; } - if (GPUVMEnable == true || DCCEnable == true) { - ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) * BandwidthAvailableForImmediateFlip / TotImmediateFlipBytes; + if (v->GPUVMEnable == true || v->DCCEnable[k] == true) { + ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) * v->BandwidthAvailableForImmediateFlip / v->TotImmediateFlipBytes; } - if (GPUVMEnable == true) { + if (v->GPUVMEnable == true) { TimeForFetchingMetaPTEImmediateFlip = dml_max3( - Tno_bw + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW, - UrgentExtraLatency + UrgentLatency * (GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1), + v->Tno_bw[k] + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW, + UrgentExtraLatency + UrgentLatency * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1), LineTime / 4.0); } else { TimeForFetchingMetaPTEImmediateFlip = 0; } - *DestinationLinesToRequestVMInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0; - if ((GPUVMEnable == true || DCCEnable == true)) { + v->DestinationLinesToRequestVMInImmediateFlip[k] = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0; + if ((v->GPUVMEnable == true || v->DCCEnable[k] == true)) { TimeForFetchingRowInVBlankImmediateFlip = dml_max3( (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / ImmediateFlipBW, UrgentLatency * (HostVMDynamicLevelsTrips + 1), @@ -3773,54 +3643,54 @@ static void CalculateFlipSchedule( TimeForFetchingRowInVBlankImmediateFlip = 0; } - *DestinationLinesToRequestRowInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0; + v->DestinationLinesToRequestRowInImmediateFlip[k] = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0; - if (GPUVMEnable == true) { - *final_flip_bw = dml_max( - PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInImmediateFlip * LineTime), - (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime)); - } else if ((GPUVMEnable == true || DCCEnable == true)) { - *final_flip_bw = (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInImmediateFlip * LineTime); + if (v->GPUVMEnable == true) { + v->final_flip_bw[k] = dml_max( + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (v->DestinationLinesToRequestVMInImmediateFlip[k] * LineTime), + (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (v->DestinationLinesToRequestRowInImmediateFlip[k] * LineTime)); + } else if ((v->GPUVMEnable == true || v->DCCEnable[k] == true)) { + v->final_flip_bw[k] = (MetaRowBytes + DPTEBytesPerRow * HostVMInefficiencyFactor) / (v->DestinationLinesToRequestRowInImmediateFlip[k] * LineTime); } else { - *final_flip_bw = 0; + v->final_flip_bw[k] = 0; } - if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10 || SourcePixelFormat == dm_rgbe_alpha) { - if (GPUVMEnable == true && DCCEnable != true) { - min_row_time = dml_min(dpte_row_height * LineTime / VRatio, dpte_row_height_chroma * LineTime / VRatioChroma); - } else if (GPUVMEnable != true && DCCEnable == true) { - min_row_time = dml_min(meta_row_height * LineTime / VRatio, meta_row_height_chroma * LineTime / VRatioChroma); + if (v->SourcePixelFormat[k] == dm_420_8 || v->SourcePixelFormat[k] == dm_420_10 || v->SourcePixelFormat[k] == dm_rgbe_alpha) { + if (v->GPUVMEnable == true && v->DCCEnable[k] != true) { + min_row_time = dml_min(v->dpte_row_height[k] * LineTime / v->VRatio[k], v->dpte_row_height_chroma[k] * LineTime / v->VRatioChroma[k]); + } else if (v->GPUVMEnable != true && v->DCCEnable[k] == true) { + min_row_time = dml_min(v->meta_row_height[k] * LineTime / v->VRatio[k], v->meta_row_height_chroma[k] * LineTime / v->VRatioChroma[k]); } else { min_row_time = dml_min4( - dpte_row_height * LineTime / VRatio, - meta_row_height * LineTime / VRatio, - dpte_row_height_chroma * LineTime / VRatioChroma, - meta_row_height_chroma * LineTime / VRatioChroma); + v->dpte_row_height[k] * LineTime / v->VRatio[k], + v->meta_row_height[k] * LineTime / v->VRatio[k], + v->dpte_row_height_chroma[k] * LineTime / v->VRatioChroma[k], + v->meta_row_height_chroma[k] * LineTime / v->VRatioChroma[k]); } } else { - if (GPUVMEnable == true && DCCEnable != true) { - min_row_time = dpte_row_height * LineTime / VRatio; - } else if (GPUVMEnable != true && DCCEnable == true) { - min_row_time = meta_row_height * LineTime / VRatio; + if (v->GPUVMEnable == true && v->DCCEnable[k] != true) { + min_row_time = v->dpte_row_height[k] * LineTime / v->VRatio[k]; + } else if (v->GPUVMEnable != true && v->DCCEnable[k] == true) { + min_row_time = v->meta_row_height[k] * LineTime / v->VRatio[k]; } else { - min_row_time = dml_min(dpte_row_height * LineTime / VRatio, meta_row_height * LineTime / VRatio); + min_row_time = dml_min(v->dpte_row_height[k] * LineTime / v->VRatio[k], v->meta_row_height[k] * LineTime / v->VRatio[k]); } } - if (*DestinationLinesToRequestVMInImmediateFlip >= 32 || *DestinationLinesToRequestRowInImmediateFlip >= 16 + if (v->DestinationLinesToRequestVMInImmediateFlip[k] >= 32 || v->DestinationLinesToRequestRowInImmediateFlip[k] >= 16 || TimeForFetchingMetaPTEImmediateFlip + 2 * TimeForFetchingRowInVBlankImmediateFlip > min_row_time) { - *ImmediateFlipSupportedForPipe = false; + v->ImmediateFlipSupportedForPipe[k] = false; } else { - *ImmediateFlipSupportedForPipe = true; + v->ImmediateFlipSupportedForPipe[k] = true; } #ifdef __DML_VBA_DEBUG__ - dml_print("DML::%s: DestinationLinesToRequestVMInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestVMInImmediateFlip); - dml_print("DML::%s: DestinationLinesToRequestRowInImmediateFlip = %f\n", __func__, *DestinationLinesToRequestRowInImmediateFlip); + dml_print("DML::%s: DestinationLinesToRequestVMInImmediateFlip = %f\n", __func__, v->DestinationLinesToRequestVMInImmediateFlip[k]); + dml_print("DML::%s: DestinationLinesToRequestRowInImmediateFlip = %f\n", __func__, v->DestinationLinesToRequestRowInImmediateFlip[k]); dml_print("DML::%s: TimeForFetchingMetaPTEImmediateFlip = %f\n", __func__, TimeForFetchingMetaPTEImmediateFlip); dml_print("DML::%s: TimeForFetchingRowInVBlankImmediateFlip = %f\n", __func__, TimeForFetchingRowInVBlankImmediateFlip); dml_print("DML::%s: min_row_time = %f\n", __func__, min_row_time); - dml_print("DML::%s: ImmediateFlipSupportedForPipe = %d\n", __func__, *ImmediateFlipSupportedForPipe); + dml_print("DML::%s: ImmediateFlipSupportedForPipe = %d\n", __func__, v->ImmediateFlipSupportedForPipe[k]); #endif } @@ -5412,33 +5282,13 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ for (k = 0; k < v->NumberOfActivePlanes; k++) { CalculateFlipSchedule( mode_lib, + k, HostVMInefficiencyFactor, v->ExtraLatency, v->UrgLatency[i], - v->GPUVMMaxPageTableLevels, - v->HostVMEnable, - v->HostVMMaxNonCachedPageTableLevels, - v->GPUVMEnable, - v->HostVMMinPageSize, v->PDEAndMetaPTEBytesPerFrame[i][j][k], v->MetaRowBytes[i][j][k], - v->DPTEBytesPerRow[i][j][k], - v->BandwidthAvailableForImmediateFlip, - v->TotImmediateFlipBytes, - v->SourcePixelFormat[k], - v->HTotal[k] / v->PixelClock[k], - v->VRatio[k], - v->VRatioChroma[k], - v->Tno_bw[k], - v->DCCEnable[k], - v->dpte_row_height[k], - v->meta_row_height[k], - v->dpte_row_height_chroma[k], - v->meta_row_height_chroma[k], - &v->DestinationLinesToRequestVMInImmediateFlip[k], - &v->DestinationLinesToRequestRowInImmediateFlip[k], - &v->final_flip_bw[k], - &v->ImmediateFlipSupportedForPipe[k]); + v->DPTEBytesPerRow[i][j][k]); } v->total_dcn_read_bw_with_flip = 0.0; for (k = 0; k < v->NumberOfActivePlanes; k++) { @@ -5496,64 +5346,28 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ CalculateWatermarksAndDRAMSpeedChangeSupport( mode_lib, v->PrefetchModePerState[i][j], - v->NumberOfActivePlanes, - v->MaxLineBufferLines, - v->LineBufferSize, - v->WritebackInterfaceBufferSize, v->DCFCLKState[i][j], v->ReturnBWPerState[i][j], - v->SynchronizedVBlank, - v->dpte_group_bytes, - v->MetaChunkSize, v->UrgLatency[i], v->ExtraLatency, - v->WritebackLatency, - v->WritebackChunkSize, v->SOCCLKPerState[i], - v->DRAMClockChangeLatency, - v->SRExitTime, - v->SREnterPlusExitTime, - v->SRExitZ8Time, - v->SREnterPlusExitZ8Time, v->ProjectedDCFCLKDeepSleep[i][j], v->DETBufferSizeYThisState, v->DETBufferSizeCThisState, v->SwathHeightYThisState, v->SwathHeightCThisState, - v->LBBitPerPixel, v->SwathWidthYThisState, v->SwathWidthCThisState, - v->HRatio, - v->HRatioChroma, - v->vtaps, - v->VTAPsChroma, - v->VRatio, - v->VRatioChroma, - v->HTotal, - v->PixelClock, - v->BlendingAndTiming, v->NoOfDPPThisState, v->BytePerPixelInDETY, v->BytePerPixelInDETC, - v->DSTXAfterScaler, - v->DSTYAfterScaler, - v->WritebackEnable, - v->WritebackPixelFormat, - v->WritebackDestinationWidth, - v->WritebackDestinationHeight, - v->WritebackSourceHeight, UnboundedRequestEnabledThisState, CompressedBufferSizeInkByteThisState, &v->DRAMClockChangeSupport[i][j], - &v->UrgentWatermark, - &v->WritebackUrgentWatermark, - &v->DRAMClockChangeWatermark, - &v->WritebackDRAMClockChangeWatermark, - &dummy, &dummy, &dummy, &dummy, - &v->MinActiveDRAMClockChangeLatencySupported); + &dummy); } } @@ -5679,64 +5493,28 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ static void CalculateWatermarksAndDRAMSpeedChangeSupport( struct display_mode_lib *mode_lib, unsigned int PrefetchMode, - unsigned int NumberOfActivePlanes, - unsigned int MaxLineBufferLines, - unsigned int LineBufferSize, - unsigned int WritebackInterfaceBufferSize, double DCFCLK, double ReturnBW, - bool SynchronizedVBlank, - unsigned int dpte_group_bytes[], - unsigned int MetaChunkSize, double UrgentLatency, double ExtraLatency, - double WritebackLatency, - double WritebackChunkSize, double SOCCLK, - double DRAMClockChangeLatency, - double SRExitTime, - double SREnterPlusExitTime, - double SRExitZ8Time, - double SREnterPlusExitZ8Time, double DCFCLKDeepSleep, unsigned int DETBufferSizeY[], unsigned int DETBufferSizeC[], unsigned int SwathHeightY[], unsigned int SwathHeightC[], - unsigned int LBBitPerPixel[], double SwathWidthY[], double SwathWidthC[], - double HRatio[], - double HRatioChroma[], - unsigned int vtaps[], - unsigned int VTAPsChroma[], - double VRatio[], - double VRatioChroma[], - unsigned int HTotal[], - double PixelClock[], - unsigned int BlendingAndTiming[], unsigned int DPPPerPlane[], double BytePerPixelDETY[], double BytePerPixelDETC[], - double DSTXAfterScaler[], - double DSTYAfterScaler[], - bool WritebackEnable[], - enum source_format_class WritebackPixelFormat[], - double WritebackDestinationWidth[], - double WritebackDestinationHeight[], - double WritebackSourceHeight[], bool UnboundedRequestEnabled, unsigned int CompressedBufferSizeInkByte, enum clock_change_support *DRAMClockChangeSupport, - double *UrgentWatermark, - double *WritebackUrgentWatermark, - double *DRAMClockChangeWatermark, - double *WritebackDRAMClockChangeWatermark, double *StutterExitWatermark, double *StutterEnterPlusExitWatermark, double *Z8StutterExitWatermark, - double *Z8StutterEnterPlusExitWatermark, - double *MinActiveDRAMClockChangeLatencySupported) + double *Z8StutterEnterPlusExitWatermark) { struct vba_vars_st *v = &mode_lib->vba; double EffectiveLBLatencyHidingY; @@ -5756,103 +5534,103 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double TotalPixelBW = 0.0; int k, j; - *UrgentWatermark = UrgentLatency + ExtraLatency; + v->UrgentWatermark = UrgentLatency + ExtraLatency; #ifdef __DML_VBA_DEBUG__ dml_print("DML::%s: UrgentLatency = %f\n", __func__, UrgentLatency); dml_print("DML::%s: ExtraLatency = %f\n", __func__, ExtraLatency); - dml_print("DML::%s: UrgentWatermark = %f\n", __func__, *UrgentWatermark); + dml_print("DML::%s: UrgentWatermark = %f\n", __func__, v->UrgentWatermark); #endif - *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark; + v->DRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->UrgentWatermark; #ifdef __DML_VBA_DEBUG__ - dml_print("DML::%s: DRAMClockChangeLatency = %f\n", __func__, DRAMClockChangeLatency); - dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, *DRAMClockChangeWatermark); + dml_print("DML::%s: v->DRAMClockChangeLatency = %f\n", __func__, v->DRAMClockChangeLatency); + dml_print("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, v->DRAMClockChangeWatermark); #endif v->TotalActiveWriteback = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (WritebackEnable[k] == true) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->WritebackEnable[k] == true) { v->TotalActiveWriteback = v->TotalActiveWriteback + 1; } } if (v->TotalActiveWriteback <= 1) { - *WritebackUrgentWatermark = WritebackLatency; + v->WritebackUrgentWatermark = v->WritebackLatency; } else { - *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + v->WritebackUrgentWatermark = v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; } if (v->TotalActiveWriteback <= 1) { - *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency; + v->WritebackDRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->WritebackLatency; } else { - *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + v->WritebackDRAMClockChangeWatermark = v->DRAMClockChangeLatency + v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; } - for (k = 0; k < NumberOfActivePlanes; ++k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { TotalPixelBW = TotalPixelBW - + DPPPerPlane[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] + SwathWidthC[k] * BytePerPixelDETC[k] * VRatioChroma[k]) - / (HTotal[k] / PixelClock[k]); + + DPPPerPlane[k] * (SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k] + SwathWidthC[k] * BytePerPixelDETC[k] * v->VRatioChroma[k]) + / (v->HTotal[k] / v->PixelClock[k]); } - for (k = 0; k < NumberOfActivePlanes; ++k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { double EffectiveDETBufferSizeY = DETBufferSizeY[k]; v->LBLatencyHidingSourceLinesY = dml_min( - (double) MaxLineBufferLines, - dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1); + (double) v->MaxLineBufferLines, + dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1); v->LBLatencyHidingSourceLinesC = dml_min( - (double) MaxLineBufferLines, - dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1); + (double) v->MaxLineBufferLines, + dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1); - EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]); + EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]); - EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]); + EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]); if (UnboundedRequestEnabled) { EffectiveDETBufferSizeY = EffectiveDETBufferSizeY - + CompressedBufferSizeInkByte * 1024 * SwathWidthY[k] * BytePerPixelDETY[k] * VRatio[k] / (HTotal[k] / PixelClock[k]) / TotalPixelBW; + + CompressedBufferSizeInkByte * 1024 * SwathWidthY[k] * BytePerPixelDETY[k] * v->VRatio[k] / (v->HTotal[k] / v->PixelClock[k]) / TotalPixelBW; } LinesInDETY[k] = (double) EffectiveDETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k]; LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]); - FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k]; + FullDETBufferingTimeY = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k]; if (BytePerPixelDETC[k] > 0) { LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k]; LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]); - FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k]; + FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (v->HTotal[k] / v->PixelClock[k]) / v->VRatioChroma[k]; } else { LinesInDETC = 0; FullDETBufferingTimeC = 999999; } ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY - - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark; + - ((double) v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) * v->HTotal[k] / v->PixelClock[k] - v->UrgentWatermark - v->DRAMClockChangeWatermark; - if (NumberOfActivePlanes > 1) { + if (v->NumberOfActivePlanes > 1) { ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k]; + - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightY[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatio[k]; } if (BytePerPixelDETC[k] > 0) { ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - - ((double) DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) * HTotal[k] / PixelClock[k] - *UrgentWatermark - *DRAMClockChangeWatermark; + - ((double) v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) * v->HTotal[k] / v->PixelClock[k] - v->UrgentWatermark - v->DRAMClockChangeWatermark; - if (NumberOfActivePlanes > 1) { + if (v->NumberOfActivePlanes > 1) { ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k]; + - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightC[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatioChroma[k]; } v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC); } else { v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY; } - if (WritebackEnable[k] == true) { - WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024 - / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4); - if (WritebackPixelFormat[k] == dm_444_64) { + if (v->WritebackEnable[k] == true) { + WritebackDRAMClockChangeLatencyHiding = v->WritebackInterfaceBufferSize * 1024 + / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4); + if (v->WritebackPixelFormat[k] == dm_444_64) { WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2; } WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark; @@ -5862,14 +5640,14 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( v->MinActiveDRAMClockChangeMargin = 999999; PlaneWithMinActiveDRAMClockChangeMargin = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) { v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k]; - if (BlendingAndTiming[k] == k) { + if (v->BlendingAndTiming[k] == k) { PlaneWithMinActiveDRAMClockChangeMargin = k; } else { - for (j = 0; j < NumberOfActivePlanes; ++j) { - if (BlendingAndTiming[k] == j) { + for (j = 0; j < v->NumberOfActivePlanes; ++j) { + if (v->BlendingAndTiming[k] == j) { PlaneWithMinActiveDRAMClockChangeMargin = j; } } @@ -5877,11 +5655,11 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( } } - *MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency; + v->MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + v->DRAMClockChangeLatency ; SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (v->BlendingAndTiming[k] == k)) && !(v->BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) { SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k]; } @@ -5889,25 +5667,25 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( v->TotalNumberOfActiveOTG = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (BlendingAndTiming[k] == k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k) { v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1; } } if (v->MinActiveDRAMClockChangeMargin > 0 && PrefetchMode == 0) { *DRAMClockChangeSupport = dm_dram_clock_change_vactive; - } else if ((SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 + } else if ((v->SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0) { *DRAMClockChangeSupport = dm_dram_clock_change_vblank; } else { *DRAMClockChangeSupport = dm_dram_clock_change_unsupported; } - *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep; - *StutterEnterPlusExitWatermark = (SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep); - *Z8StutterExitWatermark = SRExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; - *Z8StutterEnterPlusExitWatermark = SREnterPlusExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; + *StutterExitWatermark = v->SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep; + *StutterEnterPlusExitWatermark = (v->SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep); + *Z8StutterExitWatermark = v->SRExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; + *Z8StutterEnterPlusExitWatermark = v->SREnterPlusExitZ8Time + ExtraLatency + 10 / DCFCLKDeepSleep; #ifdef __DML_VBA_DEBUG__ dml_print("DML::%s: StutterExitWatermark = %f\n", __func__, *StutterExitWatermark); @@ -7407,7 +7185,7 @@ static unsigned int CalculateMaxVStartup( double line_time_us = HTotal / PixelClock; unsigned int vblank_actual = VTotal - VActive; unsigned int vblank_nom_default_in_line = dml_floor(VBlankNomDefaultUS / line_time_us, 1.0); - unsigned int vblank_nom_input = dml_min(VBlankNom, vblank_nom_default_in_line); + unsigned int vblank_nom_input = VBlankNom; //dml_min(VBlankNom, vblank_nom_default_in_line); unsigned int vblank_avail = vblank_nom_input == 0 ? vblank_nom_default_in_line : vblank_nom_input; vblank_size = (unsigned int) dml_min(vblank_actual, vblank_avail); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 7f6c977c4981..0571700f53f9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -121,8 +121,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { }, }, .num_states = 1, - .sr_exit_time_us = 20.16, - .sr_enter_plus_exit_time_us = 27.13, + .sr_exit_time_us = 42.97, + .sr_enter_plus_exit_time_us = 49.94, .sr_exit_z8_time_us = 285.0, .sr_enter_plus_exit_z8_time_us = 320, .writeback_latency_us = 12.0, @@ -244,6 +244,50 @@ void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr) } /** + * Finds dummy_latency_index when MCLK switching using firmware based + * vblank stretch is enabled. This function will iterate through the + * table of dummy pstate latencies until the lowest value that allows + * dm_allow_self_refresh_and_mclk_switch to happen is found + */ +int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + const int max_latency_table_entries = 4; + const struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + int dummy_latency_index = 0; + + dc_assert_fp_enabled(); + + while (dummy_latency_index < max_latency_table_entries) { + context->bw_ctx.dml.soc.dram_clock_change_latency_us = + dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us; + dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false); + + if (vlevel < context->bw_ctx.dml.vba.soc.num_states && + vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported) + break; + + dummy_latency_index++; + } + + if (dummy_latency_index == max_latency_table_entries) { + ASSERT(dummy_latency_index != max_latency_table_entries); + /* If the execution gets here, it means dummy p_states are + * not possible. This should never happen and would mean + * something is severely wrong. + * Here we reset dummy_latency_index to 3, because it is + * better to have underflows than system crashes. + */ + dummy_latency_index = max_latency_table_entries - 1; + } + + return dummy_latency_index; +} + +/** * dcn32_helper_populate_phantom_dlg_params - Get DLG params for phantom pipes * and populate pipe_ctx with those params. * @@ -286,41 +330,92 @@ void dcn32_helper_populate_phantom_dlg_params(struct dc *dc, } } -bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index) +/** + * ******************************************************************************************* + * dcn32_predict_pipe_split: Predict if pipe split will occur for a given DML pipe + * + * This function takes in a DML pipe (pipe_e2e) and predicts if pipe split is required (both + * ODM and MPC). For pipe split, ODM combine is determined by the ODM mode, and MPC combine is + * determined by DPPClk requirements + * + * This function follows the same policy as DML: + * - Check for ODM combine requirements / policy first + * - MPC combine is only chosen if there is no ODM combine requirements / policy in place, and + * MPC is required + * + * @param [in]: context: New DC state to be programmed + * @param [in]: pipe_e2e: DML pipe end to end context + * + * @return: Number of splits expected (1 for 2:1 split, 3 for 4:1 split, 0 for no splits). + * + * ******************************************************************************************* + */ +uint8_t dcn32_predict_pipe_split(struct dc_state *context, + display_e2e_pipe_params_st *pipe_e2e) { double pscl_throughput; double pscl_throughput_chroma; double dpp_clk_single_dpp, clock; double clk_frequency = 0.0; double vco_speed = context->bw_ctx.dml.soc.dispclk_dppclk_vco_speed_mhz; + bool total_available_pipes_support = false; + uint32_t number_of_dpp = 0; + enum odm_combine_mode odm_mode = dm_odm_combine_mode_disabled; + double req_dispclk_per_surface = 0; + uint8_t num_splits = 0; dc_assert_fp_enabled(); - dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(pipe.scale_ratio_depth.hscl_ratio, - pipe.scale_ratio_depth.hscl_ratio_c, - pipe.scale_ratio_depth.vscl_ratio, - pipe.scale_ratio_depth.vscl_ratio_c, - context->bw_ctx.dml.ip.max_dchub_pscl_bw_pix_per_clk, - context->bw_ctx.dml.ip.max_pscl_lb_bw_pix_per_clk, - pipe.dest.pixel_rate_mhz, - pipe.src.source_format, - pipe.scale_taps.htaps, - pipe.scale_taps.htaps_c, - pipe.scale_taps.vtaps, - pipe.scale_taps.vtaps_c, - /* Output */ - &pscl_throughput, &pscl_throughput_chroma, - &dpp_clk_single_dpp); + dml32_CalculateODMMode(context->bw_ctx.dml.ip.maximum_pixels_per_line_per_dsc_unit, + pipe_e2e->pipe.dest.hactive, + pipe_e2e->dout.output_format, + pipe_e2e->dout.output_type, + pipe_e2e->pipe.dest.odm_combine_policy, + context->bw_ctx.dml.soc.clock_limits[context->bw_ctx.dml.soc.num_states - 1].dispclk_mhz, + context->bw_ctx.dml.soc.clock_limits[context->bw_ctx.dml.soc.num_states - 1].dispclk_mhz, + pipe_e2e->dout.dsc_enable != 0, + 0, /* TotalNumberOfActiveDPP can be 0 since we're predicting pipe split requirement */ + context->bw_ctx.dml.ip.max_num_dpp, + pipe_e2e->pipe.dest.pixel_rate_mhz, + context->bw_ctx.dml.soc.dcn_downspread_percent, + context->bw_ctx.dml.ip.dispclk_ramp_margin_percent, + context->bw_ctx.dml.soc.dispclk_dppclk_vco_speed_mhz, + pipe_e2e->dout.dsc_slices, + /* Output */ + &total_available_pipes_support, + &number_of_dpp, + &odm_mode, + &req_dispclk_per_surface); + + dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(pipe_e2e->pipe.scale_ratio_depth.hscl_ratio, + pipe_e2e->pipe.scale_ratio_depth.hscl_ratio_c, + pipe_e2e->pipe.scale_ratio_depth.vscl_ratio, + pipe_e2e->pipe.scale_ratio_depth.vscl_ratio_c, + context->bw_ctx.dml.ip.max_dchub_pscl_bw_pix_per_clk, + context->bw_ctx.dml.ip.max_pscl_lb_bw_pix_per_clk, + pipe_e2e->pipe.dest.pixel_rate_mhz, + pipe_e2e->pipe.src.source_format, + pipe_e2e->pipe.scale_taps.htaps, + pipe_e2e->pipe.scale_taps.htaps_c, + pipe_e2e->pipe.scale_taps.vtaps, + pipe_e2e->pipe.scale_taps.vtaps_c, + /* Output */ + &pscl_throughput, &pscl_throughput_chroma, + &dpp_clk_single_dpp); clock = dpp_clk_single_dpp * (1 + context->bw_ctx.dml.soc.dcn_downspread_percent / 100); if (clock > 0) - clk_frequency = vco_speed * 4.0 / ((int)(vco_speed * 4.0)); + clk_frequency = vco_speed * 4.0 / ((int)(vco_speed * 4.0) / clock); - if (clk_frequency > context->bw_ctx.dml.soc.clock_limits[index].dppclk_mhz) - return true; - else - return false; + if (odm_mode == dm_odm_combine_mode_2to1) + num_splits = 1; + else if (odm_mode == dm_odm_combine_mode_4to1) + num_splits = 3; + else if (clk_frequency > context->bw_ctx.dml.soc.clock_limits[context->bw_ctx.dml.soc.num_states - 1].dppclk_mhz) + num_splits = 1; + + return num_splits; } static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry) @@ -579,9 +674,10 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc, * - Not able to switch in vactive naturally (switching in active means the * DET provides enough buffer to hide the P-State switch latency -- trying * to combine this with SubVP can cause issues with the scheduling). + * - Not TMZ surface */ if (pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && + pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface && vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { while (pipe) { num_pipes++; @@ -1024,7 +1120,9 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, dc->debug.force_subvp_mclk_switch)) { dcn32_merge_pipes_for_subvp(dc, context); - // to re-initialize viewport after the pipe merge + memset(merge, 0, MAX_PIPES * sizeof(bool)); + + /* to re-initialize viewport after the pipe merge */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1109,17 +1207,23 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, vba->VoltageLevel = *vlevel; } } else { - // only call dcn20_validate_apply_pipe_split_flags if we found a supported config - memset(split, 0, MAX_PIPES * sizeof(int)); - memset(merge, 0, MAX_PIPES * sizeof(bool)); - *vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge); - vba->VoltageLevel = *vlevel; - // Most populate phantom DLG params before programming hardware / timing for phantom pipe DC_FP_START(); dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt); DC_FP_END(); + /* Call validate_apply_pipe_split flags after calling DML getters for + * phantom dlg params, or some of the VBA params indicating pipe split + * can be overwritten by the getters. + * + * When setting up SubVP config, all pipes are merged before attempting to + * add phantom pipes. If pipe split (ODM / MPC) is required, both the main + * and phantom pipes will be split in the regular pipe splitting sequence. + */ + memset(split, 0, MAX_PIPES * sizeof(int)); + memset(merge, 0, MAX_PIPES * sizeof(bool)); + *vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge); + vba->VoltageLevel = *vlevel; // Note: We can't apply the phantom pipes to hardware at this time. We have to wait // until driver has acquired the DMCUB lock to do it safely. } @@ -1487,6 +1591,28 @@ bool dcn32_internal_validate_bw(struct dc *dc, if (pipe->next_odm_pipe) pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe; + /*2:1ODM+MPC Split MPO to Single Pipe + MPC Split MPO*/ + if (pipe->bottom_pipe) { + if (pipe->bottom_pipe->prev_odm_pipe || pipe->bottom_pipe->next_odm_pipe) { + /*MPC split rules will handle this case*/ + pipe->bottom_pipe->top_pipe = NULL; + } else { + if (pipe->prev_odm_pipe->bottom_pipe) { + /* 3 plane MPO*/ + pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe->bottom_pipe; + pipe->prev_odm_pipe->bottom_pipe->bottom_pipe = pipe->bottom_pipe; + } else { + /* 2 plane MPO*/ + pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe; + pipe->prev_odm_pipe->bottom_pipe = pipe->bottom_pipe; + } + } + } + + if (pipe->top_pipe) { + pipe->top_pipe->bottom_pipe = NULL; + } + pipe->bottom_pipe = NULL; pipe->next_odm_pipe = NULL; pipe->plane_state = NULL; @@ -1619,8 +1745,20 @@ bool dcn32_internal_validate_bw(struct dc *dc, goto validate_fail; } - if (repopulate_pipes) + if (repopulate_pipes) { pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + + /* repopulate_pipes = 1 means the pipes were either split or merged. In this case + * we have to re-calculate the DET allocation and run through DML once more to + * ensure all the params are calculated correctly. We do not need to run the + * pipe split check again after this call (pipes are already split / merged). + * */ + if (!fast_validate) { + context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = + dm_prefetch_support_uclk_fclk_and_stutter_if_possible; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + } + } *vlevel_out = vlevel; *pipe_cnt_out = pipe_cnt; @@ -1666,7 +1804,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(dc, context); if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { - dummy_latency_index = dcn30_find_dummy_latency_index_for_fw_based_mclk_switch(dc, + dummy_latency_index = dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(dc, context, pipes, pipe_cnt, vlevel); /* After calling dcn30_find_dummy_latency_index_for_fw_based_mclk_switch @@ -1906,6 +2044,45 @@ static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st memset(&table[--(*num_entries)], 0, sizeof(struct _vcs_dpi_voltage_scaling_st)); } +void dcn32_patch_dpm_table(struct clk_bw_params *bw_params) +{ + int i; + unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, + max_phyclk_mhz = 0, max_dtbclk_mhz = 0, max_fclk_mhz = 0, max_uclk_mhz = 0; + + for (i = 0; i < MAX_NUM_DPM_LVL; i++) { + if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz) + max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz; + if (bw_params->clk_table.entries[i].fclk_mhz > max_fclk_mhz) + max_fclk_mhz = bw_params->clk_table.entries[i].fclk_mhz; + if (bw_params->clk_table.entries[i].memclk_mhz > max_uclk_mhz) + max_uclk_mhz = bw_params->clk_table.entries[i].memclk_mhz; + if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz) + max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz; + if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz) + max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz; + if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz) + max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz; + if (bw_params->clk_table.entries[i].dtbclk_mhz > max_dtbclk_mhz) + max_dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz; + } + + /* Scan through clock values we currently have and if they are 0, + * then populate it with dcn3_2_soc.clock_limits[] value. + * + * Do it for DCFCLK, DISPCLK, DTBCLK and UCLK as any of those being + * 0, will cause it to skip building the clock table. + */ + if (max_dcfclk_mhz == 0) + bw_params->clk_table.entries[0].dcfclk_mhz = dcn3_2_soc.clock_limits[0].dcfclk_mhz; + if (max_dispclk_mhz == 0) + bw_params->clk_table.entries[0].dispclk_mhz = dcn3_2_soc.clock_limits[0].dispclk_mhz; + if (max_dtbclk_mhz == 0) + bw_params->clk_table.entries[0].dtbclk_mhz = dcn3_2_soc.clock_limits[0].dtbclk_mhz; + if (max_uclk_mhz == 0) + bw_params->clk_table.entries[0].memclk_mhz = dcn3_2_soc.clock_limits[0].dram_speed_mts / 16; +} + static int build_synthetic_soc_states(struct clk_bw_params *bw_params, struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries) { @@ -2140,6 +2317,7 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa if ((int)(dcn3_2_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns && dc->bb_overrides.urgent_latency_ns) { dcn3_2_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0; + dcn3_2_soc.urgent_latency_pixel_data_only_us = dc->bb_overrides.urgent_latency_ns / 1000.0; } if ((int)(dcn3_2_soc.dram_clock_change_latency_us * 1000) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h index 3ed06ab855be..3a3dc2ce4c73 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h @@ -29,11 +29,6 @@ #include "clk_mgr_internal.h" -#define DCN3_2_DEFAULT_DET_SIZE 256 -#define DCN3_2_MAX_DET_SIZE 1152 -#define DCN3_2_MIN_DET_SIZE 128 -#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 - void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr); void dcn32_helper_populate_phantom_dlg_params(struct dc *dc, @@ -41,9 +36,8 @@ void dcn32_helper_populate_phantom_dlg_params(struct dc *dc, display_e2e_pipe_params_st *pipes, int pipe_cnt); -bool dcn32_predict_pipe_split(struct dc_state *context, - display_pipe_params_st pipe, - int index); +uint8_t dcn32_predict_pipe_split(struct dc_state *context, + display_e2e_pipe_params_st *pipe_e2e); void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries, @@ -71,4 +65,12 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params); +int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); + +void dcn32_patch_dpm_table(struct clk_bw_params *bw_params); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index ad100658132f..75be1e1ce543 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -1992,6 +1992,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l dml32_CalculateODMMode( mode_lib->vba.MaximumPixelsPerLinePerDSCUnit, mode_lib->vba.HActive[k], + mode_lib->vba.OutputFormat[k], mode_lib->vba.Output[k], mode_lib->vba.ODMUse[k], mode_lib->vba.MaxDispclk[i], @@ -2014,6 +2015,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l dml32_CalculateODMMode( mode_lib->vba.MaximumPixelsPerLinePerDSCUnit, mode_lib->vba.HActive[k], + mode_lib->vba.OutputFormat[k], mode_lib->vba.Output[k], mode_lib->vba.ODMUse[k], mode_lib->vba.MaxDispclk[i], diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index 5b5b94f1024d..ad66e241f9ae 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -27,6 +27,8 @@ #include "display_mode_vba_32.h" #include "../display_mode_lib.h" +#define DCN32_MAX_FMT_420_BUFFER_WIDTH 4096 + unsigned int dml32_dscceComputeDelay( unsigned int bpc, double BPP, @@ -1179,6 +1181,7 @@ void dml32_CalculateDETBufferSize( void dml32_CalculateODMMode( unsigned int MaximumPixelsPerLinePerDSCUnit, unsigned int HActive, + enum output_format_class OutFormat, enum output_encoder_class Output, enum odm_combine_policy ODMUse, double StateDispclk, @@ -1253,6 +1256,29 @@ void dml32_CalculateODMMode( else *TotalAvailablePipesSupport = false; } + if (OutFormat == dm_420 && HActive > DCN32_MAX_FMT_420_BUFFER_WIDTH && + ODMUse != dm_odm_combine_policy_4to1) { + if (HActive > DCN32_MAX_FMT_420_BUFFER_WIDTH * 4) { + *ODMMode = dm_odm_combine_mode_disabled; + *NumberOfDPP = 0; + *TotalAvailablePipesSupport = false; + } else if (HActive > DCN32_MAX_FMT_420_BUFFER_WIDTH * 2 || + *ODMMode == dm_odm_combine_mode_4to1) { + *ODMMode = dm_odm_combine_mode_4to1; + *RequiredDISPCLKPerSurface = SurfaceRequiredDISPCLKWithODMCombineFourToOne; + *NumberOfDPP = 4; + } else { + *ODMMode = dm_odm_combine_mode_2to1; + *RequiredDISPCLKPerSurface = SurfaceRequiredDISPCLKWithODMCombineTwoToOne; + *NumberOfDPP = 2; + } + } + if (Output == dm_hdmi && OutFormat == dm_420 && + HActive > DCN32_MAX_FMT_420_BUFFER_WIDTH) { + *ODMMode = dm_odm_combine_mode_disabled; + *NumberOfDPP = 0; + *TotalAvailablePipesSupport = false; + } } double dml32_CalculateRequiredDispclk( diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h index 3dbc9cf46aad..55cead0d4237 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h @@ -216,6 +216,7 @@ void dml32_CalculateDETBufferSize( void dml32_CalculateODMMode( unsigned int MaximumPixelsPerLinePerDSCUnit, unsigned int HActive, + enum output_format_class OutFormat, enum output_encoder_class Output, enum odm_combine_policy ODMUse, double StateDispclk, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index 7ebf25e87933..dd90f241e906 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -489,6 +489,7 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p if ((int)(dcn3_21_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns && dc->bb_overrides.urgent_latency_ns) { dcn3_21_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0; + dcn3_21_soc.urgent_latency_pixel_data_only_us = dc->bb_overrides.urgent_latency_ns / 1000.0; } if ((int)(dcn3_21_soc.dram_clock_change_latency_us * 1000) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index c596187a1e09..f33a8879b05a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -510,6 +510,7 @@ struct _vcs_dpi_display_pipe_dest_params_st { unsigned int htotal; unsigned int vtotal; unsigned int vfront_porch; + unsigned int vblank_nom; unsigned int vactive; unsigned int hactive; unsigned int vstartup_start; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c index 503e7d984ff0..03924aed8d5c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -597,6 +597,7 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) mode_lib->vba.HTotal[mode_lib->vba.NumberOfActivePlanes] = dst->htotal; mode_lib->vba.VTotal[mode_lib->vba.NumberOfActivePlanes] = dst->vtotal; mode_lib->vba.VFrontPorch[mode_lib->vba.NumberOfActivePlanes] = dst->vfront_porch; + mode_lib->vba.VBlankNom[mode_lib->vba.NumberOfActivePlanes] = dst->vblank_nom; mode_lib->vba.DCCFractionOfZeroSizeRequestsLuma[mode_lib->vba.NumberOfActivePlanes] = src->dcc_fraction_of_zs_req_luma; mode_lib->vba.DCCFractionOfZeroSizeRequestsChroma[mode_lib->vba.NumberOfActivePlanes] = src->dcc_fraction_of_zs_req_chroma; mode_lib->vba.DCCEnable[mode_lib->vba.NumberOfActivePlanes] = diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 6682d9e181c6..b304d450b038 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -194,6 +194,11 @@ enum dc_status dpcd_configure_lttpr_mode( enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings); bool dp_retrieve_lttpr_cap(struct dc_link *link); +bool dp_is_lttpr_present(struct dc_link *link); +enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting); +void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override); +enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link); +enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link); bool dpcd_write_128b_132b_sst_payload_allocation_table( const struct dc_stream_state *stream, struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h index 68c2ed434d2c..cff5fd55a0ad 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h @@ -340,6 +340,8 @@ struct clk_mgr_internal { bool smu_present; void *wm_range_table; long long wm_range_table_addr; + + bool dpm_present; }; struct clk_mgr_internal_funcs { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index 437b64e87377..cd2be729846b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -268,10 +268,18 @@ enum dc_lut_mode { LUT_RAM_B }; -enum phy_state { - TX_OFF_SYMCLK_OFF, - TX_ON_SYMCLK_ON, - TX_OFF_SYMCLK_ON +enum symclk_state { + SYMCLK_OFF_TX_OFF, + SYMCLK_ON_TX_ON, + SYMCLK_ON_TX_OFF, +}; + +struct phy_state { + struct { + uint8_t otg : 1; + uint8_t reserved : 7; + } symclk_ref_cnts; + enum symclk_state symclk_state; }; /** diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index d7a7b2790143..d04b68dad413 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -32,11 +32,6 @@ #include "inc/hw/link_encoder.h" #include "core_status.h" -enum vline_select { - VLINE0, - VLINE1 -}; - struct pipe_ctx; struct dc_state; struct dc_stream_status; @@ -48,6 +43,7 @@ struct dc_phy_addr_space_config; struct dc_virtual_addr_space_config; struct dpp; struct dce_hwseq; +struct link_resource; struct hw_sequencer_funcs { void (*hardware_release)(struct dc *dc); @@ -88,6 +84,7 @@ struct hw_sequencer_funcs { struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); void (*update_pending_status)(struct pipe_ctx *pipe_ctx); void (*power_down)(struct dc *dc); + void (*update_dsc_pg)(struct dc *dc, struct dc_state *context, bool safe_to_disable); /* Pipe Lock Related */ void (*pipe_control_lock)(struct dc *dc, @@ -116,8 +113,7 @@ struct hw_sequencer_funcs { int group_index, int group_size, struct pipe_ctx *grouped_pipes[]); void (*setup_periodic_interrupt)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum vline_select vline); + struct pipe_ctx *pipe_ctx); void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, struct dc_crtc_timing_adjust adjust); void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, @@ -218,6 +214,25 @@ struct hw_sequencer_funcs { void (*set_pipe)(struct pipe_ctx *pipe_ctx); + void (*enable_dp_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings); + void (*enable_tmds_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock); + void (*enable_lvds_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock); + void (*disable_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + void (*get_dcc_en_bits)(struct dc *dc, int *dcc_en_bits); /* Idle Optimization Related */ @@ -245,9 +260,6 @@ struct hw_sequencer_funcs { struct tg_color *color, int mpcc_id); - void (*update_phy_state)(struct dc_state *state, struct pipe_ctx *pipe_ctx, enum phy_state target_state); - - void (*update_phantom_vp_position)(struct dc *dc, struct dc_state *context, struct pipe_ctx *phantom_pipe); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h index 1cdea0efe5c1..a4d61bb724b6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h @@ -124,6 +124,8 @@ struct hwseq_private_funcs { void (*dsc_pg_control)(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); + bool (*dsc_pg_status)(struct dce_hwseq *hws, + unsigned int dsc_inst); void (*update_odm)(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); void (*program_all_writeback_pipes_in_tree)(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 3482a877b6af..89964c980b87 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -55,9 +55,6 @@ struct link_hwss_ext { enum signal_type signal, enum clock_source_id clock_source, const struct dc_link_settings *link_settings); - void (*disable_dp_link_output)(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal); void (*set_dp_link_test_pattern)(struct dc_link *link, const struct link_resource *link_res, struct encoder_set_dp_phy_pattern_param *tp_params); @@ -79,6 +76,9 @@ struct link_hwss { void (*setup_stream_encoder)(struct pipe_ctx *pipe_ctx); void (*reset_stream_encoder)(struct pipe_ctx *pipe_ctx); void (*setup_stream_attribute)(struct pipe_ctx *pipe_ctx); + void (*disable_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); }; #endif /* __DC_LINK_HWSS_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 58158764adc0..c37d1141febe 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -219,9 +219,15 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, struct dc_state *context, uint8_t disabled_master_pipe_idx); +void reset_sync_context_for_pipe(const struct dc *dc, + struct dc_state *context, + uint8_t pipe_idx); + uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter); const struct link_hwss *get_link_hwss(const struct dc_link *link, const struct link_resource *link_res); +bool is_h_timing_divisible_by_2(struct dc_stream_state *stream); + #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c index 5e92019539c8..4227adbc646a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c @@ -130,7 +130,7 @@ void enable_dio_dp_link_output(struct dc_link *link, dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); } -void disable_dio_dp_link_output(struct dc_link *link, +void disable_dio_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal) { @@ -174,10 +174,10 @@ static const struct link_hwss dio_link_hwss = { .setup_stream_encoder = setup_dio_stream_encoder, .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, + .disable_link_output = disable_dio_link_output, .ext = { .set_throttled_vcp_size = set_dio_throttled_vcp_size, .enable_dp_link_output = enable_dio_dp_link_output, - .disable_dp_link_output = disable_dio_dp_link_output, .set_dp_link_test_pattern = set_dio_dp_link_test_pattern, .set_dp_lane_settings = set_dio_dp_lane_settings, .update_stream_allocation_table = update_dio_stream_allocation_table, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h index 08f22b32df48..126d37f847a1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h @@ -40,7 +40,7 @@ void enable_dio_dp_link_output(struct dc_link *link, enum signal_type signal, enum clock_source_id clock_source, const struct dc_link_settings *link_settings); -void disable_dio_dp_link_output(struct dc_link *link, +void disable_dio_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); void set_dio_dp_link_test_pattern(struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c index 89d4e8159138..64f7ea6a9aa3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c @@ -56,10 +56,10 @@ static const struct link_hwss dpia_link_hwss = { .setup_stream_encoder = setup_dio_stream_encoder, .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, + .disable_link_output = disable_dio_link_output, .ext = { .set_throttled_vcp_size = set_dio_throttled_vcp_size, .enable_dp_link_output = enable_dio_dp_link_output, - .disable_dp_link_output = disable_dio_dp_link_output, .set_dp_link_test_pattern = set_dio_dp_link_test_pattern, .set_dp_lane_settings = set_dio_dp_lane_settings, .update_stream_allocation_table = update_dpia_stream_allocation_table, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c index 226af06278ce..7d3147175ca2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c @@ -266,11 +266,11 @@ static const struct link_hwss hpo_dp_link_hwss = { .setup_stream_encoder = setup_hpo_dp_stream_encoder, .reset_stream_encoder = reset_hpo_dp_stream_encoder, .setup_stream_attribute = setup_hpo_dp_stream_attribute, + .disable_link_output = disable_hpo_dp_link_output, .ext = { .set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size, .set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width, .enable_dp_link_output = enable_hpo_dp_link_output, - .disable_dp_link_output = disable_hpo_dp_link_output, .set_dp_link_test_pattern = set_hpo_dp_link_test_pattern, .set_dp_lane_settings = set_hpo_dp_lane_settings, .update_stream_allocation_table = update_hpo_dp_stream_allocation_table, diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c index 501173ce270e..9522fe0b36c9 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c @@ -36,10 +36,18 @@ void virtual_setup_stream_attribute(struct pipe_ctx *pipe_ctx) void virtual_reset_stream_encoder(struct pipe_ctx *pipe_ctx) { } + +void virtual_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ +} + static const struct link_hwss virtual_link_hwss = { .setup_stream_encoder = virtual_setup_stream_encoder, .reset_stream_encoder = virtual_reset_stream_encoder, .setup_stream_attribute = virtual_setup_stream_attribute, + .disable_link_output = virtual_disable_link_output, }; const struct link_hwss *get_virtual_link_hwss(void) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 7cddbc431b57..5d1aadade8a5 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -760,6 +760,11 @@ enum dmub_cmd_dpia_type { DMUB_CMD__DPIA_MST_ALLOC_SLOTS = 2, }; +enum dmub_cmd_header_sub_type { + DMUB_CMD__SUB_TYPE_GENERAL = 0, + DMUB_CMD__SUB_TYPE_CURSOR_POSITION = 1 +}; + #pragma pack(push, 1) /** @@ -998,7 +1003,8 @@ struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 { uint8_t scale_factor_numerator; uint8_t scale_factor_denominator; uint8_t is_drr; - uint8_t pad[2]; + uint8_t main_split_pipe_index; + uint8_t phantom_split_pipe_index; } subvp_data; struct { diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index 9f3558c0ef11..c3089c673975 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -215,6 +215,7 @@ enum { #define DEVICE_ID_NV_143F 0x143F #define FAMILY_VGH 144 #define DEVICE_ID_VGH_163F 0x163F +#define DEVICE_ID_VGH_1435 0x1435 #define VANGOGH_A0 0x01 #define VANGOGH_UNKNOWN 0xFF diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index 05096c644a60..a7ba5bd8dc16 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -128,8 +128,8 @@ struct av_sync_data { uint8_t aud_del_ins3;/* DPCD 0002Dh */ }; -static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3, 0}; -static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5, 0}; +static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3}; +static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5}; static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u"; diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index d76ab72baf0c..d1e91d31d151 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -83,6 +83,7 @@ enum link_training_result { }; enum lttpr_mode { + LTTPR_MODE_UNKNOWN, LTTPR_MODE_NON_LTTPR, LTTPR_MODE_TRANSPARENT, LTTPR_MODE_NON_TRANSPARENT, diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h index d8632ccf3494..c488d4a50cf4 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h @@ -4409,6 +4409,10 @@ #define mmVMSHAREDPF0_MC_VM_XGMI_LFB_SIZE_BASE_IDX 1 #define mmVMSHAREDPF0_MC_VM_CACHEABLE_DRAM_CNTL 0x0af9 #define mmVMSHAREDPF0_MC_VM_CACHEABLE_DRAM_CNTL_BASE_IDX 1 +#define mmMC_VM_XGMI_LFB_CNTL 0x0823 +#define mmMC_VM_XGMI_LFB_CNTL_BASE_IDX 0 +#define mmMC_VM_XGMI_LFB_SIZE 0x0824 +#define mmMC_VM_XGMI_LFB_SIZE_BASE_IDX 0 // addressBlock: mmhub_utcl2_vmsharedvcdec diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h index 111a71b434e2..2969fbf282b7 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h @@ -26728,6 +26728,14 @@ //VMSHAREDPF0_MC_VM_CACHEABLE_DRAM_CNTL #define VMSHAREDPF0_MC_VM_CACHEABLE_DRAM_CNTL__ENABLE_CACHEABLE_DRAM_ADDRESS_APERTURE__SHIFT 0x0 #define VMSHAREDPF0_MC_VM_CACHEABLE_DRAM_CNTL__ENABLE_CACHEABLE_DRAM_ADDRESS_APERTURE_MASK 0x00000001L +//MC_VM_XGMI_LFB_CNTL +#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION__SHIFT 0x0 +#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION__SHIFT 0x3 +#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION_MASK 0x00000007L +#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION_MASK 0x00000038L +//MC_VM_XGMI_LFB_SIZE +#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE__SHIFT 0x0 +#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE_MASK 0x0000FFFFL // addressBlock: mmhub_utcl2_vmsharedvcdec diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index 50bfa513cb35..7e85cdc5bd34 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -269,7 +269,8 @@ union MESAPI__ADD_QUEUE { uint32_t map_kiq_utility_queue : 1; uint32_t is_kfd_process : 1; uint32_t trap_en : 1; - uint32_t reserved : 21; + uint32_t is_aql_queue : 1; + uint32_t reserved : 20; }; struct MES_API_STATUS api_status; uint64_t tma_addr; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5e318b3f6c0f..948cc75376f8 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3405,9 +3405,6 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) { - if (adev->pm.dpm_enabled == 0) - return; - if (adev->pm.int_hwmon_dev) hwmon_device_unregister(adev->pm.int_hwmon_dev); diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 1eb4e613b27a..ec055858eb95 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -1485,6 +1485,7 @@ static int pp_get_prv_buffer_details(void *handle, void **addr, size_t *size) { struct pp_hwmgr *hwmgr = handle; struct amdgpu_device *adev = hwmgr->adev; + int err; if (!addr || !size) return -EINVAL; @@ -1492,7 +1493,9 @@ static int pp_get_prv_buffer_details(void *handle, void **addr, size_t *size) *addr = NULL; *size = 0; if (adev->pm.smu_prv_buffer) { - amdgpu_bo_kmap(adev->pm.smu_prv_buffer, addr); + err = amdgpu_bo_kmap(adev->pm.smu_prv_buffer, addr); + if (err) + return err; *size = adev->pm.smu_prv_buffer_size; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c index dad3e3741a4e..190af79f3236 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c @@ -67,22 +67,21 @@ int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, int vega10_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr, uint32_t *speed) { - uint32_t current_rpm; - uint32_t percent = 0; - - if (hwmgr->thermal_controller.fanInfo.bNoFan) - return 0; + struct amdgpu_device *adev = hwmgr->adev; + uint32_t duty100, duty; + uint64_t tmp64; - if (vega10_get_current_rpm(hwmgr, ¤t_rpm)) - return -1; + duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1), + CG_FDO_CTRL1, FMAX_DUTY100); + duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS), + CG_THERMAL_STATUS, FDO_PWM_DUTY); - if (hwmgr->thermal_controller. - advanceFanControlParameters.usMaxFanRPM != 0) - percent = current_rpm * 255 / - hwmgr->thermal_controller. - advanceFanControlParameters.usMaxFanRPM; + if (!duty100) + return -EINVAL; - *speed = MIN(percent, 255); + tmp64 = (uint64_t)duty * 255; + do_div(tmp64, duty100); + *speed = MIN((uint32_t)tmp64, 255); return 0; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index 1e79baab753e..bd54fbd393b9 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -195,7 +195,6 @@ static int init_powerplay_table_information( struct phm_ppt_v3_information *pptable_information = (struct phm_ppt_v3_information *)hwmgr->pptable; uint32_t disable_power_control = 0; - int result; hwmgr->thermal_controller.ucType = powerplay_table->ucThermalControllerType; pptable_information->uc_thermal_controller_type = powerplay_table->ucThermalControllerType; @@ -257,9 +256,7 @@ static int init_powerplay_table_information( if (pptable_information->smc_pptable == NULL) return -ENOMEM; - result = append_vbios_pptable(hwmgr, (pptable_information->smc_pptable)); - - return result; + return append_vbios_pptable(hwmgr, (pptable_information->smc_pptable)); } static int vega12_pp_tables_initialize(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h index 6e0be6027705..01a7d66864f2 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h @@ -401,8 +401,6 @@ extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr); extern int phm_setup_asic(struct pp_hwmgr *hwmgr); extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr); extern int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr); -extern bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr); -extern int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block); extern int phm_set_power_state(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pcurrent_state, const struct pp_hw_power_state *pnew_power_state); diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c index 45214a364baa..e7ed2a7adf8f 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c @@ -2567,15 +2567,13 @@ static uint8_t polaris10_get_memory_modile_index(struct pp_hwmgr *hwmgr) static int polaris10_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) { - int result; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); pp_atomctrl_mc_reg_table *mc_reg_table = &smu_data->mc_reg_table; uint8_t module_index = polaris10_get_memory_modile_index(hwmgr); memset(mc_reg_table, 0, sizeof(pp_atomctrl_mc_reg_table)); - result = atomctrl_initialize_mc_reg_table_v2_2(hwmgr, module_index, mc_reg_table); - return result; + return atomctrl_initialize_mc_reg_table_v2_2(hwmgr, module_index, mc_reg_table); } static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 6e4a052dc53d..93fffdbab4f0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -210,7 +210,8 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu) if (!adev->scpm_enabled) return 0; - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7)) + if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7)) || + (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0))) return 0; /* override pptable_id from driver parameter */ @@ -219,27 +220,6 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu) dev_info(adev->dev, "override pptable id %d\n", pptable_id); } else { pptable_id = smu->smu_table.boot_values.pp_table_id; - - /* - * Temporary solution for SMU V13.0.0 with SCPM enabled: - * - use vbios carried pptable when pptable_id is 3664, 3715 or 3795 - * - use 36831 soft pptable when pptable_id is 3683 - */ - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) { - switch (pptable_id) { - case 3664: - case 3715: - case 3795: - pptable_id = 0; - break; - case 3683: - pptable_id = 36831; - break; - default: - dev_err(adev->dev, "Unsupported pptable id %d\n", pptable_id); - return -EINVAL; - } - } } /* "pptable_id == 0" means vbios carries the pptable. */ @@ -475,28 +455,8 @@ int smu_v13_0_setup_pptable(struct smu_context *smu) } else { pptable_id = smu->smu_table.boot_values.pp_table_id; - /* - * Temporary solution for SMU V13.0.0 with SCPM disabled: - * - use 3664, 3683 or 3715 on request - * - use 3664 when pptable_id is 0 - * TODO: drop these when the pptable carried in vbios is ready. - */ - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) { - switch (pptable_id) { - case 0: - pptable_id = 3664; - break; - case 3664: - case 3683: - case 3715: - break; - default: - dev_err(adev->dev, "Unsupported pptable id %d\n", pptable_id); - return -EINVAL; - } - } else if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10)) { + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10)) pptable_id = 6666; - } } /* force using vbios pptable in sriov mode */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 7db2fd9ea74a..1d454485e0d9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -239,82 +239,47 @@ smu_v13_0_0_get_allowed_feature_mask(struct smu_context *smu, uint32_t *feature_mask, uint32_t num) { struct amdgpu_device *adev = smu->adev; + u32 smu_version; if (num > 2) return -EINVAL; - memset(feature_mask, 0, sizeof(uint32_t) * num); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DATA_READ_BIT); + memset(feature_mask, 0xff, sizeof(uint32_t) * num); - if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_IMU_BIT); + if (!(adev->pm.pp_feature & PP_SCLK_DPM_MASK)) { + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_IMU_BIT); } - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_VCN_BIT); - - if ((adev->pg_flags & AMD_PG_SUPPORT_ATHUB) && - (adev->pg_flags & AMD_PG_SUPPORT_MMHUB)) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT); - - if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + if (!(adev->pg_flags & AMD_PG_SUPPORT_ATHUB) || + !(adev->pg_flags & AMD_PG_SUPPORT_MMHUB)) + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT); -#if 0 - if (adev->pm.pp_feature & PP_GFXOFF_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); -#endif - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_THROTTLERS_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FAN_CONTROL_BIT); + if (!(adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)) + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DF_CSTATE_BIT); - - if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT); + /* PMFW 78.58 contains a critical fix for gfxoff feature */ + smu_cmn_get_smc_version(smu, NULL, &smu_version); + if ((smu_version < 0x004e3a00) || + !(adev->pm.pp_feature & PP_GFXOFF_MASK)) + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT); + + if (!(adev->pm.pp_feature & PP_MCLK_DPM_MASK)) { + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_UCLK_BIT); + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT); + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT); } - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MEM_TEMP_READ_BIT); + if (!(adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)) + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); - if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_MPCLK_DS_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_MPCLK_DS_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_FCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCN_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_DCFCLK_BIT); - - if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT); + if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_LINK_BIT); + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_LCLK_BIT); } - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DSTATE_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_CG_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_FCLK_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_CTF_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_UCLK_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VR0HOT_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT); - - if (adev->pm.pp_feature & PP_ULV_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); + if (!(adev->pm.pp_feature & PP_ULV_MASK)) + *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_ULV_BIT); return 0; } @@ -410,58 +375,11 @@ static int smu_v13_0_0_setup_pptable(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct amdgpu_device *adev = smu->adev; - uint32_t pptable_id; int ret = 0; - /* - * With SCPM enabled, the pptable used will be signed. It cannot - * be used directly by driver. To get the raw pptable, we need to - * rely on the combo pptable(and its revelant SMU message). - */ - if (adev->scpm_enabled) { - ret = smu_v13_0_0_get_pptable_from_pmfw(smu, - &smu_table->power_play_table, - &smu_table->power_play_table_size); - } else { - /* override pptable_id from driver parameter */ - if (amdgpu_smu_pptable_id >= 0) { - pptable_id = amdgpu_smu_pptable_id; - dev_info(adev->dev, "override pptable id %d\n", pptable_id); - } else { - pptable_id = smu_table->boot_values.pp_table_id; - } - - /* - * Temporary solution for SMU V13.0.0 with SCPM disabled: - * - use vbios carried pptable when pptable_id is 3664, 3715 or 3795 - * - use soft pptable when pptable_id is 3683 - */ - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) { - switch (pptable_id) { - case 3664: - case 3715: - case 3795: - pptable_id = 0; - break; - case 3683: - break; - default: - dev_err(adev->dev, "Unsupported pptable id %d\n", pptable_id); - return -EINVAL; - } - } - - /* force using vbios pptable in sriov mode */ - if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1)) - ret = smu_v13_0_0_get_pptable_from_pmfw(smu, - &smu_table->power_play_table, - &smu_table->power_play_table_size); - else - ret = smu_v13_0_get_pptable_from_firmware(smu, - &smu_table->power_play_table, - &smu_table->power_play_table_size, - pptable_id); - } + ret = smu_v13_0_0_get_pptable_from_pmfw(smu, + &smu_table->power_play_table, + &smu_table->power_play_table_size); if (ret) return ret; diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 760b27971557..b9392f31e629 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -39,7 +39,7 @@ #include "ast_drv.h" -int ast_modeset = -1; +static int ast_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, ast_modeset, int, 0400); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 103bd4fa698b..1bc0220e6783 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -113,6 +113,9 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, case 1024: vbios_mode->enh_table = &res_1024x768[refresh_rate_index]; break; + case 1152: + vbios_mode->enh_table = &res_1152x864[refresh_rate_index]; + break; case 1280: if (mode->crtc_vdisplay == 800) vbios_mode->enh_table = &res_1280x800[refresh_rate_index]; @@ -310,7 +313,7 @@ static void ast_set_crtc_reg(struct ast_private *ast, u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0; u16 temp, precache = 0; - if ((ast->chip == AST2500) && + if ((ast->chip == AST2500 || ast->chip == AST2600) && (vbios_mode->enh_table->flags & AST2500PreCatchCRT)) precache = 40; @@ -351,6 +354,12 @@ static void ast_set_crtc_reg(struct ast_private *ast, ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD); + // Workaround for HSync Time non octave pixels (1920x1080@60Hz HSync 44 pixels); + if ((ast->chip == AST2600) && (mode->crtc_vdisplay == 1080)) + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xFC, 0xFD, 0x02); + else + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xFC, 0xFD, 0x00); + /* vert timings */ temp = (mode->crtc_vtotal) - 2; if (temp & 0x100) @@ -428,7 +437,7 @@ static void ast_set_dclk_reg(struct ast_private *ast, { const struct ast_vbios_dclk_info *clk_info; - if (ast->chip == AST2500) + if ((ast->chip == AST2500) || (ast->chip == AST2600)) clk_info = &dclk_table_ast2500[vbios_mode->enh_table->dclk_index]; else clk_info = &dclk_table[vbios_mode->enh_table->dclk_index]; @@ -1057,6 +1066,8 @@ ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode return MODE_OK; if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) return MODE_OK; + if ((mode->hdisplay == 1152) && (mode->vdisplay == 864)) + return MODE_OK; if ((ast->chip == AST2100) || (ast->chip == AST2200) || (ast->chip == AST2300) || (ast->chip == AST2400) || @@ -1089,6 +1100,10 @@ ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode if (mode->vdisplay == 768) status = MODE_OK; break; + case 1152: + if (mode->vdisplay == 864) + status = MODE_OK; + break; case 1280: if (mode->vdisplay == 1024) status = MODE_OK; diff --git a/drivers/gpu/drm/ast/ast_tables.h b/drivers/gpu/drm/ast/ast_tables.h index dbe1cc620f6e..0378c9bc079b 100644 --- a/drivers/gpu/drm/ast/ast_tables.h +++ b/drivers/gpu/drm/ast/ast_tables.h @@ -272,6 +272,13 @@ static const struct ast_vbios_enhtable res_1600x1200[] = { (SyncPP | Charx8Dot), 0xFF, 1, 0x33 }, }; +static const struct ast_vbios_enhtable res_1152x864[] = { + {1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* 75Hz */ + (SyncPP | Charx8Dot | NewModeInfo), 75, 1, 0x3B }, + {1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* end */ + (SyncPP | Charx8Dot | NewModeInfo), 0xFF, 1, 0x3B }, +}; + /* 16:9 */ static const struct ast_vbios_enhtable res_1360x768[] = { {1792, 1360, 64, 112, 795, 768, 3, 6, VCLK85_5, /* 60Hz */ diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index c5719908ce2d..ba060277c3fd 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -68,7 +68,6 @@ enum { BYTE_SWAP_GBR = 3, BYTE_SWAP_BRG = 4, BYTE_SWAP_BGR = 5, - BYTE_SWAP_MAX = 6, }; /* Page 0, Register 0x19 */ @@ -356,8 +355,6 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, int hsynclen = mode->hsync_end - mode->hsync_start; int vbporch = mode->vsync_start - mode->vdisplay; int vsynclen = mode->vsync_end - mode->vsync_start; - u8 byte_swap; - int ret; /* * Page 4 @@ -401,16 +398,8 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, regmap_write(priv->regmap, 0x15, vbporch); regmap_write(priv->regmap, 0x16, vsynclen); - /* Input color swap. Byte order is optional and will default to - * BYTE_SWAP_BGR to preserve backwards compatibility with existing - * driver. - */ - ret = of_property_read_u8(priv->bridge.of_node, "chrontel,byteswap", - &byte_swap); - if (!ret && byte_swap < BYTE_SWAP_MAX) - regmap_update_bits(priv->regmap, 0x18, SWAP, byte_swap); - else - regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR); + /* Input color swap. */ + regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR); /* Input clock and sync polarity. */ regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 2bb957cffd94..2767b70fa2cb 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -563,7 +563,7 @@ static void it6505_debug_print(struct it6505 *it6505, unsigned int reg, struct device *dev = &it6505->client->dev; int val; - if (likely(!(__drm_debug & DRM_UT_DRIVER))) + if (!drm_debug_enabled(DRM_UT_DRIVER)) return; val = it6505_read(it6505, reg); diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 28bad30dc4e5..3e870d45f881 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -165,30 +165,38 @@ static int lt8912_write_rxlogicres_config(struct lt8912 *lt) return ret; }; +/* enable LVDS output with some hardcoded configuration, not required for the HDMI output */ static int lt8912_write_lvds_config(struct lt8912 *lt) { const struct reg_sequence seq[] = { + // lvds power up {0x44, 0x30}, {0x51, 0x05}, - {0x50, 0x24}, - {0x51, 0x2d}, - {0x52, 0x04}, - {0x69, 0x0e}, + + // core pll bypass + {0x50, 0x24}, // cp=50uA + {0x51, 0x2d}, // Pix_clk as reference, second order passive LPF PLL + {0x52, 0x04}, // loopdiv=0, use second-order PLL + {0x69, 0x0e}, // CP_PRESET_DIV_RATIO {0x69, 0x8e}, {0x6a, 0x00}, - {0x6c, 0xb8}, + {0x6c, 0xb8}, // RGD_CP_SOFT_K_EN,RGD_CP_SOFT_K[13:8] {0x6b, 0x51}, - {0x04, 0xfb}, + + {0x04, 0xfb}, // core pll reset {0x04, 0xff}, - {0x7f, 0x00}, - {0xa8, 0x13}, - {0x02, 0xf7}, + + // scaler bypass + {0x7f, 0x00}, // disable scaler + {0xa8, 0x13}, // 0x13: JEIDA, 0x33: VESA + + {0x02, 0xf7}, // lvds pll reset {0x02, 0xff}, {0x03, 0xcf}, {0x03, 0xff}, }; - return regmap_multi_reg_write(lt->regmap[I2C_CEC_DSI], seq, ARRAY_SIZE(seq)); + return regmap_multi_reg_write(lt->regmap[I2C_MAIN], seq, ARRAY_SIZE(seq)); }; static inline struct lt8912 *bridge_to_lt8912(struct drm_bridge *b) @@ -268,7 +276,7 @@ static int lt8912_video_setup(struct lt8912 *lt) u32 hactive, h_total, hpw, hfp, hbp; u32 vactive, v_total, vpw, vfp, vbp; u8 settle = 0x08; - int ret; + int ret, hsync_activehigh, vsync_activehigh; if (!lt) return -EINVAL; @@ -278,12 +286,14 @@ static int lt8912_video_setup(struct lt8912 *lt) hpw = lt->mode.hsync_len; hbp = lt->mode.hback_porch; h_total = hactive + hfp + hpw + hbp; + hsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH; vactive = lt->mode.vactive; vfp = lt->mode.vfront_porch; vpw = lt->mode.vsync_len; vbp = lt->mode.vback_porch; v_total = vactive + vfp + vpw + vbp; + vsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH; if (vactive <= 600) settle = 0x04; @@ -317,6 +327,13 @@ static int lt8912_video_setup(struct lt8912 *lt) ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3e, hfp & 0xff); ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3f, hfp >> 8); + ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(0), + vsync_activehigh ? BIT(0) : 0); + ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(1), + hsync_activehigh ? BIT(1) : 0); + ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xb2, BIT(0), + lt->connector.display_info.is_hdmi ? BIT(0) : 0); + return ret; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index 7d2ed0ed2fe2..4efb62bcdb63 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -542,8 +542,8 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) if (ret < 0) return ret; - strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); - strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); + strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + strscpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s rev 0x%02x, irq %d", card->shortname, revision, data->irq); @@ -561,7 +561,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) dw->pcm = pcm; pcm->private_data = dw; - strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); + strscpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops); /* diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 92990a3d577a..9f055d9710ea 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2670,17 +2670,8 @@ int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *data, u8 dp_rev) { int err, i; - u8 link_config[2]; u8 test_pattern; - link_config[0] = drm_dp_link_rate_to_bw_code(data->link_rate); - link_config[1] = data->num_lanes; - if (data->enhanced_frame_cap) - link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, link_config, 2); - if (err < 0) - return err; - test_pattern = data->phy_pattern; if (dp_rev < 0x12) { test_pattern = (test_pattern << 2) & diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c index 81881e81ceae..c3ad4ab2b456 100644 --- a/drivers/gpu/drm/display/drm_scdc_helper.c +++ b/drivers/gpu/drm/display/drm_scdc_helper.c @@ -35,6 +35,19 @@ * HDMI 2.0 specification. It is a point-to-point protocol that allows the * HDMI source and HDMI sink to exchange data. The same I2C interface that * is used to access EDID serves as the transport mechanism for SCDC. + * + * Note: The SCDC status is going to be lost when the display is + * disconnected. This can happen physically when the user disconnects + * the cable, but also when a display is switched on (such as waking up + * a TV). + * + * This is further complicated by the fact that, upon a disconnection / + * reconnection, KMS won't change the mode on its own. This means that + * one can't just rely on setting the SCDC status on enable, but also + * has to track the connector status changes using interrupts and + * restore the SCDC status. The typical solution for this is to trigger an + * empty modeset in drm_connector_helper_funcs.detect_ctx(), like what vc4 does + * in vc4_hdmi_reset_link(). */ #define SCDC_I2C_SLAVE_ADDRESS 0x54 diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index fdb7d5c17ba1..3b8fdeeafd53 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -74,7 +74,7 @@ * given framebuffer memory. Ownership of the framebuffer memory is achieved * by calling devm_aperture_acquire_from_firmware(). On success, the driver * is the owner of the framebuffer range. The function fails if the - * framebuffer is already by another driver. See below for an example. + * framebuffer is already owned by another driver. See below for an example. * * .. code-block:: c * @@ -112,7 +112,7 @@ * * The generic driver is now subject to forced removal by other drivers. This * only works for platform drivers that support hot unplug. - * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al + * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al. * for the registered framebuffer range, the aperture helpers call * platform_device_unregister() and the generic driver unloads itself. It * may not access the device's registers, framebuffer memory, ROM, etc @@ -164,7 +164,7 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); * @primary: also kick vga16fb if present * @req_driver: requesting DRM driver * - * This function removes graphics device drivers which use memory range described by + * This function removes graphics device drivers which use the memory range described by * @base and @size. * * Returns: @@ -182,8 +182,8 @@ EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); * @pdev: PCI device * @req_driver: requesting DRM driver * - * This function removes graphics device drivers using memory range configured - * for any of @pdev's memory bars. The function assumes that PCI device with + * This function removes graphics device drivers using the memory range configured + * for any of @pdev's memory bars. The function assumes that a PCI device with * shadowed ROM drives a primary display and so kicks out vga16fb. * * Returns: diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ee5fea48b5cb..98cc3137c062 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -786,7 +786,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** - * drm_atomic_helper_check_wb_connector_state() - Check writeback encoder state + * drm_atomic_helper_check_wb_encoder_state() - Check writeback encoder state * @encoder: encoder state to check * @conn_state: connector state to check * diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index 937b699ac2a8..d8b2955e88fd 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -224,6 +224,7 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, const struct drm_plane_state *old_state, const struct drm_plane_state *state) { + struct drm_rect src; memset(iter, 0, sizeof(*iter)); if (!state || !state->crtc || !state->fb || !state->visible) @@ -233,10 +234,12 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, iter->num_clips = drm_plane_get_damage_clips_count(state); /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */ - iter->plane_src.x1 = state->src.x1 >> 16; - iter->plane_src.y1 = state->src.y1 >> 16; - iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF); - iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF); + src = drm_plane_state_src(state); + + iter->plane_src.x1 = src.x1 >> 16; + iter->plane_src.y1 = src.y1 >> 16; + iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF); + iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF); if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) { iter->clips = NULL; diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 56642816fdff..e2f76621453c 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -553,6 +553,7 @@ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *d drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, drm_fb_xrgb8888_to_xrgb2101010_line); } +EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) { @@ -793,3 +794,111 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc kfree(src32); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); + +static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) +{ + const uint32_t *fourccs_end = fourccs + nfourccs; + + while (fourccs < fourccs_end) { + if (*fourccs == fourcc) + return true; + ++fourccs; + } + return false; +} + +/** + * drm_fb_build_fourcc_list - Filters a list of supported color formats against + * the device's native formats + * @dev: DRM device + * @native_fourccs: 4CC codes of natively supported color formats + * @native_nfourccs: The number of entries in @native_fourccs + * @driver_fourccs: 4CC codes of all driver-supported color formats + * @driver_nfourccs: The number of entries in @driver_fourccs + * @fourccs_out: Returns 4CC codes of supported color formats + * @nfourccs_out: The number of available entries in @fourccs_out + * + * This function create a list of supported color format from natively + * supported formats and the emulated formats. + * At a minimum, most userspace programs expect at least support for + * XRGB8888 on the primary plane. Devices that have to emulate the + * format, and possibly others, can use drm_fb_build_fourcc_list() to + * create a list of supported color formats. The returned list can + * be handed over to drm_universal_plane_init() et al. Native formats + * will go before emulated formats. Other heuristics might be applied + * to optimize the order. Formats near the beginning of the list are + * usually preferred over formats near the end of the list. + * + * Returns: + * The number of color-formats 4CC codes returned in @fourccs_out. + */ +size_t drm_fb_build_fourcc_list(struct drm_device *dev, + const u32 *native_fourccs, size_t native_nfourccs, + const u32 *driver_fourccs, size_t driver_nfourccs, + u32 *fourccs_out, size_t nfourccs_out) +{ + u32 *fourccs = fourccs_out; + const u32 *fourccs_end = fourccs_out + nfourccs_out; + bool found_native = false; + size_t i; + + /* + * The device's native formats go first. + */ + + for (i = 0; i < native_nfourccs; ++i) { + u32 fourcc = native_fourccs[i]; + + if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { + continue; /* skip duplicate entries */ + } else if (fourccs == fourccs_end) { + drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc); + continue; /* end of available output buffer */ + } + + drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); + + if (!found_native) + found_native = is_listed_fourcc(driver_fourccs, driver_nfourccs, fourcc); + *fourccs = fourcc; + ++fourccs; + } + + /* + * The plane's atomic_update helper converts the framebuffer's color format + * to a native format when copying to device memory. + * + * If there is not a single format supported by both, device and + * driver, the native formats are likely not supported by the conversion + * helpers. Therefore *only* support the native formats and add a + * conversion helper ASAP. + */ + if (!found_native) { + drm_warn(dev, "Format conversion helpers required to add extra formats.\n"); + goto out; + } + + /* + * The extra formats, emulated by the driver, go second. + */ + + for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) { + u32 fourcc = driver_fourccs[i]; + + if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { + continue; /* skip duplicate and native entries */ + } else if (fourccs == fourccs_end) { + drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc); + continue; /* end of available output buffer */ + } + + drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); + + *fourccs = fourcc; + ++fourccs; + } + +out: + return fourccs - fourccs_out; +} +EXPORT_SYMBOL(drm_fb_build_fourcc_list); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 185b04762e2c..2dd97473ca10 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -87,13 +87,13 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, src_x > fb_width - src_w || src_h > fb_height || src_y > fb_height - src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", - src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, - src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, - src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, - src_y >> 16, ((src_y & 0xffff) * 15625) >> 10, - fb->width, fb->height); + drm_dbg_kms(fb->dev, "Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", + src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, + src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, + src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, + src_y >> 16, ((src_y & 0xffff) * 15625) >> 10, + fb->width, fb->height); return -ENOSPC; } @@ -125,7 +125,7 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or, r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth); if (r.pixel_format == DRM_FORMAT_INVALID) { - DRM_DEBUG("bad {bpp:%d, depth:%d}\n", or->bpp, or->depth); + drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth); return -EINVAL; } @@ -177,18 +177,18 @@ static int framebuffer_check(struct drm_device *dev, /* check if the format is supported at all */ if (!__drm_format_info(r->pixel_format)) { - DRM_DEBUG_KMS("bad framebuffer format %p4cc\n", - &r->pixel_format); + drm_dbg_kms(dev, "bad framebuffer format %p4cc\n", + &r->pixel_format); return -EINVAL; } if (r->width == 0) { - DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); + drm_dbg_kms(dev, "bad framebuffer width %u\n", r->width); return -EINVAL; } if (r->height == 0) { - DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); + drm_dbg_kms(dev, "bad framebuffer height %u\n", r->height); return -EINVAL; } @@ -202,12 +202,12 @@ static int framebuffer_check(struct drm_device *dev, u64 min_pitch = drm_format_info_min_pitch(info, i, width); if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) { - DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i); + drm_dbg_kms(dev, "Format requires non-linear modifier for plane %d\n", i); return -EINVAL; } if (!r->handles[i]) { - DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); + drm_dbg_kms(dev, "no buffer object handle for plane %d\n", i); return -EINVAL; } @@ -218,20 +218,20 @@ static int framebuffer_check(struct drm_device *dev, return -ERANGE; if (block_size && r->pitches[i] < min_pitch) { - DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); + drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { - DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", - r->modifier[i], i); + drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n", + r->modifier[i], i); return -EINVAL; } if (r->flags & DRM_MODE_FB_MODIFIERS && r->modifier[i] != r->modifier[0]) { - DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", - r->modifier[i], i); + drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n", + r->modifier[i], i); return -EINVAL; } @@ -244,7 +244,7 @@ static int framebuffer_check(struct drm_device *dev, if (r->pixel_format != DRM_FORMAT_NV12 || width % 128 || height % 32 || r->pitches[i] % 128) { - DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); + drm_dbg_kms(dev, "bad modifier data for plane %d\n", i); return -EINVAL; } break; @@ -256,7 +256,7 @@ static int framebuffer_check(struct drm_device *dev, for (i = info->num_planes; i < 4; i++) { if (r->modifier[i]) { - DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); + drm_dbg_kms(dev, "non-zero modifier for unused plane %d\n", i); return -EINVAL; } @@ -265,17 +265,17 @@ static int framebuffer_check(struct drm_device *dev, continue; if (r->handles[i]) { - DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); + drm_dbg_kms(dev, "buffer object handle for unused plane %d\n", i); return -EINVAL; } if (r->pitches[i]) { - DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); + drm_dbg_kms(dev, "non-zero pitch for unused plane %d\n", i); return -EINVAL; } if (r->offsets[i]) { - DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); + drm_dbg_kms(dev, "non-zero offset for unused plane %d\n", i); return -EINVAL; } } @@ -293,24 +293,24 @@ drm_internal_framebuffer_create(struct drm_device *dev, int ret; if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { - DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); + drm_dbg_kms(dev, "bad framebuffer flags 0x%08x\n", r->flags); return ERR_PTR(-EINVAL); } if ((config->min_width > r->width) || (r->width > config->max_width)) { - DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", - r->width, config->min_width, config->max_width); + drm_dbg_kms(dev, "bad framebuffer width %d, should be >= %d && <= %d\n", + r->width, config->min_width, config->max_width); return ERR_PTR(-EINVAL); } if ((config->min_height > r->height) || (r->height > config->max_height)) { - DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", - r->height, config->min_height, config->max_height); + drm_dbg_kms(dev, "bad framebuffer height %d, should be >= %d && <= %d\n", + r->height, config->min_height, config->max_height); return ERR_PTR(-EINVAL); } if (r->flags & DRM_MODE_FB_MODIFIERS && dev->mode_config.fb_modifiers_not_supported) { - DRM_DEBUG_KMS("driver does not support fb modifiers\n"); + drm_dbg_kms(dev, "driver does not support fb modifiers\n"); return ERR_PTR(-EINVAL); } @@ -320,7 +320,7 @@ drm_internal_framebuffer_create(struct drm_device *dev, fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { - DRM_DEBUG_KMS("could not create framebuffer\n"); + drm_dbg_kms(dev, "could not create framebuffer\n"); return fb; } @@ -356,7 +356,7 @@ int drm_mode_addfb2(struct drm_device *dev, if (IS_ERR(fb)) return PTR_ERR(fb); - DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + drm_dbg_kms(dev, "[FB:%d]\n", fb->base.id); r->fb_id = fb->base.id; /* Transfer ownership to the filp for reaping on close */ @@ -384,7 +384,7 @@ int drm_mode_addfb2_ioctl(struct drm_device *dev, * then. So block it to make userspace fallback to * ADDFB. */ - DRM_DEBUG_KMS("addfb2 broken on bigendian"); + drm_dbg_kms(dev, "addfb2 broken on bigendian"); return -EOPNOTSUPP; } #endif diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 86d670c71286..33f1d66dda60 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -165,6 +165,7 @@ void drm_gem_private_object_init(struct drm_device *dev, obj->resv = &obj->_resv; drm_vma_node_reset(&obj->vma_node); + INIT_LIST_HEAD(&obj->lru_node); } EXPORT_SYMBOL(drm_gem_private_object_init); @@ -951,6 +952,7 @@ drm_gem_object_release(struct drm_gem_object *obj) dma_resv_fini(&obj->_resv); drm_gem_free_mmap_offset(obj); + drm_gem_lru_remove(obj); } EXPORT_SYMBOL(drm_gem_object_release); @@ -1274,3 +1276,171 @@ drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, ww_acquire_fini(acquire_ctx); } EXPORT_SYMBOL(drm_gem_unlock_reservations); + +/** + * drm_gem_lru_init - initialize a LRU + * + * @lru: The LRU to initialize + * @lock: The lock protecting the LRU + */ +void +drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock) +{ + lru->lock = lock; + lru->count = 0; + INIT_LIST_HEAD(&lru->list); +} +EXPORT_SYMBOL(drm_gem_lru_init); + +static void +drm_gem_lru_remove_locked(struct drm_gem_object *obj) +{ + obj->lru->count -= obj->size >> PAGE_SHIFT; + WARN_ON(obj->lru->count < 0); + list_del(&obj->lru_node); + obj->lru = NULL; +} + +/** + * drm_gem_lru_remove - remove object from whatever LRU it is in + * + * If the object is currently in any LRU, remove it. + * + * @obj: The GEM object to remove from current LRU + */ +void +drm_gem_lru_remove(struct drm_gem_object *obj) +{ + struct drm_gem_lru *lru = obj->lru; + + if (!lru) + return; + + mutex_lock(lru->lock); + drm_gem_lru_remove_locked(obj); + mutex_unlock(lru->lock); +} +EXPORT_SYMBOL(drm_gem_lru_remove); + +static void +drm_gem_lru_move_tail_locked(struct drm_gem_lru *lru, struct drm_gem_object *obj) +{ + lockdep_assert_held_once(lru->lock); + + if (obj->lru) + drm_gem_lru_remove_locked(obj); + + lru->count += obj->size >> PAGE_SHIFT; + list_add_tail(&obj->lru_node, &lru->list); + obj->lru = lru; +} + +/** + * drm_gem_lru_move_tail - move the object to the tail of the LRU + * + * If the object is already in this LRU it will be moved to the + * tail. Otherwise it will be removed from whichever other LRU + * it is in (if any) and moved into this LRU. + * + * @lru: The LRU to move the object into. + * @obj: The GEM object to move into this LRU + */ +void +drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj) +{ + mutex_lock(lru->lock); + drm_gem_lru_move_tail_locked(lru, obj); + mutex_unlock(lru->lock); +} +EXPORT_SYMBOL(drm_gem_lru_move_tail); + +/** + * drm_gem_lru_scan - helper to implement shrinker.scan_objects + * + * If the shrink callback succeeds, it is expected that the driver + * move the object out of this LRU. + * + * If the LRU possibly contain active buffers, it is the responsibility + * of the shrink callback to check for this (ie. dma_resv_test_signaled()) + * or if necessary block until the buffer becomes idle. + * + * @lru: The LRU to scan + * @nr_to_scan: The number of pages to try to reclaim + * @shrink: Callback to try to shrink/reclaim the object. + */ +unsigned long +drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned nr_to_scan, + bool (*shrink)(struct drm_gem_object *obj)) +{ + struct drm_gem_lru still_in_lru; + struct drm_gem_object *obj; + unsigned freed = 0; + + drm_gem_lru_init(&still_in_lru, lru->lock); + + mutex_lock(lru->lock); + + while (freed < nr_to_scan) { + obj = list_first_entry_or_null(&lru->list, typeof(*obj), lru_node); + + if (!obj) + break; + + drm_gem_lru_move_tail_locked(&still_in_lru, obj); + + /* + * If it's in the process of being freed, gem_object->free() + * may be blocked on lock waiting to remove it. So just + * skip it. + */ + if (!kref_get_unless_zero(&obj->refcount)) + continue; + + /* + * Now that we own a reference, we can drop the lock for the + * rest of the loop body, to reduce contention with other + * code paths that need the LRU lock + */ + mutex_unlock(lru->lock); + + /* + * Note that this still needs to be trylock, since we can + * hit shrinker in response to trying to get backing pages + * for this obj (ie. while it's lock is already held) + */ + if (!dma_resv_trylock(obj->resv)) + goto tail; + + if (shrink(obj)) { + freed += obj->size >> PAGE_SHIFT; + + /* + * If we succeeded in releasing the object's backing + * pages, we expect the driver to have moved the object + * out of this LRU + */ + WARN_ON(obj->lru == &still_in_lru); + WARN_ON(obj->lru == lru); + } + + dma_resv_unlock(obj->resv); + +tail: + drm_gem_object_put(obj); + mutex_lock(lru->lock); + } + + /* + * Move objects we've skipped over out of the temporary still_in_lru + * back into this LRU + */ + list_for_each_entry (obj, &still_in_lru.list, lru_node) + obj->lru = lru; + list_splice_tail(&still_in_lru.list, &lru->list); + lru->count += still_in_lru.count; + + mutex_unlock(lru->lock); + + return freed; +} +EXPORT_SYMBOL(drm_gem_lru_scan); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 84abc3920b57..a6ac56580876 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -310,6 +310,24 @@ err_drm_dev_exit: } /** + * mipi_dbi_pipe_mode_valid - MIPI DBI mode-valid helper + * @pipe: Simple display pipe + * @mode: The mode to test + * + * This function validates a given display mode against the MIPI DBI's hardware + * display. Drivers can use this as their &drm_simple_display_pipe_funcs->mode_valid + * callback. + */ +enum drm_mode_status mipi_dbi_pipe_mode_valid(struct drm_simple_display_pipe *pipe, + const struct drm_display_mode *mode) +{ + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + + return drm_crtc_helper_mode_valid_fixed(&pipe->crtc, mode, &dbidev->mode); +} +EXPORT_SYMBOL(mipi_dbi_pipe_mode_valid); + +/** * mipi_dbi_pipe_update - Display pipe update helper * @pipe: Simple display pipe * @old_state: Old plane state @@ -415,26 +433,8 @@ EXPORT_SYMBOL(mipi_dbi_pipe_disable); static int mipi_dbi_connector_get_modes(struct drm_connector *connector) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev); - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &dbidev->mode); - if (!mode) { - DRM_ERROR("Failed to duplicate mode\n"); - return 0; - } - - if (mode->name[0] == '\0') - drm_mode_set_name(mode); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - - if (mode->width_mm) { - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; - } - return 1; + return drm_connector_helper_get_modes_fixed(connector, &dbidev->mode); } static const struct drm_connector_helper_funcs mipi_dbi_connector_hfuncs = { diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index bd609a978848..f858dfedf2cf 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -100,8 +100,7 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); * This is the minimal list of formats that seem to be safe for modeset use * with all current DRM drivers. Most hardware can actually support more * formats than this and drivers may specify a more accurate list when - * creating the primary plane. However drivers that still call - * drm_plane_init() will use this minimal format list as the default. + * creating the primary plane. */ static const uint32_t safe_modeset_formats[] = { DRM_FORMAT_XRGB8888, @@ -109,43 +108,9 @@ static const uint32_t safe_modeset_formats[] = { }; static const struct drm_plane_funcs primary_plane_funcs = { - .update_plane = drm_plane_helper_update_primary, - .disable_plane = drm_plane_helper_disable_primary, - .destroy = drm_plane_helper_destroy, + DRM_PLANE_NON_ATOMIC_FUNCS, }; -static struct drm_plane *create_primary_plane(struct drm_device *dev) -{ - struct drm_plane *primary; - int ret; - - primary = kzalloc(sizeof(*primary), GFP_KERNEL); - if (primary == NULL) { - DRM_DEBUG_KMS("Failed to allocate primary plane\n"); - return NULL; - } - - /* - * Remove the format_default field from drm_plane when dropping - * this helper. - */ - primary->format_default = true; - - /* possible_crtc's will be filled in later by crtc_init */ - ret = drm_universal_plane_init(dev, primary, 0, - &primary_plane_funcs, - safe_modeset_formats, - ARRAY_SIZE(safe_modeset_formats), - NULL, - DRM_PLANE_TYPE_PRIMARY, NULL); - if (ret) { - kfree(primary); - primary = NULL; - } - - return primary; -} - /** * drm_crtc_init - Legacy CRTC initialization function * @dev: DRM device @@ -177,10 +142,33 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs) { struct drm_plane *primary; + int ret; + + /* possible_crtc's will be filled in later by crtc_init */ + primary = __drm_universal_plane_alloc(dev, sizeof(*primary), 0, 0, + &primary_plane_funcs, + safe_modeset_formats, + ARRAY_SIZE(safe_modeset_formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (IS_ERR(primary)) + return PTR_ERR(primary); - primary = create_primary_plane(dev); - return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, - NULL); + /* + * Remove the format_default field from drm_plane when dropping + * this helper. + */ + primary->format_default = true; + + ret = drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, NULL); + if (ret) + goto err_drm_plane_cleanup; + + return 0; + +err_drm_plane_cleanup: + drm_plane_cleanup(primary); + kfree(primary); + return ret; } EXPORT_SYMBOL(drm_crtc_init); diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index fc1728d46ac2..8a0c0e0bb5bd 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -103,6 +103,12 @@ static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = { .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, }; +static const struct drm_dmi_panel_orientation_data lcd1080x1920_leftside_up = { + .width = 1080, + .height = 1920, + .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, +}; + static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = { .width = 1200, .height = 1920, @@ -128,6 +134,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"), }, .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* Anbernic Win600 */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Win600"), + }, + .driver_data = (void *)&lcd720x1280_rightside_up, }, { /* Asus T100HA */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), @@ -152,6 +164,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYA NEO 2021"), }, .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* AYA NEO AIR */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "AIR"), + }, + .driver_data = (void *)&lcd1080x1920_leftside_up, }, { /* AYA NEO NEXT */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AYANEO"), diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 726f2f163c26..33357629a7f5 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -448,6 +448,44 @@ void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size, } EXPORT_SYMBOL(__drmm_universal_plane_alloc); +void *__drm_universal_plane_alloc(struct drm_device *dev, size_t size, + size_t offset, uint32_t possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + const uint64_t *format_modifiers, + enum drm_plane_type type, + const char *name, ...) +{ + void *container; + struct drm_plane *plane; + va_list ap; + int ret; + + if (drm_WARN_ON(dev, !funcs)) + return ERR_PTR(-EINVAL); + + container = kzalloc(size, GFP_KERNEL); + if (!container) + return ERR_PTR(-ENOMEM); + + plane = container + offset; + + va_start(ap, name); + ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs, + formats, format_count, format_modifiers, + type, name, ap); + va_end(ap); + if (ret) + goto err_kfree; + + return container; + +err_kfree: + kfree(container); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(__drm_universal_plane_alloc); + int drm_plane_register_all(struct drm_device *dev) { unsigned int num_planes = 0; @@ -483,38 +521,6 @@ void drm_plane_unregister_all(struct drm_device *dev) } /** - * drm_plane_init - Initialize a legacy plane - * @dev: DRM device - * @plane: plane object to init - * @possible_crtcs: bitmask of possible CRTCs - * @funcs: callbacks for the new plane - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @is_primary: plane type (primary vs overlay) - * - * Legacy API to initialize a DRM plane. - * - * New drivers should call drm_universal_plane_init() instead. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, - uint32_t possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary) -{ - enum drm_plane_type type; - - type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; - return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, - formats, format_count, - NULL, type, NULL); -} -EXPORT_SYMBOL(drm_plane_init); - -/** * drm_plane_cleanup - Clean up the core plane usage * @plane: plane to cleanup * diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index c7785967f5bf..865bd999b187 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -30,8 +30,10 @@ #include <drm/drm_atomic_uapi.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_device.h> +#include <drm/drm_drv.h> #include <drm/drm_encoder.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_print.h> #include <drm/drm_rect.h> #define SUBPIXEL_MASK 0xffff @@ -195,10 +197,14 @@ int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *cr .x2 = crtc_x + crtc_w, .y2 = crtc_y + crtc_h, }; + struct drm_device *dev = plane->dev; struct drm_connector **connector_list; int num_connectors, ret; bool visible; + if (drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev))) + return -EINVAL; + ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, DRM_MODE_ROTATE_0, @@ -260,6 +266,10 @@ EXPORT_SYMBOL(drm_plane_helper_update_primary); int drm_plane_helper_disable_primary(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { + struct drm_device *dev = plane->dev; + + drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)); + return -EINVAL; } EXPORT_SYMBOL(drm_plane_helper_disable_primary); @@ -278,3 +288,33 @@ void drm_plane_helper_destroy(struct drm_plane *plane) kfree(plane); } EXPORT_SYMBOL(drm_plane_helper_destroy); + +/** + * drm_plane_helper_atomic_check() - Helper to check plane atomic-state + * @plane: plane to check + * @state: atomic state object + * + * Provides a default plane-state check handler for planes whose atomic-state + * scale and positioning are not expected to change since the plane is always + * a fullscreen scanout buffer. + * + * This is often the case for the primary plane of simple framebuffers. + * + * RETURNS: + * Zero on success, or an errno code otherwise. + */ +int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} +EXPORT_SYMBOL(drm_plane_helper_atomic_check); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index bb427c5a4f1f..69b0b2b9cc1c 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -1015,6 +1015,30 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_hpd_irq_event); /** + * drm_crtc_helper_mode_valid_fixed - Validates a display mode + * @crtc: the crtc + * @mode: the mode to validate + * @fixed_mode: the display hardware's mode + * + * Returns: + * MODE_OK on success, or another mode-status code otherwise. + */ +enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + const struct drm_display_mode *fixed_mode) +{ + if (mode->hdisplay != fixed_mode->hdisplay && mode->vdisplay != fixed_mode->vdisplay) + return MODE_ONE_SIZE; + else if (mode->hdisplay != fixed_mode->hdisplay) + return MODE_ONE_WIDTH; + else if (mode->vdisplay != fixed_mode->vdisplay) + return MODE_ONE_HEIGHT; + + return MODE_OK; +} +EXPORT_SYMBOL(drm_crtc_helper_mode_valid_fixed); + +/** * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID * property from the connector's * DDC channel @@ -1051,6 +1075,46 @@ int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector) EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc); /** + * drm_connector_helper_get_modes_fixed - Duplicates a display mode for a connector + * @connector: the connector + * @fixed_mode: the display hardware's mode + * + * This function duplicates a display modes for a connector. Drivers for hardware + * that only supports a single fixed mode can use this function in their connector's + * get_modes helper. + * + * Returns: + * The number of created modes. + */ +int drm_connector_helper_get_modes_fixed(struct drm_connector *connector, + const struct drm_display_mode *fixed_mode) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(dev, fixed_mode); + if (!mode) { + drm_err(dev, "Failed to duplicate mode " DRM_MODE_FMT "\n", + DRM_MODE_ARG(fixed_mode)); + return 0; + } + + if (mode->name[0] == '\0') + drm_mode_set_name(mode); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + if (mode->width_mm) + connector->display_info.width_mm = mode->width_mm; + if (mode->height_mm) + connector->display_info.height_mm = mode->height_mm; + + return 1; +} +EXPORT_SYMBOL(drm_connector_helper_get_modes_fixed); + +/** * drm_connector_helper_get_modes - Read EDID and update connector. * @connector: The connector * diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 10b0036f8a2e..b7c11bdce2c8 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -893,7 +893,7 @@ static int hdmi_get_modes(struct drm_connector *connector) if (!edid) return -ENODEV; - hdata->dvi_mode = !drm_detect_hdmi_monitor(edid); + hdata->dvi_mode = !connector->display_info.is_hdmi; DRM_DEV_DEBUG_KMS(hdata->dev, "%s : width[%d] x height[%d]\n", (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), edid->width_cm, edid->height_cm); @@ -922,8 +922,8 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) return -EINVAL; } -static int hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct hdmi_context *hdata = connector_to_hdmi(connector); int ret; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 65260a658684..8d333db813b7 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1045,7 +1045,7 @@ static void mixer_atomic_disable(struct exynos_drm_crtc *crtc) clear_bit(MXR_BIT_POWERED, &ctx->flags); } -static int mixer_mode_valid(struct exynos_drm_crtc *crtc, +static enum drm_mode_status mixer_mode_valid(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode) { struct mixer_context *ctx = crtc->ctx; diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 0cff20265f97..807b989e3c77 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -7,6 +7,8 @@ config DRM_GMA500 select ACPI_VIDEO if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI + select X86_PLATFORM_DEVICES if ACPI + select ACPI_WMI if ACPI help Say yes for an experimental 2D KMS framebuffer driver for the Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c index 46b9c0f13d6d..577a4987b193 100644 --- a/drivers/gpu/drm/gma500/backlight.c +++ b/drivers/gpu/drm/gma500/backlight.c @@ -7,75 +7,109 @@ * Authors: Eric Knopp */ +#include <acpi/video.h> + #include "psb_drv.h" #include "psb_intel_reg.h" #include "psb_intel_drv.h" #include "intel_bios.h" #include "power.h" -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE -static void do_gma_backlight_set(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - backlight_update_status(dev_priv->backlight_device); -} -#endif - void gma_backlight_enable(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_enabled = true; - if (dev_priv->backlight_device) { - dev_priv->backlight_device->props.brightness = dev_priv->backlight_level; - do_gma_backlight_set(dev); - } -#endif + dev_priv->ops->backlight_set(dev, dev_priv->backlight_level); } void gma_backlight_disable(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_enabled = false; - if (dev_priv->backlight_device) { - dev_priv->backlight_device->props.brightness = 0; - do_gma_backlight_set(dev); - } -#endif + dev_priv->ops->backlight_set(dev, 0); } void gma_backlight_set(struct drm_device *dev, int v) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_level = v; - if (dev_priv->backlight_device && dev_priv->backlight_enabled) { - dev_priv->backlight_device->props.brightness = v; - do_gma_backlight_set(dev); - } -#endif + if (dev_priv->backlight_enabled) + dev_priv->ops->backlight_set(dev, v); +} + +static int gma_backlight_get_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (dev_priv->ops->backlight_get) + return dev_priv->ops->backlight_get(dev); + + return dev_priv->backlight_level; } +static int gma_backlight_update_status(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + int level = backlight_get_brightness(bd); + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + gma_backlight_set(dev, level); + return 0; +} + +static const struct backlight_ops gma_backlight_ops __maybe_unused = { + .get_brightness = gma_backlight_get_brightness, + .update_status = gma_backlight_update_status, +}; + int gma_backlight_init(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct backlight_properties props __maybe_unused = {}; + int ret; + dev_priv->backlight_enabled = true; - return dev_priv->ops->backlight_init(dev); -#else - return 0; + dev_priv->backlight_level = 100; + + ret = dev_priv->ops->backlight_init(dev); + if (ret) + return ret; + + if (!acpi_video_backlight_use_native()) { + drm_info(dev, "Skipping %s backlight registration\n", + dev_priv->ops->backlight_name); + return 0; + } + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + props.brightness = dev_priv->backlight_level; + props.max_brightness = PSB_MAX_BRIGHTNESS; + props.type = BACKLIGHT_RAW; + + dev_priv->backlight_device = + backlight_device_register(dev_priv->ops->backlight_name, + dev->dev, dev, + &gma_backlight_ops, &props); + if (IS_ERR(dev_priv->backlight_device)) + return PTR_ERR(dev_priv->backlight_device); #endif + + return 0; } void gma_backlight_exit(struct drm_device *dev) { #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - if (dev_priv->backlight_device) { - dev_priv->backlight_device->props.brightness = 0; - backlight_update_status(dev_priv->backlight_device); + + if (dev_priv->backlight_device) backlight_device_unregister(dev_priv->backlight_device); - } #endif } diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index dd32b484dd82..3065596257e9 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -5,7 +5,6 @@ * **************************************************************************/ -#include <linux/backlight.h> #include <linux/delay.h> #include <drm/drm.h> @@ -62,14 +61,10 @@ static int cdv_output_init(struct drm_device *dev) return 0; } -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - /* * Cedartrail Backlght Interfaces */ -static struct backlight_device *cdv_backlight_device; - static int cdv_backlight_combination_mode(struct drm_device *dev) { return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE; @@ -92,9 +87,8 @@ static u32 cdv_get_max_backlight(struct drm_device *dev) return max; } -static int cdv_get_brightness(struct backlight_device *bd) +static int cdv_get_brightness(struct drm_device *dev) { - struct drm_device *dev = bl_get_data(bd); struct pci_dev *pdev = to_pci_dev(dev->dev); u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; @@ -106,20 +100,13 @@ static int cdv_get_brightness(struct backlight_device *bd) val *= lbpc; } return (val * 100)/cdv_get_max_backlight(dev); - } -static int cdv_set_brightness(struct backlight_device *bd) +static void cdv_set_brightness(struct drm_device *dev, int level) { - struct drm_device *dev = bl_get_data(bd); struct pci_dev *pdev = to_pci_dev(dev->dev); - int level = bd->props.brightness; u32 blc_pwm_ctl; - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - level *= cdv_get_max_backlight(dev); level /= 100; @@ -136,38 +123,18 @@ static int cdv_set_brightness(struct backlight_device *bd) blc_pwm_ctl = REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; REG_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); - return 0; } -static const struct backlight_ops cdv_ops = { - .get_brightness = cdv_get_brightness, - .update_status = cdv_set_brightness, -}; - static int cdv_backlight_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct backlight_properties props; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 100; - props.type = BACKLIGHT_PLATFORM; - - cdv_backlight_device = backlight_device_register("psb-bl", - NULL, (void *)dev, &cdv_ops, &props); - if (IS_ERR(cdv_backlight_device)) - return PTR_ERR(cdv_backlight_device); - - cdv_backlight_device->props.brightness = - cdv_get_brightness(cdv_backlight_device); - backlight_update_status(cdv_backlight_device); - dev_priv->backlight_device = cdv_backlight_device; - dev_priv->backlight_enabled = true; + + dev_priv->backlight_level = cdv_get_brightness(dev); + cdv_set_brightness(dev, dev_priv->backlight_level); + return 0; } -#endif - /* * Provide the Cedarview specific chip logic and low level methods * for power management @@ -581,11 +548,9 @@ static const struct psb_offset cdv_regmap[2] = { static int cdv_chip_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct pci_dev *pdev = to_pci_dev(dev->dev); INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func); - if (pci_enable_msi(pdev)) - dev_warn(dev->dev, "Enabling MSI failed!\n"); + dev_priv->use_msi = true; dev_priv->regmap = cdv_regmap; gma_get_core_freq(dev); psb_intel_opregion_init(dev); @@ -615,9 +580,10 @@ const struct psb_ops cdv_chip_ops = { .hotplug = cdv_hotplug_event, .hotplug_enable = cdv_hotplug_enable, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE .backlight_init = cdv_backlight_init, -#endif + .backlight_get = cdv_get_brightness, + .backlight_set = cdv_set_brightness, + .backlight_name = "psb-bl", .init_pm = cdv_init_pm, .save_regs = cdv_save_display_registers, diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index bd40c040a2c9..b0ea911b27de 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -552,28 +552,11 @@ int gma_crtc_page_flip(struct drm_crtc *crtc, return ret; } -int gma_crtc_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_device *dev = set->crtc->dev; - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - int ret; - - if (!dev_priv->rpm_enabled) - return drm_crtc_helper_set_config(set, ctx); - - pm_runtime_forbid(dev->dev); - ret = drm_crtc_helper_set_config(set, ctx); - pm_runtime_allow(dev->dev); - - return ret; -} - const struct drm_crtc_funcs gma_crtc_funcs = { .cursor_set = gma_crtc_cursor_set, .cursor_move = gma_crtc_cursor_move, .gamma_set = gma_crtc_gamma_set, - .set_config = gma_crtc_set_config, + .set_config = drm_crtc_helper_set_config, .destroy = gma_crtc_destroy, .page_flip = gma_crtc_page_flip, .enable_vblank = gma_crtc_enable_vblank, diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 113cf048105e..c8b611a2f6c6 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -69,8 +69,6 @@ extern int gma_crtc_page_flip(struct drm_crtc *crtc, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx); -extern int gma_crtc_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx); extern void gma_crtc_save(struct drm_crtc *crtc); extern void gma_crtc_restore(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 5923a9c89312..2531959d3d77 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c @@ -5,7 +5,6 @@ * **************************************************************************/ -#include <linux/backlight.h> #include <linux/delay.h> #include <linux/dmi.h> #include <linux/module.h> @@ -37,29 +36,18 @@ static int oaktrail_output_init(struct drm_device *dev) * Provide the low level interfaces for the Moorestown backlight */ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ #define BLC_PWM_FREQ_CALC_CONSTANT 32 #define MHz 1000000 #define BLC_ADJUSTMENT_MAX 100 -static struct backlight_device *oaktrail_backlight_device; -static int oaktrail_brightness; - -static int oaktrail_set_brightness(struct backlight_device *bd) +static void oaktrail_set_brightness(struct drm_device *dev, int level) { - struct drm_device *dev = bl_get_data(oaktrail_backlight_device); struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - int level = bd->props.brightness; u32 blc_pwm_ctl; u32 max_pwm_blc; - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - if (gma_power_begin(dev, 0)) { /* Calculate and set the brightness value */ max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16; @@ -82,19 +70,9 @@ static int oaktrail_set_brightness(struct backlight_device *bd) REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); gma_power_end(dev); } - oaktrail_brightness = level; - return 0; -} - -static int oaktrail_get_brightness(struct backlight_device *bd) -{ - /* return locally cached var instead of HW read (due to DPST etc.) */ - /* FIXME: ideally return actual value in case firmware fiddled with - it */ - return oaktrail_brightness; } -static int device_backlight_init(struct drm_device *dev) +static int oaktrail_backlight_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); unsigned long core_clock; @@ -123,44 +101,11 @@ static int device_backlight_init(struct drm_device *dev) REG_WRITE(BLC_PWM_CTL, value | (value << 16)); gma_power_end(dev); } - return 0; -} - -static const struct backlight_ops oaktrail_ops = { - .get_brightness = oaktrail_get_brightness, - .update_status = oaktrail_set_brightness, -}; -static int oaktrail_backlight_init(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - int ret; - struct backlight_properties props; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 100; - props.type = BACKLIGHT_PLATFORM; - - oaktrail_backlight_device = backlight_device_register("oaktrail-bl", - NULL, (void *)dev, &oaktrail_ops, &props); - - if (IS_ERR(oaktrail_backlight_device)) - return PTR_ERR(oaktrail_backlight_device); - - ret = device_backlight_init(dev); - if (ret < 0) { - backlight_device_unregister(oaktrail_backlight_device); - return ret; - } - oaktrail_backlight_device->props.brightness = 100; - oaktrail_backlight_device->props.max_brightness = 100; - backlight_update_status(oaktrail_backlight_device); - dev_priv->backlight_device = oaktrail_backlight_device; + oaktrail_set_brightness(dev, PSB_MAX_BRIGHTNESS); return 0; } -#endif - /* * Provide the Moorestown specific chip logic and low level methods * for power management @@ -501,12 +446,9 @@ static const struct psb_offset oaktrail_regmap[2] = { static int oaktrail_chip_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct pci_dev *pdev = to_pci_dev(dev->dev); int ret; - if (pci_enable_msi(pdev)) - dev_warn(dev->dev, "Enabling MSI failed!\n"); - + dev_priv->use_msi = true; dev_priv->regmap = oaktrail_regmap; ret = mid_chip_setup(dev); @@ -548,9 +490,9 @@ const struct psb_ops oaktrail_chip_ops = { .output_init = oaktrail_output_init, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE .backlight_init = oaktrail_backlight_init, -#endif + .backlight_set = oaktrail_set_brightness, + .backlight_name = "oaktrail-bl", .save_regs = oaktrail_save_display_registers, .restore_regs = oaktrail_restore_display_registers, diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 4d98df189e10..75b4eb1c8884 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -61,7 +61,6 @@ static void oaktrail_lvds_set_power(struct drm_device *dev, pp_status = REG_READ(PP_STATUS); } while (pp_status & PP_ON); dev_priv->is_lvds_on = false; - pm_request_idle(dev->dev); } gma_power_end(dev); } diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index dc494df71a48..0c271072af63 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -150,21 +150,17 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct opregion_asle *asle = dev_priv->opregion.asle; - struct backlight_device *bd = dev_priv->backlight_device; DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp); if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; - if (bd == NULL) - return ASLE_BACKLIGHT_FAILED; - bclp &= ASLE_BCLP_MSK; if (bclp > 255) return ASLE_BACKLIGHT_FAILED; - gma_backlight_set(dev, bclp * bd->props.max_brightness / 255); + gma_backlight_set(dev, bclp * PSB_MAX_BRIGHTNESS / 255); asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID; diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c index b91de6d36e41..186af29bea6f 100644 --- a/drivers/gpu/drm/gma500/power.c +++ b/drivers/gpu/drm/gma500/power.c @@ -37,9 +37,6 @@ #include <linux/mutex.h> #include <linux/pm_runtime.h> -static struct mutex power_mutex; /* Serialize power ops */ -static DEFINE_SPINLOCK(power_ctrl_lock); /* Serialize power claim */ - /** * gma_power_init - initialise power manager * @dev: our device @@ -54,13 +51,23 @@ void gma_power_init(struct drm_device *dev) dev_priv->apm_base = dev_priv->apm_reg & 0xffff; dev_priv->ospm_base &= 0xffff; - dev_priv->display_power = true; /* We start active */ - dev_priv->display_count = 0; /* Currently no users */ - dev_priv->suspended = false; /* And not suspended */ - mutex_init(&power_mutex); - if (dev_priv->ops->init_pm) dev_priv->ops->init_pm(dev); + + /* + * Runtime pm support is broken atm. So for now unconditionally + * call pm_runtime_get() here and put it again in psb_driver_unload() + * + * To fix this we need to call pm_runtime_get() once for each active + * pipe at boot and then put() / get() for each pipe disable / enable + * so that the device gets runtime suspended when no pipes are active. + * Once this is in place the pm_runtime_get() below should be replaced + * by a pm_runtime_allow() call to undo the pm_runtime_forbid() from + * pci_pm_init(). + */ + pm_runtime_get(dev->dev); + + dev_priv->pm_initialized = true; } /** @@ -71,8 +78,12 @@ void gma_power_init(struct drm_device *dev) */ void gma_power_uninit(struct drm_device *dev) { - pm_runtime_disable(dev->dev); - pm_runtime_set_suspended(dev->dev); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (!dev_priv->pm_initialized) + return; + + pm_runtime_put_noidle(dev->dev); } /** @@ -85,11 +96,8 @@ static void gma_suspend_display(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - if (dev_priv->suspended) - return; dev_priv->ops->save_regs(dev); dev_priv->ops->power_down(dev); - dev_priv->display_power = false; } /** @@ -106,8 +114,6 @@ static void gma_resume_display(struct pci_dev *pdev) /* turn on the display power island */ dev_priv->ops->power_up(dev); - dev_priv->suspended = false; - dev_priv->display_power = true; PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); pci_write_config_word(pdev, PSB_GMCH_CTRL, @@ -131,21 +137,14 @@ static void gma_suspend_pci(struct pci_dev *pdev) struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int bsm, vbt; - if (dev_priv->suspended) - return; - pci_save_state(pdev); pci_read_config_dword(pdev, 0x5C, &bsm); dev_priv->regs.saveBSM = bsm; pci_read_config_dword(pdev, 0xFC, &vbt); dev_priv->regs.saveVBT = vbt; - pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr); - pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - - dev_priv->suspended = true; } /** @@ -155,29 +154,17 @@ static void gma_suspend_pci(struct pci_dev *pdev) * Perform the resume processing on our PCI device state - rewrite * register state and re-enable the PCI device */ -static bool gma_resume_pci(struct pci_dev *pdev) +static int gma_resume_pci(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - int ret; - - if (!dev_priv->suspended) - return true; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM); pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT); - /* restoring MSI address and data in PCIx space */ - pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr); - pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data); - ret = pci_enable_device(pdev); - if (ret != 0) - dev_err(&pdev->dev, "pci_enable failed: %d\n", ret); - else - dev_priv->suspended = false; - return !dev_priv->suspended; + return pci_enable_device(pdev); } /** @@ -192,20 +179,10 @@ int gma_power_suspend(struct device *_dev) { struct pci_dev *pdev = to_pci_dev(_dev); struct drm_device *dev = pci_get_drvdata(pdev); - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - mutex_lock(&power_mutex); - if (!dev_priv->suspended) { - if (dev_priv->display_count) { - mutex_unlock(&power_mutex); - dev_err(dev->dev, "GPU hardware busy, cannot suspend\n"); - return -EBUSY; - } - gma_irq_uninstall(dev); - gma_suspend_display(dev); - gma_suspend_pci(pdev); - } - mutex_unlock(&power_mutex); + gma_irq_uninstall(dev); + gma_suspend_display(dev); + gma_suspend_pci(pdev); return 0; } @@ -220,28 +197,13 @@ int gma_power_resume(struct device *_dev) struct pci_dev *pdev = to_pci_dev(_dev); struct drm_device *dev = pci_get_drvdata(pdev); - mutex_lock(&power_mutex); gma_resume_pci(pdev); gma_resume_display(pdev); - gma_irq_preinstall(dev); - gma_irq_postinstall(dev); - mutex_unlock(&power_mutex); + gma_irq_install(dev); return 0; } /** - * gma_power_is_on - returne true if power is on - * @dev: our DRM device - * - * Returns true if the display island power is on at this moment - */ -bool gma_power_is_on(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - return dev_priv->display_power; -} - -/** * gma_power_begin - begin requiring power * @dev: our DRM device * @force_on: true to force power on @@ -251,35 +213,10 @@ bool gma_power_is_on(struct drm_device *dev) */ bool gma_power_begin(struct drm_device *dev, bool force_on) { - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct pci_dev *pdev = to_pci_dev(dev->dev); - int ret; - unsigned long flags; - - spin_lock_irqsave(&power_ctrl_lock, flags); - /* Power already on ? */ - if (dev_priv->display_power) { - dev_priv->display_count++; - pm_runtime_get(dev->dev); - spin_unlock_irqrestore(&power_ctrl_lock, flags); - return true; - } - if (force_on == false) - goto out_false; - - /* Ok power up needed */ - ret = gma_resume_pci(pdev); - if (ret == 0) { - gma_irq_preinstall(dev); - gma_irq_postinstall(dev); - pm_runtime_get(dev->dev); - dev_priv->display_count++; - spin_unlock_irqrestore(&power_ctrl_lock, flags); - return true; - } -out_false: - spin_unlock_irqrestore(&power_ctrl_lock, flags); - return false; + if (force_on) + return pm_runtime_resume_and_get(dev->dev) == 0; + else + return pm_runtime_get_if_in_use(dev->dev) == 1; } /** @@ -291,46 +228,5 @@ out_false: */ void gma_power_end(struct drm_device *dev) { - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - unsigned long flags; - spin_lock_irqsave(&power_ctrl_lock, flags); - dev_priv->display_count--; - WARN_ON(dev_priv->display_count < 0); - spin_unlock_irqrestore(&power_ctrl_lock, flags); pm_runtime_put(dev->dev); } - -int psb_runtime_suspend(struct device *dev) -{ - return gma_power_suspend(dev); -} - -int psb_runtime_resume(struct device *dev) -{ - return gma_power_resume(dev); -} - -int psb_runtime_idle(struct device *dev) -{ - struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev)); - struct drm_psb_private *dev_priv = to_drm_psb_private(drmdev); - if (dev_priv->display_count) - return 0; - else - return 1; -} - -int gma_power_thaw(struct device *_dev) -{ - return gma_power_resume(_dev); -} - -int gma_power_freeze(struct device *_dev) -{ - return gma_power_suspend(_dev); -} - -int gma_power_restore(struct device *_dev) -{ - return gma_power_resume(_dev); -} diff --git a/drivers/gpu/drm/gma500/power.h b/drivers/gpu/drm/gma500/power.h index 0c89c4d6ec20..063328d66652 100644 --- a/drivers/gpu/drm/gma500/power.h +++ b/drivers/gpu/drm/gma500/power.h @@ -43,9 +43,6 @@ void gma_power_uninit(struct drm_device *dev); */ int gma_power_suspend(struct device *dev); int gma_power_resume(struct device *dev); -int gma_power_thaw(struct device *dev); -int gma_power_freeze(struct device *dev); -int gma_power_restore(struct device *_dev); /* * These are the functions the driver should use to wrap all hw access @@ -54,19 +51,4 @@ int gma_power_restore(struct device *_dev); bool gma_power_begin(struct drm_device *dev, bool force); void gma_power_end(struct drm_device *dev); -/* - * Use this function to do an instantaneous check for if the hw is on. - * Only use this in cases where you know the mutex is already held such - * as in irq install/uninstall and you need to - * prevent a deadlock situation. Otherwise use gma_power_begin(). - */ -bool gma_power_is_on(struct drm_device *dev); - -/* - * GFX-Runtime PM callbacks - */ -int psb_runtime_suspend(struct device *dev); -int psb_runtime_resume(struct device *dev); -int psb_runtime_idle(struct device *dev); - #endif /*_PSB_POWERMGMT_H_*/ diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 71534f4ca834..3c294c38bdb4 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -5,8 +5,6 @@ * **************************************************************************/ -#include <linux/backlight.h> - #include <drm/drm.h> #include "gma_device.h" @@ -24,8 +22,6 @@ static int psb_output_init(struct drm_device *dev) return 0; } -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - /* * Poulsbo Backlight Interfaces */ @@ -41,18 +37,6 @@ static int psb_output_init(struct drm_device *dev) #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) -static int psb_brightness; -static struct backlight_device *psb_backlight_device; - -static int psb_get_brightness(struct backlight_device *bd) -{ - /* return locally cached var instead of HW read (due to DPST etc.) */ - /* FIXME: ideally return actual value in case firmware fiddled with - it */ - return psb_brightness; -} - - static int psb_backlight_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); @@ -86,62 +70,13 @@ static int psb_backlight_setup(struct drm_device *dev) REG_WRITE(BLC_PWM_CTL, (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value)); } - return 0; -} - -static int psb_set_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(psb_backlight_device); - int level = bd->props.brightness; - - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - - psb_intel_lvds_set_brightness(dev, level); - psb_brightness = level; - return 0; -} - -static const struct backlight_ops psb_ops = { - .get_brightness = psb_get_brightness, - .update_status = psb_set_brightness, -}; - -static int psb_backlight_init(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - int ret; - struct backlight_properties props; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 100; - props.type = BACKLIGHT_PLATFORM; - - psb_backlight_device = backlight_device_register("psb-bl", - NULL, (void *)dev, &psb_ops, &props); - if (IS_ERR(psb_backlight_device)) - return PTR_ERR(psb_backlight_device); - - ret = psb_backlight_setup(dev); - if (ret < 0) { - backlight_device_unregister(psb_backlight_device); - psb_backlight_device = NULL; - return ret; - } - psb_backlight_device->props.brightness = 100; - psb_backlight_device->props.max_brightness = 100; - backlight_update_status(psb_backlight_device); - dev_priv->backlight_device = psb_backlight_device; + psb_intel_lvds_set_brightness(dev, PSB_MAX_BRIGHTNESS); /* This must occur after the backlight is properly initialised */ psb_lid_timer_init(dev_priv); - return 0; } -#endif - /* * Provide the Poulsbo specific chip logic and low level methods * for power management @@ -345,9 +280,9 @@ const struct psb_ops psb_chip_ops = { .output_init = psb_output_init, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - .backlight_init = psb_backlight_init, -#endif + .backlight_init = psb_backlight_setup, + .backlight_set = psb_intel_lvds_set_brightness, + .backlight_name = "psb-bl", .init_pm = psb_init_pm, .save_regs = psb_save_display_registers, diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 1d8744f3e702..cd9c73f5a64a 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -169,8 +169,7 @@ static void psb_driver_unload(struct drm_device *dev) /* TODO: Kill vblank etc here */ - if (dev_priv->backlight_device) - gma_backlight_exit(dev); + gma_backlight_exit(dev); psb_modeset_cleanup(dev); gma_irq_uninstall(dev); @@ -383,7 +382,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - gma_irq_install(dev, pdev->irq); + gma_irq_install(dev); dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ @@ -399,6 +398,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) if (gma_encoder->type == INTEL_OUTPUT_LVDS || gma_encoder->type == INTEL_OUTPUT_MIPI) { ret = gma_backlight_init(dev); + if (ret == 0) + acpi_video_register_backlight(); break; } } @@ -407,11 +408,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) if (ret) return ret; psb_intel_opregion_enable_asle(dev); -#if 0 - /* Enable runtime pm at last */ - pm_runtime_enable(dev->dev); - pm_runtime_set_active(dev->dev); -#endif return devm_add_action_or_reset(dev->dev, psb_device_release, dev); @@ -420,33 +416,6 @@ out_err: return ret; } -static inline void get_brightness(struct backlight_device *bd) -{ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - if (bd) { - bd->props.brightness = bd->ops->get_brightness(bd); - backlight_update_status(bd); - } -#endif -} - -static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->minor->dev; - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - static unsigned int runtime_allowed; - - if (runtime_allowed == 1 && dev_priv->is_lvds_on) { - runtime_allowed++; - pm_runtime_allow(dev->dev); - dev_priv->rpm_enabled = 1; - } - return drm_ioctl(filp, cmd, arg); - /* FIXME: do we need to wrap the other side of this */ -} - static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct drm_psb_private *dev_priv; @@ -493,22 +462,13 @@ static void psb_pci_remove(struct pci_dev *pdev) drm_dev_unregister(dev); } -static const struct dev_pm_ops psb_pm_ops = { - .resume = gma_power_resume, - .suspend = gma_power_suspend, - .thaw = gma_power_thaw, - .freeze = gma_power_freeze, - .restore = gma_power_restore, - .runtime_suspend = psb_runtime_suspend, - .runtime_resume = psb_runtime_resume, - .runtime_idle = psb_runtime_idle, -}; +static DEFINE_RUNTIME_DEV_PM_OPS(psb_pm_ops, gma_power_suspend, gma_power_resume, NULL); static const struct file_operations psb_gem_fops = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, - .unlocked_ioctl = psb_unlocked_ioctl, + .unlocked_ioctl = drm_ioctl, .compat_ioctl = drm_compat_ioctl, .mmap = drm_gem_mmap, .poll = drm_poll, diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 0ea3d23575f3..ae544b69fc47 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -172,6 +172,8 @@ #define PSB_WATCHDOG_DELAY (HZ * 2) #define PSB_LID_DELAY (HZ / 10) +#define PSB_MAX_BRIGHTNESS 100 + #define PSB_PWR_STATE_ON 1 #define PSB_PWR_STATE_OFF 2 @@ -426,9 +428,7 @@ struct drm_psb_private { spinlock_t irqmask_lock; /* Power */ - bool suspended; - bool display_power; - int display_count; + bool pm_initialized; /* Modesetting */ struct psb_intel_mode_device mode_dev; @@ -486,10 +486,8 @@ struct drm_psb_private { unsigned int core_freq; uint32_t iLVDS_enable; - /* Runtime PM state */ - int rpm_enabled; - /* MID specific */ + bool use_msi; bool has_gct; struct oaktrail_gct_data gct_data; @@ -499,10 +497,6 @@ struct drm_psb_private { /* Register state */ struct psb_save_area regs; - /* MSI reg save */ - uint32_t msi_addr; - uint32_t msi_data; - /* Hotplug handling */ struct work_struct hotplug_work; @@ -530,10 +524,6 @@ struct drm_psb_private { struct drm_fb_helper *fb_helper; - /* Panel brightness */ - int brightness; - int brightness_adjusted; - bool dsr_enable; u32 dsr_fb_update; bool dpi_panel_on[3]; @@ -602,10 +592,13 @@ struct psb_ops { void (*disable_sr)(struct drm_device *dev); void (*lvds_bl_power)(struct drm_device *dev, bool on); -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + /* Backlight */ int (*backlight_init)(struct drm_device *dev); -#endif + void (*backlight_set)(struct drm_device *dev, int level); + int (*backlight_get)(struct drm_device *dev); + const char *backlight_name; + int i2c_bus; /* I2C bus identifier for Moorestown */ }; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 8ccba116821b..8a1111fe714b 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -197,8 +197,6 @@ extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level); extern void oaktrail_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); -extern void oaktrail_dsi_init(struct drm_device *dev, - struct psb_intel_mode_device *mode_dev); struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev); extern void mid_dsi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int dsi_num); @@ -219,9 +217,6 @@ extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, int sdvoB); -extern int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector); -extern void psb_intel_sdvo_set_hotplug(struct drm_connector *connector, - int enable); extern int intelfb_probe(struct drm_device *dev); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index e6e6d61bbeab..d421031462df 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -228,7 +228,7 @@ static irqreturn_t gma_irq_handler(int irq, void *arg) vdc_stat &= dev_priv->vdc_irq_mask; spin_unlock(&dev_priv->irqmask_lock); - if (dsp_int && gma_power_is_on(dev)) { + if (dsp_int) { gma_vdc_interrupt(dev, vdc_stat); handled = 1; } @@ -264,13 +264,12 @@ void gma_irq_preinstall(struct drm_device *dev) spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - if (gma_power_is_on(dev)) { - PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); - PSB_WVDC32(0x00000000, PSB_INT_MASK_R); - PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); - PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); - PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); - } + PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); + PSB_WVDC32(0x00000000, PSB_INT_MASK_R); + PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); + PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); + if (dev->vblank[0].enabled) dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; if (dev->vblank[1].enabled) @@ -316,17 +315,24 @@ void gma_irq_postinstall(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); } -int gma_irq_install(struct drm_device *dev, unsigned int irq) +int gma_irq_install(struct drm_device *dev) { + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); int ret; - if (irq == IRQ_NOTCONNECTED) + if (dev_priv->use_msi && pci_enable_msi(pdev)) { + dev_warn(dev->dev, "Enabling MSI failed!\n"); + dev_priv->use_msi = false; + } + + if (pdev->irq == IRQ_NOTCONNECTED) return -ENOTCONN; gma_irq_preinstall(dev); /* PCI devices require shared interrupts. */ - ret = request_irq(irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev); + ret = request_irq(pdev->irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev); if (ret) return ret; @@ -369,6 +375,8 @@ void gma_irq_uninstall(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); free_irq(pdev->irq, dev); + if (dev_priv->use_msi) + pci_disable_msi(pdev); } int gma_crtc_enable_vblank(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h index b51e395194ff..7648f69824a5 100644 --- a/drivers/gpu/drm/gma500/psb_irq.h +++ b/drivers/gpu/drm/gma500/psb_irq.h @@ -17,7 +17,7 @@ struct drm_device; void gma_irq_preinstall(struct drm_device *dev); void gma_irq_postinstall(struct drm_device *dev); -int gma_irq_install(struct drm_device *dev, unsigned int irq); +int gma_irq_install(struct drm_device *dev); void gma_irq_uninstall(struct drm_device *dev); int gma_crtc_enable_vblank(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 7ae3b7d67fcf..3efce05d7b57 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -23,6 +23,8 @@ config DRM_I915 # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI + select X86_PLATFORM_DEVICES if ACPI + select ACPI_WMI if ACPI select ACPI_VIDEO if ACPI select ACPI_BUTTON if ACPI select SYNC_FILE diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index e78430001f07..9df78e7caa2b 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -7,6 +7,7 @@ #include <linux/pci.h> #include <linux/acpi.h> +#include <acpi/video.h> #include "i915_drv.h" #include "intel_acpi.h" @@ -331,3 +332,29 @@ void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) */ fwnode_handle_put(fwnode); } + +void intel_acpi_video_register(struct drm_i915_private *i915) +{ + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector; + + acpi_video_register(); + + /* + * If i915 is driving an internal panel without registering its native + * backlight handler try to register the acpi_video backlight. + * For panels not driven by i915 another GPU driver may still register + * a native backlight later and acpi_video_register_backlight() should + * only be called after any native backlights have been registered. + */ + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct intel_panel *panel = &to_intel_connector(connector)->panel; + + if (panel->backlight.funcs && !panel->backlight.device) { + acpi_video_register_backlight(); + break; + } + } + drm_connector_list_iter_end(&conn_iter); +} diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h index 4a760a2baed9..6a0007452f95 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.h +++ b/drivers/gpu/drm/i915/display/intel_acpi.h @@ -14,6 +14,7 @@ void intel_unregister_dsm_handler(void); void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915); void intel_acpi_device_id_update(struct drm_i915_private *i915); void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915); +void intel_acpi_video_register(struct drm_i915_private *i915); #else static inline void intel_register_dsm_handler(void) { return; } static inline void intel_unregister_dsm_handler(void) { return; } @@ -23,6 +24,8 @@ static inline void intel_acpi_device_id_update(struct drm_i915_private *i915) { return; } static inline void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) { return; } +static inline +void intel_acpi_video_register(struct drm_i915_private *i915) { return; } #endif /* CONFIG_ACPI */ #endif /* __INTEL_ACPI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 11a1342d6d37..beba39a38c87 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -8,6 +8,8 @@ #include <linux/pwm.h> #include <linux/string_helpers.h> +#include <acpi/video.h> + #include "intel_backlight.h" #include "intel_backlight_regs.h" #include "intel_connector.h" @@ -953,6 +955,11 @@ int intel_backlight_device_register(struct intel_connector *connector) WARN_ON(panel->backlight.max == 0); + if (!acpi_video_backlight_use_native()) { + drm_info(&i915->drm, "Skipping intel_backlight registration\n"); + return 0; + } + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f0063e0d4ed3..461c62c88413 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9063,7 +9063,7 @@ void intel_display_driver_register(struct drm_i915_private *i915) /* Must be done after probing outputs */ intel_opregion_register(i915); - acpi_video_register(); + intel_acpi_video_register(i915); intel_audio_init(i915); diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index dfa942ca62da..9d085c05c49c 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -1222,8 +1222,8 @@ static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable) mtk_dp->data->smc_cmd, enable, 0, 0, 0, 0, 0, &res); - dev_dbg(mtk_dp->dev, "smc cmd: 0x%x, p1: 0x%x, ret: 0x%lx-0x%lx\n", - mtk_dp->data->smc_cmd, enable, res.a0, res.a1); + dev_dbg(mtk_dp->dev, "smc cmd: 0x%x, p1: %s, ret: 0x%lx-0x%lx\n", + mtk_dp->data->smc_cmd, enable ? "enable" : "disable", res.a0, res.a1); } static void mtk_dp_audio_mute(struct mtk_dp *mtk_dp, bool mute) @@ -1933,39 +1933,41 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge) bool enabled = mtk_dp->enabled; u8 sink_count = 0; - if (mtk_dp->train_info.cable_plugged_in) { - if (!enabled) { - /* power on aux */ - mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, - DP_PWR_STATE_BANDGAP_TPLL_LANE, - DP_PWR_STATE_MASK); - - /* power on panel */ - drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); - usleep_range(2000, 5000); - } - /* - * Some dongles still source HPD when they do not connect to any - * sink device. To avoid this, we need to read the sink count - * to make sure we do connect to sink devices. After this detect - * function, we just need to check the HPD connection to check - * whether we connect to a sink device. - */ - drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count); - if (DP_GET_SINK_COUNT(sink_count)) - ret = connector_status_connected; - - if (!enabled) { - /* power off panel */ - drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3); - usleep_range(2000, 3000); - - /* power off aux */ - mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, - DP_PWR_STATE_BANDGAP_TPLL, - DP_PWR_STATE_MASK); - } + if (!mtk_dp->train_info.cable_plugged_in) + return ret; + + if (!enabled) { + /* power on aux */ + mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, + DP_PWR_STATE_BANDGAP_TPLL_LANE, + DP_PWR_STATE_MASK); + + /* power on panel */ + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); + usleep_range(2000, 5000); } + /* + * Some dongles still source HPD when they do not connect to any + * sink device. To avoid this, we need to read the sink count + * to make sure we do connect to sink devices. After this detect + * function, we just need to check the HPD connection to check + * whether we connect to a sink device. + */ + drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count); + if (DP_GET_SINK_COUNT(sink_count)) + ret = connector_status_connected; + + if (!enabled) { + /* power off panel */ + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3); + usleep_range(2000, 3000); + + /* power off aux */ + mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, + DP_PWR_STATE_BANDGAP_TPLL, + DP_PWR_STATE_MASK); + } + return ret; } @@ -2642,7 +2644,7 @@ static const struct of_device_id mtk_dp_of_match[] = { }; MODULE_DEVICE_TABLE(of, mtk_dp_of_match); -struct platform_driver mtk_dp_driver = { +static struct platform_driver mtk_dp_driver = { .probe = mtk_dp_probe, .remove = mtk_dp_remove, .driver = { diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h index 096ad6572a5e..84e38cef03c2 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h @@ -153,8 +153,6 @@ #define CH_STATUS_1_DP_ENC0_P0_MASK GENMASK(15, 0) #define MTK_DP_ENC0_P0_3094 0x3094 #define CH_STATUS_2_DP_ENC0_P0_MASK GENMASK(7, 0) -#define MTK_DP_ENC0_P0_30A0 0x30a0 -#define DP_ENC0_30A0_MASK (BIT(7) | BIT(8) | BIT(12)) #define MTK_DP_ENC0_P0_30A4 0x30a4 #define AU_TS_CFG_DP_ENC0_P0_MASK GENMASK(7, 0) #define MTK_DP_ENC0_P0_30A8 0x30a8 @@ -171,8 +169,6 @@ #define MTK_DP_ENC0_P0_312C 0x312c #define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0) #define ASP_HB3_DP_ENC0_P0_MASK GENMASK(15, 8) -#define MTK_DP_ENC0_P0_3130 0x3130 -#define MTK_DP_ENC0_P0_3138 0x3138 #define MTK_DP_ENC0_P0_3154 0x3154 #define PGEN_HTOTAL_DP_ENC0_P0_MASK GENMASK(13, 0) #define MTK_DP_ENC0_P0_3158 0x3158 @@ -206,8 +202,6 @@ #define SDP_PACKET_TYPE_DP_ENC1_P0_MASK GENMASK(4, 0) #define SDP_PACKET_W_DP_ENC1_P0 BIT(5) #define SDP_PACKET_W_DP_ENC1_P0_MASK BIT(5) -#define MTK_DP_ENC1_P0_328C 0x328c -#define VSC_DATA_RDY_VESA_DP_ENC1_P0_MASK BIT(7) #define MTK_DP_ENC1_P0_3300 0x3300 #define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_VAL 2 #define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK GENMASK(9, 8) diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 630a4e301ef6..508a6d994e83 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -11,7 +11,6 @@ #include <linux/media-bus-format.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/of_graph.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 5f02f8d0e4fc..91f58db5915f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -833,11 +833,8 @@ static int mtk_drm_sys_prepare(struct device *dev) { struct mtk_drm_private *private = dev_get_drvdata(dev); struct drm_device *drm = private->drm; - int ret; - - ret = drm_mode_config_helper_suspend(drm); - return ret; + return drm_mode_config_helper_suspend(drm); } static void mtk_drm_sys_complete(struct device *dev) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 3196189429bc..4c80b6896dc3 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -16,7 +16,6 @@ #include <linux/mutex.h> #include <linux/of_platform.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index fcf0d493782c..3b24a924b7b9 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -388,10 +388,14 @@ static void meson_drv_unbind(struct device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); - component_unbind_all(dev, drm); free_irq(priv->vsync_irq, drm); drm_dev_put(drm); + meson_encoder_hdmi_remove(priv); + meson_encoder_cvbs_remove(priv); + + component_unbind_all(dev, drm); + if (priv->afbcd.ops) priv->afbcd.ops->exit(priv); } @@ -493,6 +497,13 @@ static int meson_drv_probe(struct platform_device *pdev) return 0; }; +static int meson_drv_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &meson_drv_master_ops); + + return 0; +} + static struct meson_drm_match_data meson_drm_gxbb_data = { .compat = VPU_COMPATIBLE_GXBB, }; @@ -530,6 +541,7 @@ static const struct dev_pm_ops meson_drv_pm_ops = { static struct platform_driver meson_drm_platform_driver = { .probe = meson_drv_probe, + .remove = meson_drv_remove, .shutdown = meson_drv_shutdown, .driver = { .name = "meson-drm", diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 177dac3ca3be..c62ee358456f 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -25,6 +25,12 @@ enum vpu_compatible { VPU_COMPATIBLE_G12A = 3, }; +enum { + MESON_ENC_CVBS = 0, + MESON_ENC_HDMI, + MESON_ENC_LAST, +}; + struct meson_drm_match_data { enum vpu_compatible compat; struct meson_afbcd_ops *afbcd_ops; @@ -51,6 +57,7 @@ struct meson_drm { struct drm_crtc *crtc; struct drm_plane *primary_plane; struct drm_plane *overlay_plane; + void *encoders[MESON_ENC_LAST]; const struct meson_drm_soc_limits *limits; diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c index 8110a6e39320..5675bc2a92cf 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c @@ -281,5 +281,18 @@ int meson_encoder_cvbs_init(struct meson_drm *priv) } drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder); + priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs; + return 0; } + +void meson_encoder_cvbs_remove(struct meson_drm *priv) +{ + struct meson_encoder_cvbs *meson_encoder_cvbs; + + if (priv->encoders[MESON_ENC_CVBS]) { + meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS]; + drm_bridge_remove(&meson_encoder_cvbs->bridge); + drm_bridge_remove(meson_encoder_cvbs->next_bridge); + } +} diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.h b/drivers/gpu/drm/meson/meson_encoder_cvbs.h index 61d9d183ce7f..09710fec3c66 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.h +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.h @@ -25,5 +25,6 @@ struct meson_cvbs_mode { extern struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT]; int meson_encoder_cvbs_init(struct meson_drm *priv); +void meson_encoder_cvbs_remove(struct meson_drm *priv); #endif /* __MESON_VENC_CVBS_H */ diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 2f616c55c271..53231bfdf7e2 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -452,6 +452,8 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) meson_encoder_hdmi->cec_notifier = notifier; } + priv->encoders[MESON_ENC_HDMI] = meson_encoder_hdmi; + dev_dbg(priv->dev, "HDMI encoder initialized\n"); return 0; @@ -460,3 +462,14 @@ err_put_node: of_node_put(remote); return ret; } + +void meson_encoder_hdmi_remove(struct meson_drm *priv) +{ + struct meson_encoder_hdmi *meson_encoder_hdmi; + + if (priv->encoders[MESON_ENC_HDMI]) { + meson_encoder_hdmi = priv->encoders[MESON_ENC_HDMI]; + drm_bridge_remove(&meson_encoder_hdmi->bridge); + drm_bridge_remove(meson_encoder_hdmi->next_bridge); + } +} diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.h b/drivers/gpu/drm/meson/meson_encoder_hdmi.h index ed19494f0956..a6cd38eb5f71 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.h +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.h @@ -8,5 +8,6 @@ #define __MESON_ENCODER_HDMI_H int meson_encoder_hdmi_init(struct meson_drm *priv); +void meson_encoder_hdmi_remove(struct meson_drm *priv); #endif /* __MESON_ENCODER_HDMI_H */ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 0ab0e1dd8bbb..2c8b9899625b 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -68,7 +68,7 @@ static void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ OUT_PKT3(ring, CP_EVENT_WRITE, 3); - OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); + OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ); OUT_RING(ring, rbmemptr(ring, fence)); OUT_RING(ring, submit->seqno); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 0c6b2a6d0b4c..7cb8d9849c07 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -62,7 +62,7 @@ static void a4xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ OUT_PKT3(ring, CP_EVENT_WRITE, 3); - OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); + OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ); OUT_RING(ring, rbmemptr(ring, fence)); OUT_RING(ring, submit->seqno); diff --git a/drivers/gpu/drm/msm/adreno/a6xx.xml.h b/drivers/gpu/drm/msm/adreno/a6xx.xml.h index b03e2c413ab1..beea4a7fc1df 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a6xx.xml.h @@ -1413,6 +1413,10 @@ static inline uint32_t REG_A6XX_RBBM_PERFCTR_RBBM_SEL(uint32_t i0) { return 0x00 #define REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL 0x00000011 +#define REG_A6XX_RBBM_GBIF_HALT 0x00000016 + +#define REG_A6XX_RBBM_GBIF_HALT_ACK 0x00000017 + #define REG_A6XX_RBBM_WAIT_FOR_GPU_IDLE_CMD 0x0000001c #define A6XX_RBBM_WAIT_FOR_GPU_IDLE_CMD_WAIT_GPU_IDLE 0x00000001 diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 310a317885a1..e033d6a67a20 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -873,9 +873,47 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu) (val & 1), 100, 1000); } +#define GBIF_CLIENT_HALT_MASK BIT(0) +#define GBIF_ARB_HALT_MASK BIT(1) + +static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) +{ + struct msm_gpu *gpu = &adreno_gpu->base; + + if (!a6xx_has_gbif(adreno_gpu)) { + gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf); + spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & + 0xf) == 0xf); + gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0); + + return; + } + + /* Halt the gx side of GBIF */ + gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1); + spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1); + + /* Halt new client requests on GBIF */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK); + spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & + (GBIF_CLIENT_HALT_MASK)) == GBIF_CLIENT_HALT_MASK); + + /* Halt all AXI requests on GBIF */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_ARB_HALT_MASK); + spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & + (GBIF_ARB_HALT_MASK)) == GBIF_ARB_HALT_MASK); + + /* The GBIF halt needs to be explicitly cleared */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); +} + /* Force the GMU off in case it isn't responsive */ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu) { + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; + /* Flush all the queues */ a6xx_hfi_stop(gmu); @@ -887,6 +925,15 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu) /* Make sure there are no outstanding RPMh votes */ a6xx_gmu_rpmh_off(gmu); + + /* Halt the gmu cm3 core */ + gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1); + + a6xx_bus_clear_pending_transactions(adreno_gpu); + + /* Reset GPU core blocks */ + gpu_write(gpu, REG_A6XX_RBBM_SW_RESET_CMD, 1); + udelay(100); } static void a6xx_gmu_set_initial_freq(struct msm_gpu *gpu, struct a6xx_gmu *gmu) @@ -1014,36 +1061,6 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu) return true; } -#define GBIF_CLIENT_HALT_MASK BIT(0) -#define GBIF_ARB_HALT_MASK BIT(1) - -static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) -{ - struct msm_gpu *gpu = &adreno_gpu->base; - - if (!a6xx_has_gbif(adreno_gpu)) { - gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf); - spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & - 0xf) == 0xf); - gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0); - - return; - } - - /* Halt new client requests on GBIF */ - gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK); - spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & - (GBIF_CLIENT_HALT_MASK)) == GBIF_CLIENT_HALT_MASK); - - /* Halt all AXI requests on GBIF */ - gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_ARB_HALT_MASK); - spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & - (GBIF_ARB_HALT_MASK)) == GBIF_ARB_HALT_MASK); - - /* The GBIF halt needs to be explicitly cleared */ - gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); -} - /* Gracefully try to shut down the GMU and by extension the GPU */ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) { @@ -1069,7 +1086,11 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) a6xx_bus_clear_pending_transactions(adreno_gpu); /* tell the GMU we want to slumber */ - a6xx_gmu_notify_slumber(gmu); + ret = a6xx_gmu_notify_slumber(gmu); + if (ret) { + a6xx_gmu_force_off(gmu); + return; + } ret = gmu_poll_timeout(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, val, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 4d501100b9e4..fdc578016e0b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -10,6 +10,7 @@ #include <linux/bitfield.h> #include <linux/devfreq.h> +#include <linux/reset.h> #include <linux/soc/qcom/llcc-qcom.h> #define GPU_PAS_ID 13 @@ -146,7 +147,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, */ OUT_PKT7(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, 0x31); + OUT_RING(ring, CACHE_INVALIDATE); if (!sysprof) { /* @@ -987,6 +988,10 @@ static int hw_init(struct msm_gpu *gpu) /* Make sure the GMU keeps the GPU on while we set it up */ a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); + /* Clear GBIF halt in case GX domain was not collapsed */ + if (a6xx_has_gbif(adreno_gpu)) + gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 0); + gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_CNTL, 0); /* @@ -1261,7 +1266,7 @@ static void a6xx_recover(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - int i; + int i, active_submits; adreno_dump_info(gpu); @@ -1272,14 +1277,46 @@ static void a6xx_recover(struct msm_gpu *gpu) if (hang_debug) a6xx_dump(gpu); + /* Halt SQE first */ + gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3); + /* * Turn off keep alive that might have been enabled by the hang * interrupt */ gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, 0); - gpu->funcs->pm_suspend(gpu); - gpu->funcs->pm_resume(gpu); + pm_runtime_dont_use_autosuspend(&gpu->pdev->dev); + + /* active_submit won't change until we make a submission */ + mutex_lock(&gpu->active_lock); + active_submits = gpu->active_submits; + + /* + * Temporarily clear active_submits count to silence a WARN() in the + * runtime suspend cb + */ + gpu->active_submits = 0; + + /* Drop the rpm refcount from active submits */ + if (active_submits) + pm_runtime_put(&gpu->pdev->dev); + + /* And the final one from recover worker */ + pm_runtime_put_sync(&gpu->pdev->dev); + + /* Call into gpucc driver to poll for cx gdsc collapse */ + reset_control_reset(gpu->cx_collapse); + + pm_runtime_use_autosuspend(&gpu->pdev->dev); + + if (active_submits) + pm_runtime_get(&gpu->pdev->dev); + + pm_runtime_get_sync(&gpu->pdev->dev); + + gpu->active_submits = active_submits; + mutex_unlock(&gpu->active_lock); msm_gpu_hw_init(gpu); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 781dcd3fb283..13ce321283ff 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -412,7 +412,6 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, struct dpu_format *format; struct dpu_hw_ctl *ctl = mixer->lm_ctl; - u32 flush_mask; uint32_t stage_idx, lm_idx; int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; bool bg_alpha_enable = false; @@ -420,6 +419,8 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, memset(fetch_active, 0, sizeof(fetch_active)); drm_atomic_crtc_for_each_plane(plane, crtc) { + enum dpu_sspp sspp_idx; + state = plane->state; if (!state) continue; @@ -430,14 +431,14 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, pstate = to_dpu_plane_state(state); fb = state->fb; - dpu_plane_get_ctl_flush(plane, ctl, &flush_mask); - set_bit(dpu_plane_pipe(plane), fetch_active); + sspp_idx = dpu_plane_pipe(plane); + set_bit(sspp_idx, fetch_active); DRM_DEBUG_ATOMIC("crtc %d stage:%d - plane %d sspp %d fb %d\n", crtc->base.id, pstate->stage, plane->base.id, - dpu_plane_pipe(plane) - SSPP_VIG0, + sspp_idx - SSPP_VIG0, state->fb ? state->fb->base.id : -1); format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); @@ -447,13 +448,13 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, stage_idx = zpos_cnt[pstate->stage]++; stage_cfg->stage[pstate->stage][stage_idx] = - dpu_plane_pipe(plane); + sspp_idx; stage_cfg->multirect_index[pstate->stage][stage_idx] = pstate->multirect_index; trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane), state, pstate, stage_idx, - dpu_plane_pipe(plane) - SSPP_VIG0, + sspp_idx - SSPP_VIG0, format->base.pixel_format, fb ? fb->modifier : 0); @@ -462,7 +463,8 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate, format); - mixer[lm_idx].flush_mask |= flush_mask; + mixer[lm_idx].lm_ctl->ops.update_pending_flush_sspp(mixer[lm_idx].lm_ctl, + sspp_idx); if (bg_alpha_enable && !format->alpha_enable) mixer[lm_idx].mixer_op_mode = 0; @@ -496,7 +498,6 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) for (i = 0; i < cstate->num_mixers; i++) { mixer[i].mixer_op_mode = 0; - mixer[i].flush_mask = 0; if (mixer[i].lm_ctl->ops.clear_all_blendstages) mixer[i].lm_ctl->ops.clear_all_blendstages( mixer[i].lm_ctl); @@ -513,17 +514,14 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); - mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, - mixer[i].hw_lm->idx); - /* stage config flush mask */ - ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); + ctl->ops.update_pending_flush_mixer(ctl, + mixer[i].hw_lm->idx); - DRM_DEBUG_ATOMIC("lm %d, op_mode 0x%X, ctl %d, flush mask 0x%x\n", + DRM_DEBUG_ATOMIC("lm %d, op_mode 0x%X, ctl %d\n", mixer[i].hw_lm->idx - LM_0, mixer[i].mixer_op_mode, - ctl->idx - CTL_0, - mixer[i].flush_mask); + ctl->idx - CTL_0); ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, &stage_cfg); @@ -767,16 +765,9 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) dspp->ops.setup_pcc(dspp, &cfg); } - mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, - mixer[i].hw_dspp->idx); - /* stage config flush mask */ - ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); - - DRM_DEBUG_ATOMIC("lm %d, ctl %d, flush mask 0x%x\n", - mixer[i].hw_lm->idx - DSPP_0, - ctl->idx - CTL_0, - mixer[i].flush_mask); + ctl->ops.update_pending_flush_dspp(ctl, + mixer[i].hw_dspp->idx); } } @@ -1235,17 +1226,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, } for (i = 1; i < SSPP_MAX; i++) { - if (pipe_staged[i]) { + if (pipe_staged[i]) dpu_plane_clear_multirect(pipe_staged[i]); - - if (is_dpu_plane_virtual(pipe_staged[i]->plane)) { - DPU_ERROR( - "r1 only virt plane:%d not supported\n", - pipe_staged[i]->plane->base.id); - rc = -EINVAL; - goto end; - } - } } z_pos = -1; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 9b67645c2574..539b68b1626a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -97,7 +97,6 @@ struct dpu_crtc_mixer { struct dpu_hw_ctl *lm_ctl; struct dpu_hw_dspp *hw_dspp; u32 mixer_op_mode; - u32 flush_mask; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index c682d4e02d1b..9c6817b5a194 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -162,7 +162,7 @@ enum dpu_enc_rc_states { * @vsync_event_work: worker to handle vsync event for autorefresh * @topology: topology of the display * @idle_timeout: idle timeout duration in milliseconds - * @dsc: msm_display_dsc_config pointer, for DSC-enabled encoders + * @dsc: drm_dsc_config pointer, for DSC-enabled encoders */ struct dpu_encoder_virt { struct drm_encoder base; @@ -208,7 +208,7 @@ struct dpu_encoder_virt { bool wide_bus_en; /* DSC configuration */ - struct msm_display_dsc_config *dsc; + struct drm_dsc_config *dsc; }; #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base) @@ -1791,12 +1791,12 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) } static u32 -dpu_encoder_dsc_initial_line_calc(struct msm_display_dsc_config *dsc, +dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc, u32 enc_ip_width) { int ssm_delay, total_pixels, soft_slice_per_enc; - soft_slice_per_enc = enc_ip_width / dsc->drm->slice_width; + soft_slice_per_enc = enc_ip_width / dsc->slice_width; /* * minimum number of initial line pixels is a sum of: @@ -1808,16 +1808,16 @@ dpu_encoder_dsc_initial_line_calc(struct msm_display_dsc_config *dsc, * 5. 6 additional pixels as the output of the rate buffer is * 48 bits wide */ - ssm_delay = ((dsc->drm->bits_per_component < 10) ? 84 : 92); - total_pixels = ssm_delay * 3 + dsc->drm->initial_xmit_delay + 47; + ssm_delay = ((dsc->bits_per_component < 10) ? 84 : 92); + total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47; if (soft_slice_per_enc > 1) total_pixels += (ssm_delay * 3); - return DIV_ROUND_UP(total_pixels, dsc->drm->slice_width); + return DIV_ROUND_UP(total_pixels, dsc->slice_width); } static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, struct dpu_hw_pingpong *hw_pp, - struct msm_display_dsc_config *dsc, + struct drm_dsc_config *dsc, u32 common_mode, u32 initial_lines) { @@ -1835,7 +1835,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, } static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, - struct msm_display_dsc_config *dsc) + struct drm_dsc_config *dsc) { /* coding only for 2LM, 2enc, 1 dsc config */ struct dpu_encoder_phys *enc_master = dpu_enc->cur_master; @@ -1858,14 +1858,15 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, } } - pic_width = dsc->drm->pic_width; + dsc_common_mode = 0; + pic_width = dsc->pic_width; dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL; if (enc_master->intf_mode == INTF_MODE_VIDEO) dsc_common_mode |= DSC_MODE_VIDEO; - this_frame_slices = pic_width / dsc->drm->slice_width; - intf_ip_w = this_frame_slices * dsc->drm->slice_width; + this_frame_slices = pic_width / dsc->slice_width; + intf_ip_w = this_frame_slices * dsc->slice_width; /* * dsc merge case: when using 2 encoders for the same stream, @@ -1980,7 +1981,6 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_mixer_cfg mixer; int i, num_lm; - u32 flush_mask = 0; struct dpu_global_state *global_state; struct dpu_hw_blk *hw_lm[2]; struct dpu_hw_mixer *hw_mixer[2]; @@ -1999,9 +1999,8 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) for (i = 0; i < num_lm; i++) { hw_mixer[i] = to_dpu_hw_mixer(hw_lm[i]); - flush_mask = phys_enc->hw_ctl->ops.get_bitmask_mixer(ctl, hw_mixer[i]->idx); - if (phys_enc->hw_ctl->ops.update_pending_flush) - phys_enc->hw_ctl->ops.update_pending_flush(ctl, flush_mask); + if (phys_enc->hw_ctl->ops.update_pending_flush_mixer) + phys_enc->hw_ctl->ops.update_pending_flush_mixer(ctl, hw_mixer[i]->idx); /* clear all blendstages */ if (phys_enc->hw_ctl->ops.setup_blendstage) @@ -2061,6 +2060,12 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) intf_cfg.stream_sel = 0; /* Don't care value for video mode */ intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + + if (phys_enc->hw_intf) + intf_cfg.intf = phys_enc->hw_intf->idx; + if (phys_enc->hw_wb) + intf_cfg.wb = phys_enc->hw_wb->idx; + if (phys_enc->hw_pp->merge_3d) intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index d4d1ecd416e3..9e7236ef34e6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -36,7 +36,7 @@ struct msm_display_info { uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY]; bool is_cmd_mode; bool is_te_using_watchdog_timer; - struct msm_display_dsc_config *dsc; + struct drm_dsc_config *dsc; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 0239a811d5ec..27f029fdc682 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -1333,7 +1333,7 @@ static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { static const struct dpu_vbif_cfg msm8998_vbif[] = { { - .name = "vbif_0", .id = VBIF_0, + .name = "vbif_rt", .id = VBIF_RT, .base = 0, .len = 0x1040, .default_ot_rd_limit = 32, .default_ot_wr_limit = 32, @@ -1363,7 +1363,7 @@ static const struct dpu_vbif_cfg msm8998_vbif[] = { static const struct dpu_vbif_cfg sdm845_vbif[] = { { - .name = "vbif_0", .id = VBIF_0, + .name = "vbif_rt", .id = VBIF_RT, .base = 0, .len = 0x1040, .features = BIT(DPU_VBIF_QOS_REMAP), .xin_halt_timeout = 0x4000, @@ -1939,11 +1939,6 @@ static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = { const struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev) { int i; - struct dpu_mdss_cfg *dpu_cfg; - - dpu_cfg = kzalloc(sizeof(*dpu_cfg), GFP_KERNEL); - if (!dpu_cfg) - return ERR_PTR(-ENOMEM); for (i = 0; i < ARRAY_SIZE(cfg_handler); i++) { if (cfg_handler[i].hw_rev == hw_rev) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 71fe4c505f5b..38aa38ab1568 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -76,7 +76,7 @@ enum { /** * MDP TOP BLOCK features - * @DPU_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe + * @DPU_MDP_PANIC_PER_PIPE Panic configuration needs to be done per pipe * @DPU_MDP_10BIT_SUPPORT, Chipset supports 10 bit pixel formats * @DPU_MDP_BWC, MDSS HW supports Bandwidth compression. * @DPU_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index e12b7fa48a7b..a35ecb6676c8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -150,92 +150,84 @@ static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx) DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } -static uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx, +static void dpu_hw_ctl_update_pending_flush_sspp(struct dpu_hw_ctl *ctx, enum dpu_sspp sspp) { - uint32_t flushbits = 0; - switch (sspp) { case SSPP_VIG0: - flushbits = BIT(0); + ctx->pending_flush_mask |= BIT(0); break; case SSPP_VIG1: - flushbits = BIT(1); + ctx->pending_flush_mask |= BIT(1); break; case SSPP_VIG2: - flushbits = BIT(2); + ctx->pending_flush_mask |= BIT(2); break; case SSPP_VIG3: - flushbits = BIT(18); + ctx->pending_flush_mask |= BIT(18); break; case SSPP_RGB0: - flushbits = BIT(3); + ctx->pending_flush_mask |= BIT(3); break; case SSPP_RGB1: - flushbits = BIT(4); + ctx->pending_flush_mask |= BIT(4); break; case SSPP_RGB2: - flushbits = BIT(5); + ctx->pending_flush_mask |= BIT(5); break; case SSPP_RGB3: - flushbits = BIT(19); + ctx->pending_flush_mask |= BIT(19); break; case SSPP_DMA0: - flushbits = BIT(11); + ctx->pending_flush_mask |= BIT(11); break; case SSPP_DMA1: - flushbits = BIT(12); + ctx->pending_flush_mask |= BIT(12); break; case SSPP_DMA2: - flushbits = BIT(24); + ctx->pending_flush_mask |= BIT(24); break; case SSPP_DMA3: - flushbits = BIT(25); + ctx->pending_flush_mask |= BIT(25); break; case SSPP_CURSOR0: - flushbits = BIT(22); + ctx->pending_flush_mask |= BIT(22); break; case SSPP_CURSOR1: - flushbits = BIT(23); + ctx->pending_flush_mask |= BIT(23); break; default: break; } - - return flushbits; } -static uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx, +static void dpu_hw_ctl_update_pending_flush_mixer(struct dpu_hw_ctl *ctx, enum dpu_lm lm) { - uint32_t flushbits = 0; - switch (lm) { case LM_0: - flushbits = BIT(6); + ctx->pending_flush_mask |= BIT(6); break; case LM_1: - flushbits = BIT(7); + ctx->pending_flush_mask |= BIT(7); break; case LM_2: - flushbits = BIT(8); + ctx->pending_flush_mask |= BIT(8); break; case LM_3: - flushbits = BIT(9); + ctx->pending_flush_mask |= BIT(9); break; case LM_4: - flushbits = BIT(10); + ctx->pending_flush_mask |= BIT(10); break; case LM_5: - flushbits = BIT(20); + ctx->pending_flush_mask |= BIT(20); break; default: - return -EINVAL; + break; } - flushbits |= CTL_FLUSH_MASK_CTL; - - return flushbits; + ctx->pending_flush_mask |= CTL_FLUSH_MASK_CTL; } static void dpu_hw_ctl_update_pending_flush_intf(struct dpu_hw_ctl *ctx, @@ -294,29 +286,25 @@ static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(MERGE_3D_IDX); } -static uint32_t dpu_hw_ctl_get_bitmask_dspp(struct dpu_hw_ctl *ctx, +static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx, enum dpu_dspp dspp) { - uint32_t flushbits = 0; - switch (dspp) { case DSPP_0: - flushbits = BIT(13); + ctx->pending_flush_mask |= BIT(13); break; case DSPP_1: - flushbits = BIT(14); + ctx->pending_flush_mask |= BIT(14); break; case DSPP_2: - flushbits = BIT(15); + ctx->pending_flush_mask |= BIT(15); break; case DSPP_3: - flushbits = BIT(21); + ctx->pending_flush_mask |= BIT(21); break; default: - return 0; + break; } - - return flushbits; } static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) @@ -685,9 +673,9 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->wait_reset_status = dpu_hw_ctl_wait_reset_status; ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; - ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; - ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; - ops->get_bitmask_dspp = dpu_hw_ctl_get_bitmask_dspp; + ops->update_pending_flush_sspp = dpu_hw_ctl_update_pending_flush_sspp; + ops->update_pending_flush_mixer = dpu_hw_ctl_update_pending_flush_mixer; + ops->update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp; if (cap & BIT(DPU_CTL_FETCH_ACTIVE)) ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 7d9ad6a3f9f6..96c012ec8467 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -130,6 +130,32 @@ struct dpu_hw_ctl_ops { enum dpu_merge_3d blk); /** + * OR in the given flushbits to the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @blk : SSPP block index + */ + void (*update_pending_flush_sspp)(struct dpu_hw_ctl *ctx, + enum dpu_sspp blk); + + /** + * OR in the given flushbits to the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @blk : LM block index + */ + void (*update_pending_flush_mixer)(struct dpu_hw_ctl *ctx, + enum dpu_lm blk); + + /** + * OR in the given flushbits to the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @blk : DSPP block index + */ + void (*update_pending_flush_dspp)(struct dpu_hw_ctl *ctx, + enum dpu_dspp blk); + /** * Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ @@ -171,15 +197,6 @@ struct dpu_hw_ctl_ops { */ int (*wait_reset_status)(struct dpu_hw_ctl *ctx); - uint32_t (*get_bitmask_sspp)(struct dpu_hw_ctl *ctx, - enum dpu_sspp blk); - - uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, - enum dpu_lm blk); - - uint32_t (*get_bitmask_dspp)(struct dpu_hw_ctl *ctx, - enum dpu_dspp blk); - /** * Set all blend stages to disabled * @ctx : ctl path ctx pointer diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index 411689ae6382..f2ddcfb6f7ee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -37,7 +37,7 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc) } static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, - struct msm_display_dsc_config *dsc, + struct drm_dsc_config *dsc, u32 mode, u32 initial_lines) { @@ -52,89 +52,89 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, if (is_cmd_mode) initial_lines += 1; - slice_last_group_size = 3 - (dsc->drm->slice_width % 3); + slice_last_group_size = 3 - (dsc->slice_width % 3); data = (initial_lines << 20); data |= ((slice_last_group_size - 1) << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ - data |= dsc->drm->bits_per_pixel << 12; - lsb = dsc->drm->bits_per_pixel % 4; - bpp = dsc->drm->bits_per_pixel / 4; + data |= dsc->bits_per_pixel << 12; + lsb = dsc->bits_per_pixel % 4; + bpp = dsc->bits_per_pixel / 4; bpp *= 4; bpp <<= 4; bpp |= lsb; data |= bpp << 8; - data |= (dsc->drm->block_pred_enable << 7); - data |= (dsc->drm->line_buf_depth << 3); - data |= (dsc->drm->simple_422 << 2); - data |= (dsc->drm->convert_rgb << 1); - data |= dsc->drm->bits_per_component; + data |= (dsc->block_pred_enable << 7); + data |= (dsc->line_buf_depth << 3); + data |= (dsc->simple_422 << 2); + data |= (dsc->convert_rgb << 1); + data |= dsc->bits_per_component; DPU_REG_WRITE(c, DSC_ENC, data); - data = dsc->drm->pic_width << 16; - data |= dsc->drm->pic_height; + data = dsc->pic_width << 16; + data |= dsc->pic_height; DPU_REG_WRITE(c, DSC_PICTURE, data); - data = dsc->drm->slice_width << 16; - data |= dsc->drm->slice_height; + data = dsc->slice_width << 16; + data |= dsc->slice_height; DPU_REG_WRITE(c, DSC_SLICE, data); - data = dsc->drm->slice_chunk_size << 16; + data = dsc->slice_chunk_size << 16; DPU_REG_WRITE(c, DSC_CHUNK_SIZE, data); - data = dsc->drm->initial_dec_delay << 16; - data |= dsc->drm->initial_xmit_delay; + data = dsc->initial_dec_delay << 16; + data |= dsc->initial_xmit_delay; DPU_REG_WRITE(c, DSC_DELAY, data); - data = dsc->drm->initial_scale_value; + data = dsc->initial_scale_value; DPU_REG_WRITE(c, DSC_SCALE_INITIAL, data); - data = dsc->drm->scale_decrement_interval; + data = dsc->scale_decrement_interval; DPU_REG_WRITE(c, DSC_SCALE_DEC_INTERVAL, data); - data = dsc->drm->scale_increment_interval; + data = dsc->scale_increment_interval; DPU_REG_WRITE(c, DSC_SCALE_INC_INTERVAL, data); - data = dsc->drm->first_line_bpg_offset; + data = dsc->first_line_bpg_offset; DPU_REG_WRITE(c, DSC_FIRST_LINE_BPG_OFFSET, data); - data = dsc->drm->nfl_bpg_offset << 16; - data |= dsc->drm->slice_bpg_offset; + data = dsc->nfl_bpg_offset << 16; + data |= dsc->slice_bpg_offset; DPU_REG_WRITE(c, DSC_BPG_OFFSET, data); - data = dsc->drm->initial_offset << 16; - data |= dsc->drm->final_offset; + data = dsc->initial_offset << 16; + data |= dsc->final_offset; DPU_REG_WRITE(c, DSC_DSC_OFFSET, data); - det_thresh_flatness = 7 + 2 * (dsc->drm->bits_per_component - 8); + det_thresh_flatness = 7 + 2 * (dsc->bits_per_component - 8); data = det_thresh_flatness << 10; - data |= dsc->drm->flatness_max_qp << 5; - data |= dsc->drm->flatness_min_qp; + data |= dsc->flatness_max_qp << 5; + data |= dsc->flatness_min_qp; DPU_REG_WRITE(c, DSC_FLATNESS, data); - data = dsc->drm->rc_model_size; + data = dsc->rc_model_size; DPU_REG_WRITE(c, DSC_RC_MODEL_SIZE, data); - data = dsc->drm->rc_tgt_offset_low << 18; - data |= dsc->drm->rc_tgt_offset_high << 14; - data |= dsc->drm->rc_quant_incr_limit1 << 9; - data |= dsc->drm->rc_quant_incr_limit0 << 4; - data |= dsc->drm->rc_edge_factor; + data = dsc->rc_tgt_offset_low << 18; + data |= dsc->rc_tgt_offset_high << 14; + data |= dsc->rc_quant_incr_limit1 << 9; + data |= dsc->rc_quant_incr_limit0 << 4; + data |= dsc->rc_edge_factor; DPU_REG_WRITE(c, DSC_RC, data); } static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc, - struct msm_display_dsc_config *dsc) + struct drm_dsc_config *dsc) { - struct drm_dsc_rc_range_parameters *rc = dsc->drm->rc_range_params; + struct drm_dsc_rc_range_parameters *rc = dsc->rc_range_params; struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; u32 off; int i; off = DSC_RC_BUF_THRESH; for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) { - DPU_REG_WRITE(c, off, dsc->drm->rc_buf_thresh[i]); + DPU_REG_WRITE(c, off, dsc->rc_buf_thresh[i]); off += 4; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index 45e4118f1fa2..c0b77fe1a696 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -31,7 +31,7 @@ struct dpu_hw_dsc_ops { * @initial_lines: amount of initial lines to be used */ void (*dsc_config)(struct dpu_hw_dsc *hw_dsc, - struct msm_display_dsc_config *dsc, + struct drm_dsc_config *dsc, u32 mode, u32 initial_lines); @@ -41,7 +41,7 @@ struct dpu_hw_dsc_ops { * @dsc: panel dsc parameters */ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, - struct msm_display_dsc_config *dsc); + struct drm_dsc_config *dsc); }; struct dpu_hw_dsc { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 9f402be55fbf..d3b0ed0a9c6c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -273,11 +273,9 @@ enum dpu_wd_timer { }; enum dpu_vbif { - VBIF_0, - VBIF_1, + VBIF_RT, + VBIF_NRT, VBIF_MAX, - VBIF_RT = VBIF_0, - VBIF_NRT = VBIF_1 }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 102c21bb4192..691c471b08c2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -780,8 +780,7 @@ static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp, } struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, - void __iomem *addr, const struct dpu_mdss_cfg *catalog, - bool is_virtual_pipe) + void __iomem *addr, const struct dpu_mdss_cfg *catalog) { struct dpu_hw_pipe *hw_pipe; const struct dpu_sspp_cfg *cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index 78b1bc9e004f..0c95b7e64f6c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -377,11 +377,9 @@ struct dpu_kms; * @idx: Pipe index for which driver object is required * @addr: Mapped register io address of MDP * @catalog : Pointer to mdss catalog data - * @is_virtual_pipe: is this pipe virtual pipe */ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, - void __iomem *addr, const struct dpu_mdss_cfg *catalog, - bool is_virtual_pipe); + void __iomem *addr, const struct dpu_mdss_cfg *catalog); /** * dpu_hw_sspp_destroy(): Destroys SSPP driver context diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 008e1420e6e5..5e6e2626151e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -384,12 +384,9 @@ static int dpu_kms_parse_data_bus_icc_path(struct dpu_kms *dpu_kms) struct icc_path *path1; struct drm_device *dev = dpu_kms->dev; struct device *dpu_dev = dev->dev; - struct device *mdss_dev = dpu_dev->parent; - /* Interconnects are a part of MDSS device tree binding, not the - * MDP/DPU device. */ - path0 = of_icc_get(mdss_dev, "mdp0-mem"); - path1 = of_icc_get(mdss_dev, "mdp1-mem"); + path0 = msm_icc_get(dpu_dev, "mdp0-mem"); + path1 = msm_icc_get(dpu_dev, "mdp1-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); @@ -782,7 +779,7 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR)); plane = dpu_plane_init(dev, catalog->sspp[i].id, type, - (1UL << max_crtc_count) - 1, 0); + (1UL << max_crtc_count) - 1); if (IS_ERR(plane)) { DPU_ERROR("dpu_plane_init failed\n"); ret = PTR_ERR(plane); @@ -826,12 +823,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) _dpu_kms_mmu_destroy(dpu_kms); if (dpu_kms->catalog) { - for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { - u32 vbif_idx = dpu_kms->catalog->vbif[i].id; - - if ((vbif_idx < VBIF_MAX) && dpu_kms->hw_vbif[vbif_idx]) { - dpu_hw_vbif_destroy(dpu_kms->hw_vbif[vbif_idx]); - dpu_kms->hw_vbif[vbif_idx] = NULL; + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + if (dpu_kms->hw_vbif[i]) { + dpu_hw_vbif_destroy(dpu_kms->hw_vbif[i]); + dpu_kms->hw_vbif[i] = NULL; } } } @@ -902,12 +897,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k int i; struct dpu_kms *dpu_kms; const struct dpu_mdss_cfg *cat; - struct dpu_hw_mdp *top; dpu_kms = to_dpu_kms(kms); cat = dpu_kms->catalog; - top = dpu_kms->hw_mdp; pm_runtime_get_sync(&dpu_kms->pdev->dev); @@ -1113,12 +1106,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms) for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { u32 vbif_idx = dpu_kms->catalog->vbif[i].id; - dpu_kms->hw_vbif[i] = dpu_hw_vbif_init(vbif_idx, + dpu_kms->hw_vbif[vbif_idx] = dpu_hw_vbif_init(vbif_idx, dpu_kms->vbif[vbif_idx], dpu_kms->catalog); - if (IS_ERR_OR_NULL(dpu_kms->hw_vbif[vbif_idx])) { + if (IS_ERR(dpu_kms->hw_vbif[vbif_idx])) { rc = PTR_ERR(dpu_kms->hw_vbif[vbif_idx]); - if (!dpu_kms->hw_vbif[vbif_idx]) - rc = -EINVAL; DPU_ERROR("failed to init vbif %d: %d\n", vbif_idx, rc); dpu_kms->hw_vbif[vbif_idx] = NULL; goto power_error; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index a617a3d8b1bc..658005f609f4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -91,7 +91,7 @@ enum dpu_plane_qos { /* * struct dpu_plane - local dpu plane structure * @aspace: address space pointer - * @mplane_list: List of multirect planes of the same pipe + * @csc_ptr: Points to dpu_csc_cfg structure to use for current * @catalog: Points to dpu catalog structure * @revalidate: force revalidation of all the plane properties */ @@ -106,8 +106,6 @@ struct dpu_plane { uint32_t color_fill; bool is_error; bool is_rt_pipe; - bool is_virtual; - struct list_head mplane_list; const struct dpu_mdss_cfg *catalog; }; @@ -225,7 +223,7 @@ static void _dpu_plane_calc_clk(struct drm_plane *plane, struct dpu_hw_pipe_cfg static int _dpu_plane_calc_fill_level(struct drm_plane *plane, const struct dpu_format *fmt, u32 src_width) { - struct dpu_plane *pdpu, *tmp; + struct dpu_plane *pdpu; struct dpu_plane_state *pstate; u32 fixed_buff_size; u32 total_fl; @@ -239,19 +237,7 @@ static int _dpu_plane_calc_fill_level(struct drm_plane *plane, pstate = to_dpu_plane_state(plane->state); fixed_buff_size = pdpu->catalog->caps->pixel_ram_size; - list_for_each_entry(tmp, &pdpu->mplane_list, mplane_list) { - u32 tmp_width; - - if (!tmp->base.state->visible) - continue; - tmp_width = drm_rect_width(&tmp->base.state->src) >> 16; - DPU_DEBUG("plane%d/%d src_width:%d/%d\n", - pdpu->base.base.id, tmp->base.base.id, - src_width, - tmp_width); - src_width = max_t(u32, src_width, - tmp_width); - } + /* FIXME: in multirect case account for the src_width of all the planes */ if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { if (fmt->chroma_sample == DPU_CHROMA_420) { @@ -854,13 +840,8 @@ int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane) } done: - if (dpu_plane[R0]->is_virtual) { - pstate[R0]->multirect_index = DPU_SSPP_RECT_1; - pstate[R1]->multirect_index = DPU_SSPP_RECT_0; - } else { - pstate[R0]->multirect_index = DPU_SSPP_RECT_0; - pstate[R1]->multirect_index = DPU_SSPP_RECT_1; - } + pstate[R0]->multirect_index = DPU_SSPP_RECT_0; + pstate[R1]->multirect_index = DPU_SSPP_RECT_1; DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n", pstate[R0]->multirect_mode, pstate[R0]->multirect_index); @@ -869,18 +850,6 @@ done: return 0; } -/** - * dpu_plane_get_ctl_flush - get control flush for the given plane - * @plane: Pointer to drm plane structure - * @ctl: Pointer to hardware control driver - * @flush_sspp: Pointer to sspp flush control word - */ -void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, - u32 *flush_sspp) -{ - *flush_sspp = ctl->ops.get_bitmask_sspp(ctl, dpu_plane_pipe(plane)); -} - static int dpu_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { @@ -1266,19 +1235,13 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) static void _dpu_plane_atomic_disable(struct drm_plane *plane) { - struct dpu_plane *pdpu = to_dpu_plane(plane); struct drm_plane_state *state = plane->state; struct dpu_plane_state *pstate = to_dpu_plane_state(state); - trace_dpu_plane_disable(DRMID(plane), is_dpu_plane_virtual(plane), + trace_dpu_plane_disable(DRMID(plane), false, pstate->multirect_mode); pstate->pending = true; - - if (is_dpu_plane_virtual(plane) && - pdpu->pipe_hw && pdpu->pipe_hw->ops.setup_multirect) - pdpu->pipe_hw->ops.setup_multirect(pdpu->pipe_hw, - DPU_SSPP_RECT_SOLO, DPU_SSPP_MULTIRECT_NONE); } static void dpu_plane_atomic_update(struct drm_plane *plane, @@ -1493,22 +1456,16 @@ enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane) return plane ? to_dpu_plane(plane)->pipe : SSPP_NONE; } -bool is_dpu_plane_virtual(struct drm_plane *plane) -{ - return plane ? to_dpu_plane(plane)->is_virtual : false; -} - /* initialize plane */ struct drm_plane *dpu_plane_init(struct drm_device *dev, uint32_t pipe, enum drm_plane_type type, - unsigned long possible_crtcs, u32 master_plane_id) + unsigned long possible_crtcs) { - struct drm_plane *plane = NULL, *master_plane = NULL; + struct drm_plane *plane = NULL; const uint32_t *format_list; struct dpu_plane *pdpu; struct msm_drm_private *priv = dev->dev_private; struct dpu_kms *kms = to_dpu_kms(priv->kms); - int zpos_max = DPU_ZPOS_MAX; uint32_t num_formats; uint32_t supported_rotations; int ret = -EINVAL; @@ -1524,18 +1481,9 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, /* cache local stuff for later */ plane = &pdpu->base; pdpu->pipe = pipe; - pdpu->is_virtual = (master_plane_id != 0); - INIT_LIST_HEAD(&pdpu->mplane_list); - master_plane = drm_plane_find(dev, NULL, master_plane_id); - if (master_plane) { - struct dpu_plane *mpdpu = to_dpu_plane(master_plane); - - list_add_tail(&pdpu->mplane_list, &mpdpu->mplane_list); - } /* initialize underlying h/w driver */ - pdpu->pipe_hw = dpu_hw_sspp_init(pipe, kms->mmio, kms->catalog, - master_plane_id != 0); + pdpu->pipe_hw = dpu_hw_sspp_init(pipe, kms->mmio, kms->catalog); if (IS_ERR(pdpu->pipe_hw)) { DPU_ERROR("[%u]SSPP init failed\n", pipe); ret = PTR_ERR(pdpu->pipe_hw); @@ -1545,14 +1493,8 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, goto clean_sspp; } - if (pdpu->is_virtual) { - format_list = pdpu->pipe_hw->cap->sblk->virt_format_list; - num_formats = pdpu->pipe_hw->cap->sblk->virt_num_formats; - } - else { - format_list = pdpu->pipe_hw->cap->sblk->format_list; - num_formats = pdpu->pipe_hw->cap->sblk->num_formats; - } + format_list = pdpu->pipe_hw->cap->sblk->format_list; + num_formats = pdpu->pipe_hw->cap->sblk->num_formats; ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, format_list, num_formats, @@ -1562,14 +1504,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, pdpu->catalog = kms->catalog; - if (kms->catalog->mixer_count && - kms->catalog->mixer[0].sblk->maxblendstages) { - zpos_max = kms->catalog->mixer[0].sblk->maxblendstages - 1; - if (zpos_max > DPU_STAGE_MAX - DPU_STAGE_0 - 1) - zpos_max = DPU_STAGE_MAX - DPU_STAGE_0 - 1; - } - - ret = drm_plane_create_zpos_property(plane, 0, 0, zpos_max); + ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX); if (ret) DPU_ERROR("failed to install zpos property, rc = %d\n", ret); @@ -1594,15 +1529,14 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, mutex_init(&pdpu->lock); - DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", plane->name, - pipe, plane->base.id, master_plane_id); + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name, + pipe, plane->base.id); return plane; clean_sspp: if (pdpu && pdpu->pipe_hw) dpu_hw_sspp_destroy(pdpu->pipe_hw); clean_plane: - list_del(&pdpu->mplane_list); kfree(pdpu); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index e1463107a6fc..b7b1b05199c2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -65,23 +65,6 @@ struct dpu_multirect_plane_states { enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane); /** - * is_dpu_plane_virtual - check for virtual plane - * @plane: Pointer to DRM plane object - * returns: true - if the plane is virtual - * false - if the plane is primary - */ -bool is_dpu_plane_virtual(struct drm_plane *plane); - -/** - * dpu_plane_get_ctl_flush - get control flush mask - * @plane: Pointer to DRM plane object - * @ctl: Pointer to control hardware - * @flush_sspp: Pointer to sspp flush control word - */ -void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, - u32 *flush_sspp); - -/** * dpu_plane_flush - final plane operations before commit flush * @plane: Pointer to drm plane structure */ @@ -99,14 +82,11 @@ void dpu_plane_set_error(struct drm_plane *plane, bool error); * @pipe: dpu hardware pipe identifier * @type: Plane type - PRIMARY/OVERLAY/CURSOR * @possible_crtcs: bitmask of crtc that can be attached to the given pipe - * @master_plane_id: primary plane id of a multirect pipe. 0 value passed for - * a regular plane initialization. A non-zero primary plane - * id will be passed for a virtual pipe initialization. * */ struct drm_plane *dpu_plane_init(struct drm_device *dev, uint32_t pipe, enum drm_plane_type type, - unsigned long possible_crtcs, u32 master_plane_id); + unsigned long possible_crtcs); /** * dpu_plane_validate_multirecti_v2 - validate the multirect planes diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c index 21d20373eb8b..1305e250b71e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -11,6 +11,26 @@ #include "dpu_hw_vbif.h" #include "dpu_trace.h" +static struct dpu_hw_vbif *dpu_get_vbif(struct dpu_kms *dpu_kms, enum dpu_vbif vbif_idx) +{ + if (vbif_idx < ARRAY_SIZE(dpu_kms->hw_vbif)) + return dpu_kms->hw_vbif[vbif_idx]; + + return NULL; +} + +static const char *dpu_vbif_name(enum dpu_vbif idx) +{ + switch (idx) { + case VBIF_RT: + return "VBIF_RT"; + case VBIF_NRT: + return "VBIF_NRT"; + default: + return "??"; + } +} + /** * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt * @vbif: Pointer to hardware vbif driver @@ -42,12 +62,12 @@ static int _dpu_vbif_wait_for_xin_halt(struct dpu_hw_vbif *vbif, u32 xin_id) if (!status) { rc = -ETIMEDOUT; - DPU_ERROR("VBIF %d client %d not halting. TIMEDOUT.\n", - vbif->idx - VBIF_0, xin_id); + DPU_ERROR("%s client %d not halting. TIMEDOUT.\n", + dpu_vbif_name(vbif->idx), xin_id); } else { rc = 0; - DRM_DEBUG_ATOMIC("VBIF %d client %d is halted\n", - vbif->idx - VBIF_0, xin_id); + DRM_DEBUG_ATOMIC("%s client %d is halted\n", + dpu_vbif_name(vbif->idx), xin_id); } return rc; @@ -87,8 +107,8 @@ static void _dpu_vbif_apply_dynamic_ot_limit(struct dpu_hw_vbif *vbif, } } - DRM_DEBUG_ATOMIC("vbif:%d xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", - vbif->idx - VBIF_0, params->xin_id, + DRM_DEBUG_ATOMIC("%s xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", + dpu_vbif_name(vbif->idx), params->xin_id, params->width, params->height, params->frame_rate, pps, *ot_lim); } @@ -133,8 +153,8 @@ static u32 _dpu_vbif_get_ot_limit(struct dpu_hw_vbif *vbif, } exit: - DRM_DEBUG_ATOMIC("vbif:%d xin:%d ot_lim:%d\n", - vbif->idx - VBIF_0, params->xin_id, ot_lim); + DRM_DEBUG_ATOMIC("%s xin:%d ot_lim:%d\n", + dpu_vbif_name(vbif->idx), params->xin_id, ot_lim); return ot_lim; } @@ -148,20 +168,15 @@ exit: void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, struct dpu_vbif_set_ot_params *params) { - struct dpu_hw_vbif *vbif = NULL; + struct dpu_hw_vbif *vbif; struct dpu_hw_mdp *mdp; bool forced_on = false; u32 ot_lim; - int ret, i; + int ret; mdp = dpu_kms->hw_mdp; - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - if (dpu_kms->hw_vbif[i] && - dpu_kms->hw_vbif[i]->idx == params->vbif_idx) - vbif = dpu_kms->hw_vbif[i]; - } - + vbif = dpu_get_vbif(dpu_kms, params->vbif_idx); if (!vbif || !mdp) { DRM_DEBUG_ATOMIC("invalid arguments vbif %d mdp %d\n", vbif != NULL, mdp != NULL); @@ -204,7 +219,7 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, struct dpu_vbif_set_qos_params *params) { - struct dpu_hw_vbif *vbif = NULL; + struct dpu_hw_vbif *vbif; struct dpu_hw_mdp *mdp; bool forced_on = false; const struct dpu_vbif_qos_tbl *qos_tbl; @@ -216,13 +231,7 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, } mdp = dpu_kms->hw_mdp; - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - if (dpu_kms->hw_vbif[i] && - dpu_kms->hw_vbif[i]->idx == params->vbif_idx) { - vbif = dpu_kms->hw_vbif[i]; - break; - } - } + vbif = dpu_get_vbif(dpu_kms, params->vbif_idx); if (!vbif || !vbif->cap) { DPU_ERROR("invalid vbif %d\n", params->vbif_idx); @@ -245,8 +254,8 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); for (i = 0; i < qos_tbl->npriority_lvl; i++) { - DRM_DEBUG_ATOMIC("vbif:%d xin:%d lvl:%d/%d\n", - params->vbif_idx, params->xin_id, i, + DRM_DEBUG_ATOMIC("%s xin:%d lvl:%d/%d\n", + dpu_vbif_name(params->vbif_idx), params->xin_id, i, qos_tbl->priority_lvl[i]); vbif->ops.set_qos_remap(vbif, params->xin_id, i, qos_tbl->priority_lvl[i]); @@ -266,8 +275,8 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) if (vbif && vbif->ops.clear_errors) { vbif->ops.clear_errors(vbif, &pnd, &src); if (pnd || src) { - DRM_DEBUG_KMS("VBIF %d: pnd 0x%X, src 0x%X\n", - vbif->idx - VBIF_0, pnd, src); + DRM_DEBUG_KMS("%s: pnd 0x%X, src 0x%X\n", + dpu_vbif_name(vbif->idx), pnd, src); } } } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index d2a48caf9d27..b0d21838a134 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -902,12 +902,9 @@ fail: static int mdp5_setup_interconnect(struct platform_device *pdev) { - /* Interconnects are a part of MDSS device tree binding, not the - * MDP5 device. */ - struct device *mdss_dev = pdev->dev.parent; - struct icc_path *path0 = of_icc_get(mdss_dev, "mdp0-mem"); - struct icc_path *path1 = of_icc_get(mdss_dev, "mdp1-mem"); - struct icc_path *path_rot = of_icc_get(mdss_dev, "rotator-mem"); + struct icc_path *path0 = msm_icc_get(&pdev->dev, "mdp0-mem"); + struct icc_path *path1 = msm_icc_get(&pdev->dev, "mdp1-mem"); + struct icc_path *path_rot = msm_icc_get(&pdev->dev, "rotator-mem"); if (IS_ERR(path0)) return PTR_ERR(path0); diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 7257515871a9..676279d0ca8d 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -431,7 +431,7 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, if (rate == link_rate_hbr3) pixel_div = 6; - else if (rate == 1620000 || rate == 270000) + else if (rate == 162000 || rate == 270000) pixel_div = 2; else if (rate == link_rate_hbr2) pixel_div = 4; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index ab6aa13b1639..3854c9f1f7e9 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1214,7 +1214,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, if (ret) return ret; - dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); + dp_ctrl_train_pattern_set(ctrl, pattern); for (tries = 0; tries <= maximum_retries; tries++) { drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); @@ -1238,8 +1238,6 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, return -ETIMEDOUT; } -static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl); - static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, int *training_step) { @@ -1358,25 +1356,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) if (ret) DRM_ERROR("Unable to start link clocks. ret=%d\n", ret); - drm_dbg_dp(ctrl->drm_dev, "link rate=%d pixel_clk=%d\n", - ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate); - - return ret; -} - -static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", - ctrl->dp_ctrl.pixel_rate * 1000); - - ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true); - if (ret) - DRM_ERROR("Unabled to start pixel clocks. ret=%d\n", ret); - - drm_dbg_dp(ctrl->drm_dev, "link rate=%d pixel_clk=%d\n", - ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate); + drm_dbg_dp(ctrl->drm_dev, "link rate=%d\n", ctrl->link->link_params.rate); return ret; } @@ -1520,8 +1500,6 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl) ctrl->link->phy_params.p_level = 0; ctrl->link->phy_params.v_level = 0; - ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; - ret = dp_ctrl_setup_main_link(ctrl, &training_step); if (ret) goto end; @@ -1535,38 +1513,6 @@ end: return ret; } -static int dp_ctrl_on_stream_phy_test_report(struct dp_ctrl *dp_ctrl); - -static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - if (!ctrl->link->phy_params.phy_test_pattern_sel) { - drm_dbg_dp(ctrl->drm_dev, - "no test pattern selected by sink\n"); - return ret; - } - - /* - * The global reset will need DP link related clocks to be - * running. Add the global reset just before disabling the - * link clocks and core clocks. - */ - ret = dp_ctrl_off(&ctrl->dp_ctrl); - if (ret) { - DRM_ERROR("failed to disable DP controller\n"); - return ret; - } - - ret = dp_ctrl_on_link(&ctrl->dp_ctrl); - if (!ret) - ret = dp_ctrl_on_stream_phy_test_report(&ctrl->dp_ctrl); - else - DRM_ERROR("failed to enable DP link controller\n"); - - return ret; -} - static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) { bool success = false; @@ -1619,6 +1565,48 @@ static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) return success; } +static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) +{ + int ret; + unsigned long pixel_rate; + + if (!ctrl->link->phy_params.phy_test_pattern_sel) { + drm_dbg_dp(ctrl->drm_dev, + "no test pattern selected by sink\n"); + return 0; + } + + /* + * The global reset will need DP link related clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + ret = dp_ctrl_off(&ctrl->dp_ctrl); + if (ret) { + DRM_ERROR("failed to disable DP controller\n"); + return ret; + } + + ret = dp_ctrl_on_link(&ctrl->dp_ctrl); + if (ret) { + DRM_ERROR("failed to enable DP link controller\n"); + return ret; + } + + pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; + dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 1000); + + ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true); + if (ret) { + DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); + return ret; + } + + dp_ctrl_send_phy_test_pattern(ctrl); + + return 0; +} + void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; @@ -1689,11 +1677,12 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) { int rc = 0; struct dp_ctrl_private *ctrl; - u32 rate = 0; + u32 rate; int link_train_max_retries = 5; u32 const phy_cts_pixel_clk_khz = 148500; u8 link_status[DP_LINK_STATUS_SIZE]; unsigned int training_step; + unsigned long pixel_rate; if (!dp_ctrl) return -EINVAL; @@ -1701,25 +1690,24 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); rate = ctrl->panel->link_info.rate; + pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; dp_power_clk_enable(ctrl->power, DP_CORE_PM, true); if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { drm_dbg_dp(ctrl->drm_dev, "using phy test link parameters\n"); - if (!ctrl->panel->dp_mode.drm_mode.clock) - ctrl->dp_ctrl.pixel_rate = phy_cts_pixel_clk_khz; + if (!pixel_rate) + pixel_rate = phy_cts_pixel_clk_khz; } else { ctrl->link->link_params.rate = rate; ctrl->link->link_params.num_lanes = ctrl->panel->link_info.num_lanes; - ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; } - drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%d\n", + drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n", ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes, - ctrl->dp_ctrl.pixel_rate); - + pixel_rate); rc = dp_ctrl_enable_mainlink_clocks(ctrl); if (rc) @@ -1816,31 +1804,12 @@ static int dp_ctrl_link_retrain(struct dp_ctrl_private *ctrl) return dp_ctrl_setup_main_link(ctrl, &training_step); } -static int dp_ctrl_on_stream_phy_test_report(struct dp_ctrl *dp_ctrl) -{ - int ret; - struct dp_ctrl_private *ctrl; - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; - - ret = dp_ctrl_enable_stream_clocks(ctrl); - if (ret) { - DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); - return ret; - } - - dp_ctrl_send_phy_test_pattern(ctrl); - - return 0; -} - int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) { int ret = 0; bool mainlink_ready = false; struct dp_ctrl_private *ctrl; + unsigned long pixel_rate; unsigned long pixel_rate_orig; if (!dp_ctrl) @@ -1848,15 +1817,14 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; + pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock; - pixel_rate_orig = ctrl->dp_ctrl.pixel_rate; if (dp_ctrl->wide_bus_en) - ctrl->dp_ctrl.pixel_rate >>= 1; + pixel_rate >>= 1; - drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%d\n", + drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n", ctrl->link->link_params.rate, - ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate); + ctrl->link->link_params.num_lanes, pixel_rate); if (!dp_power_clk_status(ctrl->power, DP_CTRL_PM)) { /* link clk is off */ ret = dp_ctrl_enable_mainlink_clocks(ctrl); @@ -1866,9 +1834,11 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) } } - ret = dp_ctrl_enable_stream_clocks(ctrl); + dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 1000); + + ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true); if (ret) { - DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); + DRM_ERROR("Unable to start pixel clocks. ret=%d\n", ret); goto end; } diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index b563e2e3bfe5..9f29734af81c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -16,7 +16,6 @@ struct dp_ctrl { bool orientation; atomic_t aborted; - u32 pixel_rate; bool wide_bus_en; }; diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 36f0af02749f..36bb6191d2f0 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -786,7 +786,7 @@ static int dp_link_process_link_training_request(struct dp_link_private *link) link->request.test_lane_count); link->dp_link.link_params.num_lanes = link->request.test_lane_count; - link->dp_link.link_params.rate = + link->dp_link.link_params.rate = drm_dp_bw_code_to_link_rate(link->request.test_link_rate); return 0; @@ -965,8 +965,7 @@ static int dp_link_process_link_status_update(struct dp_link_private *link) if (channel_eq_done && clock_recovery_done) return -EINVAL; - - return 0; + return 0; } /** diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 1625328fa430..39bbabb5daf6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -6,14 +6,6 @@ #include "dsi.h" #include "dsi_cfg.h" -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi) -{ - if (!msm_dsi || !msm_dsi_device_connected(msm_dsi)) - return NULL; - - return msm_dsi->encoder; -} - bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi) { unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host); @@ -21,7 +13,7 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi) return !(host_flags & MIPI_DSI_MODE_VIDEO); } -struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) +struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) { return msm_dsi_host_get_dsc_config(msm_dsi->host); } @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv; - struct drm_bridge *ext_bridge; int ret; if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, goto fail; } - /* - * check if the dsi encoder output is connected to a panel or an - * external bridge. We create a connector only if we're connected to a - * drm_panel device. When we're connected to an external bridge, we - * assume that the drm_bridge driver will create the connector itself. - */ - ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host); - - if (ext_bridge) - msm_dsi->connector = - msm_dsi_manager_ext_bridge_init(msm_dsi->id); - else - msm_dsi->connector = - msm_dsi_manager_connector_init(msm_dsi->id); - - if (IS_ERR(msm_dsi->connector)) { - ret = PTR_ERR(msm_dsi->connector); + ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id); + if (ret) { DRM_DEV_ERROR(dev->dev, "failed to create dsi connector: %d\n", ret); - msm_dsi->connector = NULL; goto fail; } @@ -287,12 +262,6 @@ fail: msm_dsi->bridge = NULL; } - /* don't destroy connector if we didn't make it */ - if (msm_dsi->connector && !msm_dsi->external_bridge) - msm_dsi->connector->funcs->destroy(msm_dsi->connector); - - msm_dsi->connector = NULL; - return ret; } diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 580a1e6358bf..2a96b4fe7839 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -12,7 +12,6 @@ #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> -#include <drm/drm_panel.h> #include "msm_drv.h" #include "disp/msm_disp_snapshot.h" @@ -30,27 +29,12 @@ enum msm_dsi_phy_usecase { MSM_DSI_PHY_SLAVE, }; -#define DSI_DEV_REGULATOR_MAX 8 #define DSI_BUS_CLK_MAX 4 -/* Regulators for DSI devices */ -struct dsi_reg_entry { - char name[32]; - int enable_load; - int disable_load; -}; - -struct dsi_reg_config { - int num; - struct dsi_reg_entry regs[DSI_DEV_REGULATOR_MAX]; -}; - struct msm_dsi { struct drm_device *dev; struct platform_device *pdev; - /* connector managed by us when we're connected to a drm_panel */ - struct drm_connector *connector; /* internal dsi bridge attached to MDP interface */ struct drm_bridge *bridge; @@ -58,10 +42,8 @@ struct msm_dsi { struct msm_dsi_phy *phy; /* - * panel/external_bridge connected to dsi bridge output, only one of the - * two can be valid at a time + * external_bridge connected to dsi bridge output */ - struct drm_panel *panel; struct drm_bridge *external_bridge; struct device *phy_dev; @@ -76,8 +58,7 @@ struct msm_dsi { /* dsi manager */ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id); void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge); -struct drm_connector *msm_dsi_manager_connector_init(u8 id); -struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id); +int msm_dsi_manager_ext_bridge_init(u8 id); int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len); int msm_dsi_manager_register(struct msm_dsi *msm_dsi); @@ -87,11 +68,9 @@ void msm_dsi_manager_tpg_enable(void); /* msm dsi */ static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi) { - return msm_dsi->panel || msm_dsi->external_bridge; + return msm_dsi->external_bridge; } -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi); - /* dsi host */ struct msm_dsi_host; int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, @@ -116,9 +95,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, const struct drm_display_mode *mode); enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host, const struct drm_display_mode *mode); -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host); unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host); -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); int msm_dsi_host_register(struct mipi_dsi_host *host); void msm_dsi_host_unregister(struct mipi_dsi_host *host); void msm_dsi_host_set_phy_mode(struct mipi_dsi_host *host, @@ -154,7 +131,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi); int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi); void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host); void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host); -struct msm_display_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host); +struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host); /* dsi phy */ struct msm_dsi_phy; diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 2c23324a2296..7e97c239ed48 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -9,16 +9,16 @@ static const char * const dsi_v2_bus_clk_names[] = { "core_mmss", "iface", "bus", }; +static const struct regulator_bulk_data apq8064_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 100000 }, /* 1.2 V */ + { .supply = "avdd", .init_load_uA = 10000 }, /* 3.0 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + static const struct msm_dsi_config apq8064_dsi_cfg = { .io_offset = 0, - .reg_cfg = { - .num = 3, - .regs = { - {"vdda", 100000, 100}, /* 1.2 V */ - {"avdd", 10000, 100}, /* 3.0 V */ - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = apq8064_dsi_regulators, + .num_regulators = ARRAY_SIZE(apq8064_dsi_regulators), .bus_clk_names = dsi_v2_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_v2_bus_clk_names), .io_start = { 0x4700000, 0x5800000 }, @@ -29,16 +29,16 @@ static const char * const dsi_6g_bus_clk_names[] = { "mdp_core", "iface", "bus", "core_mmss", }; +static const struct regulator_bulk_data msm8974_apq8084_regulators[] = { + { .supply = "vdd", .init_load_uA = 150000 }, /* 3.0 V */ + { .supply = "vdda", .init_load_uA = 100000 }, /* 1.2 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 3, - .regs = { - {"vdd", 150000, 100}, /* 3.0 V */ - {"vdda", 100000, 100}, /* 1.2 V */ - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = msm8974_apq8084_regulators, + .num_regulators = ARRAY_SIZE(msm8974_apq8084_regulators), .bus_clk_names = dsi_6g_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names), .io_start = { 0xfd922800, 0xfd922b00 }, @@ -49,15 +49,15 @@ static const char * const dsi_8916_bus_clk_names[] = { "mdp_core", "iface", "bus", }; +static const struct regulator_bulk_data msm8916_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 100000 }, /* 1.2 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + static const struct msm_dsi_config msm8916_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 2, - .regs = { - {"vdda", 100000, 100}, /* 1.2 V */ - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = msm8916_dsi_regulators, + .num_regulators = ARRAY_SIZE(msm8916_dsi_regulators), .bus_clk_names = dsi_8916_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_8916_bus_clk_names), .io_start = { 0x1a98000 }, @@ -68,34 +68,34 @@ static const char * const dsi_8976_bus_clk_names[] = { "mdp_core", "iface", "bus", }; +static const struct regulator_bulk_data msm8976_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 100000 }, /* 1.2 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + static const struct msm_dsi_config msm8976_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 2, - .regs = { - {"vdda", 100000, 100}, /* 1.2 V */ - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = msm8976_dsi_regulators, + .num_regulators = ARRAY_SIZE(msm8976_dsi_regulators), .bus_clk_names = dsi_8976_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_8976_bus_clk_names), .io_start = { 0x1a94000, 0x1a96000 }, .num_dsi = 2, }; +static const struct regulator_bulk_data msm8994_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 100000 }, /* 1.25 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ + { .supply = "vcca", .init_load_uA = 10000 }, /* 1.0 V */ + { .supply = "vdd", .init_load_uA = 100000 }, /* 1.8 V */ + { .supply = "lab_reg", .init_load_uA = -1 }, + { .supply = "ibb_reg", .init_load_uA = -1 }, +}; + static const struct msm_dsi_config msm8994_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 6, - .regs = { - {"vdda", 100000, 100}, /* 1.25 V */ - {"vddio", 100000, 100}, /* 1.8 V */ - {"vcca", 10000, 100}, /* 1.0 V */ - {"vdd", 100000, 100}, /* 1.8 V */ - {"lab_reg", -1, -1}, - {"ibb_reg", -1, -1}, - }, - }, + .regulator_data = msm8994_dsi_regulators, + .num_regulators = ARRAY_SIZE(msm8994_dsi_regulators), .bus_clk_names = dsi_6g_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names), .io_start = { 0xfd998000, 0xfd9a0000 }, @@ -106,16 +106,16 @@ static const char * const dsi_8996_bus_clk_names[] = { "mdp_core", "iface", "bus", "core_mmss", }; +static const struct regulator_bulk_data msm8996_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 18160 }, /* 1.25 V */ + { .supply = "vcca", .init_load_uA = 17000 }, /* 0.925 V */ + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + static const struct msm_dsi_config msm8996_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 2, - .regs = { - {"vdda", 18160, 1 }, /* 1.25 V */ - {"vcca", 17000, 32 }, /* 0.925 V */ - {"vddio", 100000, 100 },/* 1.8 V */ - }, - }, + .regulator_data = msm8996_dsi_regulators, + .num_regulators = ARRAY_SIZE(msm8996_dsi_regulators), .bus_clk_names = dsi_8996_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_8996_bus_clk_names), .io_start = { 0x994000, 0x996000 }, @@ -126,15 +126,15 @@ static const char * const dsi_msm8998_bus_clk_names[] = { "iface", "bus", "core", }; +static const struct regulator_bulk_data msm8998_dsi_regulators[] = { + { .supply = "vdd", .init_load_uA = 367000 }, /* 0.9 V */ + { .supply = "vdda", .init_load_uA = 62800 }, /* 1.2 V */ +}; + static const struct msm_dsi_config msm8998_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 2, - .regs = { - {"vdd", 367000, 16 }, /* 0.9 V */ - {"vdda", 62800, 2 }, /* 1.2 V */ - }, - }, + .regulator_data = msm8998_dsi_regulators, + .num_regulators = ARRAY_SIZE(msm8998_dsi_regulators), .bus_clk_names = dsi_msm8998_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_msm8998_bus_clk_names), .io_start = { 0xc994000, 0xc996000 }, @@ -145,14 +145,14 @@ static const char * const dsi_sdm660_bus_clk_names[] = { "iface", "bus", "core", "core_mmss", }; +static const struct regulator_bulk_data sdm660_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 12560 }, /* 1.2 V */ +}; + static const struct msm_dsi_config sdm660_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 2, - .regs = { - {"vdda", 12560, 4 }, /* 1.2 V */ - }, - }, + .regulator_data = sdm660_dsi_regulators, + .num_regulators = ARRAY_SIZE(sdm660_dsi_regulators), .bus_clk_names = dsi_sdm660_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_sdm660_bus_clk_names), .io_start = { 0xc994000, 0xc996000 }, @@ -167,28 +167,28 @@ static const char * const dsi_sc7180_bus_clk_names[] = { "iface", "bus", }; +static const struct regulator_bulk_data sdm845_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 21800 }, /* 1.2 V */ +}; + static const struct msm_dsi_config sdm845_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 1, - .regs = { - {"vdda", 21800, 4 }, /* 1.2 V */ - }, - }, + .regulator_data = sdm845_dsi_regulators, + .num_regulators = ARRAY_SIZE(sdm845_dsi_regulators), .bus_clk_names = dsi_sdm845_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names), .io_start = { 0xae94000, 0xae96000 }, .num_dsi = 2, }; +static const struct regulator_bulk_data sc7180_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 21800 }, /* 1.2 V */ +}; + static const struct msm_dsi_config sc7180_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 1, - .regs = { - {"vdda", 21800, 4 }, /* 1.2 V */ - }, - }, + .regulator_data = sc7180_dsi_regulators, + .num_regulators = ARRAY_SIZE(sc7180_dsi_regulators), .bus_clk_names = dsi_sc7180_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_sc7180_bus_clk_names), .io_start = { 0xae94000 }, @@ -199,14 +199,14 @@ static const char * const dsi_sc7280_bus_clk_names[] = { "iface", "bus", }; +static const struct regulator_bulk_data sc7280_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 8350 }, /* 1.2 V */ +}; + static const struct msm_dsi_config sc7280_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 1, - .regs = { - {"vdda", 8350, 0 }, /* 1.2 V */ - }, - }, + .regulator_data = sc7280_dsi_regulators, + .num_regulators = ARRAY_SIZE(sc7280_dsi_regulators), .bus_clk_names = dsi_sc7280_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_sc7280_bus_clk_names), .io_start = { 0xae94000 }, @@ -217,14 +217,14 @@ static const char * const dsi_qcm2290_bus_clk_names[] = { "iface", "bus", }; +static const struct regulator_bulk_data qcm2290_dsi_cfg_regulators[] = { + { .supply = "vdda", .init_load_uA = 21800 }, /* 1.2 V */ +}; + static const struct msm_dsi_config qcm2290_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, - .reg_cfg = { - .num = 1, - .regs = { - {"vdda", 21800, 4 }, /* 1.2 V */ - }, - }, + .regulator_data = qcm2290_dsi_cfg_regulators, + .num_regulators = ARRAY_SIZE(qcm2290_dsi_cfg_regulators), .bus_clk_names = dsi_qcm2290_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_qcm2290_bus_clk_names), .io_start = { 0x5e94000 }, diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index fe54a999968b..8f04e685a74e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -32,7 +32,8 @@ struct msm_dsi_config { u32 io_offset; - struct dsi_reg_config reg_cfg; + const struct regulator_bulk_data *regulator_data; + int num_regulators; const char * const *bus_clk_names; const int num_bus_clks; const resource_size_t io_start[DSI_MAX]; diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index a34078497af1..7fbf391c024f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -33,7 +33,7 @@ #define DSI_RESET_TOGGLE_DELAY_MS 20 -static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc); +static int dsi_populate_dsc_params(struct drm_dsc_config *dsc); static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { @@ -108,7 +108,7 @@ struct msm_dsi_host { void __iomem *ctrl_base; phys_addr_t ctrl_size; - struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; + struct regulator_bulk_data *supplies; int num_bus_clks; struct clk_bulk_data bus_clks[DSI_BUS_CLK_MAX]; @@ -144,7 +144,6 @@ struct msm_dsi_host { u32 err_work_state; struct work_struct err_work; - struct work_struct hpd_work; struct workqueue_struct *workqueue; /* DSI 6G TX buffer*/ @@ -161,10 +160,9 @@ struct msm_dsi_host { struct regmap *sfpb; struct drm_display_mode *mode; - struct msm_display_dsc_config *dsc; + struct drm_dsc_config *dsc; /* connected device info */ - struct device_node *device_node; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format; @@ -205,9 +203,6 @@ static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data) msm_writel(data, msm_host->ctrl_base + reg); } -static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host); -static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host); - static const struct msm_dsi_cfg_handler *dsi_get_config( struct msm_dsi_host *msm_host) { @@ -258,76 +253,6 @@ static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host) return container_of(host, struct msm_dsi_host, base); } -static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host) -{ - struct regulator_bulk_data *s = msm_host->supplies; - const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; - int num = msm_host->cfg_hnd->cfg->reg_cfg.num; - int i; - - DBG(""); - for (i = num - 1; i >= 0; i--) - if (regs[i].disable_load >= 0) - regulator_set_load(s[i].consumer, - regs[i].disable_load); - - regulator_bulk_disable(num, s); -} - -static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host) -{ - struct regulator_bulk_data *s = msm_host->supplies; - const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; - int num = msm_host->cfg_hnd->cfg->reg_cfg.num; - int ret, i; - - DBG(""); - for (i = 0; i < num; i++) { - if (regs[i].enable_load >= 0) { - ret = regulator_set_load(s[i].consumer, - regs[i].enable_load); - if (ret < 0) { - pr_err("regulator %d set op mode failed, %d\n", - i, ret); - goto fail; - } - } - } - - ret = regulator_bulk_enable(num, s); - if (ret < 0) { - pr_err("regulator enable failed, %d\n", ret); - goto fail; - } - - return 0; - -fail: - for (i--; i >= 0; i--) - regulator_set_load(s[i].consumer, regs[i].disable_load); - return ret; -} - -static int dsi_regulator_init(struct msm_dsi_host *msm_host) -{ - struct regulator_bulk_data *s = msm_host->supplies; - const struct dsi_reg_entry *regs = msm_host->cfg_hnd->cfg->reg_cfg.regs; - int num = msm_host->cfg_hnd->cfg->reg_cfg.num; - int i, ret; - - for (i = 0; i < num; i++) - s[i].supply = regs[i].name; - - ret = devm_regulator_bulk_get(&msm_host->pdev->dev, num, s); - if (ret < 0) { - pr_err("%s: failed to init regulator, ret=%d\n", - __func__, ret); - return ret; - } - - return 0; -} - int dsi_clk_init_v2(struct msm_dsi_host *msm_host) { struct platform_device *pdev = msm_host->pdev; @@ -916,7 +841,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay) { - struct msm_display_dsc_config *dsc = msm_host->dsc; + struct drm_dsc_config *dsc = msm_host->dsc; u32 reg, intf_width, reg_ctrl, reg_ctrl2; u32 slice_per_intf, total_bytes_per_intf; u32 pkt_per_line; @@ -927,24 +852,24 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod * compress mode registers */ intf_width = hdisplay; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width); + slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); /* If slice_per_pkt is greater than slice_per_intf * then default to 1. This can happen during partial * update. */ - if (slice_per_intf > dsc->drm->slice_count) - dsc->drm->slice_count = 1; + if (slice_per_intf > dsc->slice_count) + dsc->slice_count = 1; - slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->drm->slice_width); - bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * dsc->drm->bits_per_pixel, 8); + slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width); + bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8); - dsc->drm->slice_chunk_size = bytes_in_slice; + dsc->slice_chunk_size = bytes_in_slice; total_bytes_per_intf = bytes_in_slice * slice_per_intf; eol_byte_num = total_bytes_per_intf % 3; - pkt_per_line = slice_per_intf / dsc->drm->slice_count; + pkt_per_line = slice_per_intf / dsc->slice_count; if (is_cmd_mode) /* packet data type */ reg = DSI_COMMAND_COMPRESSION_MODE_CTRL_STREAM0_DATATYPE(MIPI_DSI_DCS_LONG_WRITE); @@ -1009,7 +934,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) } if (msm_host->dsc) { - struct msm_display_dsc_config *dsc = msm_host->dsc; + struct drm_dsc_config *dsc = msm_host->dsc; /* update dsc params with timing params */ if (!dsc || !mode->hdisplay || !mode->vdisplay) { @@ -1018,9 +943,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) return; } - dsc->drm->pic_width = mode->hdisplay; - dsc->drm->pic_height = mode->vdisplay; - DBG("Mode %dx%d\n", dsc->drm->pic_width, dsc->drm->pic_height); + dsc->pic_width = mode->hdisplay; + dsc->pic_height = mode->vdisplay; + DBG("Mode %dx%d\n", dsc->pic_width, dsc->pic_height); /* we do the calculations for dsc parameters here so that * panel can use these parameters @@ -1500,14 +1425,6 @@ static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host, return len; } -static void dsi_hpd_worker(struct work_struct *work) -{ - struct msm_dsi_host *msm_host = - container_of(work, struct msm_dsi_host, hpd_work); - - drm_helper_hpd_irq_event(msm_host->dev); -} - static void dsi_err_worker(struct work_struct *work) { struct msm_dsi_host *msm_host = @@ -1686,6 +1603,8 @@ static int dsi_host_attach(struct mipi_dsi_host *host, msm_host->lanes = dsi->lanes; msm_host->format = dsi->format; msm_host->mode_flags = dsi->mode_flags; + if (dsi->dsc) + msm_host->dsc = dsi->dsc; /* Some gpios defined in panel DT need to be controlled by host */ ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev); @@ -1697,8 +1616,6 @@ static int dsi_host_attach(struct mipi_dsi_host *host, return ret; DBG("id=%d", msm_host->id); - if (msm_host->dev) - queue_work(msm_host->workqueue, &msm_host->hpd_work); return 0; } @@ -1710,11 +1627,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host, dsi_dev_detach(msm_host->pdev); - msm_host->device_node = NULL; - DBG("id=%d", msm_host->id); - if (msm_host->dev) - queue_work(msm_host->workqueue, &msm_host->hpd_work); return 0; } @@ -1841,7 +1754,7 @@ static char bpg_offset[DSC_NUM_BUF_RANGES] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 }; -static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc) +static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) { int mux_words_size; int groups_per_line, groups_total; @@ -1854,98 +1767,98 @@ static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc) int final_value, final_scale; int i; - dsc->drm->rc_model_size = 8192; - dsc->drm->first_line_bpg_offset = 12; - dsc->drm->rc_edge_factor = 6; - dsc->drm->rc_tgt_offset_high = 3; - dsc->drm->rc_tgt_offset_low = 3; - dsc->drm->simple_422 = 0; - dsc->drm->convert_rgb = 1; - dsc->drm->vbr_enable = 0; + dsc->rc_model_size = 8192; + dsc->first_line_bpg_offset = 12; + dsc->rc_edge_factor = 6; + dsc->rc_tgt_offset_high = 3; + dsc->rc_tgt_offset_low = 3; + dsc->simple_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; /* handle only bpp = bpc = 8 */ for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) - dsc->drm->rc_buf_thresh[i] = dsi_dsc_rc_buf_thresh[i]; + dsc->rc_buf_thresh[i] = dsi_dsc_rc_buf_thresh[i]; for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { - dsc->drm->rc_range_params[i].range_min_qp = min_qp[i]; - dsc->drm->rc_range_params[i].range_max_qp = max_qp[i]; - dsc->drm->rc_range_params[i].range_bpg_offset = bpg_offset[i]; + dsc->rc_range_params[i].range_min_qp = min_qp[i]; + dsc->rc_range_params[i].range_max_qp = max_qp[i]; + dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i]; } - dsc->drm->initial_offset = 6144; /* Not bpp 12 */ - if (dsc->drm->bits_per_pixel != 8) - dsc->drm->initial_offset = 2048; /* bpp = 12 */ + dsc->initial_offset = 6144; /* Not bpp 12 */ + if (dsc->bits_per_pixel != 8) + dsc->initial_offset = 2048; /* bpp = 12 */ mux_words_size = 48; /* bpc == 8/10 */ - if (dsc->drm->bits_per_component == 12) + if (dsc->bits_per_component == 12) mux_words_size = 64; - dsc->drm->initial_xmit_delay = 512; - dsc->drm->initial_scale_value = 32; - dsc->drm->first_line_bpg_offset = 12; - dsc->drm->line_buf_depth = dsc->drm->bits_per_component + 1; + dsc->initial_xmit_delay = 512; + dsc->initial_scale_value = 32; + dsc->first_line_bpg_offset = 12; + dsc->line_buf_depth = dsc->bits_per_component + 1; /* bpc 8 */ - dsc->drm->flatness_min_qp = 3; - dsc->drm->flatness_max_qp = 12; - dsc->drm->rc_quant_incr_limit0 = 11; - dsc->drm->rc_quant_incr_limit1 = 11; - dsc->drm->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + dsc->flatness_min_qp = 3; + dsc->flatness_max_qp = 12; + dsc->rc_quant_incr_limit0 = 11; + dsc->rc_quant_incr_limit1 = 11; + dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of * params are calculated */ - groups_per_line = DIV_ROUND_UP(dsc->drm->slice_width, 3); - dsc->drm->slice_chunk_size = dsc->drm->slice_width * dsc->drm->bits_per_pixel / 8; - if ((dsc->drm->slice_width * dsc->drm->bits_per_pixel) % 8) - dsc->drm->slice_chunk_size++; + groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); + dsc->slice_chunk_size = dsc->slice_width * dsc->bits_per_pixel / 8; + if ((dsc->slice_width * dsc->bits_per_pixel) % 8) + dsc->slice_chunk_size++; /* rbs-min */ - min_rate_buffer_size = dsc->drm->rc_model_size - dsc->drm->initial_offset + - dsc->drm->initial_xmit_delay * dsc->drm->bits_per_pixel + - groups_per_line * dsc->drm->first_line_bpg_offset; + min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * dsc->bits_per_pixel + + groups_per_line * dsc->first_line_bpg_offset; - hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->drm->bits_per_pixel); + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->bits_per_pixel); - dsc->drm->initial_dec_delay = hrd_delay - dsc->drm->initial_xmit_delay; + dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; - dsc->drm->initial_scale_value = 8 * dsc->drm->rc_model_size / - (dsc->drm->rc_model_size - dsc->drm->initial_offset); + dsc->initial_scale_value = 8 * dsc->rc_model_size / + (dsc->rc_model_size - dsc->initial_offset); - slice_bits = 8 * dsc->drm->slice_chunk_size * dsc->drm->slice_height; + slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height; - groups_total = groups_per_line * dsc->drm->slice_height; + groups_total = groups_per_line * dsc->slice_height; - data = dsc->drm->first_line_bpg_offset * 2048; + data = dsc->first_line_bpg_offset * 2048; - dsc->drm->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->drm->slice_height - 1)); + dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); - pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->drm->bits_per_component + 4) - 2); + pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->bits_per_component + 4) - 2); num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); - data = 2048 * (dsc->drm->rc_model_size - dsc->drm->initial_offset + num_extra_mux_bits); - dsc->drm->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); + data = 2048 * (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits); + dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); /* bpp * 16 + 0.5 */ - data = dsc->drm->bits_per_pixel * 16; + data = dsc->bits_per_pixel * 16; data *= 2; data++; data /= 2; target_bpp_x16 = data; - data = (dsc->drm->initial_xmit_delay * target_bpp_x16) / 16; - final_value = dsc->drm->rc_model_size - data + num_extra_mux_bits; - dsc->drm->final_offset = final_value; + data = (dsc->initial_xmit_delay * target_bpp_x16) / 16; + final_value = dsc->rc_model_size - data + num_extra_mux_bits; + dsc->final_offset = final_value; - final_scale = 8 * dsc->drm->rc_model_size / (dsc->drm->rc_model_size - final_value); + final_scale = 8 * dsc->rc_model_size / (dsc->rc_model_size - final_value); - data = (final_scale - 9) * (dsc->drm->nfl_bpg_offset + dsc->drm->slice_bpg_offset); - dsc->drm->scale_increment_interval = (2048 * dsc->drm->final_offset) / data; + data = (final_scale - 9) * (dsc->nfl_bpg_offset + dsc->slice_bpg_offset); + dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; - dsc->drm->scale_decrement_interval = groups_per_line / (dsc->drm->initial_scale_value - 8); + dsc->scale_decrement_interval = groups_per_line / (dsc->initial_scale_value - 8); return 0; } @@ -1954,7 +1867,7 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) { struct device *dev = &msm_host->pdev->dev; struct device_node *np = dev->of_node; - struct device_node *endpoint, *device_node; + struct device_node *endpoint; int ret = 0; /* @@ -1977,16 +1890,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) goto err; } - /* Get panel node from the output port's endpoint data */ - device_node = of_graph_get_remote_node(np, 1, 0); - if (!device_node) { - DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__); - ret = -ENODEV; - goto err; - } - - msm_host->device_node = device_node; - if (of_property_read_bool(np, "syscon-sfpb")) { msm_host->sfpb = syscon_regmap_lookup_by_phandle(np, "syscon-sfpb"); @@ -1997,8 +1900,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) } } - of_node_put(device_node); - err: of_node_put(endpoint); @@ -2028,6 +1929,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) { struct msm_dsi_host *msm_host = NULL; struct platform_device *pdev = msm_dsi->pdev; + const struct msm_dsi_config *cfg; int ret; msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); @@ -2060,6 +1962,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) pr_err("%s: get config failed\n", __func__); goto fail; } + cfg = msm_host->cfg_hnd->cfg; msm_host->id = dsi_host_get_id(msm_host); if (msm_host->id < 0) { @@ -2069,13 +1972,13 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) } /* fixup base address by io offset */ - msm_host->ctrl_base += msm_host->cfg_hnd->cfg->io_offset; + msm_host->ctrl_base += cfg->io_offset; - ret = dsi_regulator_init(msm_host); - if (ret) { - pr_err("%s: regulator init failed\n", __func__); + ret = devm_regulator_bulk_get_const(&pdev->dev, cfg->num_regulators, + cfg->regulator_data, + &msm_host->supplies); + if (ret) goto fail; - } ret = dsi_clk_init(msm_host); if (ret) { @@ -2126,7 +2029,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) /* setup workqueue */ msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); INIT_WORK(&msm_host->err_work, dsi_err_worker); - INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker); msm_dsi->id = msm_host->id; @@ -2159,23 +2061,9 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - struct drm_panel *panel; int ret; msm_host->dev = dev; - panel = msm_dsi_host_get_panel(&msm_host->base); - - if (!IS_ERR(panel) && panel->dsc) { - struct msm_display_dsc_config *dsc = msm_host->dsc; - - if (!dsc) { - dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL); - if (!dsc) - return -ENOMEM; - dsc->drm = panel->dsc; - msm_host->dsc = dsc; - } - } ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); if (ret) { @@ -2556,7 +2444,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, msm_dsi_sfpb_config(msm_host, true); - ret = dsi_host_regulator_enable(msm_host); + ret = regulator_bulk_enable(msm_host->cfg_hnd->cfg->num_regulators, + msm_host->supplies); if (ret) { pr_err("%s:Failed to enable vregs.ret=%d\n", __func__, ret); @@ -2596,7 +2485,8 @@ fail_disable_clk: cfg_hnd->ops->link_clk_disable(msm_host); pm_runtime_put(&msm_host->pdev->dev); fail_disable_reg: - dsi_host_regulator_disable(msm_host); + regulator_bulk_disable(msm_host->cfg_hnd->cfg->num_regulators, + msm_host->supplies); unlock_ret: mutex_unlock(&msm_host->dev_mutex); return ret; @@ -2623,7 +2513,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host) cfg_hnd->ops->link_clk_disable(msm_host); pm_runtime_put(&msm_host->pdev->dev); - dsi_host_regulator_disable(msm_host); + regulator_bulk_disable(msm_host->cfg_hnd->cfg->num_regulators, + msm_host->supplies); msm_dsi_sfpb_config(msm_host, false); @@ -2659,45 +2550,33 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host, const struct drm_display_mode *mode) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - struct msm_display_dsc_config *dsc = msm_host->dsc; + struct drm_dsc_config *dsc = msm_host->dsc; int pic_width = mode->hdisplay; int pic_height = mode->vdisplay; if (!msm_host->dsc) return MODE_OK; - if (pic_width % dsc->drm->slice_width) { + if (pic_width % dsc->slice_width) { pr_err("DSI: pic_width %d has to be multiple of slice %d\n", - pic_width, dsc->drm->slice_width); + pic_width, dsc->slice_width); return MODE_H_ILLEGAL; } - if (pic_height % dsc->drm->slice_height) { + if (pic_height % dsc->slice_height) { pr_err("DSI: pic_height %d has to be multiple of slice %d\n", - pic_height, dsc->drm->slice_height); + pic_height, dsc->slice_height); return MODE_V_ILLEGAL; } return MODE_OK; } -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host) -{ - return of_drm_find_panel(to_msm_dsi_host(host)->device_node); -} - unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host) { return to_msm_dsi_host(host)->mode_flags; } -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host) -{ - struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - - return of_drm_find_bridge(msm_host->device_node); -} - void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); @@ -2771,7 +2650,7 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host) DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER); } -struct msm_display_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host) +struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host) { 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 cb84d185d73a..3a1417397283 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -141,14 +141,11 @@ static int enable_phy(struct msm_dsi *msm_dsi, struct msm_dsi_phy_shared_timings *shared_timings) { struct msm_dsi_phy_clk_request clk_req; - int ret; bool is_bonded_dsi = IS_BONDED_DSI(); msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req, is_bonded_dsi); - ret = msm_dsi_phy_enable(msm_dsi->phy, &clk_req, shared_timings); - - return ret; + return msm_dsi_phy_enable(msm_dsi->phy, &clk_req, shared_timings); } static int @@ -214,39 +211,26 @@ static void dsi_mgr_phy_disable(int id) } } -struct dsi_connector { - struct drm_connector base; - int id; -}; - struct dsi_bridge { struct drm_bridge base; int id; }; -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base) #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base) -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector) -{ - struct dsi_connector *dsi_connector = to_dsi_connector(connector); - return dsi_connector->id; -} - static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge) { struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge); return dsi_bridge->id; } -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id) +static void msm_dsi_manager_set_split_display(u8 id) { - struct msm_drm_private *priv = conn->dev->dev_private; - struct msm_kms *kms = priv->kms; struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); + struct msm_drm_private *priv = msm_dsi->dev->dev_private; + struct msm_kms *kms = priv->kms; struct msm_dsi *master_dsi, *slave_dsi; - struct drm_panel *panel; if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) { master_dsi = other_dsi; @@ -256,89 +240,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id) slave_dsi = other_dsi; } - /* - * There is only 1 panel in the global panel list for bonded DSI mode. - * Therefore slave dsi should get the drm_panel instance from master - * dsi. - */ - panel = msm_dsi_host_get_panel(master_dsi->host); - if (IS_ERR(panel)) { - DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id, - PTR_ERR(panel)); - return PTR_ERR(panel); - } - - if (!panel || !IS_BONDED_DSI()) - goto out; - - drm_object_attach_property(&conn->base, - conn->dev->mode_config.tile_property, 0); + if (!msm_dsi->external_bridge || !IS_BONDED_DSI()) + return; /* * Set split display info to kms once bonded DSI panel is connected to * both hosts. */ - if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) { + if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) { kms->funcs->set_split_display(kms, master_dsi->encoder, slave_dsi->encoder, msm_dsi_is_cmd_mode(msm_dsi)); } - -out: - msm_dsi->panel = panel; - return 0; -} - -static enum drm_connector_status dsi_mgr_connector_detect( - struct drm_connector *connector, bool force) -{ - int id = dsi_mgr_connector_get_id(connector); - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - - return msm_dsi->panel ? connector_status_connected : - connector_status_disconnected; -} - -static void dsi_mgr_connector_destroy(struct drm_connector *connector) -{ - struct dsi_connector *dsi_connector = to_dsi_connector(connector); - - DBG(""); - - drm_connector_cleanup(connector); - - kfree(dsi_connector); -} - -static int dsi_mgr_connector_get_modes(struct drm_connector *connector) -{ - int id = dsi_mgr_connector_get_id(connector); - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct drm_panel *panel = msm_dsi->panel; - int num; - - if (!panel) - return 0; - - /* - * In bonded DSI mode, we have one connector that can be - * attached to the drm_panel. - */ - num = drm_panel_get_modes(panel, connector); - if (!num) - return 0; - - return num; -} - -static struct drm_encoder * -dsi_mgr_connector_best_encoder(struct drm_connector *connector) -{ - int id = dsi_mgr_connector_get_id(connector); - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - - DBG(""); - return msm_dsi_get_encoder(msm_dsi); } static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge) @@ -403,7 +316,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1); struct mipi_dsi_host *host = msm_dsi->host; - struct drm_panel *panel = msm_dsi->panel; bool is_bonded_dsi = IS_BONDED_DSI(); int ret; @@ -418,18 +330,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) if (!dsi_mgr_power_on_early(bridge)) dsi_mgr_bridge_power_on(bridge); - /* Always call panel functions once, because even for dual panels, - * there is only one drm_panel instance. - */ - if (panel) { - ret = drm_panel_prepare(panel); - if (ret) { - pr_err("%s: prepare panel %d failed, %d\n", __func__, - id, ret); - goto panel_prep_fail; - } - } - ret = msm_dsi_host_enable(host); if (ret) { pr_err("%s: enable host %d failed, %d\n", __func__, id, ret); @@ -449,9 +349,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) host1_en_fail: msm_dsi_host_disable(host); host_en_fail: - if (panel) - drm_panel_unprepare(panel); -panel_prep_fail: return; } @@ -469,62 +366,12 @@ void msm_dsi_manager_tpg_enable(void) } } -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge) -{ - int id = dsi_mgr_bridge_get_id(bridge); - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct drm_panel *panel = msm_dsi->panel; - bool is_bonded_dsi = IS_BONDED_DSI(); - int ret; - - DBG("id=%d", id); - if (!msm_dsi_device_connected(msm_dsi)) - return; - - /* Do nothing with the host if it is slave-DSI in case of bonded DSI */ - if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id)) - return; - - if (panel) { - ret = drm_panel_enable(panel); - if (ret) { - pr_err("%s: enable panel %d failed, %d\n", __func__, id, - ret); - } - } -} - -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge) -{ - int id = dsi_mgr_bridge_get_id(bridge); - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct drm_panel *panel = msm_dsi->panel; - bool is_bonded_dsi = IS_BONDED_DSI(); - int ret; - - DBG("id=%d", id); - if (!msm_dsi_device_connected(msm_dsi)) - return; - - /* Do nothing with the host if it is slave-DSI in case of bonded DSI */ - if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id)) - return; - - if (panel) { - ret = drm_panel_disable(panel); - if (ret) - pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, - ret); - } -} - static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) { int id = dsi_mgr_bridge_get_id(bridge); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1); struct mipi_dsi_host *host = msm_dsi->host; - struct drm_panel *panel = msm_dsi->panel; bool is_bonded_dsi = IS_BONDED_DSI(); int ret; @@ -551,13 +398,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) pr_err("%s: host1 disable failed, %d\n", __func__, ret); } - if (panel) { - ret = drm_panel_unprepare(panel); - if (ret) - pr_err("%s: Panel %d unprepare failed,%d\n", __func__, - id, ret); - } - msm_dsi_host_disable_irq(host); if (is_bonded_dsi && msm_dsi1) msm_dsi_host_disable_irq(msm_dsi1->host); @@ -614,76 +454,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge, return msm_dsi_host_check_dsc(host, mode); } -static const struct drm_connector_funcs dsi_mgr_connector_funcs = { - .detect = dsi_mgr_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = dsi_mgr_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = { - .get_modes = dsi_mgr_connector_get_modes, - .best_encoder = dsi_mgr_connector_best_encoder, -}; - static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = { .pre_enable = dsi_mgr_bridge_pre_enable, - .enable = dsi_mgr_bridge_enable, - .disable = dsi_mgr_bridge_disable, .post_disable = dsi_mgr_bridge_post_disable, .mode_set = dsi_mgr_bridge_mode_set, .mode_valid = dsi_mgr_bridge_mode_valid, }; -/* initialize connector when we're connected to a drm_panel */ -struct drm_connector *msm_dsi_manager_connector_init(u8 id) -{ - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct drm_connector *connector = NULL; - struct dsi_connector *dsi_connector; - int ret; - - dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL); - if (!dsi_connector) - return ERR_PTR(-ENOMEM); - - dsi_connector->id = id; - - connector = &dsi_connector->base; - - ret = drm_connector_init(msm_dsi->dev, connector, - &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI); - if (ret) - return ERR_PTR(ret); - - drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs); - - /* Enable HPD to let hpd event is handled - * when panel is attached to the host. - */ - connector->polled = DRM_CONNECTOR_POLL_HPD; - - /* Display driver doesn't support interlace now. */ - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - drm_connector_attach_encoder(connector, msm_dsi->encoder); - - ret = msm_dsi_manager_panel_init(connector, id); - if (ret) { - DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret); - goto fail; - } - - return connector; - -fail: - connector->funcs->destroy(connector); - return ERR_PTR(ret); -} - /* initialize bridge */ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) { @@ -722,18 +499,21 @@ fail: return ERR_PTR(ret); } -struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) +int msm_dsi_manager_ext_bridge_init(u8 id) { struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct drm_device *dev = msm_dsi->dev; - struct drm_connector *connector; struct drm_encoder *encoder; struct drm_bridge *int_bridge, *ext_bridge; int ret; int_bridge = msm_dsi->bridge; - ext_bridge = msm_dsi->external_bridge = - msm_dsi_host_get_bridge(msm_dsi->host); + ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, + msm_dsi->pdev->dev.of_node, 1, 0); + if (IS_ERR(ext_bridge)) + return PTR_ERR(ext_bridge); + + msm_dsi->external_bridge = ext_bridge; encoder = msm_dsi->encoder; @@ -745,36 +525,32 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret == -EINVAL) { - struct drm_connector *connector; - struct list_head *connector_list; - - /* link the internal dsi bridge to the external bridge */ - drm_bridge_attach(encoder, ext_bridge, int_bridge, 0); - /* - * we need the drm_connector created by the external bridge - * driver (or someone else) to feed it to our driver's - * priv->connector[] list, mainly for msm_fbdev_init() + * link the internal dsi bridge to the external bridge, + * connector is created by the next bridge. */ - connector_list = &dev->mode_config.connector_list; + ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0); + if (ret < 0) + return ret; + } else { + struct drm_connector *connector; - list_for_each_entry(connector, connector_list, head) { - if (drm_connector_has_possible_encoder(connector, encoder)) - return connector; + /* We are in charge of the connector, create one now. */ + connector = drm_bridge_connector_init(dev, encoder); + if (IS_ERR(connector)) { + DRM_ERROR("Unable to create bridge connector\n"); + return PTR_ERR(connector); } - return ERR_PTR(-ENODEV); - } - - connector = drm_bridge_connector_init(dev, encoder); - if (IS_ERR(connector)) { - DRM_ERROR("Unable to create bridge connector\n"); - return ERR_CAST(connector); + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) + return ret; } - drm_connector_attach_encoder(connector, encoder); + /* The pipeline is ready, ping encoders if necessary */ + msm_dsi_manager_set_split_display(id); - return connector; + return 0; } void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index a39de3bdc7fa..7fc0975cb869 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -347,7 +347,7 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, } else { timing->shared_timings.clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false); - timing->shared_timings.clk_pre_inc_by_2 = 0; + timing->shared_timings.clk_pre_inc_by_2 = 0; } timing->ta_go = 3; @@ -507,82 +507,6 @@ int msm_dsi_cphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing, return 0; } -static int dsi_phy_regulator_init(struct msm_dsi_phy *phy) -{ - struct regulator_bulk_data *s = phy->supplies; - const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; - struct device *dev = &phy->pdev->dev; - int num = phy->cfg->reg_cfg.num; - int i, ret; - - for (i = 0; i < num; i++) - s[i].supply = regs[i].name; - - ret = devm_regulator_bulk_get(dev, num, s); - if (ret < 0) { - if (ret != -EPROBE_DEFER) { - DRM_DEV_ERROR(dev, - "%s: failed to init regulator, ret=%d\n", - __func__, ret); - } - - return ret; - } - - return 0; -} - -static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy) -{ - struct regulator_bulk_data *s = phy->supplies; - const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; - int num = phy->cfg->reg_cfg.num; - int i; - - DBG(""); - for (i = num - 1; i >= 0; i--) - if (regs[i].disable_load >= 0) - regulator_set_load(s[i].consumer, regs[i].disable_load); - - regulator_bulk_disable(num, s); -} - -static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy) -{ - struct regulator_bulk_data *s = phy->supplies; - const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; - struct device *dev = &phy->pdev->dev; - int num = phy->cfg->reg_cfg.num; - int ret, i; - - DBG(""); - for (i = 0; i < num; i++) { - if (regs[i].enable_load >= 0) { - ret = regulator_set_load(s[i].consumer, - regs[i].enable_load); - if (ret < 0) { - DRM_DEV_ERROR(dev, - "regulator %d set op mode failed, %d\n", - i, ret); - goto fail; - } - } - } - - ret = regulator_bulk_enable(num, s); - if (ret < 0) { - DRM_DEV_ERROR(dev, "regulator enable failed, %d\n", ret); - goto fail; - } - - return 0; - -fail: - for (i--; i >= 0; i--) - regulator_set_load(s[i].consumer, regs[i].disable_load); - return ret; -} - static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) { struct device *dev = &phy->pdev->dev; @@ -697,12 +621,9 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) phy->pdev = pdev; phy->id = dsi_phy_get_id(phy); - if (phy->id < 0) { - ret = phy->id; - DRM_DEV_ERROR(dev, "%s: couldn't identify PHY index, %d\n", - __func__, ret); - goto fail; - } + if (phy->id < 0) + return dev_err_probe(dev, phy->id, + "Couldn't identify PHY index\n"); phy->regulator_ldo_mode = of_property_read_bool(dev->of_node, "qcom,dsi-phy-regulator-ldo-mode"); @@ -710,86 +631,71 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) phy->cphy_mode = (phy_type == PHY_TYPE_CPHY); phy->base = msm_ioremap_size(pdev, "dsi_phy", &phy->base_size); - if (IS_ERR(phy->base)) { - DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__); - ret = -ENOMEM; - goto fail; - } + if (IS_ERR(phy->base)) + return dev_err_probe(dev, PTR_ERR(phy->base), + "Failed to map phy base\n"); phy->pll_base = msm_ioremap_size(pdev, "dsi_pll", &phy->pll_size); - if (IS_ERR(phy->pll_base)) { - DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__); - ret = -ENOMEM; - goto fail; - } + if (IS_ERR(phy->pll_base)) + return dev_err_probe(dev, PTR_ERR(phy->pll_base), + "Failed to map pll base\n"); if (phy->cfg->has_phy_lane) { phy->lane_base = msm_ioremap_size(pdev, "dsi_phy_lane", &phy->lane_size); - if (IS_ERR(phy->lane_base)) { - DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n", __func__); - ret = -ENOMEM; - goto fail; - } + if (IS_ERR(phy->lane_base)) + return dev_err_probe(dev, PTR_ERR(phy->lane_base), + "Failed to map phy lane base\n"); } if (phy->cfg->has_phy_regulator) { phy->reg_base = msm_ioremap_size(pdev, "dsi_phy_regulator", &phy->reg_size); - if (IS_ERR(phy->reg_base)) { - DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy regulator base\n", __func__); - ret = -ENOMEM; - goto fail; - } + if (IS_ERR(phy->reg_base)) + return dev_err_probe(dev, PTR_ERR(phy->reg_base), + "Failed to map phy regulator base\n"); } if (phy->cfg->ops.parse_dt_properties) { ret = phy->cfg->ops.parse_dt_properties(phy); if (ret) - goto fail; + return ret; } - ret = dsi_phy_regulator_init(phy); + ret = devm_regulator_bulk_get_const(dev, phy->cfg->num_regulators, + phy->cfg->regulator_data, + &phy->supplies); if (ret) - goto fail; + return ret; phy->ahb_clk = msm_clk_get(pdev, "iface"); - if (IS_ERR(phy->ahb_clk)) { - DRM_DEV_ERROR(dev, "%s: Unable to get ahb clk\n", __func__); - ret = PTR_ERR(phy->ahb_clk); - goto fail; - } + if (IS_ERR(phy->ahb_clk)) + return dev_err_probe(dev, PTR_ERR(phy->ahb_clk), + "Unable to get ahb clk\n"); /* PLL init will call into clk_register which requires * register access, so we need to enable power and ahb clock. */ ret = dsi_phy_enable_resource(phy); if (ret) - goto fail; + return ret; if (phy->cfg->ops.pll_init) { ret = phy->cfg->ops.pll_init(phy); - if (ret) { - DRM_DEV_INFO(dev, - "%s: pll init failed: %d, need separate pll clk driver\n", - __func__, ret); - goto fail; - } + if (ret) + return dev_err_probe(dev, ret, + "PLL init failed; need separate clk driver\n"); } ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, phy->provided_clocks); - if (ret) { - DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret); - goto fail; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clk provider\n"); dsi_phy_disable_resource(phy); platform_set_drvdata(pdev, phy); return 0; - -fail: - return ret; } static struct platform_driver dsi_phy_platform_driver = { @@ -829,7 +735,7 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, goto res_en_fail; } - ret = dsi_phy_regulator_enable(phy); + ret = regulator_bulk_enable(phy->cfg->num_regulators, phy->supplies); if (ret) { DRM_DEV_ERROR(dev, "%s: regulator enable failed, %d\n", __func__, ret); @@ -866,7 +772,7 @@ pll_restor_fail: if (phy->cfg->ops.disable) phy->cfg->ops.disable(phy); phy_en_fail: - dsi_phy_regulator_disable(phy); + regulator_bulk_disable(phy->cfg->num_regulators, phy->supplies); reg_en_fail: dsi_phy_disable_resource(phy); res_en_fail: @@ -880,7 +786,7 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy) phy->cfg->ops.disable(phy); - dsi_phy_regulator_disable(phy); + regulator_bulk_disable(phy->cfg->num_regulators, phy->supplies); dsi_phy_disable_resource(phy); } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index dc91b43d5a38..60a99c6525b2 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -29,7 +29,8 @@ struct msm_dsi_phy_ops { }; struct msm_dsi_phy_cfg { - struct dsi_reg_config reg_cfg; + const struct regulator_bulk_data *regulator_data; + int num_regulators; struct msm_dsi_phy_ops ops; unsigned long min_pll_rate; @@ -98,7 +99,7 @@ struct msm_dsi_phy { int id; struct clk *ahb_clk; - struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; + struct regulator_bulk_data *supplies; struct msm_dsi_dphy_timing timing; const struct msm_dsi_phy_cfg *cfg; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c index 08b015ea1b1e..27b592c776a3 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -188,19 +188,19 @@ static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config * pr_debug("SSC is enabled\n"); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, - config->ssc_stepsize & 0xff); + config->ssc_stepsize & 0xff); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, - config->ssc_stepsize >> 8); + config->ssc_stepsize >> 8); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, - config->ssc_div_per & 0xff); + config->ssc_div_per & 0xff); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, - config->ssc_div_per >> 8); + config->ssc_div_per >> 8); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, - config->ssc_adj_per & 0xff); + config->ssc_adj_per & 0xff); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, - config->ssc_adj_per >> 8); + config->ssc_adj_per >> 8); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, - SSC_EN | (config->ssc_center ? SSC_CENTER : 0)); + SSC_EN | (config->ssc_center ? SSC_CENTER : 0)); } } @@ -215,16 +215,19 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, - 0xba); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); + 0xba); + dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, + 0x0c); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); + dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, + 0x08); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); - dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); + dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, + 0xfa); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, - 0x4c); + 0x4c); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); @@ -236,18 +239,18 @@ static void dsi_pll_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config *conf dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, - config->decimal_div_start); + config->decimal_div_start); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, - config->frac_div_start & 0xff); + config->frac_div_start & 0xff); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, - (config->frac_div_start & 0xff00) >> 8); + (config->frac_div_start & 0xff00) >> 8); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, - (config->frac_div_start & 0x30000) >> 16); + (config->frac_div_start & 0x30000) >> 16); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 64); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, - config->pll_clock_inverters); + config->pll_clock_inverters); } static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, @@ -306,7 +309,7 @@ static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0, - data & ~BIT(5)); + data & ~BIT(5)); ndelay(250); } @@ -315,7 +318,7 @@ static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) u32 data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0); dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0, - data | BIT(5)); + data | BIT(5)); dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); ndelay(250); } @@ -326,7 +329,7 @@ static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, - data & ~BIT(5)); + data & ~BIT(5)); } static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) @@ -335,7 +338,7 @@ static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, - data | BIT(5)); + data | BIT(5)); } static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) @@ -356,7 +359,7 @@ static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) /* Start PLL */ dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, - 0x01); + 0x01); /* * ensure all PLL configurations are written prior to checking @@ -378,10 +381,10 @@ static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) dsi_pll_enable_global_clk(pll_10nm->slave); dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, - 0x01); + 0x01); if (pll_10nm->slave) dsi_phy_write(pll_10nm->slave->phy->base + - REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); error: return rc; @@ -486,7 +489,7 @@ static void dsi_10nm_pll_save_state(struct msm_dsi_phy *phy) u32 cmn_clk_cfg0, cmn_clk_cfg1; cached->pll_out_div = dsi_phy_read(pll_10nm->phy->pll_base + - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); cached->pll_out_div &= 0x3; cmn_clk_cfg0 = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); @@ -515,7 +518,7 @@ static int dsi_10nm_pll_restore_state(struct msm_dsi_phy *phy) dsi_phy_write(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); dsi_phy_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, - cached->bit_clk_div | (cached->pix_clk_div << 4)); + cached->bit_clk_div | (cached->pix_clk_div << 4)); val = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); val &= ~0x3; @@ -571,64 +574,59 @@ static int dsi_10nm_set_usecase(struct msm_dsi_phy *phy) */ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm, struct clk_hw **provided_clocks) { - char clk_name[32], parent[32], vco_name[32]; - char parent2[32], parent3[32], parent4[32]; + char clk_name[32]; struct clk_init_data vco_init = { .parent_data = &(const struct clk_parent_data) { .fw_name = "ref", }, .num_parents = 1, - .name = vco_name, + .name = clk_name, .flags = CLK_IGNORE_UNUSED, .ops = &clk_ops_dsi_pll_10nm_vco, }; struct device *dev = &pll_10nm->phy->pdev->dev; - struct clk_hw *hw; + struct clk_hw *hw, *pll_out_div, *pll_bit, *pll_by_2_bit; + struct clk_hw *pll_post_out_div, *pclk_mux; int ret; DBG("DSI%d", pll_10nm->phy->id); - snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_10nm->phy->id); pll_10nm->clk_hw.init = &vco_init; ret = devm_clk_hw_register(dev, &pll_10nm->clk_hw); if (ret) return ret; - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_divider(dev, clk_name, - parent, CLK_SET_RATE_PARENT, - pll_10nm->phy->pll_base + - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_out_div = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_10nm->clk_hw, CLK_SET_RATE_PARENT, + pll_10nm->phy->pll_base + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); + if (IS_ERR(pll_out_div)) { + ret = PTR_ERR(pll_out_div); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_bit_clk", pll_10nm->phy->id); /* BIT CLK: DIV_CTRL_3_0 */ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - CLK_SET_RATE_PARENT, - pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG0, - 0, 4, CLK_DIVIDER_ONE_BASED, - &pll_10nm->postdiv_lock); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_bit = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + pll_out_div, CLK_SET_RATE_PARENT, + pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 0, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); + if (IS_ERR(pll_bit)) { + ret = PTR_ERR(pll_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_byteclk", pll_10nm->phy->id); /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - CLK_SET_RATE_PARENT, 1, 8); + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name, + pll_bit, CLK_SET_RATE_PARENT, 1, 8); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -636,52 +634,45 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm, struct clk_hw **prov provided_clocks[DSI_BYTE_PLL_CLK] = hw; - snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - 0, 1, 2); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_by_2_bit = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, pll_bit, 0, 1, 2); + if (IS_ERR(pll_by_2_bit)) { + ret = PTR_ERR(pll_by_2_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - 0, 1, 4); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_post_out_div = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, pll_out_div, 0, 1, 4); + if (IS_ERR(pll_post_out_div)) { + ret = PTR_ERR(pll_post_out_div); goto fail; } - snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id); - snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id); - snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id); - snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id); - - hw = devm_clk_hw_register_mux(dev, clk_name, - ((const char *[]){ - parent, parent2, parent3, parent4 - }), 4, 0, pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG1, - 0, 2, 0, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pclk_mux", pll_10nm->phy->id); + + pclk_mux = devm_clk_hw_register_mux_parent_hws(dev, clk_name, + ((const struct clk_hw *[]){ + pll_bit, + pll_by_2_bit, + pll_out_div, + pll_post_out_div, + }), 4, 0, pll_10nm->phy->base + + REG_DSI_10nm_PHY_CMN_CLK_CFG1, 0, 2, 0, NULL); + if (IS_ERR(pclk_mux)) { + ret = PTR_ERR(pclk_mux); goto fail; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->phy->id); - snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_dsiclk", pll_10nm->phy->id); /* PIX CLK DIV : DIV_CTRL_7_4*/ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - 0, pll_10nm->phy->base + - REG_DSI_10nm_PHY_CMN_CLK_CFG0, - 4, 4, CLK_DIVIDER_ONE_BASED, - &pll_10nm->postdiv_lock); + hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name, pclk_mux, + 0, pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 4, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -1028,14 +1019,14 @@ static int dsi_10nm_phy_parse_dt(struct msm_dsi_phy *phy) return 0; } +static const struct regulator_bulk_data dsi_phy_10nm_regulators[] = { + { .supply = "vdds", .init_load_uA = 36000 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_10nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_10nm_regulators), .ops = { .enable = dsi_10nm_phy_enable, .disable = dsi_10nm_phy_disable, @@ -1052,12 +1043,8 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_10nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_10nm_regulators), .ops = { .enable = dsi_10nm_phy_enable, .disable = dsi_10nm_phy_disable, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index 8199c53567f4..0f8f4ca46429 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -711,7 +711,7 @@ static int dsi_14nm_pll_restore_state(struct msm_dsi_phy *phy) cached_state->vco_rate, 0); if (ret) { DRM_DEV_ERROR(&pll_14nm->phy->pdev->dev, - "restore vco rate failed. ret=%d\n", ret); + "restore vco rate failed. ret=%d\n", ret); return ret; } @@ -764,14 +764,14 @@ static int dsi_14nm_set_usecase(struct msm_dsi_phy *phy) static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm *pll_14nm, const char *name, - const char *parent_name, + const struct clk_hw *parent_hw, unsigned long flags, u8 shift) { struct dsi_pll_14nm_postdiv *pll_postdiv; struct device *dev = &pll_14nm->phy->pdev->dev; struct clk_init_data postdiv_init = { - .parent_names = (const char *[]) { parent_name }, + .parent_hws = (const struct clk_hw *[]) { parent_hw }, .num_parents = 1, .name = name, .flags = flags, @@ -800,72 +800,70 @@ static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm *pll_14nm, static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm, struct clk_hw **provided_clocks) { - char clk_name[32], parent[32], vco_name[32]; + char clk_name[32]; struct clk_init_data vco_init = { .parent_data = &(const struct clk_parent_data) { .fw_name = "ref", }, .num_parents = 1, - .name = vco_name, + .name = clk_name, .flags = CLK_IGNORE_UNUSED, .ops = &clk_ops_dsi_pll_14nm_vco, }; struct device *dev = &pll_14nm->phy->pdev->dev; - struct clk_hw *hw; + struct clk_hw *hw, *n1_postdiv, *n1_postdivby2; int ret; DBG("DSI%d", pll_14nm->phy->id); - snprintf(vco_name, 32, "dsi%dvco_clk", pll_14nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_14nm->phy->id); pll_14nm->clk_hw.init = &vco_init; ret = devm_clk_hw_register(dev, &pll_14nm->clk_hw); if (ret) return ret; - snprintf(clk_name, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id); - snprintf(parent, 32, "dsi%dvco_clk", pll_14nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dn1_postdiv_clk", pll_14nm->phy->id); /* N1 postdiv, bits 0-3 in REG_DSI_14nm_PHY_CMN_CLK_CFG0 */ - hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, - CLK_SET_RATE_PARENT, 0); - if (IS_ERR(hw)) - return PTR_ERR(hw); + n1_postdiv = pll_14nm_postdiv_register(pll_14nm, clk_name, + &pll_14nm->clk_hw, CLK_SET_RATE_PARENT, 0); + if (IS_ERR(n1_postdiv)) + return PTR_ERR(n1_postdiv); - snprintf(clk_name, 32, "dsi%dpllbyte", pll_14nm->phy->id); - snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dpllbyte", pll_14nm->phy->id); /* DSI Byte clock = VCO_CLK / N1 / 8 */ - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - CLK_SET_RATE_PARENT, 1, 8); + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name, + n1_postdiv, CLK_SET_RATE_PARENT, 1, 8); if (IS_ERR(hw)) return PTR_ERR(hw); provided_clocks[DSI_BYTE_PLL_CLK] = hw; - snprintf(clk_name, 32, "dsi%dn1_postdivby2_clk", pll_14nm->phy->id); - snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dn1_postdivby2_clk", pll_14nm->phy->id); /* * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider * on the way. Don't let it set parent. */ - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2); - if (IS_ERR(hw)) - return PTR_ERR(hw); + n1_postdivby2 = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, n1_postdiv, 0, 1, 2); + if (IS_ERR(n1_postdivby2)) + return PTR_ERR(n1_postdivby2); - snprintf(clk_name, 32, "dsi%dpll", pll_14nm->phy->id); - snprintf(parent, 32, "dsi%dn1_postdivby2_clk", pll_14nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dpll", pll_14nm->phy->id); /* DSI pixel clock = VCO_CLK / N1 / 2 / N2 * This is the output of N2 post-divider, bits 4-7 in * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent. */ - hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, 0, 4); + hw = pll_14nm_postdiv_register(pll_14nm, clk_name, n1_postdivby2, + 0, 4); if (IS_ERR(hw)) return PTR_ERR(hw); - provided_clocks[DSI_PIXEL_PLL_CLK] = hw; + provided_clocks[DSI_PIXEL_PLL_CLK] = hw; return 0; } @@ -952,7 +950,8 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, if (msm_dsi_dphy_timing_calc_v2(timing, clk_req)) { DRM_DEV_ERROR(&phy->pdev->dev, - "%s: D-PHY timing calculation failed\n", __func__); + "%s: D-PHY timing calculation failed\n", + __func__); return -EINVAL; } @@ -1005,7 +1004,7 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, ret = dsi_14nm_set_usecase(phy); if (ret) { DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n", - __func__, ret); + __func__, ret); return ret; } @@ -1024,14 +1023,18 @@ static void dsi_14nm_phy_disable(struct msm_dsi_phy *phy) wmb(); } +static const struct regulator_bulk_data dsi_phy_14nm_17mA_regulators[] = { + { .supply = "vcca", .init_load_uA = 17000 }, +}; + +static const struct regulator_bulk_data dsi_phy_14nm_73p4mA_regulators[] = { + { .supply = "vcca", .init_load_uA = 73400 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vcca", 17000, 32}, - }, - }, + .regulator_data = dsi_phy_14nm_17mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_14nm_17mA_regulators), .ops = { .enable = dsi_14nm_phy_enable, .disable = dsi_14nm_phy_disable, @@ -1047,12 +1050,8 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vcca", 73400, 32}, - }, - }, + .regulator_data = dsi_phy_14nm_73p4mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_14nm_73p4mA_regulators), .ops = { .enable = dsi_14nm_phy_enable, .disable = dsi_14nm_phy_disable, @@ -1068,12 +1067,8 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vcca", 17000, 32}, - }, - }, + .regulator_data = dsi_phy_14nm_17mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_14nm_17mA_regulators), .ops = { .enable = dsi_14nm_phy_enable, .disable = dsi_14nm_phy_disable, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c index ee7c418a1c29..c9752b991744 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c @@ -129,15 +129,15 @@ static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy) dsi_20nm_phy_regulator_ctrl(phy, false); } +static const struct regulator_bulk_data dsi_phy_20nm_regulators[] = { + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ + { .supply = "vcca", .init_load_uA = 10000 }, /* 1.0 V */ +}; + const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = { .has_phy_regulator = true, - .reg_cfg = { - .num = 2, - .regs = { - {"vddio", 100000, 100}, /* 1.8 V */ - {"vcca", 10000, 100}, /* 1.0 V */ - }, - }, + .regulator_data = dsi_phy_20nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_20nm_regulators), .ops = { .enable = dsi_20nm_phy_enable, .disable = dsi_20nm_phy_disable, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index 48eab80b548e..4c1bf55c5f38 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -104,7 +104,7 @@ static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm) * reset bit off and back on. */ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, - DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); + DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1); } @@ -201,9 +201,9 @@ static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate, dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2, - DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); + DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3, - DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); + DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00); /* Add hardware recommended delay for correct PLL configuration */ @@ -316,12 +316,12 @@ static int _dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm *pll_28nm) for (i = 0; i < 2; i++) { /* DSI Uniphy lock detect setting */ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, - 0x0c, 100); + 0x0c, 100); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); /* poll for PLL ready status */ - locked = pll_28nm_poll_for_ready(pll_28nm, - max_reads, timeout_us); + locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, + timeout_us); if (locked) break; @@ -508,28 +508,28 @@ static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy) } dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, - cached_state->postdiv3); + cached_state->postdiv3); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, - cached_state->postdiv1); + cached_state->postdiv1); dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG, - cached_state->byte_mux); + cached_state->byte_mux); return 0; } static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks) { - char clk_name[32], parent1[32], parent2[32], vco_name[32]; + char clk_name[32]; struct clk_init_data vco_init = { .parent_data = &(const struct clk_parent_data) { .fw_name = "ref", .name = "xo", }, .num_parents = 1, - .name = vco_name, + .name = clk_name, .flags = CLK_IGNORE_UNUSED, }; struct device *dev = &pll_28nm->phy->pdev->dev; - struct clk_hw *hw; + struct clk_hw *hw, *analog_postdiv, *indirect_path_div2, *byte_mux; int ret; DBG("%d", pll_28nm->phy->id); @@ -539,55 +539,49 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov else vco_init.ops = &clk_ops_dsi_pll_28nm_vco_hpm; - snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_28nm->phy->id); pll_28nm->clk_hw.init = &vco_init; ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw); if (ret) return ret; - snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->phy->id); - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id); - hw = devm_clk_hw_register_divider(dev, clk_name, - parent1, CLK_SET_RATE_PARENT, + snprintf(clk_name, sizeof(clk_name), "dsi%danalog_postdiv_clk", pll_28nm->phy->id); + analog_postdiv = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_28nm->clk_hw, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base + - REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, 0, 4, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->phy->id); - snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, - parent1, CLK_SET_RATE_PARENT, - 1, 2); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id); - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id); - hw = devm_clk_hw_register_divider(dev, clk_name, - parent1, 0, pll_28nm->phy->pll_base + + if (IS_ERR(analog_postdiv)) + return PTR_ERR(analog_postdiv); + + snprintf(clk_name, sizeof(clk_name), "dsi%dindirect_path_div2_clk", pll_28nm->phy->id); + indirect_path_div2 = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, analog_postdiv, CLK_SET_RATE_PARENT, 1, 2); + if (IS_ERR(indirect_path_div2)) + return PTR_ERR(indirect_path_div2); + + snprintf(clk_name, sizeof(clk_name), "dsi%dpll", pll_28nm->phy->id); + hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_28nm->clk_hw, 0, pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, - 0, 8, 0, NULL); + 0, 8, 0, NULL); if (IS_ERR(hw)) return PTR_ERR(hw); provided_clocks[DSI_PIXEL_PLL_CLK] = hw; - snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->phy->id); - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id); - snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->phy->id); - hw = devm_clk_hw_register_mux(dev, clk_name, - ((const char *[]){ - parent1, parent2 + snprintf(clk_name, sizeof(clk_name), "dsi%dbyte_mux", pll_28nm->phy->id); + byte_mux = devm_clk_hw_register_mux_parent_hws(dev, clk_name, + ((const struct clk_hw *[]){ + &pll_28nm->clk_hw, + indirect_path_div2, }), 2, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base + - REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); + REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); + if (IS_ERR(byte_mux)) + return PTR_ERR(byte_mux); - snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id); - snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, - parent1, CLK_SET_RATE_PARENT, 1, 4); + snprintf(clk_name, sizeof(clk_name), "dsi%dpllbyte", pll_28nm->phy->id); + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name, + byte_mux, CLK_SET_RATE_PARENT, 1, 4); if (IS_ERR(hw)) return PTR_ERR(hw); provided_clocks[DSI_BYTE_PLL_CLK] = hw; @@ -627,31 +621,31 @@ static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, void __iomem *base = phy->base; dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0, - DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); + DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1, - DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); + DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2, - DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); + DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); if (timing->clk_zero & BIT(8)) dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3, - DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8); + DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4, - DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); + DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5, - DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); + DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6, - DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); + DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7, - DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); + DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8, - DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); + DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9, - DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | - DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); + DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | + DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10, - DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); + DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11, - DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); + DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); } static void dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy *phy) @@ -713,7 +707,8 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, if (msm_dsi_dphy_timing_calc(timing, clk_req)) { DRM_DEV_ERROR(&phy->pdev->dev, - "%s: D-PHY timing calculation failed\n", __func__); + "%s: D-PHY timing calculation failed\n", + __func__); return -EINVAL; } @@ -769,14 +764,14 @@ static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy) wmb(); } +static const struct regulator_bulk_data dsi_phy_28nm_regulators[] = { + { .supply = "vddio", .init_load_uA = 100000 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { .has_phy_regulator = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vddio", 100000, 100}, - }, - }, + .regulator_data = dsi_phy_28nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators), .ops = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, @@ -792,12 +787,8 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = { .has_phy_regulator = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vddio", 100000, 100}, - }, - }, + .regulator_data = dsi_phy_28nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators), .ops = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, @@ -813,12 +804,8 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { .has_phy_regulator = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = dsi_phy_28nm_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators), .ops = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index fc56cdcc9ad6..26c08047e20c 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -104,29 +104,29 @@ static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate, fb_divider = (temp * VCO_PREF_DIV_RATIO) / val; fb_divider = fb_divider / 2 - 1; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1, - fb_divider & 0xff); + fb_divider & 0xff); val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2); val |= (fb_divider >> 8) & 0x07; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2, - val); + val); val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3); val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3, - val); + val); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6, - 0xf); + 0xf); val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); val |= 0x7 << 4; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, - val); + val); return 0; } @@ -206,7 +206,7 @@ static int dsi_pll_28nm_vco_prepare(struct clk_hw *hw) /* enable the PLL */ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, - DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE); + DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE); locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); @@ -367,23 +367,23 @@ static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy) cached_state->vco_rate, 0); if (ret) { DRM_DEV_ERROR(&pll_28nm->phy->pdev->dev, - "restore vco rate failed. ret=%d\n", ret); + "restore vco rate failed. ret=%d\n", ret); return ret; } dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10, - cached_state->postdiv3); + cached_state->postdiv3); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9, - cached_state->postdiv2); + cached_state->postdiv2); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, - cached_state->postdiv1); + cached_state->postdiv1); return 0; } static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks) { - char *clk_name, *parent_name, *vco_name; + char clk_name[32]; struct clk_init_data vco_init = { .parent_data = &(const struct clk_parent_data) { .fw_name = "ref", @@ -404,20 +404,8 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov if (!bytediv) return -ENOMEM; - vco_name = devm_kzalloc(dev, 32, GFP_KERNEL); - if (!vco_name) - return -ENOMEM; - - parent_name = devm_kzalloc(dev, 32, GFP_KERNEL); - if (!parent_name) - return -ENOMEM; - - clk_name = devm_kzalloc(dev, 32, GFP_KERNEL); - if (!clk_name) - return -ENOMEM; - - snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->phy->id); - vco_init.name = vco_name; + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_28nm->phy->id); + vco_init.name = clk_name; pll_28nm->clk_hw.init = &vco_init; @@ -429,13 +417,14 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov bytediv->hw.init = &bytediv_init; bytediv->reg = pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9; - snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->phy->id); - snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id + 1); + snprintf(clk_name, sizeof(clk_name), "dsi%dpllbyte", pll_28nm->phy->id + 1); bytediv_init.name = clk_name; bytediv_init.ops = &clk_bytediv_ops; bytediv_init.flags = CLK_SET_RATE_PARENT; - bytediv_init.parent_names = (const char * const *) &parent_name; + bytediv_init.parent_hws = (const struct clk_hw*[]){ + &pll_28nm->clk_hw, + }; bytediv_init.num_parents = 1; /* DIV2 */ @@ -444,12 +433,12 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov return ret; provided_clocks[DSI_BYTE_PLL_CLK] = &bytediv->hw; - snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id + 1); + snprintf(clk_name, sizeof(clk_name), "dsi%dpll", pll_28nm->phy->id + 1); /* DIV3 */ - hw = devm_clk_hw_register_divider(dev, clk_name, - parent_name, 0, pll_28nm->phy->pll_base + + hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_28nm->clk_hw, 0, pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10, - 0, 8, 0, NULL); + 0, 8, 0, NULL); if (IS_ERR(hw)) return PTR_ERR(hw); provided_clocks[DSI_PIXEL_PLL_CLK] = hw; @@ -489,29 +478,29 @@ static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, void __iomem *base = phy->base; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_0, - DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); + DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_1, - DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); + DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_2, - DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); + DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_3, 0x0); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_4, - DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); + DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_5, - DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); + DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_6, - DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); + DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_7, - DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); + DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_8, - DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); + DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_9, - DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | - DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_10, - DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); + DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_11, - DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); + DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); } static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy) @@ -523,7 +512,7 @@ static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy) dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 1); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, - 0x100); + 0x100); } static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy) @@ -544,7 +533,7 @@ static void dsi_28nm_phy_calibration(struct msm_dsi_phy *phy) int i = 5000; dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG, - 0x3); + 0x3); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2, 0x0); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1, 0x5a); @@ -577,11 +566,11 @@ static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy) dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_1(i), 0x45); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_2(i), 0x00); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(i), - 0x00); + 0x00); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(i), - 0x01); + 0x01); dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(i), - 0x66); + 0x66); } dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_0, 0x40); @@ -602,7 +591,8 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, if (msm_dsi_dphy_timing_calc(timing, clk_req)) { DRM_DEV_ERROR(&phy->pdev->dev, - "%s: D-PHY timing calculation failed\n", __func__); + "%s: D-PHY timing calculation failed\n", + __func__); return -EINVAL; } @@ -648,14 +638,14 @@ static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy) wmb(); } +static const struct regulator_bulk_data dsi_phy_28nm_8960_regulators[] = { + { .supply = "vddio", .init_load_uA = 100000 }, /* 1.8 V */ +}; + const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = { .has_phy_regulator = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vddio", 100000, 100}, /* 1.8 V */ - }, - }, + .regulator_data = dsi_phy_28nm_8960_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_28nm_8960_regulators), .ops = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 66ed1919a1db..9e7fa7d88ead 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -176,19 +176,19 @@ static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll, struct dsi_pll_config *c pr_debug("SSC is enabled\n"); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_LOW_1, - config->ssc_stepsize & 0xff); + config->ssc_stepsize & 0xff); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, - config->ssc_stepsize >> 8); + config->ssc_stepsize >> 8); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_LOW_1, - config->ssc_div_per & 0xff); + config->ssc_div_per & 0xff); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_HIGH_1, - config->ssc_div_per >> 8); + config->ssc_div_per >> 8); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_LOW_1, - config->ssc_adj_per & 0xff); + config->ssc_adj_per & 0xff); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_HIGH_1, - config->ssc_adj_per >> 8); + config->ssc_adj_per >> 8); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_CONTROL, - SSC_EN | (config->ssc_center ? SSC_CENTER : 0)); + SSC_EN | (config->ssc_center ? SSC_CENTER : 0)); } } @@ -208,7 +208,7 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) } dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1, - analog_controls_five_1); + analog_controls_five_1); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE, 0x01); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); @@ -245,17 +245,20 @@ static void dsi_pll_commit(struct dsi_pll_7nm *pll, struct dsi_pll_config *confi void __iomem *base = pll->phy->pll_base; dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); - dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, config->decimal_div_start); + dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, + config->decimal_div_start); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1, - config->frac_div_start & 0xff); + config->frac_div_start & 0xff); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1, - (config->frac_div_start & 0xff00) >> 8); + (config->frac_div_start & 0xff00) >> 8); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1, - (config->frac_div_start & 0x30000) >> 16); + (config->frac_div_start & 0x30000) >> 16); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); - dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, pll->phy->cphy_mode ? 0x00 : 0x10); - dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, config->pll_clock_inverters); + dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, + pll->phy->cphy_mode ? 0x00 : 0x10); + dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, + config->pll_clock_inverters); } static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, @@ -341,7 +344,7 @@ static void dsi_pll_enable_global_clk(struct dsi_pll_7nm *pll) data = dsi_phy_read(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, - data | BIT(5) | BIT(4)); + data | BIT(5) | BIT(4)); } static void dsi_pll_phy_dig_reset(struct dsi_pll_7nm *pll) @@ -500,7 +503,7 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy) u32 cmn_clk_cfg0, cmn_clk_cfg1; cached->pll_out_div = dsi_phy_read(pll_7nm->phy->pll_base + - REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); cached->pll_out_div &= 0x3; cmn_clk_cfg0 = dsi_phy_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0); @@ -529,7 +532,7 @@ static int dsi_7nm_pll_restore_state(struct msm_dsi_phy *phy) dsi_phy_write(pll_7nm->phy->pll_base + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, val); dsi_phy_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0, - cached->bit_clk_div | (cached->pix_clk_div << 4)); + cached->bit_clk_div | (cached->pix_clk_div << 4)); val = dsi_phy_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); val &= ~0x3; @@ -585,65 +588,60 @@ static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy) */ static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm, struct clk_hw **provided_clocks) { - char clk_name[32], parent[32], vco_name[32]; - char parent2[32]; + char clk_name[32]; struct clk_init_data vco_init = { .parent_data = &(const struct clk_parent_data) { .fw_name = "ref", }, .num_parents = 1, - .name = vco_name, + .name = clk_name, .flags = CLK_IGNORE_UNUSED, .ops = &clk_ops_dsi_pll_7nm_vco, }; struct device *dev = &pll_7nm->phy->pdev->dev; - struct clk_hw *hw; + struct clk_hw *hw, *pll_out_div, *pll_bit, *pll_by_2_bit; + struct clk_hw *pll_post_out_div, *phy_pll_out_dsi_parent; int ret; DBG("DSI%d", pll_7nm->phy->id); - snprintf(vco_name, 32, "dsi%dvco_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_7nm->phy->id); pll_7nm->clk_hw.init = &vco_init; ret = devm_clk_hw_register(dev, &pll_7nm->clk_hw); if (ret) return ret; - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%dvco_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_out_div_clk", pll_7nm->phy->id); - hw = devm_clk_hw_register_divider(dev, clk_name, - parent, CLK_SET_RATE_PARENT, - pll_7nm->phy->pll_base + - REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_out_div = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + &pll_7nm->clk_hw, CLK_SET_RATE_PARENT, + pll_7nm->phy->pll_base + + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); + if (IS_ERR(pll_out_div)) { + ret = PTR_ERR(pll_out_div); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_bit_clk", pll_7nm->phy->id); /* BIT CLK: DIV_CTRL_3_0 */ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - CLK_SET_RATE_PARENT, - pll_7nm->phy->base + - REG_DSI_7nm_PHY_CMN_CLK_CFG0, - 0, 4, CLK_DIVIDER_ONE_BASED, - &pll_7nm->postdiv_lock); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_bit = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + pll_out_div, CLK_SET_RATE_PARENT, + pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG0, + 0, 4, CLK_DIVIDER_ONE_BASED, &pll_7nm->postdiv_lock); + if (IS_ERR(pll_bit)) { + ret = PTR_ERR(pll_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_byteclk", pll_7nm->phy->id); /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - CLK_SET_RATE_PARENT, 1, - pll_7nm->phy->cphy_mode ? 7 : 8); + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name, + pll_bit, CLK_SET_RATE_PARENT, 1, + pll_7nm->phy->cphy_mode ? 7 : 8); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -651,25 +649,25 @@ static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm, struct clk_hw **provide provided_clocks[DSI_BYTE_PLL_CLK] = hw; - snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_by_2_bit_clk", pll_7nm->phy->id); - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, - 0, 1, 2); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_by_2_bit = devm_clk_hw_register_fixed_factor_parent_hw(dev, + clk_name, pll_bit, 0, 1, 2); + if (IS_ERR(pll_by_2_bit)) { + ret = PTR_ERR(pll_by_2_bit); goto fail; } - snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_pll_post_out_div_clk", pll_7nm->phy->id); if (pll_7nm->phy->cphy_mode) - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 2, 7); + pll_post_out_div = devm_clk_hw_register_fixed_factor_parent_hw( + dev, clk_name, pll_out_div, 0, 2, 7); else - hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 4); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); + pll_post_out_div = devm_clk_hw_register_fixed_factor_parent_hw( + dev, clk_name, pll_out_div, 0, 1, 4); + if (IS_ERR(pll_post_out_div)) { + ret = PTR_ERR(pll_post_out_div); goto fail; } @@ -682,34 +680,32 @@ static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm, struct clk_hw **provide data = dsi_phy_read(pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); dsi_phy_write(pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, data | 3); - snprintf(parent, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->phy->id); + phy_pll_out_dsi_parent = pll_post_out_div; } else { - snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_7nm->phy->id); - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id); - snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->phy->id); - - hw = devm_clk_hw_register_mux(dev, clk_name, - ((const char *[]){ - parent, parent2, - }), 2, 0, pll_7nm->phy->base + + snprintf(clk_name, sizeof(clk_name), "dsi%d_pclk_mux", pll_7nm->phy->id); + + hw = devm_clk_hw_register_mux_parent_hws(dev, clk_name, + ((const struct clk_hw *[]){ + pll_bit, + pll_by_2_bit, + }), 2, 0, pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, - 0, 1, 0, NULL); + 0, 1, 0, NULL); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; } - snprintf(parent, 32, "dsi%d_pclk_mux", pll_7nm->phy->id); + phy_pll_out_dsi_parent = hw; } - snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_7nm->phy->id); + snprintf(clk_name, sizeof(clk_name), "dsi%d_phy_pll_out_dsiclk", pll_7nm->phy->id); /* PIX CLK DIV : DIV_CTRL_7_4*/ - hw = devm_clk_hw_register_divider(dev, clk_name, parent, - 0, pll_7nm->phy->base + - REG_DSI_7nm_PHY_CMN_CLK_CFG0, - 4, 4, CLK_DIVIDER_ONE_BASED, - &pll_7nm->postdiv_lock); + hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name, + phy_pll_out_dsi_parent, 0, + pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG0, + 4, 4, CLK_DIVIDER_ONE_BASED, &pll_7nm->postdiv_lock); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail; @@ -841,7 +837,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, ret = msm_dsi_dphy_timing_calc_v4(timing, clk_req); if (ret) { DRM_DEV_ERROR(&phy->pdev->dev, - "%s: PHY timing calculation failed\n", __func__); + "%s: PHY timing calculation failed\n", __func__); return -EINVAL; } @@ -960,10 +956,10 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_0, 0x00); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_4, timing->hs_exit); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_5, - timing->shared_timings.clk_pre); + timing->shared_timings.clk_pre); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_6, timing->clk_prepare); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_7, - timing->shared_timings.clk_post); + timing->shared_timings.clk_post); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_8, timing->hs_rqst); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_9, 0x02); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_10, 0x04); @@ -982,9 +978,9 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_10, 0x04); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_11, 0x00); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_12, - timing->shared_timings.clk_pre); + timing->shared_timings.clk_pre); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_TIMING_CTRL_13, - timing->shared_timings.clk_post); + timing->shared_timings.clk_post); } /* DSI lane settings */ @@ -1036,14 +1032,18 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy) DBG("DSI%d PHY disabled", phy->id); } +static const struct regulator_bulk_data dsi_phy_7nm_36mA_regulators[] = { + { .supply = "vdds", .init_load_uA = 36000 }, +}; + +static const struct regulator_bulk_data dsi_phy_7nm_37750uA_regulators[] = { + { .supply = "vdds", .init_load_uA = 37550 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_7nm_36mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_36mA_regulators), .ops = { .enable = dsi_7nm_phy_enable, .disable = dsi_7nm_phy_disable, @@ -1065,12 +1065,8 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 36000, 32}, - }, - }, + .regulator_data = dsi_phy_7nm_36mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_36mA_regulators), .ops = { .enable = dsi_7nm_phy_enable, .disable = dsi_7nm_phy_disable, @@ -1087,12 +1083,8 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = { const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = { .has_phy_lane = true, - .reg_cfg = { - .num = 1, - .regs = { - {"vdds", 37550, 0}, - }, - }, + .regulator_data = dsi_phy_7nm_37750uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_37750uA_regulators), .ops = { .enable = dsi_7nm_phy_enable, .disable = dsi_7nm_phy_disable, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c index b06d9d25a189..4dd055416620 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c @@ -691,15 +691,13 @@ static const struct clk_ops hdmi_8996_pll_ops = { .is_enabled = hdmi_8996_pll_is_enabled, }; -static const char * const hdmi_pll_parents[] = { - "xo", -}; - static const struct clk_init_data pll_init = { .name = "hdmipll", .ops = &hdmi_8996_pll_ops, - .parent_names = hdmi_pll_parents, - .num_parents = ARRAY_SIZE(hdmi_pll_parents), + .parent_data = (const struct clk_parent_data[]){ + { .fw_name = "xo", .name = "xo_board" }, + }, + .num_parents = 1, .flags = CLK_IGNORE_UNUSED, }; @@ -707,8 +705,7 @@ int msm_hdmi_pll_8996_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hdmi_pll_8996 *pll; - struct clk *clk; - int i; + int i, ret; pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); if (!pll) @@ -735,10 +732,16 @@ int msm_hdmi_pll_8996_init(struct platform_device *pdev) } pll->clk_hw.init = &pll_init; - clk = devm_clk_register(dev, &pll->clk_hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(dev, &pll->clk_hw); + if (ret) { DRM_DEV_ERROR(dev, "failed to register pll clock\n"); - return -EINVAL; + return ret; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw); + if (ret) { + DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret); + return ret; } return 0; diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 7d2dab260f86..95f4374ae21c 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -7,6 +7,7 @@ #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> +#include <linux/fault-inject.h> #include <drm/drm_debugfs.h> #include <drm/drm_file.h> @@ -326,6 +327,13 @@ void msm_debugfs_init(struct drm_minor *minor) if (priv->kms && priv->kms->funcs->debugfs_init) priv->kms->funcs->debugfs_init(priv->kms, minor); + +#ifdef CONFIG_FAULT_INJECTION + fault_create_debugfs_attr("fail_gem_alloc", minor->debugfs_root, + &fail_gem_alloc); + fault_create_debugfs_attr("fail_gem_iova", minor->debugfs_root, + &fail_gem_iova); +#endif } #endif diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 226d8d4629d2..28034c21f6bc 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -6,6 +6,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/fault-inject.h> #include <linux/kthread.h> #include <linux/sched/mm.h> #include <linux/uaccess.h> @@ -78,6 +79,11 @@ static bool modeset = true; MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disable)"); module_param(modeset, bool, 0600); +#ifdef CONFIG_FAULT_INJECTION +DECLARE_FAULT_ATTR(fail_gem_alloc); +DECLARE_FAULT_ATTR(fail_gem_iova); +#endif + static irqreturn_t msm_irq(int irq, void *arg) { struct drm_device *dev = arg; @@ -418,14 +424,18 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) INIT_LIST_HEAD(&priv->objects); mutex_init(&priv->obj_lock); - INIT_LIST_HEAD(&priv->inactive_willneed); - INIT_LIST_HEAD(&priv->inactive_dontneed); - INIT_LIST_HEAD(&priv->inactive_unpinned); - mutex_init(&priv->mm_lock); + /* + * Initialize the LRUs: + */ + mutex_init(&priv->lru.lock); + drm_gem_lru_init(&priv->lru.unbacked, &priv->lru.lock); + drm_gem_lru_init(&priv->lru.pinned, &priv->lru.lock); + drm_gem_lru_init(&priv->lru.willneed, &priv->lru.lock); + drm_gem_lru_init(&priv->lru.dontneed, &priv->lru.lock); /* Teach lockdep about lock ordering wrt. shrinker: */ fs_reclaim_acquire(GFP_KERNEL); - might_lock(&priv->mm_lock); + might_lock(&priv->lru.lock); fs_reclaim_release(GFP_KERNEL); drm_mode_config_init(ddev); @@ -469,6 +479,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) } } + drm_helper_move_panel_connectors_to_head(ddev); + ddev->mode_config.funcs = &mode_config_funcs; ddev->mode_config.helper_private = &mode_config_helper_funcs; @@ -697,6 +709,9 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, flags |= MSM_BO_WC; } + if (should_fail(&fail_gem_alloc, args->size)) + return -ENOMEM; + return msm_gem_new_handle(dev, file, args->size, args->flags, &args->handle, NULL); } @@ -758,6 +773,9 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev, if (!priv->gpu) return -EINVAL; + if (should_fail(&fail_gem_iova, obj->size)) + return -ENOMEM; + /* * Don't pin the memory here - just get an address so that userspace can * be productive @@ -779,6 +797,9 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev, if (priv->gpu->aspace == ctx->aspace) return -EOPNOTSUPP; + if (should_fail(&fail_gem_iova, obj->size)) + return -ENOMEM; + return msm_gem_set_iova(obj, ctx->aspace, iova); } @@ -883,13 +904,13 @@ static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, * retired, so if the fence is not found it means there is nothing * to wait for */ - ret = mutex_lock_interruptible(&queue->lock); + ret = mutex_lock_interruptible(&queue->idr_lock); if (ret) return ret; fence = idr_find(&queue->fence_idr, fence_id); if (fence) fence = dma_fence_get_rcu(fence); - mutex_unlock(&queue->lock); + mutex_unlock(&queue->idr_lock); if (!fence) return 0; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 7d5fb0fc22dd..b2ea262296a4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -33,6 +33,13 @@ #include <drm/msm_drm.h> #include <drm/drm_gem.h> +#ifdef CONFIG_FAULT_INJECTION +extern struct fault_attr fail_gem_alloc; +extern struct fault_attr fail_gem_iova; +#else +# define should_fail(attr, size) 0 +#endif + struct msm_kms; struct msm_gpu; struct msm_mmu; @@ -95,11 +102,6 @@ struct msm_drm_thread { struct kthread_worker *worker; }; -/* DSC config */ -struct msm_display_dsc_config { - struct drm_dsc_config *drm; -}; - struct msm_drm_private { struct drm_device *dev; @@ -141,28 +143,60 @@ struct msm_drm_private { struct mutex obj_lock; /** - * LRUs of inactive GEM objects. Every bo is either in one of the - * inactive lists (depending on whether or not it is shrinkable) or - * gpu->active_list (for the gpu it is active on[1]), or transiently - * on a temporary list as the shrinker is running. + * lru: * - * Note that inactive_willneed also contains pinned and vmap'd bos, - * but the number of pinned-but-not-active objects is small (scanout - * buffers, ringbuffer, etc). + * The various LRU's that a GEM object is in at various stages of + * it's lifetime. Objects start out in the unbacked LRU. When + * pinned (for scannout or permanently mapped GPU buffers, like + * ringbuffer, memptr, fw, etc) it moves to the pinned LRU. When + * unpinned, it moves into willneed or dontneed LRU depending on + * madvise state. When backing pages are evicted (willneed) or + * purged (dontneed) it moves back into the unbacked LRU. * - * These lists are protected by mm_lock (which should be acquired - * before per GEM object lock). One should *not* hold mm_lock in - * get_pages()/vmap()/etc paths, as they can trigger the shrinker. - * - * [1] if someone ever added support for the old 2d cores, there could be - * more than one gpu object + * The dontneed LRU is considered by the shrinker for objects + * that are candidate for purging, and the willneed LRU is + * considered for objects that could be evicted. */ - struct list_head inactive_willneed; /* inactive + potentially unpin/evictable */ - struct list_head inactive_dontneed; /* inactive + shrinkable */ - struct list_head inactive_unpinned; /* inactive + purged or unpinned */ - long shrinkable_count; /* write access under mm_lock */ - long evictable_count; /* write access under mm_lock */ - struct mutex mm_lock; + struct { + /** + * unbacked: + * + * The LRU for GEM objects without backing pages allocated. + * This mostly exists so that objects are always is one + * LRU. + */ + struct drm_gem_lru unbacked; + + /** + * pinned: + * + * The LRU for pinned GEM objects + */ + struct drm_gem_lru pinned; + + /** + * willneed: + * + * The LRU for unpinned GEM objects which are in madvise + * WILLNEED state (ie. can be evicted) + */ + struct drm_gem_lru willneed; + + /** + * dontneed: + * + * The LRU for unpinned GEM objects which are in madvise + * DONTNEED state (ie. can be purged) + */ + struct drm_gem_lru dontneed; + + /** + * lock: + * + * Protects manipulation of all of the LRUs. + */ + struct mutex lock; + } lru; struct workqueue_struct *wq; @@ -289,7 +323,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi); bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi); bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi); -struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi); +struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi); #else static inline void __init msm_dsi_register(void) { @@ -319,7 +353,7 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi) return false; } -static inline struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) +static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) { return NULL; } @@ -432,6 +466,8 @@ void __iomem *msm_ioremap_size(struct platform_device *pdev, const char *name, phys_addr_t *size); void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name); +struct icc_path *msm_icc_get(struct device *dev, const char *name); + #define msm_writel(data, addr) writel((data), (addr)) #define msm_readl(addr) readl((addr)) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 8ddbd2e001d4..1dee0d18abbb 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -19,7 +19,7 @@ #include "msm_gpu.h" #include "msm_mmu.h" -static void update_inactive(struct msm_gem_object *msm_obj); +static void update_lru(struct drm_gem_object *obj); static dma_addr_t physaddr(struct drm_gem_object *obj) { @@ -97,7 +97,7 @@ static struct page **get_pages(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); if (!msm_obj->pages) { struct drm_device *dev = obj->dev; @@ -132,7 +132,7 @@ static struct page **get_pages(struct drm_gem_object *obj) if (msm_obj->flags & MSM_BO_WC) sync_for_device(msm_obj); - update_inactive(msm_obj); + update_lru(obj); } return msm_obj->pages; @@ -174,40 +174,45 @@ static void put_pages(struct drm_gem_object *obj) put_pages_vram(obj); msm_obj->pages = NULL; + update_lru(obj); } } -struct page **msm_gem_get_pages(struct drm_gem_object *obj) +static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); struct page **p; - msm_gem_lock(obj); + msm_gem_assert_locked(obj); if (GEM_WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { - msm_gem_unlock(obj); return ERR_PTR(-EBUSY); } p = get_pages(obj); - if (!IS_ERR(p)) { - msm_obj->pin_count++; - update_inactive(msm_obj); + to_msm_bo(obj)->pin_count++; + update_lru(obj); } - msm_gem_unlock(obj); return p; } -void msm_gem_put_pages(struct drm_gem_object *obj) +struct page **msm_gem_pin_pages(struct drm_gem_object *obj) { - struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct page **p; msm_gem_lock(obj); - msm_obj->pin_count--; - GEM_WARN_ON(msm_obj->pin_count < 0); - update_inactive(msm_obj); + p = msm_gem_pin_pages_locked(obj); + msm_gem_unlock(obj); + + return p; +} + +void msm_gem_unpin_pages(struct drm_gem_object *obj) +{ + msm_gem_lock(obj); + msm_gem_unpin_locked(obj); msm_gem_unlock(obj); } @@ -273,7 +278,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj) struct drm_device *dev = obj->dev; int ret; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); /* Make it mmapable */ ret = drm_gem_create_mmap_offset(obj); @@ -302,7 +307,7 @@ static struct msm_gem_vma *add_vma(struct drm_gem_object *obj, struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_vma *vma; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); vma = kzalloc(sizeof(*vma), GFP_KERNEL); if (!vma) @@ -321,7 +326,7 @@ static struct msm_gem_vma *lookup_vma(struct drm_gem_object *obj, struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_vma *vma; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); list_for_each_entry(vma, &msm_obj->vmas, list) { if (vma->aspace == aspace) @@ -352,7 +357,7 @@ put_iova_spaces(struct drm_gem_object *obj, bool close) struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_vma *vma; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); list_for_each_entry(vma, &msm_obj->vmas, list) { if (vma->aspace) { @@ -370,7 +375,7 @@ put_iova_vmas(struct drm_gem_object *obj) struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_vma *vma, *tmp; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) { del_vma(vma); @@ -383,7 +388,7 @@ static struct msm_gem_vma *get_vma_locked(struct drm_gem_object *obj, { struct msm_gem_vma *vma; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); vma = lookup_vma(obj, aspace); @@ -423,19 +428,18 @@ int msm_gem_pin_vma_locked(struct drm_gem_object *obj, struct msm_gem_vma *vma) if (msm_obj->flags & MSM_BO_CACHED_COHERENT) prot |= IOMMU_CACHE; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); if (GEM_WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) return -EBUSY; - pages = get_pages(obj); + pages = msm_gem_pin_pages_locked(obj); if (IS_ERR(pages)) return PTR_ERR(pages); ret = msm_gem_map_vma(vma->aspace, vma, prot, msm_obj->sgt, obj->size); - - if (!ret) - msm_obj->pin_count++; + if (ret) + msm_gem_unpin_locked(obj); return ret; } @@ -444,12 +448,12 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); msm_obj->pin_count--; GEM_WARN_ON(msm_obj->pin_count < 0); - update_inactive(msm_obj); + update_lru(obj); } struct msm_gem_vma *msm_gem_get_vma_locked(struct drm_gem_object *obj, @@ -465,7 +469,7 @@ static int get_and_pin_iova_range_locked(struct drm_gem_object *obj, struct msm_gem_vma *vma; int ret; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); vma = get_vma_locked(obj, aspace, range_start, range_end); if (IS_ERR(vma)) @@ -626,7 +630,7 @@ static void *get_vaddr(struct drm_gem_object *obj, unsigned madv) struct msm_gem_object *msm_obj = to_msm_bo(obj); int ret = 0; - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); if (obj->import_attach) return ERR_PTR(-ENODEV); @@ -658,7 +662,7 @@ static void *get_vaddr(struct drm_gem_object *obj, unsigned madv) goto fail; } - update_inactive(msm_obj); + update_lru(obj); } return msm_obj->vaddr; @@ -699,7 +703,7 @@ void msm_gem_put_vaddr_locked(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); GEM_WARN_ON(msm_obj->vmap_count < 1); msm_obj->vmap_count--; @@ -729,8 +733,7 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) /* If the obj is inactive, we might need to move it * between inactive lists */ - if (msm_obj->active_count == 0) - update_inactive(msm_obj); + update_lru(obj); msm_gem_unlock(obj); @@ -742,7 +745,7 @@ void msm_gem_purge(struct drm_gem_object *obj) struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); GEM_WARN_ON(!is_purgeable(msm_obj)); /* Get rid of any iommu mapping(s): */ @@ -757,7 +760,6 @@ void msm_gem_purge(struct drm_gem_object *obj) put_iova_vmas(obj); msm_obj->madv = __MSM_MADV_PURGED; - update_inactive(msm_obj); drm_gem_free_mmap_offset(obj); @@ -780,10 +782,8 @@ void msm_gem_evict(struct drm_gem_object *obj) struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); GEM_WARN_ON(is_unevictable(msm_obj)); - GEM_WARN_ON(!msm_obj->evictable); - GEM_WARN_ON(msm_obj->active_count); /* Get rid of any iommu mapping(s): */ put_iova_spaces(obj, false); @@ -791,15 +791,13 @@ void msm_gem_evict(struct drm_gem_object *obj) drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); put_pages(obj); - - update_inactive(msm_obj); } void msm_gem_vunmap(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(obj); if (!msm_obj->vaddr || GEM_WARN_ON(!is_vunmapable(msm_obj))) return; @@ -808,66 +806,37 @@ void msm_gem_vunmap(struct drm_gem_object *obj) msm_obj->vaddr = NULL; } -void msm_gem_active_get(struct drm_gem_object *obj, struct msm_gpu *gpu) +static void update_lru(struct drm_gem_object *obj) { - struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_drm_private *priv = obj->dev->dev_private; - - might_sleep(); - GEM_WARN_ON(!msm_gem_is_locked(obj)); - GEM_WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED); - GEM_WARN_ON(msm_obj->dontneed); - - if (msm_obj->active_count++ == 0) { - mutex_lock(&priv->mm_lock); - if (msm_obj->evictable) - mark_unevictable(msm_obj); - list_move_tail(&msm_obj->mm_list, &gpu->active_list); - mutex_unlock(&priv->mm_lock); - } -} - -void msm_gem_active_put(struct drm_gem_object *obj) -{ struct msm_gem_object *msm_obj = to_msm_bo(obj); - might_sleep(); - GEM_WARN_ON(!msm_gem_is_locked(obj)); + msm_gem_assert_locked(&msm_obj->base); - if (--msm_obj->active_count == 0) { - update_inactive(msm_obj); + if (!msm_obj->pages) { + GEM_WARN_ON(msm_obj->pin_count); + GEM_WARN_ON(msm_obj->vmap_count); + + drm_gem_lru_move_tail(&priv->lru.unbacked, obj); + } else if (msm_obj->pin_count || msm_obj->vmap_count) { + drm_gem_lru_move_tail(&priv->lru.pinned, obj); + } else if (msm_obj->madv == MSM_MADV_WILLNEED) { + drm_gem_lru_move_tail(&priv->lru.willneed, obj); + } else { + GEM_WARN_ON(msm_obj->madv != MSM_MADV_DONTNEED); + + drm_gem_lru_move_tail(&priv->lru.dontneed, obj); } } -static void update_inactive(struct msm_gem_object *msm_obj) +bool msm_gem_active(struct drm_gem_object *obj) { - struct msm_drm_private *priv = msm_obj->base.dev->dev_private; - - GEM_WARN_ON(!msm_gem_is_locked(&msm_obj->base)); + msm_gem_assert_locked(obj); - if (msm_obj->active_count != 0) - return; - - mutex_lock(&priv->mm_lock); - - if (msm_obj->dontneed) - mark_unpurgeable(msm_obj); - if (msm_obj->evictable) - mark_unevictable(msm_obj); - - list_del(&msm_obj->mm_list); - if ((msm_obj->madv == MSM_MADV_WILLNEED) && msm_obj->sgt) { - list_add_tail(&msm_obj->mm_list, &priv->inactive_willneed); - mark_evictable(msm_obj); - } else if (msm_obj->madv == MSM_MADV_DONTNEED) { - list_add_tail(&msm_obj->mm_list, &priv->inactive_dontneed); - mark_purgeable(msm_obj); - } else { - GEM_WARN_ON((msm_obj->madv != __MSM_MADV_PURGED) && msm_obj->sgt); - list_add_tail(&msm_obj->mm_list, &priv->inactive_unpinned); - } + if (to_msm_bo(obj)->pin_count) + return true; - mutex_unlock(&priv->mm_lock); + return !dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(true)); } int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) @@ -910,7 +879,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m, stats->all.count++; stats->all.size += obj->size; - if (is_active(msm_obj)) { + if (msm_gem_active(obj)) { stats->active.count++; stats->active.size += obj->size; } @@ -938,7 +907,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m, } seq_printf(m, "%08x: %c %2d (%2d) %08llx %p", - msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', + msm_obj->flags, msm_gem_active(obj) ? 'A' : 'I', obj->name, kref_read(&obj->refcount), off, msm_obj->vaddr); @@ -1015,15 +984,6 @@ static void msm_gem_free_object(struct drm_gem_object *obj) list_del(&msm_obj->node); mutex_unlock(&priv->obj_lock); - mutex_lock(&priv->mm_lock); - if (msm_obj->dontneed) - mark_unpurgeable(msm_obj); - list_del(&msm_obj->mm_list); - mutex_unlock(&priv->mm_lock); - - /* object should not be on active list: */ - GEM_WARN_ON(is_active(msm_obj)); - put_iova_spaces(obj, true); if (obj->import_attach) { @@ -1183,13 +1143,6 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32 to_msm_bo(obj)->vram_node = &vma->node; - /* Call chain get_pages() -> update_inactive() tries to - * access msm_obj->mm_list, but it is not initialized yet. - * To avoid NULL pointer dereference error, initialize - * mm_list to be empty. - */ - INIT_LIST_HEAD(&msm_obj->mm_list); - msm_gem_lock(obj); pages = get_pages(obj); msm_gem_unlock(obj); @@ -1212,9 +1165,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32 mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER); } - mutex_lock(&priv->mm_lock); - list_add_tail(&msm_obj->mm_list, &priv->inactive_unpinned); - mutex_unlock(&priv->mm_lock); + drm_gem_lru_move_tail(&priv->lru.unbacked, obj); mutex_lock(&priv->obj_lock); list_add_tail(&msm_obj->node, &priv->objects); @@ -1270,9 +1221,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, msm_gem_unlock(obj); - mutex_lock(&priv->mm_lock); - list_add_tail(&msm_obj->mm_list, &priv->inactive_unpinned); - mutex_unlock(&priv->mm_lock); + drm_gem_lru_move_tail(&priv->lru.pinned, obj); mutex_lock(&priv->obj_lock); list_add_tail(&msm_obj->node, &priv->objects); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 432032ad4aed..c4844cf3a585 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -94,16 +94,6 @@ struct msm_gem_object { uint8_t madv; /** - * Is object on inactive_dontneed list (ie. counted in priv->shrinkable_count)? - */ - bool dontneed : 1; - - /** - * Is object evictable (ie. counted in priv->evictable_count)? - */ - bool evictable : 1; - - /** * count of active vmap'ing */ uint8_t vmap_count; @@ -114,17 +104,6 @@ struct msm_gem_object { */ struct list_head node; - /** - * An object is either: - * inactive - on priv->inactive_dontneed or priv->inactive_willneed - * (depending on purgeability status) - * active - on one one of the gpu's active_list.. well, at - * least for now we don't have (I don't think) hw sync between - * 2d and 3d one devices which have both, meaning we need to - * block on submit if a bo is already on other ring - */ - struct list_head mm_list; - struct page **pages; struct sg_table *sgt; void *vaddr; @@ -138,7 +117,6 @@ struct msm_gem_object { char name[32]; /* Identifier to print for the debugfs files */ - int active_count; int pin_count; }; #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) @@ -159,8 +137,8 @@ int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, struct msm_gem_address_space *aspace, uint64_t *iova); void msm_gem_unpin_iova(struct drm_gem_object *obj, struct msm_gem_address_space *aspace); -struct page **msm_gem_get_pages(struct drm_gem_object *obj); -void msm_gem_put_pages(struct drm_gem_object *obj); +struct page **msm_gem_pin_pages(struct drm_gem_object *obj); +void msm_gem_unpin_pages(struct drm_gem_object *obj); int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, @@ -171,8 +149,7 @@ void *msm_gem_get_vaddr_active(struct drm_gem_object *obj); void msm_gem_put_vaddr_locked(struct drm_gem_object *obj); void msm_gem_put_vaddr(struct drm_gem_object *obj); int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); -void msm_gem_active_get(struct drm_gem_object *obj, struct msm_gpu *gpu); -void msm_gem_active_put(struct drm_gem_object *obj); +bool msm_gem_active(struct drm_gem_object *obj); int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_fini(struct drm_gem_object *obj); int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, @@ -208,12 +185,6 @@ msm_gem_lock(struct drm_gem_object *obj) dma_resv_lock(obj->resv, NULL); } -static inline bool __must_check -msm_gem_trylock(struct drm_gem_object *obj) -{ - return dma_resv_trylock(obj->resv); -} - static inline int msm_gem_lock_interruptible(struct drm_gem_object *obj) { @@ -226,8 +197,8 @@ msm_gem_unlock(struct drm_gem_object *obj) dma_resv_unlock(obj->resv); } -static inline bool -msm_gem_is_locked(struct drm_gem_object *obj) +static inline void +msm_gem_assert_locked(struct drm_gem_object *obj) { /* * Destroying the object is a special case.. msm_gem_free_object() @@ -241,13 +212,10 @@ msm_gem_is_locked(struct drm_gem_object *obj) * Unfortunately lockdep is not aware of this detail. So when the * refcount drops to zero, we pretend it is already locked. */ - return dma_resv_is_locked(obj->resv) || (kref_read(&obj->refcount) == 0); -} - -static inline bool is_active(struct msm_gem_object *msm_obj) -{ - GEM_WARN_ON(!msm_gem_is_locked(&msm_obj->base)); - return msm_obj->active_count; + lockdep_assert_once( + (kref_read(&obj->refcount) == 0) || + (lockdep_is_held(&obj->resv->lock.base) != LOCK_STATE_NOT_HELD) + ); } /* imported/exported objects are not purgeable: */ @@ -264,81 +232,15 @@ static inline bool is_purgeable(struct msm_gem_object *msm_obj) static inline bool is_vunmapable(struct msm_gem_object *msm_obj) { - GEM_WARN_ON(!msm_gem_is_locked(&msm_obj->base)); + msm_gem_assert_locked(&msm_obj->base); return (msm_obj->vmap_count == 0) && msm_obj->vaddr; } -static inline void mark_purgeable(struct msm_gem_object *msm_obj) -{ - struct msm_drm_private *priv = msm_obj->base.dev->dev_private; - - GEM_WARN_ON(!mutex_is_locked(&priv->mm_lock)); - - if (is_unpurgeable(msm_obj)) - return; - - if (GEM_WARN_ON(msm_obj->dontneed)) - return; - - priv->shrinkable_count += msm_obj->base.size >> PAGE_SHIFT; - msm_obj->dontneed = true; -} - -static inline void mark_unpurgeable(struct msm_gem_object *msm_obj) -{ - struct msm_drm_private *priv = msm_obj->base.dev->dev_private; - - GEM_WARN_ON(!mutex_is_locked(&priv->mm_lock)); - - if (is_unpurgeable(msm_obj)) - return; - - if (GEM_WARN_ON(!msm_obj->dontneed)) - return; - - priv->shrinkable_count -= msm_obj->base.size >> PAGE_SHIFT; - GEM_WARN_ON(priv->shrinkable_count < 0); - msm_obj->dontneed = false; -} - static inline bool is_unevictable(struct msm_gem_object *msm_obj) { return is_unpurgeable(msm_obj) || msm_obj->vaddr; } -static inline void mark_evictable(struct msm_gem_object *msm_obj) -{ - struct msm_drm_private *priv = msm_obj->base.dev->dev_private; - - WARN_ON(!mutex_is_locked(&priv->mm_lock)); - - if (is_unevictable(msm_obj)) - return; - - if (WARN_ON(msm_obj->evictable)) - return; - - priv->evictable_count += msm_obj->base.size >> PAGE_SHIFT; - msm_obj->evictable = true; -} - -static inline void mark_unevictable(struct msm_gem_object *msm_obj) -{ - struct msm_drm_private *priv = msm_obj->base.dev->dev_private; - - WARN_ON(!mutex_is_locked(&priv->mm_lock)); - - if (is_unevictable(msm_obj)) - return; - - if (WARN_ON(!msm_obj->evictable)) - return; - - priv->evictable_count -= msm_obj->base.size >> PAGE_SHIFT; - WARN_ON(priv->evictable_count < 0); - msm_obj->evictable = false; -} - void msm_gem_purge(struct drm_gem_object *obj); void msm_gem_evict(struct drm_gem_object *obj); void msm_gem_vunmap(struct drm_gem_object *obj); @@ -390,9 +292,8 @@ struct msm_gem_submit { /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ #define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ #define BO_LOCKED 0x4000 /* obj lock is held */ -#define BO_ACTIVE 0x2000 /* active refcnt is held */ -#define BO_OBJ_PINNED 0x1000 /* obj (pages) is pinned and on active list */ -#define BO_VMA_PINNED 0x0800 /* vma (virtual address) is pinned */ +#define BO_OBJ_PINNED 0x2000 /* obj (pages) is pinned and on active list */ +#define BO_VMA_PINNED 0x1000 /* vma (virtual address) is pinned */ uint32_t flags; union { struct msm_gem_object *obj; diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index dcc8a573bc76..c1d91863df05 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -63,12 +63,12 @@ struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, int msm_gem_prime_pin(struct drm_gem_object *obj) { if (!obj->import_attach) - msm_gem_get_pages(obj); + msm_gem_pin_pages(obj); return 0; } void msm_gem_prime_unpin(struct drm_gem_object *obj) { if (!obj->import_attach) - msm_gem_put_pages(obj); + msm_gem_unpin_pages(obj); } diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 0317055e3253..1de14e67f96b 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -24,103 +24,77 @@ static bool can_swap(void) return enable_eviction && get_nr_swap_pages() > 0; } +static bool can_block(struct shrink_control *sc) +{ + if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) + return false; + return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); +} + static unsigned long msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) { struct msm_drm_private *priv = container_of(shrinker, struct msm_drm_private, shrinker); - unsigned count = priv->shrinkable_count; + unsigned count = priv->lru.dontneed.count; if (can_swap()) - count += priv->evictable_count; + count += priv->lru.willneed.count; return count; } static bool -purge(struct msm_gem_object *msm_obj) +purge(struct drm_gem_object *obj) { - if (!is_purgeable(msm_obj)) + if (!is_purgeable(to_msm_bo(obj))) return false; - /* - * This will move the obj out of still_in_list to - * the purged list - */ - msm_gem_purge(&msm_obj->base); + if (msm_gem_active(obj)) + return false; + + msm_gem_purge(obj); return true; } static bool -evict(struct msm_gem_object *msm_obj) +evict(struct drm_gem_object *obj) { - if (is_unevictable(msm_obj)) + if (is_unevictable(to_msm_bo(obj))) + return false; + + if (msm_gem_active(obj)) return false; - msm_gem_evict(&msm_obj->base); + msm_gem_evict(obj); return true; } -static unsigned long -scan(struct msm_drm_private *priv, unsigned nr_to_scan, struct list_head *list, - bool (*shrink)(struct msm_gem_object *msm_obj)) +static bool +wait_for_idle(struct drm_gem_object *obj) { - unsigned freed = 0; - struct list_head still_in_list; - - INIT_LIST_HEAD(&still_in_list); - - mutex_lock(&priv->mm_lock); - - while (freed < nr_to_scan) { - struct msm_gem_object *msm_obj = list_first_entry_or_null( - list, typeof(*msm_obj), mm_list); - - if (!msm_obj) - break; - - list_move_tail(&msm_obj->mm_list, &still_in_list); - - /* - * If it is in the process of being freed, msm_gem_free_object - * can be blocked on mm_lock waiting to remove it. So just - * skip it. - */ - if (!kref_get_unless_zero(&msm_obj->base.refcount)) - continue; - - /* - * Now that we own a reference, we can drop mm_lock for the - * rest of the loop body, to reduce contention with the - * retire_submit path (which could make more objects purgeable) - */ - - mutex_unlock(&priv->mm_lock); - - /* - * Note that this still needs to be trylock, since we can - * hit shrinker in response to trying to get backing pages - * for this obj (ie. while it's lock is already held) - */ - if (!msm_gem_trylock(&msm_obj->base)) - goto tail; - - if (shrink(msm_obj)) - freed += msm_obj->base.size >> PAGE_SHIFT; + enum dma_resv_usage usage = dma_resv_usage_rw(true); + return dma_resv_wait_timeout(obj->resv, usage, false, 1000) > 0; +} - msm_gem_unlock(&msm_obj->base); +static bool +active_purge(struct drm_gem_object *obj) +{ + if (!wait_for_idle(obj)) + return false; -tail: - drm_gem_object_put(&msm_obj->base); - mutex_lock(&priv->mm_lock); - } + return purge(obj); +} - list_splice_tail(&still_in_list, list); - mutex_unlock(&priv->mm_lock); +static bool +active_evict(struct drm_gem_object *obj) +{ + if (!wait_for_idle(obj)) + return false; - return freed; + return evict(obj); } static unsigned long @@ -128,21 +102,34 @@ msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) { struct msm_drm_private *priv = container_of(shrinker, struct msm_drm_private, shrinker); - unsigned long freed; - - freed = scan(priv, sc->nr_to_scan, &priv->inactive_dontneed, purge); - - if (freed > 0) - trace_msm_gem_purge(freed << PAGE_SHIFT); - - if (can_swap() && freed < sc->nr_to_scan) { - int evicted = scan(priv, sc->nr_to_scan - freed, - &priv->inactive_willneed, evict); + struct { + struct drm_gem_lru *lru; + bool (*shrink)(struct drm_gem_object *obj); + bool cond; + unsigned long freed; + } stages[] = { + /* Stages of progressively more aggressive/expensive reclaim: */ + { &priv->lru.dontneed, purge, true }, + { &priv->lru.willneed, evict, can_swap() }, + { &priv->lru.dontneed, active_purge, can_block(sc) }, + { &priv->lru.willneed, active_evict, can_swap() && can_block(sc) }, + }; + long nr = sc->nr_to_scan; + unsigned long freed = 0; - if (evicted > 0) - trace_msm_gem_evict(evicted << PAGE_SHIFT); + for (unsigned i = 0; (nr > 0) && (i < ARRAY_SIZE(stages)); i++) { + if (!stages[i].cond) + continue; + stages[i].freed = + drm_gem_lru_scan(stages[i].lru, nr, stages[i].shrink); + nr -= stages[i].freed; + freed += stages[i].freed; + } - freed += evicted; + if (freed) { + trace_msm_gem_shrink(sc->nr_to_scan, stages[0].freed, + stages[1].freed, stages[2].freed, + stages[3].freed); } return (freed > 0) ? freed : SHRINK_STOP; @@ -173,12 +160,12 @@ msm_gem_shrinker_shrink(struct drm_device *dev, unsigned long nr_to_scan) static const int vmap_shrink_limit = 15; static bool -vmap_shrink(struct msm_gem_object *msm_obj) +vmap_shrink(struct drm_gem_object *obj) { - if (!is_vunmapable(msm_obj)) + if (!is_vunmapable(to_msm_bo(obj))) return false; - msm_gem_vunmap(&msm_obj->base); + msm_gem_vunmap(obj); return true; } @@ -188,17 +175,18 @@ msm_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr) { struct msm_drm_private *priv = container_of(nb, struct msm_drm_private, vmap_notifier); - struct list_head *mm_lists[] = { - &priv->inactive_dontneed, - &priv->inactive_willneed, - priv->gpu ? &priv->gpu->active_list : NULL, + struct drm_gem_lru *lrus[] = { + &priv->lru.dontneed, + &priv->lru.willneed, + &priv->lru.pinned, NULL, }; unsigned idx, unmapped = 0; - for (idx = 0; mm_lists[idx] && unmapped < vmap_shrink_limit; idx++) { - unmapped += scan(priv, vmap_shrink_limit - unmapped, - mm_lists[idx], vmap_shrink); + for (idx = 0; lrus[idx] && unmapped < vmap_shrink_limit; idx++) { + unmapped += drm_gem_lru_scan(lrus[idx], + vmap_shrink_limit - unmapped, + vmap_shrink); } *(unsigned long *)ptr += unmapped; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index c9e4aeb14f4a..5599d93ec0d2 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -26,6 +26,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, struct msm_gpu_submitqueue *queue, uint32_t nr_bos, uint32_t nr_cmds) { + static atomic_t ident = ATOMIC_INIT(0); struct msm_gem_submit *submit; uint64_t sz; int ret; @@ -36,7 +37,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, if (sz > SIZE_MAX) return ERR_PTR(-ENOMEM); - submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + submit = kzalloc(sz, GFP_KERNEL); if (!submit) return ERR_PTR(-ENOMEM); @@ -52,9 +53,13 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit->gpu = gpu; submit->cmd = (void *)&submit->bos[nr_bos]; submit->queue = queue; + submit->pid = get_pid(task_pid(current)); submit->ring = gpu->rb[queue->ring_nr]; submit->fault_dumped = false; + /* Get a unique identifier for the submission for logging purposes */ + submit->ident = atomic_inc_return(&ident) - 1; + INIT_LIST_HEAD(&submit->node); return submit; @@ -67,9 +72,9 @@ void __msm_gem_submit_destroy(struct kref *kref) unsigned i; if (submit->fence_id) { - mutex_lock(&submit->queue->lock); + mutex_lock(&submit->queue->idr_lock); idr_remove(&submit->queue->fence_idr, submit->fence_id); - mutex_unlock(&submit->queue->lock); + mutex_unlock(&submit->queue->idr_lock); } dma_fence_put(submit->user_fence); @@ -238,17 +243,13 @@ static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, if (flags & BO_OBJ_PINNED) msm_gem_unpin_locked(obj); - if (flags & BO_ACTIVE) - msm_gem_active_put(obj); - if (flags & BO_LOCKED) dma_resv_unlock(obj->resv); } static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) { - unsigned cleanup_flags = BO_VMA_PINNED | BO_OBJ_PINNED | - BO_ACTIVE | BO_LOCKED; + unsigned cleanup_flags = BO_VMA_PINNED | BO_OBJ_PINNED | BO_LOCKED; submit_cleanup_bo(submit, i, cleanup_flags); if (!(submit->bos[i].flags & BO_VALID)) @@ -353,18 +354,6 @@ static int submit_pin_objects(struct msm_gem_submit *submit) submit->valid = true; - /* - * Increment active_count first, so if under memory pressure, we - * don't inadvertently evict a bo needed by the submit in order - * to pin an earlier bo in the same submit. - */ - for (i = 0; i < submit->nr_bos; i++) { - struct drm_gem_object *obj = &submit->bos[i].obj->base; - - msm_gem_active_get(obj, submit->gpu); - submit->bos[i].flags |= BO_ACTIVE; - } - for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = &submit->bos[i].obj->base; struct msm_gem_vma *vma; @@ -512,11 +501,11 @@ out: */ static void submit_cleanup(struct msm_gem_submit *submit, bool error) { - unsigned cleanup_flags = BO_LOCKED; + unsigned cleanup_flags = BO_LOCKED | BO_OBJ_PINNED; unsigned i; if (error) - cleanup_flags |= BO_VMA_PINNED | BO_OBJ_PINNED | BO_ACTIVE; + cleanup_flags |= BO_VMA_PINNED; for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; @@ -533,10 +522,6 @@ void msm_submit_retire(struct msm_gem_submit *submit) for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = &submit->bos[i].obj->base; - msm_gem_lock(obj); - /* Note, VMA already fence-unpinned before submit: */ - submit_cleanup_bo(submit, i, BO_OBJ_PINNED | BO_ACTIVE); - msm_gem_unlock(obj); drm_gem_object_put(obj); } } @@ -718,7 +703,6 @@ static void msm_process_post_deps(struct msm_submit_post_dep *post_deps, int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) { - static atomic_t ident = ATOMIC_INIT(0); struct msm_drm_private *priv = dev->dev_private; struct drm_msm_gem_submit *args = data; struct msm_file_private *ctx = file->driver_priv; @@ -729,10 +713,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_submit_post_dep *post_deps = NULL; struct drm_syncobj **syncobjs_to_reset = NULL; int out_fence_fd = -1; - struct pid *pid = get_pid(task_pid(current)); bool has_ww_ticket = false; unsigned i; - int ret, submitid; + int ret; if (!gpu) return -ENXIO; @@ -764,35 +747,26 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (!queue) return -ENOENT; - /* Get a unique identifier for the submission for logging purposes */ - submitid = atomic_inc_return(&ident) - 1; - ring = gpu->rb[queue->ring_nr]; - trace_msm_gpu_submit(pid_nr(pid), ring->id, submitid, - args->nr_bos, args->nr_cmds); - - ret = mutex_lock_interruptible(&queue->lock); - if (ret) - goto out_post_unlock; if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) { out_fence_fd = get_unused_fd_flags(O_CLOEXEC); if (out_fence_fd < 0) { ret = out_fence_fd; - goto out_unlock; + return ret; } } - submit = submit_create(dev, gpu, queue, args->nr_bos, - args->nr_cmds); - if (IS_ERR(submit)) { - ret = PTR_ERR(submit); - submit = NULL; - goto out_unlock; - } + submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds); + if (IS_ERR(submit)) + return PTR_ERR(submit); + + trace_msm_gpu_submit(pid_nr(submit->pid), ring->id, submit->ident, + args->nr_bos, args->nr_cmds); - submit->pid = pid; - submit->ident = submitid; + ret = mutex_lock_interruptible(&queue->lock); + if (ret) + goto out_post_unlock; if (args->flags & MSM_SUBMIT_SUDO) submit->in_rb = true; @@ -887,6 +861,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit->nr_cmds = i; + mutex_lock(&queue->idr_lock); + /* * If using userspace provided seqno fence, validate that the id * is available before arming sched job. Since access to fence_idr @@ -895,6 +871,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, */ if ((args->flags & MSM_SUBMIT_FENCE_SN_IN) && idr_find(&queue->fence_idr, args->fence)) { + mutex_unlock(&queue->idr_lock); ret = -EINVAL; goto out; } @@ -927,6 +904,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit->user_fence, 1, INT_MAX, GFP_KERNEL); } + + mutex_unlock(&queue->idr_lock); + if (submit->fence_id < 0) { ret = submit->fence_id; submit->fence_id = 0; @@ -965,9 +945,9 @@ out_unlock: if (ret && (out_fence_fd >= 0)) put_unused_fd(out_fence_fd); mutex_unlock(&queue->lock); +out_post_unlock: if (submit) msm_gem_submit_put(submit); -out_post_unlock: if (!IS_ERR_OR_NULL(post_deps)) { for (i = 0; i < args->nr_out_syncobjs; ++i) { kfree(post_deps[i].chain); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c2bfcf3f1f40..0098ee8438aa 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -16,6 +16,7 @@ #include <generated/utsrelease.h> #include <linux/string_helpers.h> #include <linux/devcoredump.h> +#include <linux/reset.h> #include <linux/sched/task.h> /* @@ -394,7 +395,6 @@ static void recover_worker(struct kthread_work *work) /* Record the crash state */ pm_runtime_get_sync(&gpu->pdev->dev); msm_gpu_crashstate_capture(gpu, submit, comm, cmd); - pm_runtime_put_sync(&gpu->pdev->dev); kfree(cmd); kfree(comm); @@ -423,9 +423,7 @@ static void recover_worker(struct kthread_work *work) /* retire completed submits, plus the one that hung: */ retire_submits(gpu); - pm_runtime_get_sync(&gpu->pdev->dev); gpu->funcs->recover(gpu); - pm_runtime_put_sync(&gpu->pdev->dev); /* * Replay all remaining submits starting with highest priority @@ -442,6 +440,8 @@ static void recover_worker(struct kthread_work *work) } } + pm_runtime_put(&gpu->pdev->dev); + mutex_unlock(&gpu->lock); msm_gpu_retire(gpu); @@ -664,11 +664,12 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring, mutex_lock(&gpu->active_lock); gpu->active_submits--; WARN_ON(gpu->active_submits < 0); - if (!gpu->active_submits) + if (!gpu->active_submits) { msm_devfreq_idle(gpu); - mutex_unlock(&gpu->active_lock); + pm_runtime_put_autosuspend(&gpu->pdev->dev); + } - pm_runtime_put_autosuspend(&gpu->pdev->dev); + mutex_unlock(&gpu->active_lock); msm_gem_submit_put(submit); } @@ -757,14 +758,17 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* Update devfreq on transition from idle->active: */ mutex_lock(&gpu->active_lock); - if (!gpu->active_submits) + if (!gpu->active_submits) { + pm_runtime_get(&gpu->pdev->dev); msm_devfreq_active(gpu); + } gpu->active_submits++; mutex_unlock(&gpu->active_lock); gpu->funcs->submit(gpu, submit); gpu->cur_ctx_seqno = submit->queue->ctx->seqno; + pm_runtime_put(&gpu->pdev->dev); hangcheck_timer_reset(gpu); } @@ -846,7 +850,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, sched_set_fifo_low(gpu->worker->task); - INIT_LIST_HEAD(&gpu->active_list); mutex_init(&gpu->active_lock); mutex_init(&gpu->lock); init_waitqueue_head(&gpu->retire_event); @@ -901,6 +904,9 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (IS_ERR(gpu->gpu_cx)) gpu->gpu_cx = NULL; + gpu->cx_collapse = devm_reset_control_get_optional_exclusive(&pdev->dev, + "cx_collapse"); + gpu->pdev = pdev; platform_set_drvdata(pdev, &gpu->adreno_smmu); @@ -974,8 +980,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) DBG("%s", gpu->name); - WARN_ON(!list_empty(&gpu->active_list)); - for (i = 0; i < ARRAY_SIZE(gpu->rb); i++) { msm_ringbuffer_destroy(gpu->rb[i]); gpu->rb[i] = NULL; diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 4d935fedd2ac..ff911e7305ce 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -13,6 +13,7 @@ #include <linux/interconnect.h> #include <linux/pm_opp.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include "msm_drv.h" #include "msm_fence.h" @@ -187,12 +188,6 @@ struct msm_gpu { */ int cur_ctx_seqno; - /* - * List of GEM active objects on this gpu. Protected by - * msm_drm_private::mm_lock - */ - struct list_head active_list; - /** * lock: * @@ -277,6 +272,9 @@ struct msm_gpu { bool hw_apriv; struct thermal_cooling_device *cooling; + + /* To poll for cx gdsc collapse during gpu recovery */ + struct reset_control *cx_collapse; }; static inline struct msm_gpu *dev_to_gpu(struct device *dev) @@ -466,7 +464,8 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, * @node: node in the context's list of submitqueues * @fence_idr: maps fence-id to dma_fence for userspace visible fence * seqno, protected by submitqueue lock - * @lock: submitqueue lock + * @idr_lock: for serializing access to fence_idr + * @lock: submitqueue lock for serializing submits on a queue * @ref: reference count * @entity: the submit job-queue */ @@ -479,6 +478,7 @@ struct msm_gpu_submitqueue { struct msm_file_private *ctx; struct list_head node; struct idr fence_idr; + struct mutex idr_lock; struct mutex lock; struct kref ref; struct drm_sched_entity *entity; diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index d1f70426f554..85c443a37e4e 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -213,6 +213,8 @@ void msm_devfreq_init(struct msm_gpu *gpu) if (IS_ERR(df->devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); + dev_pm_qos_remove_request(&df->idle_freq); + dev_pm_qos_remove_request(&df->boost_freq); df->devfreq = NULL; return; } diff --git a/drivers/gpu/drm/msm/msm_gpu_trace.h b/drivers/gpu/drm/msm/msm_gpu_trace.h index ca0b08d7875b..ac40d857bc45 100644 --- a/drivers/gpu/drm/msm/msm_gpu_trace.h +++ b/drivers/gpu/drm/msm/msm_gpu_trace.h @@ -115,29 +115,27 @@ TRACE_EVENT(msm_gmu_freq_change, ); -TRACE_EVENT(msm_gem_purge, - TP_PROTO(u32 bytes), - TP_ARGS(bytes), +TRACE_EVENT(msm_gem_shrink, + TP_PROTO(u32 nr_to_scan, u32 purged, u32 evicted, + u32 active_purged, u32 active_evicted), + TP_ARGS(nr_to_scan, purged, evicted, active_purged, active_evicted), TP_STRUCT__entry( - __field(u32, bytes) + __field(u32, nr_to_scan) + __field(u32, purged) + __field(u32, evicted) + __field(u32, active_purged) + __field(u32, active_evicted) ), TP_fast_assign( - __entry->bytes = bytes; + __entry->nr_to_scan = nr_to_scan; + __entry->purged = purged; + __entry->evicted = evicted; + __entry->active_purged = active_purged; + __entry->active_evicted = active_evicted; ), - TP_printk("Purging %u bytes", __entry->bytes) -); - - -TRACE_EVENT(msm_gem_evict, - TP_PROTO(u32 bytes), - TP_ARGS(bytes), - TP_STRUCT__entry( - __field(u32, bytes) - ), - TP_fast_assign( - __entry->bytes = bytes; - ), - TP_printk("Evicting %u bytes", __entry->bytes) + TP_printk("nr_to_scan=%u pg, purged=%u pg, evicted=%u pg, active_purged=%u pg, active_evicted=%u pg", + __entry->nr_to_scan, __entry->purged, __entry->evicted, + __entry->active_purged, __entry->active_evicted) ); diff --git a/drivers/gpu/drm/msm/msm_io_utils.c b/drivers/gpu/drm/msm/msm_io_utils.c index 7b504617833a..d02cd29ce829 100644 --- a/drivers/gpu/drm/msm/msm_io_utils.c +++ b/drivers/gpu/drm/msm/msm_io_utils.c @@ -5,6 +5,8 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/interconnect.h> + #include "msm_drv.h" /* @@ -124,3 +126,23 @@ void msm_hrtimer_work_init(struct msm_hrtimer_work *work, work->worker = worker; kthread_init_work(&work->work, fn); } + +struct icc_path *msm_icc_get(struct device *dev, const char *name) +{ + struct device *mdss_dev = dev->parent; + struct icc_path *path; + + path = of_icc_get(dev, name); + if (path) + return path; + + /* + * If there are no interconnects attached to the corresponding device + * node, of_icc_get() will return NULL. + * + * If the MDP5/DPU device node doesn't have interconnects, lookup the + * path in the parent (MDSS) device. + */ + return of_icc_get(mdss_dev, name); + +} diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index a54ed354578b..5577cea7c009 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -21,6 +21,7 @@ struct msm_iommu_pagetable { struct msm_mmu base; struct msm_mmu *parent; struct io_pgtable_ops *pgtbl_ops; + unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ phys_addr_t ttbr; u32 asid; }; @@ -29,23 +30,84 @@ static struct msm_iommu_pagetable *to_pagetable(struct msm_mmu *mmu) return container_of(mmu, struct msm_iommu_pagetable, base); } +/* based on iommu_pgsize() in iommu.c: */ +static size_t calc_pgsize(struct msm_iommu_pagetable *pagetable, + unsigned long iova, phys_addr_t paddr, + size_t size, size_t *count) +{ + unsigned int pgsize_idx, pgsize_idx_next; + unsigned long pgsizes; + size_t offset, pgsize, pgsize_next; + unsigned long addr_merge = paddr | iova; + + /* Page sizes supported by the hardware and small enough for @size */ + pgsizes = pagetable->pgsize_bitmap & GENMASK(__fls(size), 0); + + /* Constrain the page sizes further based on the maximum alignment */ + if (likely(addr_merge)) + pgsizes &= GENMASK(__ffs(addr_merge), 0); + + /* Make sure we have at least one suitable page size */ + BUG_ON(!pgsizes); + + /* Pick the biggest page size remaining */ + pgsize_idx = __fls(pgsizes); + pgsize = BIT(pgsize_idx); + if (!count) + return pgsize; + + /* Find the next biggest support page size, if it exists */ + pgsizes = pagetable->pgsize_bitmap & ~GENMASK(pgsize_idx, 0); + if (!pgsizes) + goto out_set_count; + + pgsize_idx_next = __ffs(pgsizes); + pgsize_next = BIT(pgsize_idx_next); + + /* + * There's no point trying a bigger page size unless the virtual + * and physical addresses are similarly offset within the larger page. + */ + if ((iova ^ paddr) & (pgsize_next - 1)) + goto out_set_count; + + /* Calculate the offset to the next page size alignment boundary */ + offset = pgsize_next - (addr_merge & (pgsize_next - 1)); + + /* + * If size is big enough to accommodate the larger page, reduce + * the number of smaller pages. + */ + if (offset + pgsize_next <= size) + size = offset; + +out_set_count: + *count = size >> pgsize_idx; + return pgsize; +} + static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova, size_t size) { struct msm_iommu_pagetable *pagetable = to_pagetable(mmu); struct io_pgtable_ops *ops = pagetable->pgtbl_ops; - size_t unmapped = 0; - /* Unmap the block one page at a time */ while (size) { - unmapped += ops->unmap(ops, iova, 4096, NULL); - iova += 4096; - size -= 4096; + size_t unmapped, pgsize, count; + + pgsize = calc_pgsize(pagetable, iova, iova, size, &count); + + unmapped = ops->unmap_pages(ops, iova, pgsize, count, NULL); + if (!unmapped) + break; + + iova += unmapped; + size -= unmapped; } iommu_flush_iotlb_all(to_msm_iommu(pagetable->parent)->domain); - return (unmapped == size) ? 0 : -EINVAL; + return (size == 0) ? 0 : -EINVAL; } static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova, @@ -54,7 +116,6 @@ static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova, struct msm_iommu_pagetable *pagetable = to_pagetable(mmu); struct io_pgtable_ops *ops = pagetable->pgtbl_ops; struct scatterlist *sg; - size_t mapped = 0; u64 addr = iova; unsigned int i; @@ -62,17 +123,26 @@ static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova, size_t size = sg->length; phys_addr_t phys = sg_phys(sg); - /* Map the block one page at a time */ while (size) { - if (ops->map(ops, addr, phys, 4096, prot, GFP_KERNEL)) { - msm_iommu_pagetable_unmap(mmu, iova, mapped); + size_t pgsize, count, mapped = 0; + int ret; + + pgsize = calc_pgsize(pagetable, addr, phys, size, &count); + + ret = ops->map_pages(ops, addr, phys, pgsize, count, + prot, GFP_KERNEL, &mapped); + + /* map_pages could fail after mapping some of the pages, + * so update the counters before error handling. + */ + phys += mapped; + addr += mapped; + size -= mapped; + + if (ret) { + msm_iommu_pagetable_unmap(mmu, iova, addr - iova); return -EINVAL; } - - phys += 4096; - addr += 4096; - size -= 4096; - mapped += 4096; } } @@ -207,6 +277,7 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) /* Needed later for TLB flush */ pagetable->parent = parent; + pagetable->pgsize_bitmap = ttbr0_cfg.pgsize_bitmap; pagetable->ttbr = ttbr0_cfg.arm_lpae_s1_cfg.ttbr; /* diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index a92ffde53f0b..db2f847c8535 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -196,6 +196,9 @@ static int rd_open(struct inode *inode, struct file *file) file->private_data = rd; rd->open = true; + /* Reset fifo to clear any previously unread data: */ + rd->fifo.head = rd->fifo.tail = 0; + /* the parsing tools need to know gpu-id to know which * register database to load. * diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 56eecb4a72dc..cad4c3525f0b 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -29,8 +29,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) msm_gem_unlock(obj); } - pm_runtime_get_sync(&gpu->pdev->dev); - /* TODO move submit path over to using a per-ring lock.. */ mutex_lock(&gpu->lock); @@ -38,8 +36,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) mutex_unlock(&gpu->lock); - pm_runtime_put(&gpu->pdev->dev); - return dma_fence_get(submit->hw_fence); } diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c index f486a3cd4e55..c6929e205b51 100644 --- a/drivers/gpu/drm/msm/msm_submitqueue.c +++ b/drivers/gpu/drm/msm/msm_submitqueue.c @@ -200,6 +200,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx, *id = queue->id; idr_init(&queue->fence_idr); + mutex_init(&queue->idr_lock); mutex_init(&queue->lock); list_add_tail(&queue->node, &ctx->submitqueues); diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 660c4cbc0b3d..ee92d576d277 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1276,37 +1276,9 @@ static const uint32_t modeset_formats[] = { }; static const struct drm_plane_funcs nv04_primary_plane_funcs = { - .update_plane = drm_plane_helper_update_primary, - .disable_plane = drm_plane_helper_disable_primary, - .destroy = drm_plane_helper_destroy, + DRM_PLANE_NON_ATOMIC_FUNCS, }; -static struct drm_plane * -create_primary_plane(struct drm_device *dev) -{ - struct drm_plane *primary; - int ret; - - primary = kzalloc(sizeof(*primary), GFP_KERNEL); - if (primary == NULL) { - DRM_DEBUG_KMS("Failed to allocate primary plane\n"); - return NULL; - } - - /* possible_crtc's will be filled in later by crtc_init */ - ret = drm_universal_plane_init(dev, primary, 0, - &nv04_primary_plane_funcs, - modeset_formats, - ARRAY_SIZE(modeset_formats), NULL, - DRM_PLANE_TYPE_PRIMARY, NULL); - if (ret) { - kfree(primary); - primary = NULL; - } - - return primary; -} - static int nv04_crtc_vblank_handler(struct nvif_notify *notify) { struct nouveau_crtc *nv_crtc = @@ -1321,6 +1293,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) { struct nouveau_display *disp = nouveau_display(dev); struct nouveau_crtc *nv_crtc; + struct drm_plane *primary; int ret; nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); @@ -1335,8 +1308,18 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) nv_crtc->save = nv_crtc_save; nv_crtc->restore = nv_crtc_restore; - drm_crtc_init_with_planes(dev, &nv_crtc->base, - create_primary_plane(dev), NULL, + primary = __drm_universal_plane_alloc(dev, sizeof(*primary), 0, 0, + &nv04_primary_plane_funcs, + modeset_formats, + ARRAY_SIZE(modeset_formats), NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (IS_ERR(primary)) { + ret = PTR_ERR(primary); + kfree(nv_crtc); + return ret; + } + + drm_crtc_init_with_planes(dev, &nv_crtc->base, primary, NULL, &nv04_crtc_funcs, NULL); drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 37e63e98cd08..33f29736024a 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -296,9 +296,10 @@ nv10_overlay_init(struct drm_device *device) break; } - ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, - &nv10_plane_funcs, - formats, num_formats, false); + ret = drm_universal_plane_init(device, &plane->base, 3 /* both crtc's */, + &nv10_plane_funcs, + formats, num_formats, NULL, + DRM_PLANE_TYPE_OVERLAY, NULL); if (ret) goto err; @@ -475,9 +476,9 @@ nv04_overlay_init(struct drm_device *device) if (!plane) return; - ret = drm_plane_init(device, &plane->base, 1 /* single crtc */, - &nv04_plane_funcs, - formats, 2, false); + ret = drm_universal_plane_init(device, &plane->base, 1 /* single crtc */, + &nv04_plane_funcs, formats, 2, NULL, + DRM_PLANE_TYPE_OVERLAY, NULL); if (ret) goto err; diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 6140db756d06..8cf096f841a9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -386,3 +386,13 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) return kmemdup(edid, EDID_LENGTH, GFP_KERNEL); } + +bool nouveau_acpi_video_backlight_use_native(void) +{ + return acpi_video_backlight_use_native(); +} + +void nouveau_acpi_video_register_backlight(void) +{ + acpi_video_register_backlight(); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h b/drivers/gpu/drm/nouveau/nouveau_acpi.h index 330f9b837066..e39dd8b94b8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.h +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h @@ -11,6 +11,8 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); void nouveau_switcheroo_optimus_dsm(void); void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *); +bool nouveau_acpi_video_backlight_use_native(void); +void nouveau_acpi_video_register_backlight(void); #else static inline bool nouveau_is_optimus(void) { return false; }; static inline bool nouveau_is_v1_dsm(void) { return false; }; @@ -18,6 +20,8 @@ static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} static inline void nouveau_switcheroo_optimus_dsm(void) {} static inline void *nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return NULL; } +static inline bool nouveau_acpi_video_backlight_use_native(void) { return true; } +static inline void nouveau_acpi_video_register_backlight(void) {} #endif #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index a2141d3d9b1d..a614582779ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -38,6 +38,7 @@ #include "nouveau_reg.h" #include "nouveau_encoder.h" #include "nouveau_connector.h" +#include "nouveau_acpi.h" static struct ida bl_ida; #define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0' @@ -405,6 +406,11 @@ nouveau_backlight_init(struct drm_connector *connector) goto fail_alloc; } + if (!nouveau_acpi_video_backlight_use_native()) { + NV_INFO(drm, "Skipping nv_backlight registration\n"); + goto fail_alloc; + } + if (!nouveau_get_backlight_name(backlight_name, bl)) { NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); goto fail_alloc; @@ -430,6 +436,13 @@ nouveau_backlight_init(struct drm_connector *connector) fail_alloc: kfree(bl); + /* + * If we get here we have an internal panel, but no nv_backlight, + * try registering an ACPI video backlight device instead. + */ + if (ret == 0) + nouveau_acpi_video_register_backlight(); + return ret; } diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index c4de142cc85b..0ee344ebcd1c 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2451,7 +2451,7 @@ static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc, *decim_x = DIV_ROUND_UP(width, in_width_max); - *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; + *decim_x = max(*decim_x, decim_x_min); if (*decim_x > *x_predecim) return -EINVAL; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 0399f3390a0a..c4febb861910 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1176,6 +1176,7 @@ static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports) default: break; } + of_node_put(port); } } @@ -1208,11 +1209,13 @@ static int dss_init_ports(struct dss_device *dss) default: break; } + of_node_put(port); } return 0; error: + of_node_put(port); __dss_uninit_ports(dss, i); return r; } diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index ac869acf80ea..61a27dd7392e 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -813,10 +813,8 @@ static int omap_dmm_probe(struct platform_device *dev) } omap_dmm->irq = platform_get_irq(dev, 0); - if (omap_dmm->irq < 0) { - dev_err(&dev->dev, "failed to get IRQ resource\n"); + if (omap_dmm->irq < 0) goto fail; - } omap_dmm->dev = &dev->dev; diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 060f4f98bc04..4b546b02d3ae 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -403,17 +403,10 @@ static int panel_edp_unprepare(struct drm_panel *panel) static int panel_edp_get_hpd_gpio(struct device *dev, struct panel_edp *p) { - int err; - p->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); - if (IS_ERR(p->hpd_gpio)) { - err = PTR_ERR(p->hpd_gpio); - - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get 'hpd' GPIO: %d\n", err); - - return err; - } + if (IS_ERR(p->hpd_gpio)) + return dev_err_probe(dev, PTR_ERR(p->hpd_gpio), + "failed to get 'hpd' GPIO\n"); return 0; } @@ -832,12 +825,9 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(panel->enable_gpio)) { - err = PTR_ERR(panel->enable_gpio); - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to request GPIO: %d\n", err); - return err; - } + if (IS_ERR(panel->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(panel->enable_gpio), + "failed to request GPIO\n"); err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); if (err) { @@ -1878,6 +1868,7 @@ static const struct panel_delay delay_200_500_e200 = { static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), @@ -1885,10 +1876,15 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index 7da09e34385d..39dc40cf681f 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -576,6 +576,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = ili9341_dbi_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index edd5a0c35437..252fd66011cc 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -575,12 +575,9 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(panel->enable_gpio)) { - err = PTR_ERR(panel->enable_gpio); - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to request GPIO: %d\n", err); - return err; - } + if (IS_ERR(panel->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(panel->enable_gpio), + "failed to request GPIO\n"); err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); if (err) { @@ -2701,6 +2698,36 @@ static const struct panel_desc multi_inno_mi0700s4t_6 = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct display_timing multi_inno_mi0800ft_9_timing = { + .pixelclock = { 32000000, 40000000, 50000000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 16, 210, 354 }, + .hback_porch = { 6, 26, 45 }, + .hsync_len = { 1, 20, 40 }, + .vactive = { 600, 600, 600 }, + .vfront_porch = { 1, 12, 77 }, + .vback_porch = { 3, 13, 22 }, + .vsync_len = { 1, 10, 20 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, +}; + +static const struct panel_desc multi_inno_mi0800ft_9 = { + .timings = &multi_inno_mi0800ft_9_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 162, + .height = 122, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct display_timing multi_inno_mi1010ait_1cp_timing = { .pixelclock = { 68900000, 70000000, 73400000 }, .hactive = { 1280, 1280, 1280 }, @@ -4133,6 +4160,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "multi-inno,mi0700s4t-6", .data = &multi_inno_mi0700s4t_6, }, { + .compatible = "multi-inno,mi0800ft-9", + .data = &multi_inno_mi0800ft_9, + }, { .compatible = "multi-inno,mi1010ait-1cp", .data = &multi_inno_mi1010ait_1cp, }, { diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 7b00c955cd82..63aa96a69752 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -53,17 +53,11 @@ void qxl_ring_free(struct qxl_ring *ring) kfree(ring); } -void qxl_ring_init_hdr(struct qxl_ring *ring) -{ - ring->ring->header.notify_on_prod = ring->n_elements; -} - struct qxl_ring * qxl_ring_create(struct qxl_ring_header *header, int element_size, int n_elements, int prod_notify, - bool set_prod_notify, wait_queue_head_t *push_event) { struct qxl_ring *ring; @@ -77,8 +71,6 @@ qxl_ring_create(struct qxl_ring_header *header, ring->n_elements = n_elements; ring->prod_notify = prod_notify; ring->push_event = push_event; - if (set_prod_notify) - qxl_ring_init_hdr(ring); spin_lock_init(&ring->lock); return ring; } diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 47c169673088..432758ad39a3 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -277,10 +277,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, int element_size, int n_elements, int prod_notify, - bool set_prod_notify, wait_queue_head_t *push_event); void qxl_ring_free(struct qxl_ring *ring); -void qxl_ring_init_hdr(struct qxl_ring *ring); int qxl_check_idle(struct qxl_ring *ring); static inline uint64_t diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 9bf6d4cc98d4..dc3828db1991 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -194,7 +194,6 @@ int qxl_device_init(struct qxl_device *qdev, sizeof(struct qxl_command), QXL_COMMAND_RING_SIZE, qdev->io_base + QXL_IO_NOTIFY_CMD, - false, &qdev->display_event); if (!qdev->command_ring) { DRM_ERROR("Unable to create command ring\n"); @@ -207,7 +206,6 @@ int qxl_device_init(struct qxl_device *qdev, sizeof(struct qxl_command), QXL_CURSOR_RING_SIZE, qdev->io_base + QXL_IO_NOTIFY_CURSOR, - false, &qdev->cursor_event); if (!qdev->cursor_ring) { @@ -219,7 +217,7 @@ int qxl_device_init(struct qxl_device *qdev, qdev->release_ring = qxl_ring_create( &(qdev->ram_header->release_ring_hdr), sizeof(uint64_t), - QXL_RELEASE_RING_SIZE, 0, true, + QXL_RELEASE_RING_SIZE, 0, NULL); if (!qdev->release_ring) { diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 0eae05dfb385..c841c273222e 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -32,6 +32,8 @@ #include <drm/drm_file.h> #include <drm/radeon_drm.h> +#include <acpi/video.h> + #include "atom.h" #include "radeon_atombios.h" #include "radeon.h" @@ -209,6 +211,11 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) return; + if (!acpi_video_backlight_use_native()) { + drm_info(dev, "Skipping radeon atom DIG backlight registration\n"); + return; + } + pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); if (!pdata) { DRM_ERROR("Memory allocation failed\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 8be4799a98ef..638f861af80f 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -34,8 +34,6 @@ #include "r600_reg_safe.h" static int r600_nomm; -extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size); - struct r600_cs_track { /* configuration we mirror so that we use same code btw kms/ums */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 08f83bf2c330..166c18d62f6d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -116,7 +116,6 @@ extern int radeon_use_pflipirq; extern int radeon_bapm; extern int radeon_backlight; extern int radeon_auxch; -extern int radeon_mst; extern int radeon_uvd; extern int radeon_vce; extern int radeon_si_support; @@ -2950,8 +2949,6 @@ struct radeon_hdmi_acr { }; -extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock); - extern u32 r6xx_remap_render_backend(struct radeon_device *rdev, u32 tiling_pipe_num, u32 max_rb_num, diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 35c535e48b8d..fbc0a2182318 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -30,6 +30,8 @@ #include <drm/drm_device.h> #include <drm/radeon_drm.h> +#include <acpi/video.h> + #include "radeon.h" #include "radeon_atombios.h" #include "radeon_legacy_encoders.h" @@ -167,7 +169,7 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, return; if (radeon_backlight == 0) { - return; + use_bl = false; } else if (radeon_backlight == 1) { use_bl = true; } else if (radeon_backlight == -1) { @@ -193,6 +195,13 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, else radeon_legacy_backlight_init(radeon_encoder, connector); } + + /* + * If there is no native backlight device (which may happen even when + * use_bl==true) try registering an ACPI video backlight device instead. + */ + if (!rdev->mode_info.bl_encoder) + acpi_video_register_backlight(); } void diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 1a66fb969ee7..0cd32c65456c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -33,6 +33,8 @@ #include <drm/drm_util.h> #include <drm/radeon_drm.h> +#include <acpi/video.h> + #include "radeon.h" #include "radeon_asic.h" #include "radeon_legacy_encoders.h" @@ -387,6 +389,11 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, return; #endif + if (!acpi_video_backlight_use_native()) { + drm_info(dev, "Skipping radeon legacy LVDS backlight registration\n"); + return; + } + pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); if (!pdata) { DRM_ERROR("Memory allocation failed\n"); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 6a6a73204226..9f5be416454f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -874,7 +874,6 @@ extern struct radeon_encoder_tv_dac * radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder); extern struct radeon_encoder_lvds * radeon_combios_get_lvds_info(struct radeon_encoder *encoder); -extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); extern struct radeon_encoder_tv_dac * radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); extern struct radeon_encoder_primary_dac * diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 110e83aad9bb..bf6948125b84 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -179,6 +179,23 @@ #define RK3399_TXRX_SRC_SEL_ISP0 BIT(4) #define RK3399_TXRX_TURNREQUEST GENMASK(3, 0) +#define RK3568_GRF_VO_CON2 0x0368 +#define RK3568_DSI0_SKEWCALHS (0x1f << 11) +#define RK3568_DSI0_FORCETXSTOPMODE (0xf << 4) +#define RK3568_DSI0_TURNDISABLE BIT(2) +#define RK3568_DSI0_FORCERXMODE BIT(0) + +/* + * Note these registers do not appear in the datasheet, they are + * however present in the BSP driver which is where these values + * come from. Name GRF_VO_CON3 is assumed. + */ +#define RK3568_GRF_VO_CON3 0x36c +#define RK3568_DSI1_SKEWCALHS (0x1f << 11) +#define RK3568_DSI1_FORCETXSTOPMODE (0xf << 4) +#define RK3568_DSI1_TURNDISABLE BIT(2) +#define RK3568_DSI1_FORCERXMODE BIT(0) + #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) enum { @@ -735,8 +752,9 @@ static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi) static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi, int mux) { - regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg, - mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big); + if (dsi->cdata->lcdsel_grf_reg < 0) + regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg, + mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big); } static int @@ -963,6 +981,8 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev, DRM_DEV_ERROR(dev, "Failed to create drm encoder\n"); goto out_pll_clk; } + rockchip_drm_encoder_set_crtc_endpoint_id(&dsi->encoder, + dev->of_node, 0, 0); ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder.encoder); if (ret) { @@ -1612,6 +1632,30 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { { /* sentinel */ } }; +static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { + { + .reg = 0xfe060000, + .lcdsel_grf_reg = -1, + .lanecfg1_grf_reg = RK3568_GRF_VO_CON2, + .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI0_SKEWCALHS | + RK3568_DSI0_FORCETXSTOPMODE | + RK3568_DSI0_TURNDISABLE | + RK3568_DSI0_FORCERXMODE), + .max_data_lanes = 4, + }, + { + .reg = 0xfe070000, + .lcdsel_grf_reg = -1, + .lanecfg1_grf_reg = RK3568_GRF_VO_CON3, + .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI1_SKEWCALHS | + RK3568_DSI1_FORCETXSTOPMODE | + RK3568_DSI1_TURNDISABLE | + RK3568_DSI1_FORCERXMODE), + .max_data_lanes = 4, + }, + { /* sentinel */ } +}; + static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { { .compatible = "rockchip,px30-mipi-dsi", @@ -1622,6 +1666,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { }, { .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_chip_data, + }, { + .compatible = "rockchip,rk3568-mipi-dsi", + .data = &rk3568_chip_data, }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bdd48f87d098..c356de5dd220 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -9,6 +9,7 @@ #include <linux/delay.h> #include <linux/iopoll.h> #include <linux/kernel.h> +#include <linux/log2.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -67,6 +68,9 @@ #define VOP_REG_SET(vop, group, name, v) \ vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name) +#define VOP_HAS_REG(vop, group, name) \ + (!!(vop->data->group->name.mask)) + #define VOP_INTR_SET_TYPE(vop, name, type, v) \ do { \ int i, reg = 0, mask = 0; \ @@ -184,12 +188,6 @@ struct vop { struct vop_win win[]; }; -static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v) -{ - writel(v, vop->regs + offset); - vop->regsbak[offset >> 2] = v; -} - static inline uint32_t vop_readl(struct vop *vop, uint32_t offset) { return readl(vop->regs + offset); @@ -1188,7 +1186,7 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, * * Key points: * - * - DRM works in in kHz. + * - DRM works in kHz. * - Clock framework works in Hz. * - Rockchip's clock driver picks the clock rate that is the * same _OR LOWER_ than the one requested. @@ -1223,17 +1221,22 @@ static bool vop_dsp_lut_is_enabled(struct vop *vop) return vop_read_reg(vop, 0, &vop->data->common->dsp_lut_en); } +static u32 vop_lut_buffer_index(struct vop *vop) +{ + return vop_read_reg(vop, 0, &vop->data->common->lut_buffer_index); +} + static void vop_crtc_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc) { struct drm_color_lut *lut = crtc->state->gamma_lut->data; - unsigned int i; + unsigned int i, bpc = ilog2(vop->data->lut_size); for (i = 0; i < crtc->gamma_size; i++) { u32 word; - word = (drm_color_lut_extract(lut[i].red, 10) << 20) | - (drm_color_lut_extract(lut[i].green, 10) << 10) | - drm_color_lut_extract(lut[i].blue, 10); + word = (drm_color_lut_extract(lut[i].red, bpc) << (2 * bpc)) | + (drm_color_lut_extract(lut[i].green, bpc) << bpc) | + drm_color_lut_extract(lut[i].blue, bpc); writel(word, vop->lut_regs + i * 4); } } @@ -1243,38 +1246,66 @@ static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, { struct drm_crtc_state *state = crtc->state; unsigned int idle; + u32 lut_idx, old_idx; int ret; if (!vop->lut_regs) return; - /* - * To disable gamma (gamma_lut is null) or to write - * an update to the LUT, clear dsp_lut_en. - */ - spin_lock(&vop->reg_lock); - VOP_REG_SET(vop, common, dsp_lut_en, 0); - vop_cfg_done(vop); - spin_unlock(&vop->reg_lock); - /* - * In order to write the LUT to the internal memory, - * we need to first make sure the dsp_lut_en bit is cleared. - */ - ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop, - idle, !idle, 5, 30 * 1000); - if (ret) { - DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n"); - return; - } + if (!state->gamma_lut || !VOP_HAS_REG(vop, common, update_gamma_lut)) { + /* + * To disable gamma (gamma_lut is null) or to write + * an update to the LUT, clear dsp_lut_en. + */ + spin_lock(&vop->reg_lock); + VOP_REG_SET(vop, common, dsp_lut_en, 0); + vop_cfg_done(vop); + spin_unlock(&vop->reg_lock); - if (!state->gamma_lut) - return; + /* + * In order to write the LUT to the internal memory, + * we need to first make sure the dsp_lut_en bit is cleared. + */ + ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop, + idle, !idle, 5, 30 * 1000); + if (ret) { + DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n"); + return; + } + + if (!state->gamma_lut) + return; + } else { + /* + * On RK3399 the gamma LUT can updated without clearing dsp_lut_en, + * by setting update_gamma_lut then waiting for lut_buffer_index change + */ + old_idx = vop_lut_buffer_index(vop); + } spin_lock(&vop->reg_lock); vop_crtc_write_gamma_lut(vop, crtc); VOP_REG_SET(vop, common, dsp_lut_en, 1); + VOP_REG_SET(vop, common, update_gamma_lut, 1); vop_cfg_done(vop); spin_unlock(&vop->reg_lock); + + if (VOP_HAS_REG(vop, common, update_gamma_lut)) { + ret = readx_poll_timeout(vop_lut_buffer_index, vop, + lut_idx, lut_idx != old_idx, 5, 30 * 1000); + if (ret) { + DRM_DEV_ERROR(vop->dev, "gamma LUT update timeout!\n"); + return; + } + + /* + * update_gamma_lut is auto cleared by HW, but write 0 to clear the bit + * in our backup of the regs. + */ + spin_lock(&vop->reg_lock); + VOP_REG_SET(vop, common, update_gamma_lut, 0); + spin_unlock(&vop->reg_lock); + } } static void vop_crtc_atomic_begin(struct drm_crtc *crtc, @@ -1324,14 +1355,6 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, return; } - /* - * If we have a GAMMA LUT in the state, then let's make sure - * it's updated. We might be coming out of suspend, - * which means the LUT internal memory needs to be re-written. - */ - if (crtc->state->gamma_lut) - vop_crtc_gamma_set(vop, crtc, old_state); - mutex_lock(&vop->vop_lock); WARN_ON(vop->event); @@ -1422,6 +1445,14 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, VOP_REG_SET(vop, common, standby, 0); mutex_unlock(&vop->vop_lock); + + /* + * If we have a GAMMA LUT in the state, then let's make sure + * it's updated. We might be coming out of suspend, + * which means the LUT internal memory needs to be re-written. + */ + if (crtc->state->gamma_lut) + vop_crtc_gamma_set(vop, crtc, old_state); } static bool vop_fs_irq_is_pending(struct vop *vop) @@ -2147,8 +2178,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { - if (!vop_data->lut_size) { - DRM_DEV_ERROR(dev, "no gamma LUT size defined\n"); + if (vop_data->lut_size != 1024 && vop_data->lut_size != 256) { + DRM_DEV_ERROR(dev, "unsupported gamma LUT size %d\n", vop_data->lut_size); return -EINVAL; } vop->lut_regs = devm_ioremap_resource(dev, res); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index ba88addc1a75..8502849833d9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -113,6 +113,8 @@ struct vop_common { struct vop_reg dither_down_en; struct vop_reg dither_up; struct vop_reg dsp_lut_en; + struct vop_reg update_gamma_lut; + struct vop_reg lut_buffer_index; struct vop_reg gate_en; struct vop_reg mmu_en; struct vop_reg out_mode; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index d03dd0402923..014f99e8928e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -875,6 +875,24 @@ static const struct vop_output rk3399_output = { .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), }; +static const struct vop_common rk3399_common = { + .standby = VOP_REG_SYNC(RK3399_SYS_CTRL, 0x1, 22), + .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), + .mmu_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 20), + .dither_down_sel = VOP_REG(RK3399_DSP_CTRL1, 0x1, 4), + .dither_down_mode = VOP_REG(RK3399_DSP_CTRL1, 0x1, 3), + .dither_down_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 2), + .pre_dither_down = VOP_REG(RK3399_DSP_CTRL1, 0x1, 1), + .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6), + .dsp_lut_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 0), + .update_gamma_lut = VOP_REG(RK3399_DSP_CTRL1, 0x1, 7), + .lut_buffer_index = VOP_REG(RK3399_DBG_POST_REG1, 0x1, 1), + .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), + .dsp_blank = VOP_REG(RK3399_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3399_REG_CFG_DONE, 0x1, 0), +}; + static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = { .y2r_coefficients = { VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0), @@ -957,7 +975,7 @@ static const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_RGB10, .intr = &rk3366_vop_intr, - .common = &rk3288_common, + .common = &rk3399_common, .modeset = &rk3288_modeset, .output = &rk3399_output, .afbc = &rk3399_vop_afbc, @@ -965,6 +983,7 @@ static const struct vop_data rk3399_vop_big = { .win = rk3399_vop_win_data, .win_size = ARRAY_SIZE(rk3399_vop_win_data), .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, + .lut_size = 1024, }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { @@ -983,13 +1002,14 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { static const struct vop_data rk3399_vop_lit = { .version = VOP_VERSION(3, 6), .intr = &rk3366_vop_intr, - .common = &rk3288_common, + .common = &rk3399_common, .modeset = &rk3288_modeset, .output = &rk3399_output, .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, + .lut_size = 256, }; static const struct vop_win_data rk3228_vop_win_data[] = { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 0b3cd65ba5c1..406e981c75bd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -628,6 +628,7 @@ #define RK3399_YUV2YUV_WIN 0x02c0 #define RK3399_YUV2YUV_POST 0x02c4 #define RK3399_AUTO_GATING_EN 0x02cc +#define RK3399_DBG_POST_REG1 0x036c #define RK3399_WIN0_CSC_COE 0x03a0 #define RK3399_WIN1_CSC_COE 0x03c0 #define RK3399_WIN2_CSC_COE 0x03e0 diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 54228424793a..6c5f0cbe7d95 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -252,9 +252,10 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index) splane->index = index; splane->alpha = 255; - ret = drm_plane_init(sdev->ddev, &splane->plane, 1, - &shmob_drm_plane_funcs, formats, - ARRAY_SIZE(formats), false); + ret = drm_universal_plane_init(sdev->ddev, &splane->plane, 1, + &shmob_drm_plane_funcs, + formats, ARRAY_SIZE(formats), NULL, + DRM_PLANE_TYPE_OVERLAY, NULL); return ret; } diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index c95221fff474..bc41a5ae810a 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -555,37 +555,28 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_m if (!buf) return -ENOMEM; + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + goto out_free; + iosys_map_set_vaddr(&dst, buf); drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect); + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); + ssd130x_update_rect(ssd130x, buf, rect); +out_free: kfree(buf); return ret; } -static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *new_state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); - struct drm_crtc *new_crtc = new_plane_state->crtc; - struct drm_crtc_state *new_crtc_state = NULL; - - if (new_crtc) - new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); - - return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); -} - static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *old_state) + struct drm_atomic_state *state) { - struct drm_plane_state *plane_state = plane->state; - struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_device *drm = plane->dev; struct drm_rect src_clip, dst_clip; @@ -607,7 +598,7 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, } static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *old_state) + struct drm_atomic_state *state) { struct drm_device *drm = plane->dev; struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); @@ -623,7 +614,7 @@ static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane, static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, - .atomic_check = ssd130x_primary_plane_helper_atomic_check, + .atomic_check = drm_plane_helper_atomic_check, .atomic_update = ssd130x_primary_plane_helper_atomic_update, .atomic_disable = ssd130x_primary_plane_helper_atomic_disable, }; diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index d76f83833e75..7a2b2d6bc3fe 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -13,7 +13,7 @@ #include "../lib/drm_random.h" -#define IGT_TIMEOUT(name__) \ +#define TIMEOUT(name__) \ unsigned long name__ = jiffies + MAX_SCHEDULE_TIMEOUT static unsigned int random_seed; @@ -24,7 +24,7 @@ static inline u64 get_size(int order, u64 chunk_size) } __printf(2, 3) -static bool __igt_timeout(unsigned long timeout, const char *fmt, ...) +static bool __timeout(unsigned long timeout, const char *fmt, ...) { va_list va; @@ -43,8 +43,8 @@ static bool __igt_timeout(unsigned long timeout, const char *fmt, ...) return true; } -static void __igt_dump_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block, bool buddy) +static void __dump_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block, bool buddy) { kunit_err(test, "block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%d buddy=%d\n", block->header, drm_buddy_block_state(block), @@ -52,20 +52,20 @@ static void __igt_dump_block(struct kunit *test, struct drm_buddy *mm, drm_buddy_block_size(mm, block), !block->parent, buddy); } -static void igt_dump_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block) +static void dump_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block) { struct drm_buddy_block *buddy; - __igt_dump_block(test, mm, block, false); + __dump_block(test, mm, block, false); buddy = drm_get_buddy(block); if (buddy) - __igt_dump_block(test, mm, buddy, true); + __dump_block(test, mm, buddy, true); } -static int igt_check_block(struct kunit *test, struct drm_buddy *mm, - struct drm_buddy_block *block) +static int check_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block) { struct drm_buddy_block *buddy; unsigned int block_state; @@ -137,8 +137,8 @@ static int igt_check_block(struct kunit *test, struct drm_buddy *mm, return err; } -static int igt_check_blocks(struct kunit *test, struct drm_buddy *mm, - struct list_head *blocks, u64 expected_size, bool is_contiguous) +static int check_blocks(struct kunit *test, struct drm_buddy *mm, + struct list_head *blocks, u64 expected_size, bool is_contiguous) { struct drm_buddy_block *block; struct drm_buddy_block *prev; @@ -150,7 +150,7 @@ static int igt_check_blocks(struct kunit *test, struct drm_buddy *mm, total = 0; list_for_each_entry(block, blocks, link) { - err = igt_check_block(test, mm, block); + err = check_block(test, mm, block); if (!drm_buddy_block_is_allocated(block)) { kunit_err(test, "block not allocated\n"); @@ -190,16 +190,16 @@ static int igt_check_blocks(struct kunit *test, struct drm_buddy *mm, if (prev) { kunit_err(test, "prev block, dump:\n"); - igt_dump_block(test, mm, prev); + dump_block(test, mm, prev); } kunit_err(test, "bad block, dump:\n"); - igt_dump_block(test, mm, block); + dump_block(test, mm, block); return err; } -static int igt_check_mm(struct kunit *test, struct drm_buddy *mm) +static int check_mm(struct kunit *test, struct drm_buddy *mm) { struct drm_buddy_block *root; struct drm_buddy_block *prev; @@ -233,7 +233,7 @@ static int igt_check_mm(struct kunit *test, struct drm_buddy *mm) break; } - err = igt_check_block(test, mm, root); + err = check_block(test, mm, root); if (!drm_buddy_block_is_free(root)) { kunit_err(test, "root not free\n"); @@ -289,18 +289,18 @@ static int igt_check_mm(struct kunit *test, struct drm_buddy *mm) if (prev) { kunit_err(test, "prev root(%u), dump:\n", i - 1); - igt_dump_block(test, mm, prev); + dump_block(test, mm, prev); } if (root) { kunit_err(test, "bad root(%u), dump:\n", i); - igt_dump_block(test, mm, root); + dump_block(test, mm, root); } return err; } -static void igt_mm_config(u64 *size, u64 *chunk_size) +static void mm_config(u64 *size, u64 *chunk_size) { DRM_RND_STATE(prng, random_seed); u32 s, ms; @@ -321,7 +321,7 @@ static void igt_mm_config(u64 *size, u64 *chunk_size) *size = (u64)s << 12; } -static void igt_buddy_alloc_pathological(struct kunit *test) +static void drm_test_buddy_alloc_pathological(struct kunit *test) { u64 mm_size, size, start = 0; struct drm_buddy_block *block; @@ -402,7 +402,7 @@ static void igt_buddy_alloc_pathological(struct kunit *test) drm_buddy_fini(&mm); } -static void igt_buddy_alloc_smoke(struct kunit *test) +static void drm_test_buddy_alloc_smoke(struct kunit *test) { u64 mm_size, chunk_size, start = 0; unsigned long flags = 0; @@ -411,9 +411,9 @@ static void igt_buddy_alloc_smoke(struct kunit *test) int i; DRM_RND_STATE(prng, random_seed); - IGT_TIMEOUT(end_time); + TIMEOUT(end_time); - igt_mm_config(&mm_size, &chunk_size); + mm_config(&mm_size, &chunk_size); KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, chunk_size), "buddy_init failed\n"); @@ -430,7 +430,7 @@ static void igt_buddy_alloc_smoke(struct kunit *test) LIST_HEAD(tmp); int order, err; - KUNIT_ASSERT_FALSE_MSG(test, igt_check_mm(test, &mm), + KUNIT_ASSERT_FALSE_MSG(test, check_mm(test, &mm), "pre-mm check failed, abort\n"); order = max_order; @@ -466,19 +466,19 @@ retry: total += drm_buddy_block_size(&mm, block); - if (__igt_timeout(end_time, NULL)) { + if (__timeout(end_time, NULL)) { timeout = true; break; } } while (total < mm.size); if (!err) - err = igt_check_blocks(test, &mm, &blocks, total, false); + err = check_blocks(test, &mm, &blocks, total, false); drm_buddy_free_list(&mm, &blocks); if (!err) { - KUNIT_EXPECT_FALSE_MSG(test, igt_check_mm(test, &mm), + KUNIT_EXPECT_FALSE_MSG(test, check_mm(test, &mm), "post-mm check failed\n"); } @@ -492,7 +492,7 @@ retry: drm_buddy_fini(&mm); } -static void igt_buddy_alloc_pessimistic(struct kunit *test) +static void drm_test_buddy_alloc_pessimistic(struct kunit *test) { u64 mm_size, size, start = 0; struct drm_buddy_block *block, *bn; @@ -587,7 +587,7 @@ static void igt_buddy_alloc_pessimistic(struct kunit *test) drm_buddy_fini(&mm); } -static void igt_buddy_alloc_optimistic(struct kunit *test) +static void drm_test_buddy_alloc_optimistic(struct kunit *test) { u64 mm_size, size, start = 0; struct drm_buddy_block *block; @@ -633,7 +633,7 @@ static void igt_buddy_alloc_optimistic(struct kunit *test) drm_buddy_fini(&mm); } -static void igt_buddy_alloc_range(struct kunit *test) +static void drm_test_buddy_alloc_range(struct kunit *test) { unsigned long flags = DRM_BUDDY_RANGE_ALLOCATION; u64 offset, size, rem, chunk_size, end; @@ -641,12 +641,12 @@ static void igt_buddy_alloc_range(struct kunit *test) struct drm_buddy mm; LIST_HEAD(blocks); - igt_mm_config(&size, &chunk_size); + mm_config(&size, &chunk_size); KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, size, chunk_size), "buddy_init failed"); - KUNIT_ASSERT_FALSE_MSG(test, igt_check_mm(test, &mm), + KUNIT_ASSERT_FALSE_MSG(test, check_mm(test, &mm), "pre-mm check failed, abort!"); rem = mm.size; @@ -671,7 +671,7 @@ static void igt_buddy_alloc_range(struct kunit *test) "alloc_range start offset mismatch, found=%llx, expected=%llx\n", drm_buddy_block_offset(block), offset); - KUNIT_ASSERT_FALSE(test, igt_check_blocks(test, &mm, &tmp, size, true)); + KUNIT_ASSERT_FALSE(test, check_blocks(test, &mm, &tmp, size, true)); list_splice_tail(&tmp, &blocks); @@ -686,12 +686,12 @@ static void igt_buddy_alloc_range(struct kunit *test) drm_buddy_free_list(&mm, &blocks); - KUNIT_EXPECT_FALSE_MSG(test, igt_check_mm(test, &mm), "post-mm check failed\n"); + KUNIT_EXPECT_FALSE_MSG(test, check_mm(test, &mm), "post-mm check failed\n"); drm_buddy_fini(&mm); } -static void igt_buddy_alloc_limit(struct kunit *test) +static void drm_test_buddy_alloc_limit(struct kunit *test) { u64 size = U64_MAX, start = 0; struct drm_buddy_block *block; @@ -735,12 +735,12 @@ static int drm_buddy_init_test(struct kunit *test) } static struct kunit_case drm_buddy_tests[] = { - KUNIT_CASE(igt_buddy_alloc_limit), - KUNIT_CASE(igt_buddy_alloc_range), - KUNIT_CASE(igt_buddy_alloc_optimistic), - KUNIT_CASE(igt_buddy_alloc_pessimistic), - KUNIT_CASE(igt_buddy_alloc_smoke), - KUNIT_CASE(igt_buddy_alloc_pathological), + KUNIT_CASE(drm_test_buddy_alloc_limit), + KUNIT_CASE(drm_test_buddy_alloc_range), + KUNIT_CASE(drm_test_buddy_alloc_optimistic), + KUNIT_CASE(drm_test_buddy_alloc_pessimistic), + KUNIT_CASE(drm_test_buddy_alloc_smoke), + KUNIT_CASE(drm_test_buddy_alloc_pathological), {} }; diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c index 09b806e27506..34790e7a3760 100644 --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -11,7 +11,7 @@ static const struct drm_connector no_connector = {}; -static void drm_cmdline_test_force_e_only(struct kunit *test) +static void drm_test_cmdline_force_e_only(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "e"; @@ -29,7 +29,7 @@ static void drm_cmdline_test_force_e_only(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_force_D_only_not_digital(struct kunit *test) +static void drm_test_cmdline_force_D_only_not_digital(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "D"; @@ -51,7 +51,7 @@ static const struct drm_connector connector_hdmi = { .connector_type = DRM_MODE_CONNECTOR_HDMIB, }; -static void drm_cmdline_test_force_D_only_hdmi(struct kunit *test) +static void drm_test_cmdline_force_D_only_hdmi(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "D"; @@ -73,7 +73,7 @@ static const struct drm_connector connector_dvi = { .connector_type = DRM_MODE_CONNECTOR_DVII, }; -static void drm_cmdline_test_force_D_only_dvi(struct kunit *test) +static void drm_test_cmdline_force_D_only_dvi(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "D"; @@ -91,7 +91,7 @@ static void drm_cmdline_test_force_D_only_dvi(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL); } -static void drm_cmdline_test_force_d_only(struct kunit *test) +static void drm_test_cmdline_force_d_only(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "d"; @@ -109,7 +109,7 @@ static void drm_cmdline_test_force_d_only(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF); } -static void drm_cmdline_test_res(struct kunit *test) +static void drm_test_cmdline_res(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480"; @@ -131,7 +131,7 @@ static void drm_cmdline_test_res(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_vesa(struct kunit *test) +static void drm_test_cmdline_res_vesa(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480M"; @@ -153,7 +153,7 @@ static void drm_cmdline_test_res_vesa(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_vesa_rblank(struct kunit *test) +static void drm_test_cmdline_res_vesa_rblank(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480MR"; @@ -175,7 +175,7 @@ static void drm_cmdline_test_res_vesa_rblank(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_rblank(struct kunit *test) +static void drm_test_cmdline_res_rblank(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480R"; @@ -197,7 +197,7 @@ static void drm_cmdline_test_res_rblank(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_bpp(struct kunit *test) +static void drm_test_cmdline_res_bpp(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24"; @@ -220,7 +220,7 @@ static void drm_cmdline_test_res_bpp(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_refresh(struct kunit *test) +static void drm_test_cmdline_res_refresh(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480@60"; @@ -243,7 +243,7 @@ static void drm_cmdline_test_res_refresh(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_bpp_refresh(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60"; @@ -267,7 +267,7 @@ static void drm_cmdline_test_res_bpp_refresh(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_bpp_refresh_interlaced(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_interlaced(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60i"; @@ -291,7 +291,7 @@ static void drm_cmdline_test_res_bpp_refresh_interlaced(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_bpp_refresh_margins(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_margins(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60m"; @@ -315,7 +315,7 @@ static void drm_cmdline_test_res_bpp_refresh_margins(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_res_bpp_refresh_force_off(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_force_off(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60d"; @@ -339,7 +339,7 @@ static void drm_cmdline_test_res_bpp_refresh_force_off(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF); } -static void drm_cmdline_test_res_bpp_refresh_force_on(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_force_on(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60e"; @@ -363,7 +363,7 @@ static void drm_cmdline_test_res_bpp_refresh_force_on(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_res_bpp_refresh_force_on_analog(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_force_on_analog(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60D"; @@ -387,7 +387,7 @@ static void drm_cmdline_test_res_bpp_refresh_force_on_analog(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_res_bpp_refresh_force_on_digital(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_force_on_digital(struct kunit *test) { struct drm_cmdline_mode mode = { }; static const struct drm_connector connector = { @@ -414,7 +414,7 @@ static void drm_cmdline_test_res_bpp_refresh_force_on_digital(struct kunit *test KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL); } -static void drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(struct kunit *test) +static void drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24@60ime"; @@ -438,7 +438,7 @@ static void drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(struct KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_res_margins_force_on(struct kunit *test) +static void drm_test_cmdline_res_margins_force_on(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480me"; @@ -460,7 +460,7 @@ static void drm_cmdline_test_res_margins_force_on(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_res_vesa_margins(struct kunit *test) +static void drm_test_cmdline_res_vesa_margins(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480Mm"; @@ -482,7 +482,7 @@ static void drm_cmdline_test_res_vesa_margins(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_name(struct kunit *test) +static void drm_test_cmdline_name(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "NTSC"; @@ -494,7 +494,7 @@ static void drm_cmdline_test_name(struct kunit *test) KUNIT_EXPECT_FALSE(test, mode.bpp_specified); } -static void drm_cmdline_test_name_bpp(struct kunit *test) +static void drm_test_cmdline_name_bpp(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "NTSC-24"; @@ -509,7 +509,7 @@ static void drm_cmdline_test_name_bpp(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.bpp, 24); } -static void drm_cmdline_test_name_option(struct kunit *test) +static void drm_test_cmdline_name_option(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "NTSC,rotate=180"; @@ -521,7 +521,7 @@ static void drm_cmdline_test_name_option(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); } -static void drm_cmdline_test_name_bpp_option(struct kunit *test) +static void drm_test_cmdline_name_bpp_option(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "NTSC-24,rotate=180"; @@ -535,7 +535,7 @@ static void drm_cmdline_test_name_bpp_option(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.bpp, 24); } -static void drm_cmdline_test_rotate_0(struct kunit *test) +static void drm_test_cmdline_rotate_0(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,rotate=0"; @@ -558,7 +558,7 @@ static void drm_cmdline_test_rotate_0(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_rotate_90(struct kunit *test) +static void drm_test_cmdline_rotate_90(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,rotate=90"; @@ -581,7 +581,7 @@ static void drm_cmdline_test_rotate_90(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_rotate_180(struct kunit *test) +static void drm_test_cmdline_rotate_180(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,rotate=180"; @@ -604,7 +604,7 @@ static void drm_cmdline_test_rotate_180(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_rotate_270(struct kunit *test) +static void drm_test_cmdline_rotate_270(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,rotate=270"; @@ -627,7 +627,7 @@ static void drm_cmdline_test_rotate_270(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_hmirror(struct kunit *test) +static void drm_test_cmdline_hmirror(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,reflect_x"; @@ -650,7 +650,7 @@ static void drm_cmdline_test_hmirror(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_vmirror(struct kunit *test) +static void drm_test_cmdline_vmirror(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,reflect_y"; @@ -673,7 +673,7 @@ static void drm_cmdline_test_vmirror(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_margin_options(struct kunit *test) +static void drm_test_cmdline_margin_options(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = @@ -700,7 +700,7 @@ static void drm_cmdline_test_margin_options(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_multiple_options(struct kunit *test) +static void drm_test_cmdline_multiple_options(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480,rotate=270,reflect_x"; @@ -723,7 +723,7 @@ static void drm_cmdline_test_multiple_options(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_bpp_extra_and_option(struct kunit *test) +static void drm_test_cmdline_bpp_extra_and_option(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480-24e,rotate=180"; @@ -747,7 +747,7 @@ static void drm_cmdline_test_bpp_extra_and_option(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_extra_and_option(struct kunit *test) +static void drm_test_cmdline_extra_and_option(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "720x480e,rotate=180"; @@ -769,7 +769,7 @@ static void drm_cmdline_test_extra_and_option(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_freestanding_options(struct kunit *test) +static void drm_test_cmdline_freestanding_options(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "margin_right=14,margin_left=24,margin_bottom=36,margin_top=42"; @@ -792,7 +792,7 @@ static void drm_cmdline_test_freestanding_options(struct kunit *test) KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); } -static void drm_cmdline_test_freestanding_force_e_and_options(struct kunit *test) +static void drm_test_cmdline_freestanding_force_e_and_options(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42"; @@ -815,7 +815,7 @@ static void drm_cmdline_test_freestanding_force_e_and_options(struct kunit *test KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); } -static void drm_cmdline_test_panel_orientation(struct kunit *test) +static void drm_test_cmdline_panel_orientation(struct kunit *test) { struct drm_cmdline_mode mode = { }; const char *cmdline = "panel_orientation=upside_down"; @@ -840,7 +840,7 @@ struct drm_cmdline_invalid_test { const char *cmdline; }; -static void drm_cmdline_test_invalid(struct kunit *test) +static void drm_test_cmdline_invalid(struct kunit *test) { const struct drm_cmdline_invalid_test *params = test->param_value; struct drm_cmdline_mode mode = { }; @@ -938,45 +938,45 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t, KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc); static struct kunit_case drm_cmdline_parser_tests[] = { - KUNIT_CASE(drm_cmdline_test_force_d_only), - KUNIT_CASE(drm_cmdline_test_force_D_only_dvi), - KUNIT_CASE(drm_cmdline_test_force_D_only_hdmi), - KUNIT_CASE(drm_cmdline_test_force_D_only_not_digital), - KUNIT_CASE(drm_cmdline_test_force_e_only), - KUNIT_CASE(drm_cmdline_test_res), - KUNIT_CASE(drm_cmdline_test_res_vesa), - KUNIT_CASE(drm_cmdline_test_res_vesa_rblank), - KUNIT_CASE(drm_cmdline_test_res_rblank), - KUNIT_CASE(drm_cmdline_test_res_bpp), - KUNIT_CASE(drm_cmdline_test_res_refresh), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_margins), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_off), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_analog), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_digital), - KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on), - KUNIT_CASE(drm_cmdline_test_res_margins_force_on), - KUNIT_CASE(drm_cmdline_test_res_vesa_margins), - KUNIT_CASE(drm_cmdline_test_name), - KUNIT_CASE(drm_cmdline_test_name_bpp), - KUNIT_CASE(drm_cmdline_test_name_option), - KUNIT_CASE(drm_cmdline_test_name_bpp_option), - KUNIT_CASE(drm_cmdline_test_rotate_0), - KUNIT_CASE(drm_cmdline_test_rotate_90), - KUNIT_CASE(drm_cmdline_test_rotate_180), - KUNIT_CASE(drm_cmdline_test_rotate_270), - KUNIT_CASE(drm_cmdline_test_hmirror), - KUNIT_CASE(drm_cmdline_test_vmirror), - KUNIT_CASE(drm_cmdline_test_margin_options), - KUNIT_CASE(drm_cmdline_test_multiple_options), - KUNIT_CASE(drm_cmdline_test_bpp_extra_and_option), - KUNIT_CASE(drm_cmdline_test_extra_and_option), - KUNIT_CASE(drm_cmdline_test_freestanding_options), - KUNIT_CASE(drm_cmdline_test_freestanding_force_e_and_options), - KUNIT_CASE(drm_cmdline_test_panel_orientation), - KUNIT_CASE_PARAM(drm_cmdline_test_invalid, drm_cmdline_invalid_gen_params), + KUNIT_CASE(drm_test_cmdline_force_d_only), + KUNIT_CASE(drm_test_cmdline_force_D_only_dvi), + KUNIT_CASE(drm_test_cmdline_force_D_only_hdmi), + KUNIT_CASE(drm_test_cmdline_force_D_only_not_digital), + KUNIT_CASE(drm_test_cmdline_force_e_only), + KUNIT_CASE(drm_test_cmdline_res), + KUNIT_CASE(drm_test_cmdline_res_vesa), + KUNIT_CASE(drm_test_cmdline_res_vesa_rblank), + KUNIT_CASE(drm_test_cmdline_res_rblank), + KUNIT_CASE(drm_test_cmdline_res_bpp), + KUNIT_CASE(drm_test_cmdline_res_refresh), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_interlaced), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_margins), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_force_off), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_force_on), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_force_on_analog), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_force_on_digital), + KUNIT_CASE(drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on), + KUNIT_CASE(drm_test_cmdline_res_margins_force_on), + KUNIT_CASE(drm_test_cmdline_res_vesa_margins), + KUNIT_CASE(drm_test_cmdline_name), + KUNIT_CASE(drm_test_cmdline_name_bpp), + KUNIT_CASE(drm_test_cmdline_name_option), + KUNIT_CASE(drm_test_cmdline_name_bpp_option), + KUNIT_CASE(drm_test_cmdline_rotate_0), + KUNIT_CASE(drm_test_cmdline_rotate_90), + KUNIT_CASE(drm_test_cmdline_rotate_180), + KUNIT_CASE(drm_test_cmdline_rotate_270), + KUNIT_CASE(drm_test_cmdline_hmirror), + KUNIT_CASE(drm_test_cmdline_vmirror), + KUNIT_CASE(drm_test_cmdline_margin_options), + KUNIT_CASE(drm_test_cmdline_multiple_options), + KUNIT_CASE(drm_test_cmdline_bpp_extra_and_option), + KUNIT_CASE(drm_test_cmdline_extra_and_option), + KUNIT_CASE(drm_test_cmdline_freestanding_options), + KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options), + KUNIT_CASE(drm_test_cmdline_panel_orientation), + KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params), {} }; diff --git a/drivers/gpu/drm/tests/drm_damage_helper_test.c b/drivers/gpu/drm/tests/drm_damage_helper_test.c index bf250bd08d7e..115034fc3421 100644 --- a/drivers/gpu/drm/tests/drm_damage_helper_test.c +++ b/drivers/gpu/drm/tests/drm_damage_helper_test.c @@ -59,6 +59,11 @@ static int drm_damage_helper_init(struct kunit *test) static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2, int y2) { + state->src_x = x1; + state->src_y = y1; + state->src_w = x2 - x1; + state->src_h = y2 - y1; + state->src.x1 = x1; state->src.y1 = y1; state->src.x2 = x2; @@ -111,7 +116,7 @@ static void check_damage_clip(struct kunit *test, struct drm_rect *r, r->x1, r->y1, r->x2, r->y2, x1, y1, x2, y2); } -static void igt_damage_iter_no_damage(struct kunit *test) +static void drm_test_damage_iter_no_damage(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -129,7 +134,7 @@ static void igt_damage_iter_no_damage(struct kunit *test) check_damage_clip(test, &clip, 0, 0, 2048, 2048); } -static void igt_damage_iter_no_damage_fractional_src(struct kunit *test) +static void drm_test_damage_iter_no_damage_fractional_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -150,7 +155,7 @@ static void igt_damage_iter_no_damage_fractional_src(struct kunit *test) check_damage_clip(test, &clip, 3, 3, 1028, 772); } -static void igt_damage_iter_no_damage_src_moved(struct kunit *test) +static void drm_test_damage_iter_no_damage_src_moved(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -169,7 +174,7 @@ static void igt_damage_iter_no_damage_src_moved(struct kunit *test) check_damage_clip(test, &clip, 10, 10, 1034, 778); } -static void igt_damage_iter_no_damage_fractional_src_moved(struct kunit *test) +static void drm_test_damage_iter_no_damage_fractional_src_moved(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -189,7 +194,7 @@ static void igt_damage_iter_no_damage_fractional_src_moved(struct kunit *test) check_damage_clip(test, &clip, 4, 4, 1029, 773); } -static void igt_damage_iter_no_damage_not_visible(struct kunit *test) +static void drm_test_damage_iter_no_damage_not_visible(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -207,7 +212,7 @@ static void igt_damage_iter_no_damage_not_visible(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); } -static void igt_damage_iter_no_damage_no_crtc(struct kunit *test) +static void drm_test_damage_iter_no_damage_no_crtc(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -225,7 +230,7 @@ static void igt_damage_iter_no_damage_no_crtc(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); } -static void igt_damage_iter_no_damage_no_fb(struct kunit *test) +static void drm_test_damage_iter_no_damage_no_fb(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -243,7 +248,7 @@ static void igt_damage_iter_no_damage_no_fb(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); } -static void igt_damage_iter_simple_damage(struct kunit *test) +static void drm_test_damage_iter_simple_damage(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -266,7 +271,7 @@ static void igt_damage_iter_simple_damage(struct kunit *test) check_damage_clip(test, &clip, 0, 0, 1024, 768); } -static void igt_damage_iter_single_damage(struct kunit *test) +static void drm_test_damage_iter_single_damage(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -288,7 +293,7 @@ static void igt_damage_iter_single_damage(struct kunit *test) check_damage_clip(test, &clip, 256, 192, 768, 576); } -static void igt_damage_iter_single_damage_intersect_src(struct kunit *test) +static void drm_test_damage_iter_single_damage_intersect_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -311,7 +316,7 @@ static void igt_damage_iter_single_damage_intersect_src(struct kunit *test) check_damage_clip(test, &clip, 256, 192, 1024, 768); } -static void igt_damage_iter_single_damage_outside_src(struct kunit *test) +static void drm_test_damage_iter_single_damage_outside_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -333,7 +338,7 @@ static void igt_damage_iter_single_damage_outside_src(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); } -static void igt_damage_iter_single_damage_fractional_src(struct kunit *test) +static void drm_test_damage_iter_single_damage_fractional_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -358,7 +363,7 @@ static void igt_damage_iter_single_damage_fractional_src(struct kunit *test) check_damage_clip(test, &clip, 10, 10, 256, 330); } -static void igt_damage_iter_single_damage_intersect_fractional_src(struct kunit *test) +static void drm_test_damage_iter_single_damage_intersect_fractional_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -385,7 +390,7 @@ static void igt_damage_iter_single_damage_intersect_fractional_src(struct kunit check_damage_clip(test, &clip, 10, 4, 1029, 330); } -static void igt_damage_iter_single_damage_outside_fractional_src(struct kunit *test) +static void drm_test_damage_iter_single_damage_outside_fractional_src(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -410,7 +415,7 @@ static void igt_damage_iter_single_damage_outside_fractional_src(struct kunit *t KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); } -static void igt_damage_iter_single_damage_src_moved(struct kunit *test) +static void drm_test_damage_iter_single_damage_src_moved(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -435,7 +440,7 @@ static void igt_damage_iter_single_damage_src_moved(struct kunit *test) check_damage_clip(test, &clip, 10, 10, 1034, 778); } -static void igt_damage_iter_single_damage_fractional_src_moved(struct kunit *test) +static void drm_test_damage_iter_single_damage_fractional_src_moved(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -462,7 +467,7 @@ static void igt_damage_iter_single_damage_fractional_src_moved(struct kunit *tes check_damage_clip(test, &clip, 4, 4, 1029, 773); } -static void igt_damage_iter_damage(struct kunit *test) +static void drm_test_damage_iter_damage(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -490,7 +495,7 @@ static void igt_damage_iter_damage(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set."); } -static void igt_damage_iter_damage_one_intersect(struct kunit *test) +static void drm_test_damage_iter_damage_one_intersect(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -520,7 +525,7 @@ static void igt_damage_iter_damage_one_intersect(struct kunit *test) KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set."); } -static void igt_damage_iter_damage_one_outside(struct kunit *test) +static void drm_test_damage_iter_damage_one_outside(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -544,7 +549,7 @@ static void igt_damage_iter_damage_one_outside(struct kunit *test) check_damage_clip(test, &clip, 240, 200, 280, 250); } -static void igt_damage_iter_damage_src_moved(struct kunit *test) +static void drm_test_damage_iter_damage_src_moved(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -571,7 +576,7 @@ static void igt_damage_iter_damage_src_moved(struct kunit *test) check_damage_clip(test, &clip, 3, 3, 1028, 772); } -static void igt_damage_iter_damage_not_visible(struct kunit *test) +static void drm_test_damage_iter_damage_not_visible(struct kunit *test) { struct drm_damage_mock *mock = test->priv; struct drm_atomic_helper_damage_iter iter; @@ -599,27 +604,27 @@ static void igt_damage_iter_damage_not_visible(struct kunit *test) } static struct kunit_case drm_damage_helper_tests[] = { - KUNIT_CASE(igt_damage_iter_no_damage), - KUNIT_CASE(igt_damage_iter_no_damage_fractional_src), - KUNIT_CASE(igt_damage_iter_no_damage_src_moved), - KUNIT_CASE(igt_damage_iter_no_damage_fractional_src_moved), - KUNIT_CASE(igt_damage_iter_no_damage_not_visible), - KUNIT_CASE(igt_damage_iter_no_damage_no_crtc), - KUNIT_CASE(igt_damage_iter_no_damage_no_fb), - KUNIT_CASE(igt_damage_iter_simple_damage), - KUNIT_CASE(igt_damage_iter_single_damage), - KUNIT_CASE(igt_damage_iter_single_damage_intersect_src), - KUNIT_CASE(igt_damage_iter_single_damage_outside_src), - KUNIT_CASE(igt_damage_iter_single_damage_fractional_src), - KUNIT_CASE(igt_damage_iter_single_damage_intersect_fractional_src), - KUNIT_CASE(igt_damage_iter_single_damage_outside_fractional_src), - KUNIT_CASE(igt_damage_iter_single_damage_src_moved), - KUNIT_CASE(igt_damage_iter_single_damage_fractional_src_moved), - KUNIT_CASE(igt_damage_iter_damage), - KUNIT_CASE(igt_damage_iter_damage_one_intersect), - KUNIT_CASE(igt_damage_iter_damage_one_outside), - KUNIT_CASE(igt_damage_iter_damage_src_moved), - KUNIT_CASE(igt_damage_iter_damage_not_visible), + KUNIT_CASE(drm_test_damage_iter_no_damage), + KUNIT_CASE(drm_test_damage_iter_no_damage_fractional_src), + KUNIT_CASE(drm_test_damage_iter_no_damage_src_moved), + KUNIT_CASE(drm_test_damage_iter_no_damage_fractional_src_moved), + KUNIT_CASE(drm_test_damage_iter_no_damage_not_visible), + KUNIT_CASE(drm_test_damage_iter_no_damage_no_crtc), + KUNIT_CASE(drm_test_damage_iter_no_damage_no_fb), + KUNIT_CASE(drm_test_damage_iter_simple_damage), + KUNIT_CASE(drm_test_damage_iter_single_damage), + KUNIT_CASE(drm_test_damage_iter_single_damage_intersect_src), + KUNIT_CASE(drm_test_damage_iter_single_damage_outside_src), + KUNIT_CASE(drm_test_damage_iter_single_damage_fractional_src), + KUNIT_CASE(drm_test_damage_iter_single_damage_intersect_fractional_src), + KUNIT_CASE(drm_test_damage_iter_single_damage_outside_fractional_src), + KUNIT_CASE(drm_test_damage_iter_single_damage_src_moved), + KUNIT_CASE(drm_test_damage_iter_single_damage_fractional_src_moved), + KUNIT_CASE(drm_test_damage_iter_damage), + KUNIT_CASE(drm_test_damage_iter_damage_one_intersect), + KUNIT_CASE(drm_test_damage_iter_damage_one_outside), + KUNIT_CASE(drm_test_damage_iter_damage_src_moved), + KUNIT_CASE(drm_test_damage_iter_damage_not_visible), { } }; diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index 1d2fade56227..65c9d225b558 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -16,7 +16,7 @@ #include "../display/drm_dp_mst_topology_internal.h" -static void igt_dp_mst_calc_pbn_mode(struct kunit *test) +static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) { int pbn, i; const struct { @@ -177,7 +177,7 @@ out: return result; } -static void igt_dp_mst_sideband_msg_req_decode(struct kunit *test) +static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) { struct drm_dp_sideband_msg_req_body in = { 0 }; u8 data[] = { 0xff, 0x0, 0xdd }; @@ -271,8 +271,8 @@ static void igt_dp_mst_sideband_msg_req_decode(struct kunit *test) } static struct kunit_case drm_dp_mst_helper_tests[] = { - KUNIT_CASE(igt_dp_mst_calc_pbn_mode), - KUNIT_CASE(igt_dp_mst_sideband_msg_req_decode), + KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode), + KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode), { } }; diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 828487071796..8d86c250c2ec 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -16,6 +16,11 @@ #define TEST_BUF_SIZE 50 +struct convert_to_gray8_result { + unsigned int dst_pitch; + const u8 expected[TEST_BUF_SIZE]; +}; + struct convert_to_rgb332_result { unsigned int dst_pitch; const u8 expected[TEST_BUF_SIZE]; @@ -27,13 +32,26 @@ struct convert_to_rgb565_result { const u16 expected_swab[TEST_BUF_SIZE]; }; +struct convert_to_rgb888_result { + unsigned int dst_pitch; + const u8 expected[TEST_BUF_SIZE]; +}; + +struct convert_to_xrgb2101010_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + struct convert_xrgb8888_case { const char *name; unsigned int pitch; struct drm_rect clip; const u32 xrgb8888[TEST_BUF_SIZE]; + struct convert_to_gray8_result gray8_result; struct convert_to_rgb332_result rgb332_result; struct convert_to_rgb565_result rgb565_result; + struct convert_to_rgb888_result rgb888_result; + struct convert_to_xrgb2101010_result xrgb2101010_result; }; static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { @@ -42,6 +60,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .pitch = 1 * 4, .clip = DRM_RECT_INIT(0, 0, 1, 1), .xrgb8888 = { 0x01FF0000 }, + .gray8_result = { + .dst_pitch = 0, + .expected = { 0x4C }, + }, .rgb332_result = { .dst_pitch = 0, .expected = { 0xE0 }, @@ -51,6 +73,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, + .rgb888_result = { + .dst_pitch = 0, + .expected = { 0x00, 0x00, 0xFF }, + }, + .xrgb2101010_result = { + .dst_pitch = 0, + .expected = { 0x3FF00000 }, + }, }, { .name = "single_pixel_clip_rectangle", @@ -60,6 +90,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x00000000, 0x00000000, 0x10FF0000, }, + .gray8_result = { + .dst_pitch = 0, + .expected = { 0x4C }, + }, .rgb332_result = { .dst_pitch = 0, .expected = { 0xE0 }, @@ -69,6 +103,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, + .rgb888_result = { + .dst_pitch = 0, + .expected = { 0x00, 0x00, 0xFF }, + }, + .xrgb2101010_result = { + .dst_pitch = 0, + .expected = { 0x3FF00000 }, + }, }, { /* Well known colors: White, black, red, green, blue, magenta, @@ -85,6 +127,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000, 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, }, + .gray8_result = { + .dst_pitch = 0, + .expected = { + 0xFF, 0x00, + 0x4C, 0x99, + 0x19, 0x66, + 0xE5, 0xB2, + }, + }, .rgb332_result = { .dst_pitch = 0, .expected = { @@ -109,6 +160,24 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0xE0FF, 0xFF07, }, }, + .rgb888_result = { + .dst_pitch = 0, + .expected = { + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + }, + }, + .xrgb2101010_result = { + .dst_pitch = 0, + .expected = { + 0x3FFFFFFF, 0x00000000, + 0x3FF00000, 0x000FFC00, + 0x000003FF, 0x3FF003FF, + 0x3FFFFC00, 0x000FFFFF, + }, + }, }, { /* Randomly picked colors. Full buffer within the clip area. */ @@ -120,6 +189,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0xD16C7073, 0xA20E449C, 0xB2114D05, 0xC2A80303, 0xD26C7073, 0xA30E449C, }, + .gray8_result = { + .dst_pitch = 5, + .expected = { + 0x3C, 0x33, 0x34, 0x00, 0x00, + 0x6F, 0x3C, 0x33, 0x00, 0x00, + 0x34, 0x6F, 0x3C, 0x00, 0x00, + }, + }, .rgb332_result = { .dst_pitch = 5, .expected = { @@ -141,6 +218,25 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000, }, }, + .rgb888_result = { + .dst_pitch = 15, + .expected = { + 0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11, 0x03, 0x03, 0xA8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x03, 0xA8, 0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + .xrgb2101010_result = { + .dst_pitch = 20, + .expected = { + 0x03844672, 0x0444D414, 0x2A20300C, 0x00000000, 0x00000000, + 0x1B1705CD, 0x03844672, 0x0444D414, 0x00000000, 0x00000000, + 0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000, + }, + }, }, }; @@ -192,7 +288,37 @@ static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t, KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases, convert_xrgb8888_case_desc); -static void xrgb8888_to_rgb332_test(struct kunit *test) +static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_gray8_result *result = ¶ms->gray8_result; + size_t dst_size; + __u8 *buf = NULL; + __u32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch, + ¶ms->clip); + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); +} + +static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) { const struct convert_xrgb8888_case *params = test->param_value; const struct convert_to_rgb332_result *result = ¶ms->rgb332_result; @@ -222,7 +348,7 @@ static void xrgb8888_to_rgb332_test(struct kunit *test) KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); } -static void xrgb8888_to_rgb565_test(struct kunit *test) +static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) { const struct convert_xrgb8888_case *params = test->param_value; const struct convert_to_rgb565_result *result = ¶ms->rgb565_result; @@ -255,9 +381,73 @@ static void xrgb8888_to_rgb565_test(struct kunit *test) KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0); } +static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_rgb888_result *result = ¶ms->rgb888_result; + size_t dst_size; + __u8 *buf = NULL; + __u32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch, + ¶ms->clip); + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); +} + +static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_xrgb2101010_result *result = ¶ms->xrgb2101010_result; + size_t dst_size; + __u32 *buf = NULL; + __u32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010, + result->dst_pitch, ¶ms->clip); + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, buf, TEST_BUF_SIZE); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); +} + static struct kunit_case drm_format_helper_test_cases[] = { - KUNIT_CASE_PARAM(xrgb8888_to_rgb332_test, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(xrgb8888_to_rgb565_test, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params), {} }; diff --git a/drivers/gpu/drm/tests/drm_format_test.c b/drivers/gpu/drm/tests/drm_format_test.c index afb4bca72187..ec6996ce819a 100644 --- a/drivers/gpu/drm/tests/drm_format_test.c +++ b/drivers/gpu/drm/tests/drm_format_test.c @@ -9,103 +9,136 @@ #include <drm/drm_fourcc.h> -static void igt_check_drm_format_block_width(struct kunit *test) +static void drm_test_format_block_width_invalid(struct kunit *test) { const struct drm_format_info *info = NULL; - /* Test invalid arguments */ - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); - - /* Test 1 plane format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); - - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 2)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); - - /* Test 3 planes format */ - info = drm_format_info(DRM_FORMAT_YUV422); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 2)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 3)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); - - /* Test a tiled format */ - info = drm_format_info(DRM_FORMAT_X0L0); - KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0); +} + +static void drm_test_format_block_width_one_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0); +} + +static void drm_test_format_block_width_two_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0); +} + +static void drm_test_format_block_width_three_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 3), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0); +} + +static void drm_test_format_block_width_tiled(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0); + + KUNIT_ASSERT_NOT_NULL(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 2); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0); } -static void igt_check_drm_format_block_height(struct kunit *test) +static void drm_test_format_block_height_invalid(struct kunit *test) { const struct drm_format_info *info = NULL; - /* Test invalid arguments */ - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); - - /* Test 1 plane format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); - - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 2)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); - - /* Test 3 planes format */ - info = drm_format_info(DRM_FORMAT_YUV422); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1)); - KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 2)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 3)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); - - /* Test a tiled format */ - info = drm_format_info(DRM_FORMAT_X0L0); - KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0); +} + +static void drm_test_format_block_height_one_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0); +} + +static void drm_test_format_block_height_two_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0); +} + +static void drm_test_format_block_height_three_plane(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 3), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0); +} + +static void drm_test_format_block_height_tiled(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0); + + KUNIT_ASSERT_NOT_NULL(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 2); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); - KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0); } -static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) +static void drm_test_format_min_pitch_invalid(struct kunit *test) { const struct drm_format_info *info = NULL; - /* Test invalid arguments */ - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); +} + +static void drm_test_format_min_pitch_one_plane_8bpp(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB332); - /* Test 1 plane 8 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_RGB332); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2); @@ -118,13 +151,17 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) (uint64_t)UINT_MAX); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), (uint64_t)(UINT_MAX - 1)); +} + +static void drm_test_format_min_pitch_one_plane_16bpp(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444); - /* Test 1 plane 16 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4); @@ -137,13 +174,17 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) (uint64_t)UINT_MAX * 2); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), (uint64_t)(UINT_MAX - 1) * 2); +} + +static void drm_test_format_min_pitch_one_plane_24bpp(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB888); - /* Test 1 plane 24 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_RGB888); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 3); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 6); @@ -154,15 +195,19 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2013); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), (uint64_t)UINT_MAX * 3); - KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1), (uint64_t)(UINT_MAX - 1) * 3); +} - /* Test 1 plane 32 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_ABGR8888); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); +static void drm_test_format_min_pitch_one_plane_32bpp(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_ABGR8888); + + KUNIT_ASSERT_NOT_NULL(test, info); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 4); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 8); @@ -173,21 +218,20 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2684); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), (uint64_t)UINT_MAX * 4); - KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1), (uint64_t)(UINT_MAX - 1) * 4); } -static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test) +static void drm_test_format_min_pitch_two_plane(struct kunit *test) { - const struct drm_format_info *info = NULL; + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12); + + KUNIT_ASSERT_NOT_NULL(test, info); - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0)); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2); @@ -211,15 +255,19 @@ static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test) (uint64_t)(UINT_MAX - 1)); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2), (uint64_t)(UINT_MAX - 1)); +} + +static void drm_test_format_min_pitch_three_plane_8bpp(struct kunit *test) +{ + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422); + + KUNIT_ASSERT_NOT_NULL(test, info); - /* Test 3 planes 8 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_YUV422); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 3, 0)); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 3, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 1); @@ -256,16 +304,15 @@ static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test) (uint64_t)(UINT_MAX - 1) / 2); } -static void igt_check_drm_format_min_pitch_for_tiled_format(struct kunit *test) +static void drm_test_format_min_pitch_tiled(struct kunit *test) { - const struct drm_format_info *info = NULL; + const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L2); + + KUNIT_ASSERT_NOT_NULL(test, info); - /* Test tiled format */ - info = drm_format_info(DRM_FORMAT_X0L2); - KUNIT_EXPECT_TRUE(test, info); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); - KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2); KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4); @@ -281,12 +328,25 @@ static void igt_check_drm_format_min_pitch_for_tiled_format(struct kunit *test) } static struct kunit_case drm_format_tests[] = { - KUNIT_CASE(igt_check_drm_format_block_width), - KUNIT_CASE(igt_check_drm_format_block_height), - KUNIT_CASE(igt_check_drm_format_min_pitch_for_single_plane), - KUNIT_CASE(igt_check_drm_format_min_pitch_for_multi_planar), - KUNIT_CASE(igt_check_drm_format_min_pitch_for_tiled_format), - { } + KUNIT_CASE(drm_test_format_block_width_invalid), + KUNIT_CASE(drm_test_format_block_width_one_plane), + KUNIT_CASE(drm_test_format_block_width_two_plane), + KUNIT_CASE(drm_test_format_block_width_three_plane), + KUNIT_CASE(drm_test_format_block_width_tiled), + KUNIT_CASE(drm_test_format_block_height_invalid), + KUNIT_CASE(drm_test_format_block_height_one_plane), + KUNIT_CASE(drm_test_format_block_height_two_plane), + KUNIT_CASE(drm_test_format_block_height_three_plane), + KUNIT_CASE(drm_test_format_block_height_tiled), + KUNIT_CASE(drm_test_format_min_pitch_invalid), + KUNIT_CASE(drm_test_format_min_pitch_one_plane_8bpp), + KUNIT_CASE(drm_test_format_min_pitch_one_plane_16bpp), + KUNIT_CASE(drm_test_format_min_pitch_one_plane_24bpp), + KUNIT_CASE(drm_test_format_min_pitch_one_plane_32bpp), + KUNIT_CASE(drm_test_format_min_pitch_two_plane), + KUNIT_CASE(drm_test_format_min_pitch_three_plane_8bpp), + KUNIT_CASE(drm_test_format_min_pitch_tiled), + {} }; static struct kunit_suite drm_format_test_suite = { diff --git a/drivers/gpu/drm/tests/drm_framebuffer_test.c b/drivers/gpu/drm/tests/drm_framebuffer_test.c index ec7a08ba4056..df235b7fdaa5 100644 --- a/drivers/gpu/drm/tests/drm_framebuffer_test.c +++ b/drivers/gpu/drm/tests/drm_framebuffer_test.c @@ -25,7 +25,7 @@ struct drm_framebuffer_test { const char *name; }; -static struct drm_framebuffer_test createbuffer_tests[] = { +static const struct drm_framebuffer_test drm_framebuffer_create_cases[] = { { .buffer_created = 1, .name = "ABGR8888 normal sizes", .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888, .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 }, @@ -330,43 +330,50 @@ static struct drm_mode_config_funcs mock_config_funcs = { .fb_create = fb_create_mock, }; -static struct drm_device mock_drm_device = { - .mode_config = { - .min_width = MIN_WIDTH, - .max_width = MAX_WIDTH, - .min_height = MIN_HEIGHT, - .max_height = MAX_HEIGHT, - .funcs = &mock_config_funcs, - }, -}; +static int drm_framebuffer_test_init(struct kunit *test) +{ + struct drm_device *mock; + + mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock); -static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r) + mock->mode_config.min_width = MIN_WIDTH; + mock->mode_config.max_width = MAX_WIDTH; + mock->mode_config.min_height = MIN_HEIGHT; + mock->mode_config.max_height = MAX_HEIGHT; + mock->mode_config.funcs = &mock_config_funcs; + + test->priv = mock; + return 0; +} + +static void drm_test_framebuffer_create(struct kunit *test) { + const struct drm_framebuffer_test *params = test->param_value; + struct drm_device *mock = test->priv; int buffer_created = 0; - mock_drm_device.dev_private = &buffer_created; - drm_internal_framebuffer_create(&mock_drm_device, r, NULL); - return buffer_created; + mock->dev_private = &buffer_created; + drm_internal_framebuffer_create(mock, ¶ms->cmd, NULL); + KUNIT_EXPECT_EQ(test, params->buffer_created, buffer_created); } -static void igt_check_drm_framebuffer_create(struct kunit *test) +static void drm_framebuffer_test_to_desc(const struct drm_framebuffer_test *t, char *desc) { - int i = 0; - - for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) { - KUNIT_EXPECT_EQ_MSG(test, createbuffer_tests[i].buffer_created, - execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd), - "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name); - } + strcpy(desc, t->name); } +KUNIT_ARRAY_PARAM(drm_framebuffer_create, drm_framebuffer_create_cases, + drm_framebuffer_test_to_desc); + static struct kunit_case drm_framebuffer_tests[] = { - KUNIT_CASE(igt_check_drm_framebuffer_create), + KUNIT_CASE_PARAM(drm_test_framebuffer_create, drm_framebuffer_create_gen_params), { } }; static struct kunit_suite drm_framebuffer_test_suite = { .name = "drm_framebuffer", + .init = drm_framebuffer_test_init, .test_cases = drm_framebuffer_tests, }; diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c index 1e2c1aa524bd..659d1af4dca7 100644 --- a/drivers/gpu/drm/tests/drm_mm_test.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -191,7 +191,7 @@ static bool assert_node(struct kunit *test, struct drm_mm_node *node, struct drm return ok; } -static void igt_mm_init(struct kunit *test) +static void drm_test_mm_init(struct kunit *test) { const unsigned int size = 4096; struct drm_mm mm; @@ -245,7 +245,7 @@ out: drm_mm_takedown(&mm); } -static void igt_mm_debug(struct kunit *test) +static void drm_test_mm_debug(struct kunit *test) { struct drm_mm mm; struct drm_mm_node nodes[2]; @@ -341,7 +341,7 @@ static bool check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, return true; } -static int __igt_reserve(struct kunit *test, unsigned int count, u64 size) +static int __drm_test_mm_reserve(struct kunit *test, unsigned int count, u64 size) { DRM_RND_STATE(prng, random_seed); struct drm_mm mm; @@ -349,7 +349,7 @@ static int __igt_reserve(struct kunit *test, unsigned int count, u64 size) unsigned int *order, n, m, o = 0; int ret, err; - /* For exercising drm_mm_reserve_node(struct kunit *test, ), we want to check that + /* For exercising drm_mm_reserve_node(), we want to check that * reservations outside of the drm_mm range are rejected, and to * overlapping and otherwise already occupied ranges. Afterwards, * the tree and nodes should be intact. @@ -463,7 +463,7 @@ err: return ret; } -static void igt_mm_reserve(struct kunit *test) +static void drm_test_mm_reserve(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); int n; @@ -471,9 +471,9 @@ static void igt_mm_reserve(struct kunit *test) for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size - 1)); - KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size)); - KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size + 1)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size - 1)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size + 1)); cond_resched(); } @@ -524,7 +524,7 @@ static bool expect_insert_fail(struct kunit *test, struct drm_mm *mm, u64 size) return false; } -static int __igt_insert(struct kunit *test, unsigned int count, u64 size, bool replace) +static int __drm_test_mm_insert(struct kunit *test, unsigned int count, u64 size, bool replace) { DRM_RND_STATE(prng, random_seed); const struct insert_mode *mode; @@ -660,7 +660,7 @@ err_nodes: return ret; } -static void igt_mm_insert(struct kunit *test) +static void drm_test_mm_insert(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); unsigned int n; @@ -668,20 +668,20 @@ static void igt_mm_insert(struct kunit *test) for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size - 1, false)); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size, false)); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size + 1, false)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, false)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, false)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, false)); cond_resched(); } } -static void igt_mm_replace(struct kunit *test) +static void drm_test_mm_replace(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); unsigned int n; - /* Reuse igt_insert to exercise replacement by inserting a dummy node, + /* Reuse __drm_test_mm_insert to exercise replacement by inserting a dummy node, * then replacing it with the intended node. We want to check that * the tree is intact and all the information we need is carried * across to the target node. @@ -690,9 +690,9 @@ static void igt_mm_replace(struct kunit *test) for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size - 1, true)); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size, true)); - KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size + 1, true)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, true)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, true)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, true)); cond_resched(); } @@ -808,7 +808,8 @@ static bool assert_contiguous_in_range(struct kunit *test, struct drm_mm *mm, return true; } -static int __igt_insert_range(struct kunit *test, unsigned int count, u64 size, u64 start, u64 end) +static int __drm_test_mm_insert_range(struct kunit *test, unsigned int count, u64 size, + u64 start, u64 end) { const struct insert_mode *mode; struct drm_mm mm; @@ -820,7 +821,7 @@ static int __igt_insert_range(struct kunit *test, unsigned int count, u64 size, DRM_MM_BUG_ON(!size); DRM_MM_BUG_ON(end <= start); - /* Very similar to __igt_insert(struct kunit *test, ), but now instead of populating the + /* Very similar to __drm_test_mm_insert(), but now instead of populating the * full range of the drm_mm, we try to fill a small portion of it. */ @@ -921,7 +922,7 @@ static int insert_outside_range(struct kunit *test) return 0; } -static void igt_mm_insert_range(struct kunit *test) +static void drm_test_mm_insert_range(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); unsigned int n; @@ -933,21 +934,21 @@ static void igt_mm_insert_range(struct kunit *test) const u64 size = BIT_ULL(n); const u64 max = count * size; - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max)); - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 1, max)); - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max - 1)); - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max / 2)); - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, max / 2, max / 2)); - KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, - max / 4 + 1, 3 * max / 4 - 1)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 1, max)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max - 1)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max / 2)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, + max / 2, max / 2)); + KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, + max / 4 + 1, 3 * max / 4 - 1)); cond_resched(); } } -static int prepare_igt_frag(struct kunit *test, struct drm_mm *mm, - struct drm_mm_node *nodes, unsigned int num_insert, - const struct insert_mode *mode) +static int prepare_frag(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *nodes, + unsigned int num_insert, const struct insert_mode *mode) { unsigned int size = 4096; unsigned int i; @@ -987,7 +988,7 @@ static u64 get_insert_time(struct kunit *test, struct drm_mm *mm, return ktime_to_ns(ktime_sub(ktime_get(), start)); } -static void igt_mm_frag(struct kunit *test) +static void drm_test_mm_frag(struct kunit *test) { struct drm_mm mm; const struct insert_mode *mode; @@ -997,15 +998,15 @@ static void igt_mm_frag(struct kunit *test) /* We need 4 * insert_size nodes to hold intermediate allocated * drm_mm nodes. - * 1 times for prepare_igt_frag(struct kunit *test, ) - * 1 times for get_insert_time(struct kunit *test, ) - * 2 times for get_insert_time(struct kunit *test, ) + * 1 times for prepare_frag() + * 1 times for get_insert_time() + * 2 times for get_insert_time() */ nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); KUNIT_ASSERT_TRUE(test, nodes); /* For BOTTOMUP and TOPDOWN, we first fragment the - * address space using prepare_igt_frag(struct kunit *test, ) and then try to verify + * address space using prepare_frag() and then try to verify * that insertions scale quadratically from 10k to 20k insertions */ drm_mm_init(&mm, 1, U64_MAX - 2); @@ -1016,7 +1017,7 @@ static void igt_mm_frag(struct kunit *test) mode->mode != DRM_MM_INSERT_HIGH) continue; - if (prepare_igt_frag(test, &mm, nodes, insert_size, mode)) + if (prepare_frag(test, &mm, nodes, insert_size, mode)) goto err; insert_time1 = get_insert_time(test, &mm, insert_size, @@ -1049,7 +1050,7 @@ err: vfree(nodes); } -static void igt_mm_align(struct kunit *test) +static void drm_test_mm_align(struct kunit *test) { const struct insert_mode *mode; const unsigned int max_count = min(8192u, max_prime); @@ -1096,7 +1097,7 @@ out: vfree(nodes); } -static void igt_align_pot(struct kunit *test, int max) +static void drm_test_mm_align_pot(struct kunit *test, int max) { struct drm_mm mm; struct drm_mm_node *node, *next; @@ -1133,14 +1134,14 @@ out: drm_mm_takedown(&mm); } -static void igt_mm_align32(struct kunit *test) +static void drm_test_mm_align32(struct kunit *test) { - igt_align_pot(test, 32); + drm_test_mm_align_pot(test, 32); } -static void igt_mm_align64(struct kunit *test) +static void drm_test_mm_align64(struct kunit *test) { - igt_align_pot(test, 64); + drm_test_mm_align_pot(test, 64); } static void show_scan(struct kunit *test, const struct drm_mm_scan *scan) @@ -1386,7 +1387,7 @@ static int evict_something(struct kunit *test, struct drm_mm *mm, return 0; } -static void igt_mm_evict(struct kunit *test) +static void drm_test_mm_evict(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int size = 8192; @@ -1477,7 +1478,7 @@ err_nodes: vfree(nodes); } -static void igt_mm_evict_range(struct kunit *test) +static void drm_test_mm_evict_range(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int size = 8192; @@ -1490,7 +1491,7 @@ static void igt_mm_evict_range(struct kunit *test) struct drm_mm_node *node, *next; unsigned int *order, n; - /* Like igt_evict() but now we are limiting the search to a + /* Like drm_test_mm_evict() but now we are limiting the search to a * small portion of the full drm_mm. */ @@ -1564,7 +1565,7 @@ static unsigned int node_index(const struct drm_mm_node *node) return div64_u64(node->start, node->size); } -static void igt_mm_topdown(struct kunit *test) +static void drm_test_mm_topdown(struct kunit *test) { const struct insert_mode *topdown = &insert_modes[TOPDOWN]; @@ -1671,7 +1672,7 @@ err_nodes: vfree(nodes); } -static void igt_mm_bottomup(struct kunit *test) +static void drm_test_mm_bottomup(struct kunit *test) { const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; @@ -1683,7 +1684,7 @@ static void igt_mm_bottomup(struct kunit *test) struct drm_mm_node *nodes, *node, *next; unsigned int *order, n, m, o = 0; - /* Like igt_topdown, but instead of searching for the last hole, + /* Like drm_test_mm_topdown, but instead of searching for the last hole, * we search for the first. */ @@ -1763,7 +1764,7 @@ err_nodes: vfree(nodes); } -static void __igt_once(struct kunit *test, unsigned int mode) +static void drm_test_mm_once(struct kunit *test, unsigned int mode) { struct drm_mm mm; struct drm_mm_node rsvd_lo, rsvd_hi, node; @@ -1806,14 +1807,14 @@ err: drm_mm_takedown(&mm); } -static void igt_mm_lowest(struct kunit *test) +static void drm_test_mm_lowest(struct kunit *test) { - __igt_once(test, DRM_MM_INSERT_LOW); + drm_test_mm_once(test, DRM_MM_INSERT_LOW); } -static void igt_mm_highest(struct kunit *test) +static void drm_test_mm_highest(struct kunit *test) { - __igt_once(test, DRM_MM_INSERT_HIGH); + drm_test_mm_once(test, DRM_MM_INSERT_HIGH); } static void separate_adjacent_colors(const struct drm_mm_node *node, @@ -1842,7 +1843,7 @@ static bool colors_abutt(struct kunit *test, const struct drm_mm_node *node) return false; } -static void igt_mm_color(struct kunit *test) +static void drm_test_mm_color(struct kunit *test) { const unsigned int count = min(4096u, max_iterations); const struct insert_mode *mode; @@ -2041,7 +2042,7 @@ static int evict_color(struct kunit *test, struct drm_mm *mm, u64 range_start, return 0; } -static void igt_mm_color_evict(struct kunit *test) +static void drm_test_mm_color_evict(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int total_size = min(8192u, max_iterations); @@ -2122,7 +2123,7 @@ err_nodes: vfree(nodes); } -static void igt_mm_color_evict_range(struct kunit *test) +static void drm_test_mm_color_evict_range(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int total_size = 8192; @@ -2136,7 +2137,7 @@ static void igt_mm_color_evict_range(struct kunit *test) struct drm_mm_node *node, *next; unsigned int *order, n; - /* Like igt_color_evict(), but limited to small portion of the full + /* Like drm_test_mm_color_evict(), but limited to small portion of the full * drm_mm range. */ @@ -2221,25 +2222,25 @@ module_param(max_iterations, uint, 0400); module_param(max_prime, uint, 0400); static struct kunit_case drm_mm_tests[] = { - KUNIT_CASE(igt_mm_init), - KUNIT_CASE(igt_mm_debug), - KUNIT_CASE(igt_mm_reserve), - KUNIT_CASE(igt_mm_insert), - KUNIT_CASE(igt_mm_replace), - KUNIT_CASE(igt_mm_insert_range), - KUNIT_CASE(igt_mm_frag), - KUNIT_CASE(igt_mm_align), - KUNIT_CASE(igt_mm_align32), - KUNIT_CASE(igt_mm_align64), - KUNIT_CASE(igt_mm_evict), - KUNIT_CASE(igt_mm_evict_range), - KUNIT_CASE(igt_mm_topdown), - KUNIT_CASE(igt_mm_bottomup), - KUNIT_CASE(igt_mm_lowest), - KUNIT_CASE(igt_mm_highest), - KUNIT_CASE(igt_mm_color), - KUNIT_CASE(igt_mm_color_evict), - KUNIT_CASE(igt_mm_color_evict_range), + KUNIT_CASE(drm_test_mm_init), + KUNIT_CASE(drm_test_mm_debug), + KUNIT_CASE(drm_test_mm_reserve), + KUNIT_CASE(drm_test_mm_insert), + KUNIT_CASE(drm_test_mm_replace), + KUNIT_CASE(drm_test_mm_insert_range), + KUNIT_CASE(drm_test_mm_frag), + KUNIT_CASE(drm_test_mm_align), + KUNIT_CASE(drm_test_mm_align32), + KUNIT_CASE(drm_test_mm_align64), + KUNIT_CASE(drm_test_mm_evict), + KUNIT_CASE(drm_test_mm_evict_range), + KUNIT_CASE(drm_test_mm_topdown), + KUNIT_CASE(drm_test_mm_bottomup), + KUNIT_CASE(drm_test_mm_lowest), + KUNIT_CASE(drm_test_mm_highest), + KUNIT_CASE(drm_test_mm_color), + KUNIT_CASE(drm_test_mm_color_evict), + KUNIT_CASE(drm_test_mm_color_evict_range), {} }; diff --git a/drivers/gpu/drm/tests/drm_plane_helper_test.c b/drivers/gpu/drm/tests/drm_plane_helper_test.c index be6cff0020ed..ec71af791f1f 100644 --- a/drivers/gpu/drm/tests/drm_plane_helper_test.c +++ b/drivers/gpu/drm/tests/drm_plane_helper_test.c @@ -73,7 +73,7 @@ static bool check_crtc_eq(struct drm_plane_state *plane_state, return true; } -static void igt_check_plane_state(struct kunit *test) +static void drm_test_check_plane_state(struct kunit *test) { int ret; @@ -223,7 +223,7 @@ static void igt_check_plane_state(struct kunit *test) } static struct kunit_case drm_plane_helper_test[] = { - KUNIT_CASE(igt_check_plane_state), + KUNIT_CASE(drm_test_check_plane_state), {} }; diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c index c1dbefd49a4c..e9809ea32696 100644 --- a/drivers/gpu/drm/tests/drm_rect_test.c +++ b/drivers/gpu/drm/tests/drm_rect_test.c @@ -9,7 +9,7 @@ #include <drm/drm_rect.h> -static void igt_drm_rect_clip_scaled_div_by_zero(struct kunit *test) +static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test) { struct drm_rect src, dst, clip; bool visible; @@ -35,7 +35,7 @@ static void igt_drm_rect_clip_scaled_div_by_zero(struct kunit *test) KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n"); } -static void igt_drm_rect_clip_scaled_not_clipped(struct kunit *test) +static void drm_test_rect_clip_scaled_not_clipped(struct kunit *test) { struct drm_rect src, dst, clip; bool visible; @@ -83,7 +83,7 @@ static void igt_drm_rect_clip_scaled_not_clipped(struct kunit *test) KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); } -static void igt_drm_rect_clip_scaled_clipped(struct kunit *test) +static void drm_test_rect_clip_scaled_clipped(struct kunit *test) { struct drm_rect src, dst, clip; bool visible; @@ -173,7 +173,7 @@ static void igt_drm_rect_clip_scaled_clipped(struct kunit *test) KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); } -static void igt_drm_rect_clip_scaled_signed_vs_unsigned(struct kunit *test) +static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test) { struct drm_rect src, dst, clip; bool visible; @@ -197,10 +197,10 @@ static void igt_drm_rect_clip_scaled_signed_vs_unsigned(struct kunit *test) } static struct kunit_case drm_rect_tests[] = { - KUNIT_CASE(igt_drm_rect_clip_scaled_div_by_zero), - KUNIT_CASE(igt_drm_rect_clip_scaled_not_clipped), - KUNIT_CASE(igt_drm_rect_clip_scaled_clipped), - KUNIT_CASE(igt_drm_rect_clip_scaled_signed_vs_unsigned), + KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero), + KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped), + KUNIT_CASE(drm_test_rect_clip_scaled_clipped), + KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned), { } }; diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index b61db8f279e9..afb2879980c6 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -70,7 +70,7 @@ static int tidss_atomic_check(struct drm_device *ddev, * changes. This is needed for updating the plane positions in * tidss_crtc_position_planes() which is called from * crtc_atomic_enable() and crtc_atomic_flush(). We have an - * extra flag to to mark x,y-position changes and together + * extra flag to mark x,y-position changes and together * with zpos_changed the condition recognizes all the above * cases. */ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c index 0ccf791301cb..cf77a8ce7398 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -105,11 +105,10 @@ int tilcdc_plane_init(struct drm_device *dev, struct tilcdc_drm_private *priv = dev->dev_private; int ret; - ret = drm_plane_init(dev, plane, 1, - &tilcdc_plane_funcs, - priv->pixelformats, - priv->num_pixelformats, - true); + ret = drm_universal_plane_init(dev, plane, 1, &tilcdc_plane_funcs, + priv->pixelformats, + priv->num_pixelformats, + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) { dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c index 57f229a785bf..48c24aa8c28a 100644 --- a/drivers/gpu/drm/tiny/hx8357d.c +++ b/drivers/gpu/drm/tiny/hx8357d.c @@ -181,6 +181,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = yx240qv29_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c index 86439e50e304..9a1a5943bee0 100644 --- a/drivers/gpu/drm/tiny/ili9163.c +++ b/drivers/gpu/drm/tiny/ili9163.c @@ -100,6 +100,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs ili9163_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = yx240qv29_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c index b8826a0b086b..69b265e78096 100644 --- a/drivers/gpu/drm/tiny/ili9341.c +++ b/drivers/gpu/drm/tiny/ili9341.c @@ -137,6 +137,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = yx240qv29_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index a5b433a8e0d8..c80028bb1d11 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -150,6 +150,7 @@ static void waveshare_enable(struct drm_simple_display_pipe *pipe, } static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = waveshare_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c index 27f1bd4da2f4..bc522fb3d94d 100644 --- a/drivers/gpu/drm/tiny/mi0283qt.c +++ b/drivers/gpu/drm/tiny/mi0283qt.c @@ -141,6 +141,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = mi0283qt_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c index a76fefa8adbc..955a61d628e7 100644 --- a/drivers/gpu/drm/tiny/panel-mipi-dbi.c +++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c @@ -212,6 +212,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = panel_mipi_dbi_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index c4c1be3ac0b8..e62f4d16b2c6 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -621,6 +621,15 @@ static void power_off(struct repaper_epd *epd) gpiod_set_value_cansleep(epd->discharge, 0); } +static enum drm_mode_status repaper_pipe_mode_valid(struct drm_simple_display_pipe *pipe, + const struct drm_display_mode *mode) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct repaper_epd *epd = drm_to_epd(crtc->dev); + + return drm_crtc_helper_mode_valid_fixed(crtc, mode, epd->mode); +} + static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) @@ -831,6 +840,7 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, } static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { + .mode_valid = repaper_pipe_mode_valid, .enable = repaper_pipe_enable, .disable = repaper_pipe_disable, .update = repaper_pipe_update, @@ -839,22 +849,8 @@ static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { static int repaper_connector_get_modes(struct drm_connector *connector) { struct repaper_epd *epd = drm_to_epd(connector->dev); - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, epd->mode); - if (!mode) { - DRM_ERROR("Failed to duplicate mode\n"); - return 0; - } - - drm_mode_set_name(mode); - mode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; - return 1; + return drm_connector_helper_get_modes_fixed(connector, epd->mode); } static const struct drm_connector_helper_funcs repaper_connector_hfuncs = { diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index a81f91814595..18489779fb8a 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -31,16 +31,6 @@ #define DRIVER_MINOR 0 /* - * Assume a monitor resolution of 96 dpi to - * get a somewhat reasonable screen size. - */ -#define RES_MM(d) \ - (((d) * 254ul) / (96ul * 10ul)) - -#define SIMPLEDRM_MODE(hd, vd) \ - DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd)) - -/* * Helpers for simplefb */ @@ -479,64 +469,46 @@ static const uint64_t simpledrm_primary_plane_format_modifiers[] = { DRM_FORMAT_MOD_INVALID }; -static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *new_state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); - struct drm_crtc *new_crtc = new_plane_state->crtc; - struct drm_crtc_state *new_crtc_state = NULL; - int ret; - - if (new_crtc) - new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); - - ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); - if (ret) - return ret; - else if (!new_plane_state->visible) - return 0; - - return 0; -} - static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *old_state) + struct drm_atomic_state *state) { - struct drm_plane_state *plane_state = plane->state; - struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_device *dev = plane->dev; struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); - struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base); - struct drm_rect src_clip, dst_clip; - int idx; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + int ret, idx; - if (!fb) + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) return; - if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip)) - return; + if (!drm_dev_enter(dev, &idx)) + goto out_drm_gem_fb_end_cpu_access; - dst_clip = plane_state->dst; - if (!drm_rect_intersect(&dst_clip, &src_clip)) - return; + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base); + struct drm_rect dst_clip = plane_state->dst; - if (!drm_dev_enter(dev, &idx)) - return; + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; - iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); - drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb, - &src_clip); + iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); + drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb, + &damage); + } drm_dev_exit(idx); +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); } static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *old_state) + struct drm_atomic_state *state) { struct drm_device *dev = plane->dev; struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); @@ -553,7 +525,7 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, - .atomic_check = simpledrm_primary_plane_helper_atomic_check, + .atomic_check = drm_plane_helper_atomic_check, .atomic_update = simpledrm_primary_plane_helper_atomic_update, .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, }; @@ -570,15 +542,7 @@ static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *cr { struct simpledrm_device *sdev = simpledrm_device_of_dev(crtc->dev); - if (mode->hdisplay != sdev->mode.hdisplay && - mode->vdisplay != sdev->mode.vdisplay) - return MODE_ONE_SIZE; - else if (mode->hdisplay != sdev->mode.hdisplay) - return MODE_ONE_WIDTH; - else if (mode->vdisplay != sdev->mode.vdisplay) - return MODE_ONE_HEIGHT; - - return MODE_OK; + return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode); } static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, @@ -620,24 +584,8 @@ static const struct drm_encoder_funcs simpledrm_encoder_funcs = { static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) { struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev); - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &sdev->mode); - if (!mode) - return 0; - - if (mode->name[0] == '\0') - drm_mode_set_name(mode); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - if (mode->width_mm) - connector->display_info.width_mm = mode->width_mm; - if (mode->height_mm) - connector->display_info.height_mm = mode->height_mm; - - return 1; + return drm_connector_helper_get_modes_fixed(connector, &sdev->mode); } static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { @@ -665,51 +613,17 @@ static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { static struct drm_display_mode simpledrm_mode(unsigned int width, unsigned int height) { - struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; - - mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */; - drm_mode_set_name(&mode); - - return mode; -} - -static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev, - size_t *nformats_out) -{ - struct drm_device *dev = &sdev->dev; - size_t i; - - if (sdev->nformats) - goto out; /* don't rebuild list on recurring calls */ - - /* native format goes first */ - sdev->formats[0] = sdev->format->format; - sdev->nformats = 1; - - /* default formats go second */ - for (i = 0; i < ARRAY_SIZE(simpledrm_primary_plane_formats); ++i) { - if (simpledrm_primary_plane_formats[i] == sdev->format->format) - continue; /* native format already went first */ - sdev->formats[sdev->nformats] = simpledrm_primary_plane_formats[i]; - sdev->nformats++; - } - /* - * TODO: The simpledrm driver converts framebuffers to the native - * format when copying them to device memory. If there are more - * formats listed than supported by the driver, the native format - * is not supported by the conversion helpers. Therefore *only* - * support the native format and add a conversion helper ASAP. + * Assume a monitor resolution of 96 dpi to + * get a somewhat reasonable screen size. */ - if (drm_WARN_ONCE(dev, i != sdev->nformats, - "format conversion helpers required for %p4cc", - &sdev->format->format)) { - sdev->nformats = 1; - } + const struct drm_display_mode mode = { + DRM_MODE_INIT(60, width, height, + DRM_MODE_RES_MM(width, 96ul), + DRM_MODE_RES_MM(height, 96ul)) + }; -out: - *nformats_out = sdev->nformats; - return sdev->formats; + return mode; } static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, @@ -728,7 +642,6 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, struct drm_encoder *encoder; struct drm_connector *connector; unsigned long max_width, max_height; - const uint32_t *formats; size_t nformats; int ret; @@ -779,8 +692,11 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, drm_err(dev, "no simplefb configuration found\n"); return ERR_PTR(-ENODEV); } - if (!stride) - stride = DIV_ROUND_UP(drm_format_info_bpp(format, 0) * width, 8); + if (!stride) { + stride = drm_format_info_min_pitch(format, 0, width); + if (drm_WARN_ON(dev, !stride)) + return ERR_PTR(-EINVAL); + } sdev->mode = simpledrm_mode(width, height); sdev->format = format; @@ -840,11 +756,14 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, /* Primary plane */ - formats = simpledrm_device_formats(sdev, &nformats); + nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, + simpledrm_primary_plane_formats, + ARRAY_SIZE(simpledrm_primary_plane_formats), + sdev->formats, ARRAY_SIZE(sdev->formats)); primary_plane = &sdev->primary_plane; ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs, - formats, nformats, + sdev->formats, nformats, simpledrm_primary_plane_format_modifiers, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index d2042a0f02dd..c36ba08acda1 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -133,6 +133,7 @@ out_exit: } static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = { + .mode_valid = mipi_dbi_pipe_mode_valid, .enable = st7735r_pipe_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 1530982338e9..497ee1fdbad7 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -402,6 +402,8 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map) struct ttm_resource *mem = bo->resource; int ret; + dma_resv_assert_held(bo->base.resv); + ret = ttm_mem_io_reserve(bo->bdev, mem); if (ret) return ret; @@ -460,6 +462,8 @@ void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map) { struct ttm_resource *mem = bo->resource; + dma_resv_assert_held(bo->base.resv); + if (iosys_map_is_null(map)) return; diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 5703277c6f52..91effdcefb6d 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -21,8 +21,14 @@ static int udl_usb_suspend(struct usb_interface *interface, pm_message_t message) { struct drm_device *dev = usb_get_intfdata(interface); + int ret; - return drm_mode_config_helper_suspend(dev); + ret = drm_mode_config_helper_suspend(dev); + if (ret) + return ret; + + udl_sync_pending_urbs(dev); + return 0; } static int udl_usb_resume(struct usb_interface *interface) @@ -32,6 +38,16 @@ static int udl_usb_resume(struct usb_interface *interface) return drm_mode_config_helper_resume(dev); } +static int udl_usb_reset_resume(struct usb_interface *interface) +{ + struct drm_device *dev = usb_get_intfdata(interface); + struct udl_device *udl = to_udl(dev); + + udl_select_std_channel(udl); + + return drm_mode_config_helper_resume(dev); +} + /* * FIXME: Dma-buf sharing requires DMA support by the importing device. * This function is a workaround to make USB devices work as well. @@ -140,6 +156,7 @@ static struct usb_driver udl_driver = { .disconnect = udl_usb_disconnect, .suspend = udl_usb_suspend, .resume = udl_usb_resume, + .reset_resume = udl_usb_reset_resume, .id_table = id_table, }; module_usb_driver(udl_driver); diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 28aaf75d71cf..b4cc7cc568c7 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -39,7 +39,6 @@ struct urb_node { struct urb_list { struct list_head list; - struct list_head in_flight; spinlock_t lock; wait_queue_head_t sleep; int available; @@ -75,17 +74,10 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl) int udl_modeset_init(struct drm_device *dev); struct drm_connector *udl_connector_init(struct drm_device *dev); -struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout); - -#define GET_URB_TIMEOUT HZ -static inline struct urb *udl_get_urb(struct drm_device *dev) -{ - return udl_get_urb_timeout(dev, GET_URB_TIMEOUT); -} +struct urb *udl_get_urb(struct drm_device *dev); int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len); -int udl_sync_pending_urbs(struct drm_device *dev); -void udl_kill_pending_urbs(struct drm_device *dev); +void udl_sync_pending_urbs(struct drm_device *dev); void udl_urb_completion(struct urb *urb); int udl_init(struct udl_device *udl); @@ -95,6 +87,7 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width); int udl_drop_usb(struct drm_device *dev); +int udl_select_std_channel(struct udl_device *udl); #define CMD_WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */ #define CMD_WRITE_RL8 "\xAF\x61" /**< 8 bit run length command. */ diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index fdafbf8f3c3c..061cb88c08a2 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -20,9 +20,11 @@ #define NR_USB_REQUEST_CHANNEL 0x12 #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) -#define WRITES_IN_FLIGHT (4) +#define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 +static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout); + static int udl_parse_vendor_descriptor(struct udl_device *udl) { struct usb_device *udev = udl_to_usb_device(udl); @@ -92,7 +94,7 @@ success: /* * Need to ensure a channel is selected before submitting URBs */ -static int udl_select_std_channel(struct udl_device *udl) +int udl_select_std_channel(struct udl_device *udl) { static const u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7, 0x1C, 0x88, 0x5E, 0x15, @@ -126,6 +128,7 @@ void udl_urb_completion(struct urb *urb) if (urb->status) { if (!(urb->status == -ENOENT || urb->status == -ECONNRESET || + urb->status == -EPROTO || urb->status == -ESHUTDOWN)) { DRM_ERROR("%s - nonzero write bulk status received: %d\n", __func__, urb->status); @@ -135,7 +138,7 @@ void udl_urb_completion(struct urb *urb) urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */ spin_lock_irqsave(&udl->urbs.lock, flags); - list_move(&unode->entry, &udl->urbs.list); + list_add_tail(&unode->entry, &udl->urbs.list); udl->urbs.available++; spin_unlock_irqrestore(&udl->urbs.lock, flags); @@ -145,15 +148,17 @@ void udl_urb_completion(struct urb *urb) static void udl_free_urb_list(struct drm_device *dev) { struct udl_device *udl = to_udl(dev); - int count = udl->urbs.count; struct urb_node *unode; struct urb *urb; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); /* keep waiting and freeing, until we've got 'em all */ - while (count--) { - urb = udl_get_urb_timeout(dev, MAX_SCHEDULE_TIMEOUT); + while (udl->urbs.count) { + spin_lock_irq(&udl->urbs.lock); + urb = udl_get_urb_locked(udl, MAX_SCHEDULE_TIMEOUT); + udl->urbs.count--; + spin_unlock_irq(&udl->urbs.lock); if (WARN_ON(!urb)) break; unode = urb->context; @@ -163,7 +168,8 @@ static void udl_free_urb_list(struct drm_device *dev) usb_free_urb(urb); kfree(unode); } - udl->urbs.count = 0; + + wake_up_all(&udl->urbs.sleep); } static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) @@ -176,16 +182,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) struct usb_device *udev = udl_to_usb_device(udl); spin_lock_init(&udl->urbs.lock); - -retry: - udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); - INIT_LIST_HEAD(&udl->urbs.in_flight); - init_waitqueue_head(&udl->urbs.sleep); udl->urbs.count = 0; udl->urbs.available = 0; +retry: + udl->urbs.size = size; + while (udl->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); if (!unode) @@ -228,43 +232,56 @@ retry: return udl->urbs.count; } -struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout) +static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout) { - struct udl_device *udl = to_udl(dev); - struct urb_node *unode = NULL; + struct urb_node *unode; - if (!udl->urbs.count) - return NULL; + assert_spin_locked(&udl->urbs.lock); /* Wait for an in-flight buffer to complete and get re-queued */ - spin_lock_irq(&udl->urbs.lock); if (!wait_event_lock_irq_timeout(udl->urbs.sleep, + !udl->urbs.count || !list_empty(&udl->urbs.list), udl->urbs.lock, timeout)) { DRM_INFO("wait for urb interrupted: available: %d\n", udl->urbs.available); - goto unlock; + return NULL; } + if (!udl->urbs.count) + return NULL; + unode = list_first_entry(&udl->urbs.list, struct urb_node, entry); - list_move(&unode->entry, &udl->urbs.in_flight); + list_del_init(&unode->entry); udl->urbs.available--; -unlock: - spin_unlock_irq(&udl->urbs.lock); return unode ? unode->urb : NULL; } +#define GET_URB_TIMEOUT HZ +struct urb *udl_get_urb(struct drm_device *dev) +{ + struct udl_device *udl = to_udl(dev); + struct urb *urb; + + spin_lock_irq(&udl->urbs.lock); + urb = udl_get_urb_locked(udl, GET_URB_TIMEOUT); + spin_unlock_irq(&udl->urbs.lock); + return urb; +} + int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) { struct udl_device *udl = to_udl(dev); int ret; - if (WARN_ON(len > udl->urbs.size)) - return -EINVAL; - + if (WARN_ON(len > udl->urbs.size)) { + ret = -EINVAL; + goto error; + } urb->transfer_buffer_length = len; /* set to actual payload len */ ret = usb_submit_urb(urb, GFP_ATOMIC); + error: if (ret) { udl_urb_completion(urb); /* because no one else will */ DRM_ERROR("usb_submit_urb error %x\n", ret); @@ -273,36 +290,17 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) } /* wait until all pending URBs have been processed */ -int udl_sync_pending_urbs(struct drm_device *dev) +void udl_sync_pending_urbs(struct drm_device *dev) { struct udl_device *udl = to_udl(dev); - int ret = 0; spin_lock_irq(&udl->urbs.lock); /* 2 seconds as a sane timeout */ if (!wait_event_lock_irq_timeout(udl->urbs.sleep, - list_empty(&udl->urbs.in_flight), + udl->urbs.available == udl->urbs.count, udl->urbs.lock, msecs_to_jiffies(2000))) - ret = -ETIMEDOUT; - spin_unlock_irq(&udl->urbs.lock); - return ret; -} - -/* kill pending URBs */ -void udl_kill_pending_urbs(struct drm_device *dev) -{ - struct udl_device *udl = to_udl(dev); - struct urb_node *unode; - - spin_lock_irq(&udl->urbs.lock); - while (!list_empty(&udl->urbs.in_flight)) { - unode = list_first_entry(&udl->urbs.in_flight, - struct urb_node, entry); - spin_unlock_irq(&udl->urbs.lock); - usb_kill_urb(unode->urb); - spin_lock_irq(&udl->urbs.lock); - } + drm_err(dev, "Timeout for syncing pending URBs\n"); spin_unlock_irq(&udl->urbs.lock); } @@ -354,7 +352,6 @@ int udl_drop_usb(struct drm_device *dev) { struct udl_device *udl = to_udl(dev); - udl_kill_pending_urbs(dev); udl_free_urb_list(dev); put_device(udl->dmadev); udl->dmadev = NULL; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 169110d8fc2e..ec6876f449f3 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -242,38 +242,15 @@ static long udl_log_cpp(unsigned int cpp) return __ffs(cpp); } -static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y, - int width, int height) -{ - int x1, x2; - - if (WARN_ON_ONCE(x < 0) || - WARN_ON_ONCE(y < 0) || - WARN_ON_ONCE(width < 0) || - WARN_ON_ONCE(height < 0)) - return -EINVAL; - - x1 = ALIGN_DOWN(x, sizeof(unsigned long)); - x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1; - - clip->x1 = x1; - clip->y1 = y; - clip->x2 = x2; - clip->y2 = y + height; - - return 0; -} - static int udl_handle_damage(struct drm_framebuffer *fb, const struct iosys_map *map, - int x, int y, int width, int height) + const struct drm_rect *clip) { struct drm_device *dev = fb->dev; void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */ int i, ret; char *cmd; struct urb *urb; - struct drm_rect clip; int log_bpp; ret = udl_log_cpp(fb->format->cpp[0]); @@ -281,12 +258,6 @@ static int udl_handle_damage(struct drm_framebuffer *fb, return ret; log_bpp = ret; - ret = udl_aligned_damage_clip(&clip, x, y, width, height); - if (ret) - return ret; - else if ((clip.x2 > fb->width) || (clip.y2 > fb->height)) - return -EINVAL; - ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); if (ret) return ret; @@ -298,11 +269,11 @@ static int udl_handle_damage(struct drm_framebuffer *fb, } cmd = urb->transfer_buffer; - for (i = clip.y1; i < clip.y2; i++) { + for (i = clip->y1; i < clip->y2; i++) { const int line_offset = fb->pitches[0] * i; - const int byte_offset = line_offset + (clip.x1 << log_bpp); - const int dev_byte_offset = (fb->width * i + clip.x1) << log_bpp; - const int byte_width = (clip.x2 - clip.x1) << log_bpp; + const int byte_offset = line_offset + (clip->x1 << log_bpp); + const int dev_byte_offset = (fb->width * i + clip->x1) << log_bpp; + const int byte_width = drm_rect_width(clip) << log_bpp; ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr, &cmd, byte_offset, dev_byte_offset, byte_width); @@ -355,6 +326,7 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct udl_device *udl = to_udl(dev); struct drm_display_mode *mode = &crtc_state->mode; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_rect clip = DRM_RECT_INIT(0, 0, fb->width, fb->height); char *buf; char *wrptr; int color_depth = UDL_COLOR_DEPTH_16BPP; @@ -380,10 +352,7 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, udl->mode_buf_len = wrptr - buf; - udl_handle_damage(fb, &shadow_plane_state->data[0], 0, 0, fb->width, fb->height); - - if (!crtc_state->mode_changed) - return; + udl_handle_damage(fb, &shadow_plane_state->data[0], &clip); /* enable display */ udl_crtc_write_mode_to_hw(crtc); @@ -397,8 +366,6 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) struct urb *urb; char *buf; - udl_kill_pending_urbs(dev); - urb = udl_get_urb(dev); if (!urb) return; @@ -410,8 +377,6 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) buf = udl_dummy_render(buf); udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); - - udl_sync_pending_urbs(dev); } static void @@ -427,8 +392,7 @@ udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect)) - udl_handle_damage(fb, &shadow_plane_state->data[0], rect.x1, rect.y1, - rect.x2 - rect.x1, rect.y2 - rect.y1); + udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); } static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = { @@ -483,6 +447,7 @@ int udl_modeset_init(struct drm_device *dev) format_count, NULL, connector); if (ret) return ret; + drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane); drm_mode_config_reset(dev); diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 176ef2a6a731..b57844632dbd 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -25,46 +25,6 @@ #define MIN_RAW_PIX_BYTES 2 #define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES) -/* - * Trims identical data from front and back of line - * Sets new front buffer address and width - * And returns byte count of identical pixels - * Assumes CPU natural alignment (unsigned long) - * for back and front buffer ptrs and width - */ -#if 0 -static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) -{ - int j, k; - const unsigned long *back = (const unsigned long *) bback; - const unsigned long *front = (const unsigned long *) *bfront; - const int width = *width_bytes / sizeof(unsigned long); - int identical = width; - int start = width; - int end = width; - - for (j = 0; j < width; j++) { - if (back[j] != front[j]) { - start = j; - break; - } - } - - for (k = width - 1; k > j; k--) { - if (back[k] != front[k]) { - end = k+1; - break; - } - } - - identical = start + (width - end); - *bfront = (u8 *) &front[start]; - *width_bytes = (end - start) * sizeof(unsigned long); - - return identical * sizeof(unsigned long); -} -#endif - static inline u16 pixel32_to_be16(const uint32_t pixel) { return (((pixel >> 3) & 0x001f) | @@ -220,8 +180,11 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; - if (WARN_ON(!(log_bpp == 1 || log_bpp == 2))) + if (WARN_ON(!(log_bpp == 1 || log_bpp == 2))) { + /* need to finish URB at error from this function */ + udl_urb_completion(urb); return -EINVAL; + } line_start = (u8 *) (front + byte_offset); next_pixel = line_start; diff --git a/drivers/gpu/drm/vboxvideo/vboxvideo.h b/drivers/gpu/drm/vboxvideo/vboxvideo.h index a5de40fe1a76..f60d82504da0 100644 --- a/drivers/gpu/drm/vboxvideo/vboxvideo.h +++ b/drivers/gpu/drm/vboxvideo/vboxvideo.h @@ -43,7 +43,7 @@ * VBE_DISPI_INDEX_VBOX_VIDEO is used to read the configuration information * from the host and issue commands to the host. * - * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the the + * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the * following operations with the VBE data register can be performed: * * Operation Result diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 25299fbc083b..64f9feabf43e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -124,6 +124,23 @@ static unsigned long long vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, unsigned int bpc, enum vc4_hdmi_output_format fmt); +static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder) +{ + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_info *display = &vc4_hdmi->connector.display_info; + + lockdep_assert_held(&vc4_hdmi->mutex); + + if (!display->is_hdmi) + return false; + + if (!display->hdmi.scdc.supported || + !display->hdmi.scdc.scrambling.supported) + return false; + + return true; +} + static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, unsigned int bpc, enum vc4_hdmi_output_format fmt) @@ -271,47 +288,172 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {} #endif -static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder); +static int reset_pipe(struct drm_crtc *crtc, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + int ret; + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return -ENOMEM; -static enum drm_connector_status -vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) + state->acquire_ctx = ctx; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto out; + } + + crtc_state->connectors_changed = true; + + ret = drm_atomic_commit(state); +out: + drm_atomic_state_put(state); + + return ret; +} + +static int vc4_hdmi_reset_link(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx) { + struct drm_device *drm = connector->dev; struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); - bool connected = false; + struct drm_encoder *encoder = &vc4_hdmi->encoder.base; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + bool scrambling_needed; + u8 config; + int ret; - mutex_lock(&vc4_hdmi->mutex); + if (!connector) + return 0; + + ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx); + if (ret) + return ret; + + conn_state = connector->state; + crtc = conn_state->crtc; + if (!crtc) + return 0; + + ret = drm_modeset_lock(&crtc->mutex, ctx); + if (ret) + return ret; + + crtc_state = crtc->state; + if (!crtc_state->active) + return 0; + + if (!vc4_hdmi_supports_scrambling(encoder)) + return 0; + + scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode, + vc4_hdmi->output_bpc, + vc4_hdmi->output_format); + if (!scrambling_needed) + return 0; + + if (conn_state->commit && + !try_wait_for_completion(&conn_state->commit->hw_done)) + return 0; + + ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config); + if (ret < 0) { + drm_err(drm, "Failed to read TMDS config: %d\n", ret); + return 0; + } + + if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) + return 0; + + /* + * HDMI 2.0 says that one should not send scrambled data + * prior to configuring the sink scrambling, and that + * TMDS clock/data transmission should be suspended when + * changing the TMDS clock rate in the sink. So let's + * just do a full modeset here, even though some sinks + * would be perfectly happy if were to just reconfigure + * the SCDC settings on the fly. + */ + return reset_pipe(crtc, ctx); +} + +static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, + struct drm_modeset_acquire_ctx *ctx, + enum drm_connector_status status) +{ + struct drm_connector *connector = &vc4_hdmi->connector; + struct edid *edid; + + /* + * NOTE: This function should really be called with + * vc4_hdmi->mutex held, but doing so results in reentrancy + * issues since cec_s_phys_addr_from_edid might call + * .adap_enable, which leads to that funtion being called with + * our mutex held. + * + * A similar situation occurs with + * drm_atomic_helper_connector_hdmi_reset_link() that will call + * into our KMS hooks if the scrambling was enabled. + * + * Concurrency isn't an issue at the moment since we don't share + * any state with any of the other frameworks so we can ignore + * the lock for now. + */ + + if (status == connector_status_disconnected) { + cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + return; + } + + edid = drm_get_edid(connector, vc4_hdmi->ddc); + if (!edid) + return; + + cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); + kfree(edid); + + vc4_hdmi_reset_link(connector, ctx); +} + +static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); + enum drm_connector_status status = connector_status_disconnected; + + /* + * NOTE: This function should really take vc4_hdmi->mutex, but + * doing so results in reentrancy issues since + * vc4_hdmi_handle_hotplug() can call into other functions that + * would take the mutex while it's held here. + * + * Concurrency isn't an issue at the moment since we don't share + * any state with any of the other frameworks so we can ignore + * the lock for now. + */ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); if (vc4_hdmi->hpd_gpio) { if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) - connected = true; + status = connector_status_connected; } else { if (vc4_hdmi->variant->hp_detect && vc4_hdmi->variant->hp_detect(vc4_hdmi)) - connected = true; - } - - if (connected) { - if (connector->status != connector_status_connected) { - struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc); - - if (edid) { - cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - kfree(edid); - } - } - - vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base); - pm_runtime_put(&vc4_hdmi->pdev->dev); - mutex_unlock(&vc4_hdmi->mutex); - return connector_status_connected; + status = connector_status_connected; } - cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status); pm_runtime_put(&vc4_hdmi->pdev->dev); - mutex_unlock(&vc4_hdmi->mutex); - return connector_status_disconnected; + + return status; } static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) @@ -320,14 +462,21 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) int ret = 0; struct edid *edid; - mutex_lock(&vc4_hdmi->mutex); + /* + * NOTE: This function should really take vc4_hdmi->mutex, but + * doing so results in reentrancy issues since + * cec_s_phys_addr_from_edid might call .adap_enable, which + * leads to that funtion being called with our mutex held. + * + * Concurrency isn't an issue at the moment since we don't share + * any state with any of the other frameworks so we can ignore + * the lock for now. + */ edid = drm_get_edid(connector, vc4_hdmi->ddc); cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - if (!edid) { - ret = -ENODEV; - goto out; - } + if (!edid) + return -ENODEV; drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); @@ -335,7 +484,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) if (vc4_hdmi->disable_4kp60) { struct drm_device *drm = connector->dev; - struct drm_display_mode *mode; + const struct drm_display_mode *mode; list_for_each_entry(mode, &connector->probed_modes, head) { if (vc4_hdmi_mode_needs_scrambling(mode, 8, VC4_HDMI_OUTPUT_RGB)) { @@ -345,9 +494,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) } } -out: - mutex_unlock(&vc4_hdmi->mutex); - return ret; } @@ -419,7 +565,6 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) } static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { - .detect = vc4_hdmi_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .reset = vc4_hdmi_connector_reset, .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, @@ -427,6 +572,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { }; static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { + .detect_ctx = vc4_hdmi_connector_detect_ctx, .get_modes = vc4_hdmi_connector_get_modes, .atomic_check = vc4_hdmi_connector_atomic_check, }; @@ -708,37 +854,19 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) vc4_hdmi_set_hdr_infoframe(encoder); } -static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - struct drm_display_info *display = &vc4_hdmi->connector.display_info; - - lockdep_assert_held(&vc4_hdmi->mutex); - - if (!display->is_hdmi) - return false; - - if (!display->hdmi.scdc.supported || - !display->hdmi.scdc.scrambling.supported) - return false; - - return true; -} - #define SCRAMBLING_POLLING_DELAY_MS 1000 static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_device *drm = vc4_hdmi->connector.dev; - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long flags; int idx; lockdep_assert_held(&vc4_hdmi->mutex); - if (!vc4_hdmi_supports_scrambling(encoder, mode)) + if (!vc4_hdmi_supports_scrambling(encoder)) return; if (!vc4_hdmi_mode_needs_scrambling(mode, @@ -1077,7 +1205,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *drm = vc4_hdmi->connector.dev; bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; @@ -1141,7 +1269,7 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *drm = vc4_hdmi->connector.dev; const struct vc4_hdmi_connector_state *vc4_state = @@ -1303,7 +1431,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, drm_atomic_get_new_connector_state(state, connector); struct vc4_hdmi_connector_state *vc4_conn_state = conn_state_to_vc4_hdmi_conn_state(conn_state); - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long tmds_char_rate = vc4_conn_state->tmds_char_rate; unsigned long bvb_rate, hsm_rate; unsigned long flags; @@ -1416,7 +1544,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_connector *connector = &vc4_hdmi->connector; - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, connector); unsigned long flags; @@ -1445,7 +1573,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_device *drm = vc4_hdmi->connector.dev; - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_display_info *display = &vc4_hdmi->connector.display_info; bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; @@ -2668,17 +2796,6 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) int ret; int idx; - /* - * NOTE: This function should really take vc4_hdmi->mutex, but doing so - * results in a reentrancy since cec_s_phys_addr_from_edid() called in - * .detect or .get_modes might call .adap_enable, which leads to this - * function being called with that mutex held. - * - * Concurrency is not an issue for the moment since we don't share any - * state with KMS, so we can ignore the lock for now, but we need to - * keep it in mind if we were to change that assumption. - */ - if (!drm_dev_enter(drm, &idx)) /* * We can't return an error code, because the CEC @@ -2693,6 +2810,8 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) return ret; } + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); val = HDMI_READ(HDMI_CEC_CNTRL_5); @@ -2727,6 +2846,7 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + mutex_unlock(&vc4_hdmi->mutex); drm_dev_exit(idx); return 0; @@ -2747,16 +2867,7 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap) */ return 0; - /* - * NOTE: This function should really take vc4_hdmi->mutex, but doing so - * results in a reentrancy since cec_s_phys_addr_from_edid() called in - * .detect or .get_modes might call .adap_enable, which leads to this - * function being called with that mutex held. - * - * Concurrency is not an issue for the moment since we don't share any - * state with KMS, so we can ignore the lock for now, but we need to - * keep it in mind if we were to change that assumption. - */ + mutex_lock(&vc4_hdmi->mutex); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -2768,6 +2879,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap) spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + mutex_unlock(&vc4_hdmi->mutex); + pm_runtime_put(&vc4_hdmi->pdev->dev); drm_dev_exit(idx); @@ -2790,17 +2903,6 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) unsigned long flags; int idx; - /* - * NOTE: This function should really take vc4_hdmi->mutex, but doing so - * results in a reentrancy since cec_s_phys_addr_from_edid() called in - * .detect or .get_modes might call .adap_enable, which leads to this - * function being called with that mutex held. - * - * Concurrency is not an issue for the moment since we don't share any - * state with KMS, so we can ignore the lock for now, but we need to - * keep it in mind if we were to change that assumption. - */ - if (!drm_dev_enter(drm, &idx)) /* * We can't return an error code, because the CEC @@ -2809,11 +2911,13 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) */ return 0; + mutex_lock(&vc4_hdmi->mutex); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_CEC_CNTRL_1, (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + mutex_unlock(&vc4_hdmi->mutex); drm_dev_exit(idx); @@ -2830,17 +2934,6 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, unsigned int i; int idx; - /* - * NOTE: This function should really take vc4_hdmi->mutex, but doing so - * results in a reentrancy since cec_s_phys_addr_from_edid() called in - * .detect or .get_modes might call .adap_enable, which leads to this - * function being called with that mutex held. - * - * Concurrency is not an issue for the moment since we don't share any - * state with KMS, so we can ignore the lock for now, but we need to - * keep it in mind if we were to change that assumption. - */ - if (!drm_dev_enter(dev, &idx)) return -ENODEV; @@ -2850,6 +2943,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, return -ENOMEM; } + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); for (i = 0; i < msg->len; i += 4) @@ -2869,7 +2964,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, HDMI_WRITE(HDMI_CEC_CNTRL_1, val); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - + mutex_unlock(&vc4_hdmi->mutex); drm_dev_exit(idx); return 0; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 99b0bc1297be..db823efb2563 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -72,7 +72,7 @@ struct vc4_hdmi_variant { /* Callback to configure the video timings in the HDMI block */ void (*set_timings)(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); /* Callback to initialize the PHY according to the connector state */ void (*phy_init)(struct vc4_hdmi *vc4_hdmi, @@ -195,15 +195,7 @@ struct vc4_hdmi { /** * @mutex: Mutex protecting the driver access across multiple - * frameworks (KMS, ALSA). - * - * NOTE: While supported, CEC has been left out since - * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a - * reentrancy issue between .get_modes (or .detect) and .adap_enable. - * Since we don't share any state between the CEC hooks and KMS', it's - * not a big deal. The only trouble might come from updating the CEC - * clock divider which might be affected by a modeset, but CEC should - * be resilient to that. + * frameworks (KMS, ALSA, CEC). */ struct mutex mutex; diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 3b1701607aae..5d05093014ac 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -47,7 +47,7 @@ static int virtio_gpu_fence_event_create(struct drm_device *dev, struct virtio_gpu_fence_event *e = NULL; int ret; - if (!(vfpriv->ring_idx_mask & (1 << ring_idx))) + if (!(vfpriv->ring_idx_mask & BIT_ULL(ring_idx))) return 0; e = kzalloc(sizeof(*e), GFP_KERNEL); diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index f4319066adcc..c3a845220e10 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -105,11 +105,12 @@ static void vkms_plane_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state; struct drm_framebuffer *fb = new_state->fb; struct vkms_frame_info *frame_info; - u32 fmt = fb->format->format; + u32 fmt; if (!new_state->crtc || !fb) return; + fmt = fb->format->format; vkms_plane_state = to_vkms_plane_state(new_state); shadow_plane_state = &vkms_plane_state->base; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index be19aa6e1f13..09e2d738aa87 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -877,7 +877,6 @@ static inline void vmw_user_resource_noref_release(void) /** * Buffer object helper functions - vmwgfx_bo.c */ -extern bool vmw_bo_is_vmw_bo(struct ttm_buffer_object *bo); extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv, struct vmw_buffer_object *bo, struct ttm_placement *placement, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 2aceac7856e2..089046fa21be 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -1076,6 +1076,7 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, if (desc_len < 0) { atomic_set(&dev_priv->mksstat_user_pids[slot], 0); + __free_page(page); return -EFAULT; } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f2f98e942cf2..0cc5ac35fc57 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -93,6 +93,7 @@ config PEAQ_WMI config NVIDIA_WMI_EC_BACKLIGHT tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems" + depends on ACPI_VIDEO depends on ACPI_WMI depends on BACKLIGHT_CLASS_DEVICE help diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index e0230ea0cb7e..b933a5165edb 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -643,69 +643,6 @@ static const struct dmi_system_id non_acer_quirks[] __initconst = { {} }; -static int __init -video_set_backlight_video_vendor(const struct dmi_system_id *d) -{ - interface->capability &= ~ACER_CAP_BRIGHTNESS; - pr_info("Brightness must be controlled by generic video driver\n"); - return 0; -} - -static const struct dmi_system_id video_vendor_dmi_table[] __initconst = { - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer TravelMate 4750", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Extensa 5235", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer TravelMate 5760", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Aspire 5750", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Aspire 5741", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), - }, - }, - { - /* - * Note no video_set_backlight_video_vendor, we must use the - * acer interface, as there is no native backlight interface. - */ - .ident = "Acer KAV80", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), - }, - }, - {} -}; - /* Find which quirks are needed for a particular vendor/ model pair */ static void __init find_quirks(void) { @@ -2477,9 +2414,6 @@ static int __init acer_wmi_init(void) set_quirks(); - if (dmi_check_system(video_vendor_dmi_table)) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) interface->capability &= ~ACER_CAP_BRIGHTNESS; diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index ffe98a18440b..ca33df7ea550 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -21,7 +21,6 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/vga_switcheroo.h> -#include <acpi/video.h> #include <asm/io.h> /** @@ -694,7 +693,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) * backlight control and supports more levels than other options. * Disable the other backlight choices. */ - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); apple_bl_unregister(); gmux_data->power_state = VGA_SWITCHEROO_ON; @@ -804,7 +802,6 @@ static void gmux_remove(struct pnp_dev *pnp) apple_gmux_data = NULL; kfree(gmux_data); - acpi_video_register(); apple_bl_register(); } diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 478dd300b9c9..bbfed85051ee 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -79,12 +79,10 @@ static struct quirk_entry quirk_asus_q500a = { /* * For those machines that need software to control bt/wifi status - * and can't adjust brightness through ACPI interface * and have duplicate events(ACPI and WMI) for display toggle */ static struct quirk_entry quirk_asus_x55u = { .wapf = 4, - .wmi_backlight_power = true, .wmi_backlight_set_devstate = true, .no_display_toggle = true, }; @@ -99,11 +97,6 @@ static struct quirk_entry quirk_asus_x200ca = { .wmi_backlight_set_devstate = true, }; -static struct quirk_entry quirk_asus_ux303ub = { - .wmi_backlight_native = true, - .wmi_backlight_set_devstate = true, -}; - static struct quirk_entry quirk_asus_x550lb = { .wmi_backlight_set_devstate = true, .xusb2pr = 0x01D9, @@ -147,11 +140,6 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "U32U"), }, - /* - * Note this machine has a Brazos APU, and most Brazos Asus - * machines need quirk_asus_x55u / wmi_backlight_power but - * here acpi-video seems to work fine for backlight control. - */ .driver_data = &quirk_asus_wapf4, }, { @@ -381,15 +369,6 @@ static const struct dmi_system_id asus_quirks[] = { }, { .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. UX303UB", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), - }, - .driver_data = &quirk_asus_ux303ub, - }, - { - .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. UX330UAK", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 89b604e04d7f..434249ac47a5 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3553,7 +3553,6 @@ static int asus_wmi_add(struct platform_device *pdev) struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); struct asus_wmi *asus; - const char *chassis_type; acpi_status status; int err; u32 result; @@ -3635,18 +3634,6 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_force_als_set) asus_wmi_set_als(); - /* Some Asus desktop boards export an acpi-video backlight interface, - stop this from showing up */ - chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); - if (chassis_type && !strcmp(chassis_type, "3")) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - - if (asus->driver->quirks->wmi_backlight_power) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - - if (asus->driver->quirks->wmi_backlight_native) - acpi_video_set_dmi_backlight_type(acpi_backlight_native); - if (asus->driver->quirks->xusb2pr) asus_wmi_set_xusb2pr(asus); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index b302415bf1d9..f30252efe1db 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,8 +29,6 @@ struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; - bool wmi_backlight_power; - bool wmi_backlight_native; bool wmi_backlight_set_devstate; bool wmi_force_als_set; bool use_kbd_dock_devid; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index ce86d84ee796..32d9f0ba6be3 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -96,11 +96,6 @@ static struct quirk_entry quirk_asus_et2012_type3 = { .store_backlight_power = true, }; -static struct quirk_entry quirk_asus_x101ch = { - /* We need this when ACPI function doesn't do this well */ - .wmi_backlight_power = true, -}; - static struct quirk_entry *quirks; static void et2012_quirks(void) @@ -151,25 +146,7 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_unknown, }, - { - .callback = dmi_matched, - .ident = "ASUSTeK Computer INC. X101CH", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), - }, - .driver_data = &quirk_asus_x101ch, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK Computer INC. 1015CX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), - }, - .driver_data = &quirk_asus_x101ch, - }, - {}, + {} }; static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c index 61e37194df70..baccdf658538 100644 --- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c +++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c @@ -7,73 +7,10 @@ #include <linux/backlight.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h> #include <linux/types.h> #include <linux/wmi.h> - -/** - * enum wmi_brightness_method - WMI method IDs - * @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status - * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source - */ -enum wmi_brightness_method { - WMI_BRIGHTNESS_METHOD_LEVEL = 1, - WMI_BRIGHTNESS_METHOD_SOURCE = 2, - WMI_BRIGHTNESS_METHOD_MAX -}; - -/** - * enum wmi_brightness_mode - Operation mode for WMI-wrapped method - * @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source. - * @WMI_BRIGHTNESS_MODE_SET: Set the brightness level. - * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This - * is only valid when the WMI method is - * %WMI_BRIGHTNESS_METHOD_LEVEL. - */ -enum wmi_brightness_mode { - WMI_BRIGHTNESS_MODE_GET = 0, - WMI_BRIGHTNESS_MODE_SET = 1, - WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2, - WMI_BRIGHTNESS_MODE_MAX -}; - -/** - * enum wmi_brightness_source - Backlight brightness control source selection - * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU. - * @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the - * system's Embedded Controller (EC). - * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the - * DisplayPort AUX channel. - */ -enum wmi_brightness_source { - WMI_BRIGHTNESS_SOURCE_GPU = 1, - WMI_BRIGHTNESS_SOURCE_EC = 2, - WMI_BRIGHTNESS_SOURCE_AUX = 3, - WMI_BRIGHTNESS_SOURCE_MAX -}; - -/** - * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method - * @mode: Pass in an &enum wmi_brightness_mode value to select between - * getting or setting a value. - * @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET - * mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or - * %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode. - * @ret: Out parameter returning retrieved value when operating in - * %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL - * mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode. - * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct. - * - * This is the parameters structure for the WmiBrightnessNotify ACPI method as - * wrapped by WMI. The value passed in to @val or returned by @ret will be a - * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or - * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE. - */ -struct wmi_brightness_args { - u32 mode; - u32 val; - u32 ret; - u32 ignored[3]; -}; +#include <acpi/video.h> /** * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method @@ -151,19 +88,10 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct { struct backlight_properties props = {}; struct backlight_device *bdev; - u32 source; int ret; - ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE, - WMI_BRIGHTNESS_MODE_GET, &source); - if (ret) - return ret; - - /* - * This driver is only to be used when brightness control is handled - * by the EC; otherwise, the GPU driver(s) should control brightness. - */ - if (source != WMI_BRIGHTNESS_SOURCE_EC) + /* drivers/acpi/video_detect.c also checks that SOURCE == EC */ + if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec) return -ENODEV; /* @@ -191,8 +119,6 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct return PTR_ERR_OR_ZERO(bdev); } -#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" - static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = { { .guid_string = WMI_BRIGHTNESS_GUID }, { } diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index c187dcdf82f0..cc30cf08f32d 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -356,23 +356,13 @@ struct samsung_laptop { }; struct samsung_quirks { - bool broken_acpi_video; bool four_kbd_backlight_levels; bool enable_kbd_backlight; - bool use_native_backlight; bool lid_handling; }; static struct samsung_quirks samsung_unknown = {}; -static struct samsung_quirks samsung_broken_acpi_video = { - .broken_acpi_video = true, -}; - -static struct samsung_quirks samsung_use_native_backlight = { - .use_native_backlight = true, -}; - static struct samsung_quirks samsung_np740u3e = { .four_kbd_backlight_levels = true, .enable_kbd_backlight = true, @@ -1542,76 +1532,6 @@ static const struct dmi_system_id samsung_dmi_table[] __initconst = { /* Specific DMI ids for laptop with quirks */ { .callback = samsung_dmi_matched, - .ident = "N150P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), - DMI_MATCH(DMI_BOARD_NAME, "N150P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "N145P/N250P/N260P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), - DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "N150/N210/N220", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "NF110/NF210/NF310", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), - DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "X360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "N250P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), - DMI_MATCH(DMI_BOARD_NAME, "N250P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "NC210", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"), - DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, .ident = "730U3E/740U3E", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), @@ -1654,15 +1574,8 @@ static int __init samsung_init(void) samsung->handle_backlight = true; samsung->quirks = quirks; -#ifdef CONFIG_ACPI - if (samsung->quirks->broken_acpi_video) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (samsung->quirks->use_native_backlight) - acpi_video_set_dmi_backlight_type(acpi_backlight_native); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) samsung->handle_backlight = false; -#endif ret = samsung_platform_init(samsung); if (ret) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0fc9e8b8827b..030dc37d50b8 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -272,14 +272,6 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = { }; /* - * List of models which have a broken acpi-video backlight interface and thus - * need to use the toshiba (vendor) interface instead. - */ -static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { - {} -}; - -/* * Utility */ @@ -2881,14 +2873,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } - /* - * Tell acpi-video-detect code to prefer vendor backlight on all - * systems with transflective backlight and on dmi matched systems. - */ - if (dev->tr_backlight_supported || - dmi_check_system(toshiba_vendor_backlight_dmi)) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return 0; diff --git a/include/acpi/video.h b/include/acpi/video.h index db8548ff03ce..a275c35e5249 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h @@ -48,15 +48,18 @@ enum acpi_backlight_type { acpi_backlight_video, acpi_backlight_vendor, acpi_backlight_native, + acpi_backlight_nvidia_wmi_ec, + acpi_backlight_apple_gmux, }; #if IS_ENABLED(CONFIG_ACPI_VIDEO) extern int acpi_video_register(void); extern void acpi_video_unregister(void); +extern void acpi_video_register_backlight(void); extern int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, void **edid); extern enum acpi_backlight_type acpi_video_get_backlight_type(void); -extern void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type); +extern bool acpi_video_backlight_use_native(void); /* * Note: The value returned by acpi_video_handles_brightness_key_presses() * may change over time and should not be cached. @@ -68,6 +71,7 @@ extern int acpi_video_get_levels(struct acpi_device *device, #else static inline int acpi_video_register(void) { return -ENODEV; } static inline void acpi_video_unregister(void) { return; } +static inline void acpi_video_register_backlight(void) { return; } static inline int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, void **edid) { @@ -77,8 +81,9 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void) { return acpi_backlight_vendor; } -static inline void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type) +static inline bool acpi_video_backlight_use_native(void) { + return true; } static inline bool acpi_video_handles_brightness_key_presses(void) { diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index caa181194335..eb5c98cf82b8 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -6,11 +6,15 @@ #ifndef __LINUX_DRM_FORMAT_HELPER_H #define __LINUX_DRM_FORMAT_HELPER_H -struct iosys_map; +#include <linux/types.h> + +struct drm_device; struct drm_format_info; struct drm_framebuffer; struct drm_rect; +struct iosys_map; + unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format, const struct drm_rect *clip); @@ -44,4 +48,9 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc const struct iosys_map *src, const struct drm_framebuffer *fb, const struct drm_rect *clip); +size_t drm_fb_build_fourcc_list(struct drm_device *dev, + const u32 *native_fourccs, size_t native_nfourccs, + const u32 *extra_fourccs, size_t extra_nfourccs, + u32 *fourccs_out, size_t nfourccs_out); + #endif /* __LINUX_DRM_FORMAT_HELPER_H */ diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 58a18a17c67e..bd42f25e449c 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -175,6 +175,41 @@ struct drm_gem_object_funcs { }; /** + * struct drm_gem_lru - A simple LRU helper + * + * A helper for tracking GEM objects in a given state, to aid in + * driver's shrinker implementation. Tracks the count of pages + * for lockless &shrinker.count_objects, and provides + * &drm_gem_lru_scan for driver's &shrinker.scan_objects + * implementation. + */ +struct drm_gem_lru { + /** + * @lock: + * + * Lock protecting movement of GEM objects between LRUs. All + * LRUs that the object can move between should be protected + * by the same lock. + */ + struct mutex *lock; + + /** + * @count: + * + * The total number of backing pages of the GEM objects in + * this LRU. + */ + long count; + + /** + * @list: + * + * The LRU list. + */ + struct list_head list; +}; + +/** * struct drm_gem_object - GEM buffer object * * This structure defines the generic parts for GEM buffer objects, which are @@ -312,6 +347,20 @@ struct drm_gem_object { * */ const struct drm_gem_object_funcs *funcs; + + /** + * @lru_node: + * + * List node in a &drm_gem_lru. + */ + struct list_head lru_node; + + /** + * @lru: + * + * The current LRU list that the GEM object is on. + */ + struct drm_gem_lru *lru; }; /** @@ -420,4 +469,10 @@ void drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, u32 handle, u64 *offset); +void drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock); +void drm_gem_lru_remove(struct drm_gem_object *obj); +void drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj); +unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned nr_to_scan, + bool (*shrink)(struct drm_gem_object *obj)); + #endif /* __DRM_GEM_H__ */ diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h index dad2f187b64b..14eaecb1825c 100644 --- a/include/drm/drm_mipi_dbi.h +++ b/include/drm/drm_mipi_dbi.h @@ -155,6 +155,8 @@ int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, const struct drm_simple_display_pipe_funcs *funcs, const struct drm_display_mode *mode, unsigned int rotation); +enum drm_mode_status mipi_dbi_pipe_mode_valid(struct drm_simple_display_pipe *pipe, + const struct drm_display_mode *mode); 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_dev *dbidev, diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 53e3a8a2f241..20b21b577dea 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -179,6 +179,7 @@ struct mipi_dsi_device_info { * @lp_rate: maximum lane frequency for low power mode in hertz, this should * be set to the real limits of the hardware, zero is only accepted for * legacy drivers + * @dsc: panel/bridge DSC pps payload to be sent */ struct mipi_dsi_device { struct mipi_dsi_host *host; @@ -191,6 +192,7 @@ struct mipi_dsi_device { unsigned long mode_flags; unsigned long hs_rate; unsigned long lp_rate; + struct drm_dsc_config *dsc; }; #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:" diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index a80ae9639e96..b0c680e6f670 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -139,6 +139,35 @@ enum drm_mode_status { .vscan = (vs), .flags = (f) /** + * DRM_MODE_RES_MM - Calculates the display size from resolution and DPI + * @res: The resolution in pixel + * @dpi: The number of dots per inch + */ +#define DRM_MODE_RES_MM(res, dpi) \ + (((res) * 254ul) / ((dpi) * 10ul)) + +#define __DRM_MODE_INIT(pix, hd, vd, hd_mm, vd_mm) \ + .type = DRM_MODE_TYPE_DRIVER, .clock = (pix), \ + .hdisplay = (hd), .hsync_start = (hd), .hsync_end = (hd), \ + .htotal = (hd), .vdisplay = (vd), .vsync_start = (vd), \ + .vsync_end = (vd), .vtotal = (vd), .width_mm = (hd_mm), \ + .height_mm = (vd_mm) + +/** + * DRM_MODE_INIT - Initialize display mode + * @hz: Vertical refresh rate in Hertz + * @hd: Horizontal resolution, width + * @vd: Vertical resolution, height + * @hd_mm: Display width in millimeters + * @vd_mm: Display height in millimeters + * + * This macro initializes a &drm_display_mode that contains information about + * refresh rate, resolution and physical size. + */ +#define DRM_MODE_INIT(hz, hd, vd, hd_mm, vd_mm) \ + __DRM_MODE_INIT((hd) * (vd) * (hz) / 1000 /* kHz */, hd, vd, hd_mm, vd_mm) + +/** * DRM_SIMPLE_MODE - Simple display mode * @hd: Horizontal resolution, width * @vd: Vertical resolution, height @@ -149,11 +178,7 @@ enum drm_mode_status { * resolution and physical size. */ #define DRM_SIMPLE_MODE(hd, vd, hd_mm, vd_mm) \ - .type = DRM_MODE_TYPE_DRIVER, .clock = 1 /* pass validation */, \ - .hdisplay = (hd), .hsync_start = (hd), .hsync_end = (hd), \ - .htotal = (hd), .vdisplay = (vd), .vsync_start = (vd), \ - .vsync_end = (vd), .vtotal = (vd), .width_mm = (hd_mm), \ - .height_mm = (vd_mm) + __DRM_MODE_INIT(1 /* pass validation */, hd, vd, hd_mm, vd_mm) #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 3a271128c078..994bfcdd84c5 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -188,13 +188,6 @@ struct drm_panel { * Panel entry in registry. */ struct list_head list; - - /** - * @dsc: - * - * Panel DSC pps payload to be sent - */ - struct drm_dsc_config *dsc; }; void drm_panel_init(struct drm_panel *panel, struct device *dev, diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 89ea54652e87..447e664e49d5 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -631,7 +631,7 @@ struct drm_plane { unsigned int format_count; /** * @format_default: driver hasn't supplied supported formats for the - * plane. Used by the drm_plane_init compatibility wrapper only. + * plane. Used by the non-atomic driver compatibility wrapper only. */ bool format_default; @@ -762,12 +762,6 @@ int drm_universal_plane_init(struct drm_device *dev, const uint64_t *format_modifiers, enum drm_plane_type type, const char *name, ...); -int drm_plane_init(struct drm_device *dev, - struct drm_plane *plane, - uint32_t possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary); void drm_plane_cleanup(struct drm_plane *plane); __printf(10, 11) @@ -815,6 +809,50 @@ void *__drmm_universal_plane_alloc(struct drm_device *dev, format_count, format_modifiers, \ plane_type, name, ##__VA_ARGS__)) +__printf(10, 11) +void *__drm_universal_plane_alloc(struct drm_device *dev, + size_t size, size_t offset, + uint32_t possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, + unsigned int format_count, + const uint64_t *format_modifiers, + enum drm_plane_type plane_type, + const char *name, ...); + +/** + * drm_universal_plane_alloc() - Allocate and initialize an universal plane object + * @dev: DRM device + * @type: the type of the struct which contains struct &drm_plane + * @member: the name of the &drm_plane within @type + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (DRM_FORMAT\_\*) + * @format_count: number of elements in @formats + * @format_modifiers: array of struct drm_format modifiers terminated by + * DRM_FORMAT_MOD_INVALID + * @plane_type: type of plane (overlay, primary, cursor) + * @name: printf style format string for the plane name, or NULL for default name + * + * Allocates and initializes a plane object of type @type. The caller + * is responsible for releasing the allocated memory with kfree(). + * + * Drivers are encouraged to use drmm_universal_plane_alloc() instead. + * + * Drivers that only support the DRM_FORMAT_MOD_LINEAR modifier support may set + * @format_modifiers to NULL. The plane will advertise the linear modifier. + * + * Returns: + * Pointer to new plane, or ERR_PTR on failure. + */ +#define drm_universal_plane_alloc(dev, type, member, possible_crtcs, funcs, formats, \ + format_count, format_modifiers, plane_type, name, ...) \ + ((type *)__drm_universal_plane_alloc(dev, sizeof(type), \ + offsetof(type, member), \ + possible_crtcs, funcs, formats, \ + format_count, format_modifiers, \ + plane_type, name, ##__VA_ARGS__)) + /** * drm_plane_index - find the index of a registered plane * @plane: plane to find index for diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 1781fab24dd6..ff83d2621687 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -41,5 +41,18 @@ int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *cr int drm_plane_helper_disable_primary(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); void drm_plane_helper_destroy(struct drm_plane *plane); +int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state); + +/** + * DRM_PLANE_NON_ATOMIC_FUNCS - Default plane functions for non-atomic drivers + * + * This macro initializes plane functions for non-atomic drivers to default + * values. Non-atomic interfaces are deprecated and should not be used in new + * drivers. + */ +#define DRM_PLANE_NON_ATOMIC_FUNCS \ + .update_plane = drm_plane_helper_update_primary, \ + .disable_plane = drm_plane_helper_disable_primary, \ + .destroy = drm_plane_helper_destroy #endif diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h index 8075e02aa865..5880daa14624 100644 --- a/include/drm/drm_probe_helper.h +++ b/include/drm/drm_probe_helper.h @@ -3,9 +3,10 @@ #ifndef __DRM_PROBE_HELPER_H__ #define __DRM_PROBE_HELPER_H__ -#include <linux/types.h> +#include <drm/drm_modes.h> struct drm_connector; +struct drm_crtc; struct drm_device; struct drm_modeset_acquire_ctx; @@ -26,7 +27,13 @@ void drm_kms_helper_poll_disable(struct drm_device *dev); void drm_kms_helper_poll_enable(struct drm_device *dev); bool drm_kms_helper_is_poll_worker(void); +enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + const struct drm_display_mode *fixed_mode); + int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector); +int drm_connector_helper_get_modes_fixed(struct drm_connector *connector, + const struct drm_display_mode *fixed_mode); int drm_connector_helper_get_modes(struct drm_connector *connector); #endif diff --git a/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h b/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h new file mode 100644 index 000000000000..23d60130272c --- /dev/null +++ b/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#ifndef __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H +#define __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H + +#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" + +/** + * enum wmi_brightness_method - WMI method IDs + * @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status + * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source + */ +enum wmi_brightness_method { + WMI_BRIGHTNESS_METHOD_LEVEL = 1, + WMI_BRIGHTNESS_METHOD_SOURCE = 2, + WMI_BRIGHTNESS_METHOD_MAX +}; + +/** + * enum wmi_brightness_mode - Operation mode for WMI-wrapped method + * @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source. + * @WMI_BRIGHTNESS_MODE_SET: Set the brightness level. + * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This + * is only valid when the WMI method is + * %WMI_BRIGHTNESS_METHOD_LEVEL. + */ +enum wmi_brightness_mode { + WMI_BRIGHTNESS_MODE_GET = 0, + WMI_BRIGHTNESS_MODE_SET = 1, + WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2, + WMI_BRIGHTNESS_MODE_MAX +}; + +/** + * enum wmi_brightness_source - Backlight brightness control source selection + * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU. + * @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the + * system's Embedded Controller (EC). + * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the + * DisplayPort AUX channel. + */ +enum wmi_brightness_source { + WMI_BRIGHTNESS_SOURCE_GPU = 1, + WMI_BRIGHTNESS_SOURCE_EC = 2, + WMI_BRIGHTNESS_SOURCE_AUX = 3, + WMI_BRIGHTNESS_SOURCE_MAX +}; + +/** + * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method + * @mode: Pass in an &enum wmi_brightness_mode value to select between + * getting or setting a value. + * @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET + * mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or + * %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode. + * @ret: Out parameter returning retrieved value when operating in + * %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL + * mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode. + * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct. + * + * This is the parameters structure for the WmiBrightnessNotify ACPI method as + * wrapped by WMI. The value passed in to @val or returned by @ret will be a + * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or + * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE. + */ +struct wmi_brightness_args { + u32 mode; + u32 val; + u32 ret; + u32 ignored[3]; +}; + +#endif diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index c2c9c674a223..7ee65c0b4f70 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -755,6 +755,14 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_FW_TOC 0x15 /* Subquery id: Query CAP firmware version */ #define AMDGPU_INFO_FW_CAP 0x16 + /* Subquery id: Query GFX RLCP firmware version */ + #define AMDGPU_INFO_FW_GFX_RLCP 0x17 + /* Subquery id: Query GFX RLCV firmware version */ + #define AMDGPU_INFO_FW_GFX_RLCV 0x18 + /* Subquery id: Query MES_KIQ firmware version */ + #define AMDGPU_INFO_FW_MES_KIQ 0x19 + /* Subquery id: Query MES firmware version */ + #define AMDGPU_INFO_FW_MES 0x1a /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f |