Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'drm-misc-next-2024-10-31' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.13:

All of the previous pull request, with MORE!

Core Changes:
- Update documentation for scheduler start/stop and job init.
- Add dedede and sm8350-hdk hardware to ci runs.

Driver Changes:
- Small fixes and cleanups to panfrost, omap, nouveau, ivpu, zynqmp, v3d,
panthor docs, and leadtek-ltk050h3146w.
- Crashdump support for qaic.
- Support DP compliance in zynqmp.
- Add Samsung S6E88A0-AMS427AP24 panel.

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/deeef745-f3fb-4e85-a9d0-e8d38d43c1cf@linux.intel.com

+6423 -979
+14 -1
Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml
··· 81 81 82 82 properties: 83 83 port@0: 84 - $ref: /schemas/graph.yaml#/properties/port 84 + unevaluatedProperties: false 85 + $ref: /schemas/graph.yaml#/$defs/port-base 85 86 description: Parallel RGB input port 87 + 88 + properties: 89 + endpoint: 90 + $ref: /schemas/graph.yaml#/$defs/endpoint-base 91 + unevaluatedProperties: false 92 + 93 + properties: 94 + bus-width: 95 + description: 96 + Endpoint bus width. 97 + enum: [ 16, 18, 24 ] 98 + default: 24 86 99 87 100 port@1: 88 101 $ref: /schemas/graph.yaml#/properties/port
+4
Documentation/devicetree/bindings/display/bridge/toshiba,tc358768.yaml
··· 60 60 data-lines: 61 61 $ref: /schemas/types.yaml#/definitions/uint32 62 62 enum: [ 16, 18, 24 ] 63 + deprecated: true 64 + 65 + bus-width: 66 + enum: [ 16, 18, 24 ] 63 67 64 68 port@1: 65 69 $ref: /schemas/graph.yaml#/properties/port
+8
Documentation/devicetree/bindings/display/panel/panel-common.yaml
··· 51 51 $ref: /schemas/types.yaml#/definitions/uint32 52 52 enum: [0, 90, 180, 270] 53 53 54 + flip-horizontal: 55 + description: boolean to flip image horizontally 56 + type: boolean 57 + 58 + flip-vertical: 59 + description: boolean to flip image vertically 60 + type: boolean 61 + 54 62 # Display Timings 55 63 panel-timing: 56 64 description:
+2
Documentation/devicetree/bindings/display/panel/panel-simple.yaml
··· 200 200 - logictechno,lttd800480070-l2rt 201 201 # Logic Technologies LTTD800480070-L6WH-RT 7” 800x480 TFT Resistive Touch Module 202 202 - logictechno,lttd800480070-l6wh-rt 203 + # Microchip AC69T88A 5" 800X480 LVDS interface TFT LCD Panel 204 + - microchip,ac69t88a 203 205 # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel 204 206 - mitsubishi,aa070mc01-ca1 205 207 # Mitsubishi AA084XE01 8.4" XGA TFT LCD panel
+65
Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams427ap24.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/display/panel/samsung,s6e88a0-ams427ap24.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Samsung AMS427AP24 panel with S6E88A0 controller 8 + 9 + maintainers: 10 + - Jakob Hauser <jahau@rocketmail.com> 11 + 12 + allOf: 13 + - $ref: panel-common.yaml# 14 + 15 + properties: 16 + compatible: 17 + const: samsung,s6e88a0-ams427ap24 18 + 19 + reg: 20 + maxItems: 1 21 + 22 + port: true 23 + reset-gpios: true 24 + flip-horizontal: true 25 + 26 + vdd3-supply: 27 + description: core voltage supply 28 + 29 + vci-supply: 30 + description: voltage supply for analog circuits 31 + 32 + required: 33 + - compatible 34 + - reg 35 + - port 36 + - reset-gpios 37 + - vdd3-supply 38 + - vci-supply 39 + 40 + additionalProperties: false 41 + 42 + examples: 43 + - | 44 + #include <dt-bindings/gpio/gpio.h> 45 + 46 + dsi { 47 + #address-cells = <1>; 48 + #size-cells = <0>; 49 + 50 + panel@0 { 51 + compatible = "samsung,s6e88a0-ams427ap24"; 52 + reg = <0>; 53 + 54 + vdd3-supply = <&pm8916_l17>; 55 + vci-supply = <&pm8916_l6>; 56 + reset-gpios = <&tlmm 25 GPIO_ACTIVE_LOW>; 57 + flip-horizontal; 58 + 59 + port { 60 + panel_in: endpoint { 61 + remote-endpoint = <&mdss_dsi0_out>; 62 + }; 63 + }; 64 + }; 65 + };
+2 -8
Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.yaml
··· 21 21 22 22 reset-gpios: true 23 23 display-timings: true 24 + flip-horizontal: true 25 + flip-vertical: true 24 26 25 27 vdd3-supply: 26 28 description: core voltage supply ··· 47 45 48 46 panel-height-mm: 49 47 description: physical panel height [mm] 50 - 51 - flip-horizontal: 52 - description: boolean to flip image horizontally 53 - type: boolean 54 - 55 - flip-vertical: 56 - description: boolean to flip image vertically 57 - type: boolean 58 48 59 49 required: 60 50 - compatible
+188
Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Rockchip DW HDMI QP TX Encoder 8 + 9 + maintainers: 10 + - Cristian Ciocaltea <cristian.ciocaltea@collabora.com> 11 + 12 + description: | 13 + Rockchip RK3588 SoC integrates the Synopsys DesignWare HDMI QP TX controller 14 + IP and a HDMI/eDP TX Combo PHY based on a Samsung IP block, providing the 15 + following features, among others: 16 + 17 + * Fixed Rate Link (FRL) 18 + * Display Stream Compression (DSC) 19 + * 4K@120Hz and 8K@60Hz video modes 20 + * Variable Refresh Rate (VRR) including Quick Media Switching (QMS) 21 + * Fast Vactive (FVA) 22 + * SCDC I2C DDC access 23 + * Multi-stream audio 24 + * Enhanced Audio Return Channel (EARC) 25 + 26 + allOf: 27 + - $ref: /schemas/sound/dai-common.yaml# 28 + 29 + properties: 30 + compatible: 31 + enum: 32 + - rockchip,rk3588-dw-hdmi-qp 33 + 34 + reg: 35 + maxItems: 1 36 + 37 + clocks: 38 + items: 39 + - description: Peripheral/APB bus clock 40 + - description: EARC RX biphase clock 41 + - description: Reference clock 42 + - description: Audio interface clock 43 + - description: TMDS/FRL link clock 44 + - description: Video datapath clock 45 + 46 + clock-names: 47 + items: 48 + - const: pclk 49 + - const: earc 50 + - const: ref 51 + - const: aud 52 + - const: hdp 53 + - const: hclk_vo1 54 + 55 + interrupts: 56 + items: 57 + - description: AVP Unit interrupt 58 + - description: CEC interrupt 59 + - description: eARC RX interrupt 60 + - description: Main Unit interrupt 61 + - description: HPD interrupt 62 + 63 + interrupt-names: 64 + items: 65 + - const: avp 66 + - const: cec 67 + - const: earc 68 + - const: main 69 + - const: hpd 70 + 71 + phys: 72 + maxItems: 1 73 + description: The HDMI/eDP PHY 74 + 75 + ports: 76 + $ref: /schemas/graph.yaml#/properties/ports 77 + 78 + properties: 79 + port@0: 80 + $ref: /schemas/graph.yaml#/properties/port 81 + description: Video port for RGB/YUV input. 82 + 83 + port@1: 84 + $ref: /schemas/graph.yaml#/properties/port 85 + description: Video port for HDMI/eDP output. 86 + 87 + required: 88 + - port@0 89 + - port@1 90 + 91 + power-domains: 92 + maxItems: 1 93 + 94 + resets: 95 + maxItems: 2 96 + 97 + reset-names: 98 + items: 99 + - const: ref 100 + - const: hdp 101 + 102 + "#sound-dai-cells": 103 + const: 0 104 + 105 + rockchip,grf: 106 + $ref: /schemas/types.yaml#/definitions/phandle 107 + description: 108 + Some HDMI QP related data is accessed through SYS GRF regs. 109 + 110 + rockchip,vo-grf: 111 + $ref: /schemas/types.yaml#/definitions/phandle 112 + description: 113 + Additional HDMI QP related data is accessed through VO GRF regs. 114 + 115 + required: 116 + - compatible 117 + - reg 118 + - clocks 119 + - clock-names 120 + - interrupts 121 + - interrupt-names 122 + - phys 123 + - ports 124 + - resets 125 + - reset-names 126 + - rockchip,grf 127 + - rockchip,vo-grf 128 + 129 + unevaluatedProperties: false 130 + 131 + examples: 132 + - | 133 + #include <dt-bindings/clock/rockchip,rk3588-cru.h> 134 + #include <dt-bindings/interrupt-controller/arm-gic.h> 135 + #include <dt-bindings/interrupt-controller/irq.h> 136 + #include <dt-bindings/power/rk3588-power.h> 137 + #include <dt-bindings/reset/rockchip,rk3588-cru.h> 138 + 139 + soc { 140 + #address-cells = <2>; 141 + #size-cells = <2>; 142 + 143 + hdmi@fde80000 { 144 + compatible = "rockchip,rk3588-dw-hdmi-qp"; 145 + reg = <0x0 0xfde80000 0x0 0x20000>; 146 + clocks = <&cru PCLK_HDMITX0>, 147 + <&cru CLK_HDMITX0_EARC>, 148 + <&cru CLK_HDMITX0_REF>, 149 + <&cru MCLK_I2S5_8CH_TX>, 150 + <&cru CLK_HDMIHDP0>, 151 + <&cru HCLK_VO1>; 152 + clock-names = "pclk", "earc", "ref", "aud", "hdp", "hclk_vo1"; 153 + interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH 0>, 154 + <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>, 155 + <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH 0>, 156 + <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH 0>, 157 + <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH 0>; 158 + interrupt-names = "avp", "cec", "earc", "main", "hpd"; 159 + phys = <&hdptxphy_hdmi0>; 160 + power-domains = <&power RK3588_PD_VO1>; 161 + resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>; 162 + reset-names = "ref", "hdp"; 163 + rockchip,grf = <&sys_grf>; 164 + rockchip,vo-grf = <&vo1_grf>; 165 + #sound-dai-cells = <0>; 166 + 167 + ports { 168 + #address-cells = <1>; 169 + #size-cells = <0>; 170 + 171 + port@0 { 172 + reg = <0>; 173 + 174 + hdmi0_in_vp0: endpoint { 175 + remote-endpoint = <&vp0_out_hdmi0>; 176 + }; 177 + }; 178 + 179 + port@1 { 180 + reg = <1>; 181 + 182 + hdmi0_out_con0: endpoint { 183 + remote-endpoint = <&hdmi_con0_in>; 184 + }; 185 + }; 186 + }; 187 + }; 188 + };
+92
Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/display/sharp,ls010b7dh04.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Sharp Memory LCD panels 8 + 9 + maintainers: 10 + - Alex Lanzano <lanzano.alex@gmail.com> 11 + 12 + description: 13 + Sharp Memory LCDs are a series of monochrome displays that operate over 14 + a SPI bus. The displays require a signal (VCOM) to be generated to prevent 15 + DC bias build up resulting in pixels being unable to change. Three modes 16 + can be used to provide the VCOM signal ("software", "external", "pwm"). 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - sharp,ls010b7dh04 22 + - sharp,ls011b7dh03 23 + - sharp,ls012b7dd01 24 + - sharp,ls013b7dh03 25 + - sharp,ls013b7dh05 26 + - sharp,ls018b7dh02 27 + - sharp,ls027b7dh01 28 + - sharp,ls027b7dh01a 29 + - sharp,ls032b7dd02 30 + - sharp,ls044q7dh01 31 + 32 + reg: 33 + maxItems: 1 34 + 35 + spi-max-frequency: 36 + maximum: 2000000 37 + 38 + sharp,vcom-mode: 39 + $ref: /schemas/types.yaml#/definitions/string 40 + description: | 41 + software - This mode relies on a software operation to send a 42 + "maintain display" message to the display, toggling the vcom 43 + bit on and off with each message 44 + 45 + external - This mode relies on an external clock to generate 46 + the signal on the EXTCOMM pin 47 + 48 + pwm - This mode relies on a pwm device to generate the signal 49 + on the EXTCOMM pin 50 + 51 + enum: [software, external, pwm] 52 + 53 + enable-gpios: true 54 + 55 + pwms: 56 + maxItems: 1 57 + description: External VCOM signal 58 + 59 + required: 60 + - compatible 61 + - reg 62 + - sharp,vcom-mode 63 + 64 + allOf: 65 + - $ref: panel/panel-common.yaml# 66 + - $ref: /schemas/spi/spi-peripheral-props.yaml# 67 + 68 + - if: 69 + properties: 70 + sharp,vcom-mode: 71 + const: pwm 72 + then: 73 + required: 74 + - pwms 75 + 76 + unevaluatedProperties: false 77 + 78 + examples: 79 + - | 80 + spi { 81 + #address-cells = <1>; 82 + #size-cells = <0>; 83 + 84 + display@0 { 85 + compatible = "sharp,ls013b7dh03"; 86 + reg = <0>; 87 + spi-cs-high; 88 + spi-max-frequency = <1000000>; 89 + sharp,vcom-mode = "software"; 90 + }; 91 + }; 92 + ...
+2
Documentation/gpu/drivers.rst
··· 22 22 afbc 23 23 komeda-kms 24 24 panfrost 25 + panthor 26 + zynqmp 25 27 26 28 .. only:: subproject and html 27 29
+3
Documentation/gpu/drm-client.rst
··· 13 13 14 14 .. kernel-doc:: drivers/gpu/drm/drm_client_modeset.c 15 15 :export: 16 + 17 + .. kernel-doc:: drivers/gpu/drm/drm_client_event.c 18 + :export:
-9
Documentation/gpu/drm-kms-helpers.rst
··· 110 110 .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c 111 111 :doc: fbdev helpers 112 112 113 - .. kernel-doc:: drivers/gpu/drm/drm_fbdev_dma.c 114 - :export: 115 - 116 - .. kernel-doc:: drivers/gpu/drm/drm_fbdev_shmem.c 117 - :export: 118 - 119 - .. kernel-doc:: drivers/gpu/drm/drm_fbdev_ttm.c 120 - :export: 121 - 122 113 .. kernel-doc:: include/drm/drm_fb_helper.h 123 114 :internal: 124 115
+1
Documentation/gpu/drm-usage-stats.rst
··· 210 210 211 211 * :ref:`i915-usage-stats` 212 212 * :ref:`panfrost-usage-stats` 213 + * :ref:`panthor-usage-stats` 213 214 * :ref:`xe-usage-stats`
+1 -1
Documentation/gpu/panthor.rst
··· 4 4 drm/Panthor CSF driver 5 5 ========================= 6 6 7 - .. _panfrost-usage-stats: 7 + .. _panthor-usage-stats: 8 8 9 9 Panthor DRM client usage stats implementation 10 10 ==============================================
+149
Documentation/gpu/zynqmp.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0+ 2 + 3 + =============================================== 4 + Xilinx ZynqMP Ultrascale+ DisplayPort Subsystem 5 + =============================================== 6 + 7 + This subsystem handles DisplayPort video and audio output on the ZynqMP. It 8 + supports in-memory framebuffers with the DisplayPort DMA controller 9 + (xilinx-dpdma), as well as "live" video and audio from the programmable logic 10 + (PL). This subsystem can perform several transformations, including color space 11 + conversion, alpha blending, and audio mixing, although not all features are 12 + currently supported. 13 + 14 + debugfs 15 + ------- 16 + 17 + To support debugging and compliance testing, several test modes can be enabled 18 + though debugfs. The following files in /sys/kernel/debug/dri/X/DP-1/test/ 19 + control the DisplayPort test modes: 20 + 21 + active: 22 + Writing a 1 to this file will activate test mode, and writing a 0 will 23 + deactivate test mode. Writing a 1 or 0 when the test mode is already 24 + active/inactive will re-activate/re-deactivate test mode. When test 25 + mode is inactive, changes made to other files will have no (immediate) 26 + effect, although the settings will be saved for when test mode is 27 + activated. When test mode is active, changes made to other files will 28 + apply immediately. 29 + 30 + custom: 31 + Custom test pattern value 32 + 33 + downspread: 34 + Enable/disable clock downspreading (spread-spectrum clocking) by 35 + writing 1/0 36 + 37 + enhanced: 38 + Enable/disable enhanced framing 39 + 40 + ignore_aux_errors: 41 + Ignore AUX errors when set to 1. Writes to this file take effect 42 + immediately (regardless of whether test mode is active) and affect all 43 + AUX transfers. 44 + 45 + ignore_hpd: 46 + Ignore hotplug events (such as cable removals or monitor link 47 + retraining requests) when set to 1. Writes to this file take effect 48 + immediately (regardless of whether test mode is active). 49 + 50 + laneX_preemphasis: 51 + Preemphasis from 0 (lowest) to 2 (highest) for lane X 52 + 53 + laneX_swing: 54 + Voltage swing from 0 (lowest) to 3 (highest) for lane X 55 + 56 + lanes: 57 + Number of lanes to use (1, 2, or 4) 58 + 59 + pattern: 60 + Test pattern. May be one of: 61 + 62 + video 63 + Use regular video input 64 + 65 + symbol-error 66 + Symbol error measurement pattern 67 + 68 + prbs7 69 + Output of the PRBS7 (x^7 + x^6 + 1) polynomial 70 + 71 + 80bit-custom 72 + A custom 80-bit pattern 73 + 74 + cp2520 75 + HBR2 compliance eye pattern 76 + 77 + tps1 78 + Link training symbol pattern TPS1 (/D10.2/) 79 + 80 + tps2 81 + Link training symbol pattern TPS2 82 + 83 + tps3 84 + Link training symbol pattern TPS3 (for HBR2) 85 + 86 + rate: 87 + Rate in hertz. One of 88 + 89 + * 5400000000 (HBR2) 90 + * 2700000000 (HBR) 91 + * 1620000000 (RBR) 92 + 93 + You can dump the displayport test settings with the following command:: 94 + 95 + for prop in /sys/kernel/debug/dri/1/DP-1/test/*; do 96 + printf '%-17s ' ${prop##*/} 97 + if [ ${prop##*/} = custom ]; then 98 + hexdump -C $prop | head -1 99 + else 100 + cat $prop 101 + fi 102 + done 103 + 104 + The output could look something like:: 105 + 106 + active 1 107 + custom 00000000 00 00 00 00 00 00 00 00 00 00 |..........| 108 + downspread 0 109 + enhanced 1 110 + ignore_aux_errors 1 111 + ignore_hpd 1 112 + lane0_preemphasis 0 113 + lane0_swing 3 114 + lane1_preemphasis 0 115 + lane1_swing 3 116 + lanes 2 117 + pattern prbs7 118 + rate 1620000000 119 + 120 + The recommended test procedure is to connect the board to a monitor, 121 + configure test mode, activate test mode, and then disconnect the cable 122 + and connect it to your test equipment of choice. For example, one 123 + sequence of commands could be:: 124 + 125 + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/enhanced 126 + echo tps1 > /sys/kernel/debug/dri/1/DP-1/test/pattern 127 + echo 1620000000 > /sys/kernel/debug/dri/1/DP-1/test/rate 128 + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/ignore_aux_errors 129 + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/ignore_hpd 130 + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/active 131 + 132 + at which point the cable could be disconnected from the monitor. 133 + 134 + Internals 135 + --------- 136 + 137 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_disp.h 138 + 139 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dpsub.h 140 + 141 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_kms.h 142 + 143 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_disp.c 144 + 145 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dp.c 146 + 147 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dpsub.c 148 + 149 + .. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_kms.c
+7
MAINTAINERS
··· 7387 7387 F: Documentation/devicetree/bindings/display/panel/samsung,s6e3ha8.yaml 7388 7388 F: drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c 7389 7389 7390 + DRM DRIVER FOR SHARP MEMORY LCD 7391 + M: Alex Lanzano <lanzano.alex@gmail.com> 7392 + S: Maintained 7393 + F: Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml 7394 + F: drivers/gpu/drm/tiny/sharp-memory.c 7395 + 7390 7396 DRM DRIVER FOR SITRONIX ST7586 PANELS 7391 7397 M: David Lechner <david@lechnology.com> 7392 7398 S: Maintained ··· 7838 7832 S: Maintained 7839 7833 T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7840 7834 F: Documentation/devicetree/bindings/display/xlnx/ 7835 + F: Documentation/gpu/zynqmp.rst 7841 7836 F: drivers/gpu/drm/xlnx/ 7842 7837 7843 7838 DRM GPU SCHEDULER
+9
drivers/accel/ivpu/Kconfig
··· 16 16 and Deep Learning applications. 17 17 18 18 If "M" is selected, the module will be called intel_vpu. 19 + 20 + config DRM_ACCEL_IVPU_DEBUG 21 + bool "Intel NPU debug mode" 22 + depends on DRM_ACCEL_IVPU 23 + help 24 + Choose this option to enable additional 25 + debug features for the Intel NPU driver: 26 + - Always print debug messages regardless of dyndbg config, 27 + - Enable unsafe module params.
+2
drivers/accel/ivpu/Makefile
··· 24 24 25 25 obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o 26 26 27 + subdir-ccflags-$(CONFIG_DRM_ACCEL_IVPU_DEBUG) += -DDEBUG 28 + 27 29 CFLAGS_ivpu_trace_points.o = -I$(src)
+15 -16
drivers/accel/ivpu/ivpu_drv.c
··· 43 43 MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); 44 44 45 45 int ivpu_test_mode; 46 + #if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) 46 47 module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); 47 48 MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); 49 + #endif 48 50 49 51 u8 ivpu_pll_min_ratio; 50 52 module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); ··· 88 86 89 87 ivpu_cmdq_release_all_locked(file_priv); 90 88 ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx); 91 - ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); 89 + ivpu_mmu_context_fini(vdev, &file_priv->ctx); 92 90 file_priv->bound = false; 93 91 drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id)); 94 92 } ··· 106 104 pm_runtime_get_sync(vdev->drm.dev); 107 105 mutex_lock(&vdev->context_list_lock); 108 106 file_priv_unbind(vdev, file_priv); 107 + drm_WARN_ON(&vdev->drm, !xa_empty(&file_priv->cmdq_xa)); 108 + xa_destroy(&file_priv->cmdq_xa); 109 109 mutex_unlock(&vdev->context_list_lock); 110 110 pm_runtime_put_autosuspend(vdev->drm.dev); 111 111 ··· 258 254 goto err_unlock; 259 255 } 260 256 261 - ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id); 262 - if (ret) 263 - goto err_xa_erase; 257 + ivpu_mmu_context_init(vdev, &file_priv->ctx, ctx_id); 264 258 265 - file_priv->default_job_limit.min = FIELD_PREP(IVPU_JOB_ID_CONTEXT_MASK, 266 - (file_priv->ctx.id - 1)); 267 - file_priv->default_job_limit.max = file_priv->default_job_limit.min | IVPU_JOB_ID_JOB_MASK; 268 - file_priv->job_limit = file_priv->default_job_limit; 259 + file_priv->job_limit.min = FIELD_PREP(IVPU_JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1)); 260 + file_priv->job_limit.max = file_priv->job_limit.min | IVPU_JOB_ID_JOB_MASK; 261 + 262 + xa_init_flags(&file_priv->cmdq_xa, XA_FLAGS_ALLOC1); 263 + file_priv->cmdq_limit.min = IVPU_CMDQ_MIN_ID; 264 + file_priv->cmdq_limit.max = IVPU_CMDQ_MAX_ID; 269 265 270 266 mutex_unlock(&vdev->context_list_lock); 271 267 drm_dev_exit(idx); ··· 277 273 278 274 return 0; 279 275 280 - err_xa_erase: 281 - xa_erase_irq(&vdev->context_xa, ctx_id); 282 276 err_unlock: 283 277 mutex_unlock(&vdev->context_list_lock); 284 278 mutex_destroy(&file_priv->ms_lock); ··· 624 622 lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); 625 623 INIT_LIST_HEAD(&vdev->bo_list); 626 624 627 - vdev->default_db_limit.min = IVPU_MIN_DB; 628 - vdev->default_db_limit.max = IVPU_MAX_DB; 629 - vdev->db_limit = vdev->default_db_limit; 625 + vdev->db_limit.min = IVPU_MIN_DB; 626 + vdev->db_limit.max = IVPU_MAX_DB; 630 627 631 628 ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); 632 629 if (ret) ··· 653 652 if (ret) 654 653 goto err_shutdown; 655 654 656 - ret = ivpu_mmu_global_context_init(vdev); 657 - if (ret) 658 - goto err_shutdown; 655 + ivpu_mmu_global_context_init(vdev); 659 656 660 657 ret = ivpu_mmu_init(vdev); 661 658 if (ret)
+9 -7
drivers/accel/ivpu/ivpu_drv.h
··· 49 49 #define IVPU_JOB_ID_JOB_MASK GENMASK(7, 0) 50 50 #define IVPU_JOB_ID_CONTEXT_MASK GENMASK(31, 8) 51 51 52 - #define IVPU_NUM_ENGINES 2 53 52 #define IVPU_NUM_PRIORITIES 4 54 - #define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_ENGINES * IVPU_NUM_PRIORITIES) 53 + #define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_PRIORITIES) 55 54 56 - #define IVPU_CMDQ_INDEX(engine, priority) ((engine) * IVPU_NUM_PRIORITIES + (priority)) 55 + #define IVPU_CMDQ_MIN_ID 1 56 + #define IVPU_CMDQ_MAX_ID 255 57 57 58 58 #define IVPU_PLATFORM_SILICON 0 59 59 #define IVPU_PLATFORM_SIMICS 2 ··· 140 140 141 141 struct xarray db_xa; 142 142 struct xa_limit db_limit; 143 - struct xa_limit default_db_limit; 143 + u32 db_next; 144 144 145 145 struct mutex bo_list_lock; /* Protects bo_list */ 146 146 struct list_head bo_list; ··· 171 171 struct kref ref; 172 172 struct ivpu_device *vdev; 173 173 struct mutex lock; /* Protects cmdq */ 174 - struct ivpu_cmdq *cmdq[IVPU_NUM_CMDQS_PER_CTX]; 174 + struct xarray cmdq_xa; 175 175 struct ivpu_mmu_context ctx; 176 176 struct mutex ms_lock; /* Protects ms_instance_list, ms_info_bo */ 177 177 struct list_head ms_instance_list; 178 178 struct ivpu_bo *ms_info_bo; 179 179 struct xa_limit job_limit; 180 - struct xa_limit default_job_limit; 180 + u32 job_id_next; 181 + struct xa_limit cmdq_limit; 182 + u32 cmdq_id_next; 181 183 bool has_mmu_faults; 182 184 bool bound; 183 185 bool aborted; ··· 197 195 #define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) 198 196 #define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) 199 197 #define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5) 200 - #define IVPU_TEST_MODE_PREEMPTION_DISABLE BIT(6) 198 + #define IVPU_TEST_MODE_MIP_DISABLE BIT(6) 201 199 #define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8) 202 200 #define IVPU_TEST_MODE_TURBO BIT(9) 203 201 extern int ivpu_test_mode;
+6 -2
drivers/accel/ivpu/ivpu_fw.c
··· 46 46 #define IVPU_FOCUS_PRESENT_TIMER_MS 1000 47 47 48 48 static char *ivpu_firmware; 49 + #if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) 49 50 module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); 50 51 MODULE_PARM_DESC(firmware, "NPU firmware binary in /lib/firmware/.."); 52 + #endif 51 53 52 54 static struct { 53 55 int gen; ··· 584 582 boot_params->ipc_payload_area_start = ipc_mem_rx->vpu_addr + ivpu_bo_size(ipc_mem_rx) / 2; 585 583 boot_params->ipc_payload_area_size = ivpu_bo_size(ipc_mem_rx) / 2; 586 584 587 - boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start; 588 - boot_params->global_aliased_pio_size = ivpu_hw_range_size(&vdev->hw->ranges.user); 585 + if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 586 + boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start; 587 + boot_params->global_aliased_pio_size = ivpu_hw_range_size(&vdev->hw->ranges.user); 588 + } 589 589 590 590 /* Allow configuration for L2C_PAGE_TABLE with boot param value */ 591 591 boot_params->autoconfig = 1;
+5 -5
drivers/accel/ivpu/ivpu_hw.c
··· 114 114 { 115 115 if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { 116 116 ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 117 - ivpu_hw_range_init(&vdev->hw->ranges.user, 0xc0000000, 255 * SZ_1M); 117 + ivpu_hw_range_init(&vdev->hw->ranges.user, 0x88000000, 511 * SZ_1M); 118 118 ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x180000000, SZ_2G); 119 - ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 119 + ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_128G); 120 120 } else { 121 121 ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); 122 - ivpu_hw_range_init(&vdev->hw->ranges.user, 0x80000000, SZ_256M); 123 - ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000 + SZ_256M, SZ_2G - SZ_256M); 124 - ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); 122 + ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000, SZ_2G); 123 + ivpu_hw_range_init(&vdev->hw->ranges.user, 0x100000000, SZ_256G); 124 + vdev->hw->ranges.dma = vdev->hw->ranges.user; 125 125 } 126 126 } 127 127
+3 -9
drivers/accel/ivpu/ivpu_hw_btrs.c
··· 141 141 } 142 142 143 143 config = REG_GET_FLD(VPU_HW_BTRS_LNL_TILE_FUSE, CONFIG, fuse); 144 - if (!tile_disable_check(config)) { 145 - ivpu_err(vdev, "Fuse: Invalid tile disable config (0x%x)\n", config); 146 - return -EIO; 147 - } 144 + if (!tile_disable_check(config)) 145 + ivpu_warn(vdev, "More than 1 tile disabled, tile fuse config mask: 0x%x\n", config); 148 146 149 - if (config) 150 - ivpu_dbg(vdev, MISC, "Fuse: %d tiles enabled. Tile number %d disabled\n", 151 - BTRS_LNL_TILE_MAX_NUM - 1, ffs(config) - 1); 152 - else 153 - ivpu_dbg(vdev, MISC, "Fuse: All %d tiles enabled\n", BTRS_LNL_TILE_MAX_NUM); 147 + ivpu_dbg(vdev, MISC, "Tile disable config mask: 0x%x\n", config); 154 148 155 149 *tile_fuse_config = config; 156 150 return 0;
+57 -91
drivers/accel/ivpu/ivpu_job.c
··· 35 35 u64 primary_size = ALIGN(vdev->fw->primary_preempt_buf_size, PAGE_SIZE); 36 36 u64 secondary_size = ALIGN(vdev->fw->secondary_preempt_buf_size, PAGE_SIZE); 37 37 38 - if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW) 38 + if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW || 39 + ivpu_test_mode & IVPU_TEST_MODE_MIP_DISABLE) 39 40 return 0; 40 41 41 42 cmdq->primary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.user, ··· 46 45 return -ENOMEM; 47 46 } 48 47 49 - cmdq->secondary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.shave, 48 + cmdq->secondary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.dma, 50 49 secondary_size, DRM_IVPU_BO_WC); 51 50 if (!cmdq->secondary_preempt_buf) { 52 51 ivpu_err(vdev, "Failed to create secondary preemption buffer\n"); ··· 73 72 ivpu_bo_free(cmdq->secondary_preempt_buf); 74 73 } 75 74 76 - static int ivpu_id_alloc(struct xarray *xa, u32 *id, void *entry, struct xa_limit *limit, 77 - const struct xa_limit default_limit) 78 - { 79 - int ret; 80 - 81 - ret = __xa_alloc(xa, id, entry, *limit, GFP_KERNEL); 82 - if (ret) { 83 - limit->min = default_limit.min; 84 - ret = __xa_alloc(xa, id, entry, *limit, GFP_KERNEL); 85 - if (ret) 86 - return ret; 87 - } 88 - 89 - limit->min = *id + 1; 90 - if (limit->min > limit->max) 91 - limit->min = default_limit.min; 92 - 93 - return ret; 94 - } 95 - 96 75 static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv *file_priv) 97 76 { 98 77 struct ivpu_device *vdev = file_priv->vdev; ··· 83 102 if (!cmdq) 84 103 return NULL; 85 104 86 - xa_lock(&vdev->db_xa); /* lock here to protect db_limit */ 87 - ret = ivpu_id_alloc(&vdev->db_xa, &cmdq->db_id, NULL, &vdev->db_limit, 88 - vdev->default_db_limit); 89 - xa_unlock(&vdev->db_xa); 90 - if (ret) { 105 + ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, &vdev->db_next, 106 + GFP_KERNEL); 107 + if (ret < 0) { 91 108 ivpu_err(vdev, "Failed to allocate doorbell id: %d\n", ret); 92 109 goto err_free_cmdq; 93 110 } 94 111 112 + ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, file_priv->cmdq_limit, 113 + &file_priv->cmdq_id_next, GFP_KERNEL); 114 + if (ret < 0) { 115 + ivpu_err(vdev, "Failed to allocate command queue id: %d\n", ret); 116 + goto err_erase_db_xa; 117 + } 118 + 95 119 cmdq->mem = ivpu_bo_create_global(vdev, SZ_4K, DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE); 96 120 if (!cmdq->mem) 97 - goto err_erase_xa; 121 + goto err_erase_cmdq_xa; 98 122 99 123 ret = ivpu_preemption_buffers_create(vdev, file_priv, cmdq); 100 124 if (ret) ··· 107 121 108 122 return cmdq; 109 123 110 - err_erase_xa: 124 + err_erase_cmdq_xa: 125 + xa_erase(&file_priv->cmdq_xa, cmdq->id); 126 + err_erase_db_xa: 111 127 xa_erase(&vdev->db_xa, cmdq->db_id); 112 128 err_free_cmdq: 113 129 kfree(cmdq); ··· 133 145 struct ivpu_device *vdev = file_priv->vdev; 134 146 int ret; 135 147 136 - ret = ivpu_jsm_hws_create_cmdq(vdev, file_priv->ctx.id, file_priv->ctx.id, cmdq->db_id, 148 + ret = ivpu_jsm_hws_create_cmdq(vdev, file_priv->ctx.id, file_priv->ctx.id, cmdq->id, 137 149 task_pid_nr(current), engine, 138 150 cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); 139 151 if (ret) 140 152 return ret; 141 153 142 - ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->db_id, 154 + ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->id, 143 155 priority); 144 156 if (ret) 145 157 return ret; ··· 153 165 int ret; 154 166 155 167 if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) 156 - ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->db_id, cmdq->db_id, 168 + ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->id, cmdq->db_id, 157 169 cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); 158 170 else 159 171 ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id, 160 172 cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); 161 173 162 174 if (!ret) 163 - ivpu_dbg(vdev, JOB, "DB %d registered to ctx %d\n", cmdq->db_id, file_priv->ctx.id); 175 + ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d\n", 176 + cmdq->db_id, cmdq->id, file_priv->ctx.id); 164 177 165 178 return ret; 166 179 } 167 180 168 181 static int 169 - ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 engine, u8 priority) 182 + ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u8 priority) 170 183 { 171 184 struct ivpu_device *vdev = file_priv->vdev; 172 185 struct vpu_job_queue_header *jobq_header; ··· 183 194 184 195 cmdq->jobq = (struct vpu_job_queue *)ivpu_bo_vaddr(cmdq->mem); 185 196 jobq_header = &cmdq->jobq->header; 186 - jobq_header->engine_idx = engine; 197 + jobq_header->engine_idx = VPU_ENGINE_COMPUTE; 187 198 jobq_header->head = 0; 188 199 jobq_header->tail = 0; 189 200 if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) { ··· 194 205 wmb(); /* Flush WC buffer for jobq->header */ 195 206 196 207 if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { 197 - ret = ivpu_hws_cmdq_init(file_priv, cmdq, engine, priority); 208 + ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, priority); 198 209 if (ret) 199 210 return ret; 200 211 } ··· 221 232 cmdq->db_registered = false; 222 233 223 234 if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { 224 - ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->db_id); 235 + ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id); 225 236 if (!ret) 226 - ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->db_id); 237 + ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->id); 227 238 } 228 239 229 240 ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id); ··· 233 244 return 0; 234 245 } 235 246 236 - static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u16 engine, 237 - u8 priority) 247 + static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u8 priority) 238 248 { 239 - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); 240 - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; 249 + struct ivpu_cmdq *cmdq; 250 + unsigned long cmdq_id; 241 251 int ret; 242 252 243 253 lockdep_assert_held(&file_priv->lock); 254 + 255 + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) 256 + if (cmdq->priority == priority) 257 + break; 244 258 245 259 if (!cmdq) { 246 260 cmdq = ivpu_cmdq_alloc(file_priv); 247 261 if (!cmdq) 248 262 return NULL; 249 - file_priv->cmdq[cmdq_idx] = cmdq; 263 + cmdq->priority = priority; 250 264 } 251 265 252 - ret = ivpu_cmdq_init(file_priv, cmdq, engine, priority); 266 + ret = ivpu_cmdq_init(file_priv, cmdq, priority); 253 267 if (ret) 254 268 return NULL; 255 269 256 270 return cmdq; 257 271 } 258 272 259 - static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engine, u8 priority) 273 + void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) 260 274 { 261 - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); 262 - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; 275 + struct ivpu_cmdq *cmdq; 276 + unsigned long cmdq_id; 263 277 264 278 lockdep_assert_held(&file_priv->lock); 265 279 266 - if (cmdq) { 267 - file_priv->cmdq[cmdq_idx] = NULL; 280 + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) { 281 + xa_erase(&file_priv->cmdq_xa, cmdq_id); 268 282 ivpu_cmdq_fini(file_priv, cmdq); 269 283 ivpu_cmdq_free(file_priv, cmdq); 270 284 } 271 - } 272 - 273 - void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) 274 - { 275 - u16 engine; 276 - u8 priority; 277 - 278 - lockdep_assert_held(&file_priv->lock); 279 - 280 - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) 281 - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) 282 - ivpu_cmdq_release_locked(file_priv, engine, priority); 283 285 } 284 286 285 287 /* ··· 281 301 */ 282 302 static void ivpu_cmdq_reset(struct ivpu_file_priv *file_priv) 283 303 { 284 - u16 engine; 285 - u8 priority; 304 + struct ivpu_cmdq *cmdq; 305 + unsigned long cmdq_id; 286 306 287 307 mutex_lock(&file_priv->lock); 288 308 289 - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) { 290 - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) { 291 - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); 292 - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; 293 - 294 - if (cmdq) 295 - cmdq->db_registered = false; 296 - } 297 - } 309 + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) 310 + cmdq->db_registered = false; 298 311 299 312 mutex_unlock(&file_priv->lock); 300 313 } ··· 307 334 308 335 static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv) 309 336 { 310 - u16 engine; 311 - u8 priority; 337 + struct ivpu_cmdq *cmdq; 338 + unsigned long cmdq_id; 312 339 313 - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) { 314 - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) { 315 - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); 316 - 317 - if (file_priv->cmdq[cmdq_idx]) 318 - ivpu_cmdq_fini(file_priv, file_priv->cmdq[cmdq_idx]); 319 - } 320 - } 340 + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) 341 + ivpu_cmdq_fini(file_priv, cmdq); 321 342 } 322 343 323 344 void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) ··· 336 369 337 370 /* Check if there is space left in job queue */ 338 371 if (next_entry == header->head) { 339 - ivpu_dbg(vdev, JOB, "Job queue full: ctx %d engine %d db %d head %d tail %d\n", 340 - job->file_priv->ctx.id, job->engine_idx, cmdq->db_id, header->head, tail); 372 + ivpu_dbg(vdev, JOB, "Job queue full: ctx %d cmdq %d db %d head %d tail %d\n", 373 + job->file_priv->ctx.id, cmdq->id, cmdq->db_id, header->head, tail); 341 374 return -EBUSY; 342 375 } 343 376 ··· 348 381 if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) 349 382 entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; 350 383 351 - if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW && 352 - (unlikely(!(ivpu_test_mode & IVPU_TEST_MODE_PREEMPTION_DISABLE)))) { 384 + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { 353 385 if (cmdq->primary_preempt_buf) { 354 386 entry->primary_preempt_buf_addr = cmdq->primary_preempt_buf->vpu_addr; 355 387 entry->primary_preempt_buf_size = ivpu_bo_size(cmdq->primary_preempt_buf); ··· 523 557 524 558 mutex_lock(&file_priv->lock); 525 559 526 - cmdq = ivpu_cmdq_acquire(file_priv, job->engine_idx, priority); 560 + cmdq = ivpu_cmdq_acquire(file_priv, priority); 527 561 if (!cmdq) { 528 562 ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d engine %d prio %d\n", 529 563 file_priv->ctx.id, job->engine_idx, priority); ··· 533 567 534 568 xa_lock(&vdev->submitted_jobs_xa); 535 569 is_first_job = xa_empty(&vdev->submitted_jobs_xa); 536 - ret = ivpu_id_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, &file_priv->job_limit, 537 - file_priv->default_job_limit); 538 - if (ret) { 570 + ret = __xa_alloc_cyclic(&vdev->submitted_jobs_xa, &job->job_id, job, file_priv->job_limit, 571 + &file_priv->job_id_next, GFP_KERNEL); 572 + if (ret < 0) { 539 573 ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n", 540 574 file_priv->ctx.id); 541 575 ret = -EBUSY; ··· 665 699 int idx, ret; 666 700 u8 priority; 667 701 668 - if (params->engine > DRM_IVPU_ENGINE_COPY) 702 + if (params->engine != DRM_IVPU_ENGINE_COMPUTE) 669 703 return -EINVAL; 670 704 671 705 if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
+2
drivers/accel/ivpu/ivpu_job.h
··· 28 28 struct ivpu_bo *secondary_preempt_buf; 29 29 struct ivpu_bo *mem; 30 30 u32 entry_count; 31 + u32 id; 31 32 u32 db_id; 32 33 bool db_registered; 34 + u8 priority; 33 35 }; 34 36 35 37 /**
+4 -4
drivers/accel/ivpu/ivpu_jsm_msg.c
··· 132 132 struct vpu_jsm_msg resp; 133 133 int ret; 134 134 135 - if (engine > VPU_ENGINE_COPY) 135 + if (engine != VPU_ENGINE_COMPUTE) 136 136 return -EINVAL; 137 137 138 138 req.payload.query_engine_hb.engine_idx = engine; ··· 155 155 struct vpu_jsm_msg resp; 156 156 int ret; 157 157 158 - if (engine > VPU_ENGINE_COPY) 158 + if (engine != VPU_ENGINE_COMPUTE) 159 159 return -EINVAL; 160 160 161 161 req.payload.engine_reset.engine_idx = engine; ··· 174 174 struct vpu_jsm_msg resp; 175 175 int ret; 176 176 177 - if (engine > VPU_ENGINE_COPY) 177 + if (engine != VPU_ENGINE_COMPUTE) 178 178 return -EINVAL; 179 179 180 180 req.payload.engine_preempt.engine_idx = engine; ··· 346 346 struct vpu_jsm_msg resp; 347 347 int ret; 348 348 349 - if (engine >= VPU_ENGINE_NB) 349 + if (engine != VPU_ENGINE_COMPUTE) 350 350 return -EINVAL; 351 351 352 352 req.payload.hws_resume_engine.engine_idx = engine;
+35 -62
drivers/accel/ivpu/ivpu_mmu.c
··· 696 696 return ret; 697 697 } 698 698 699 - static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma) 699 + static int ivpu_mmu_cdtab_entry_set(struct ivpu_device *vdev, u32 ssid, u64 cd_dma, bool valid) 700 700 { 701 701 struct ivpu_mmu_info *mmu = vdev->mmu; 702 702 struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab; ··· 708 708 return -EINVAL; 709 709 710 710 entry = cdtab->base + (ssid * IVPU_MMU_CDTAB_ENT_SIZE); 711 + drm_WARN_ON(&vdev->drm, (entry[0] & IVPU_MMU_CD_0_V) == valid); 711 712 712 - if (cd_dma != 0) { 713 - cd[0] = FIELD_PREP(IVPU_MMU_CD_0_TCR_T0SZ, IVPU_MMU_T0SZ_48BIT) | 714 - FIELD_PREP(IVPU_MMU_CD_0_TCR_TG0, 0) | 715 - FIELD_PREP(IVPU_MMU_CD_0_TCR_IRGN0, 0) | 716 - FIELD_PREP(IVPU_MMU_CD_0_TCR_ORGN0, 0) | 717 - FIELD_PREP(IVPU_MMU_CD_0_TCR_SH0, 0) | 718 - FIELD_PREP(IVPU_MMU_CD_0_TCR_IPS, IVPU_MMU_IPS_48BIT) | 719 - FIELD_PREP(IVPU_MMU_CD_0_ASID, ssid) | 720 - IVPU_MMU_CD_0_TCR_EPD1 | 721 - IVPU_MMU_CD_0_AA64 | 722 - IVPU_MMU_CD_0_R | 723 - IVPU_MMU_CD_0_ASET | 724 - IVPU_MMU_CD_0_V; 725 - cd[1] = cd_dma & IVPU_MMU_CD_1_TTB0_MASK; 726 - cd[2] = 0; 727 - cd[3] = 0x0000000000007444; 713 + cd[0] = FIELD_PREP(IVPU_MMU_CD_0_TCR_T0SZ, IVPU_MMU_T0SZ_48BIT) | 714 + FIELD_PREP(IVPU_MMU_CD_0_TCR_TG0, 0) | 715 + FIELD_PREP(IVPU_MMU_CD_0_TCR_IRGN0, 0) | 716 + FIELD_PREP(IVPU_MMU_CD_0_TCR_ORGN0, 0) | 717 + FIELD_PREP(IVPU_MMU_CD_0_TCR_SH0, 0) | 718 + FIELD_PREP(IVPU_MMU_CD_0_TCR_IPS, IVPU_MMU_IPS_48BIT) | 719 + FIELD_PREP(IVPU_MMU_CD_0_ASID, ssid) | 720 + IVPU_MMU_CD_0_TCR_EPD1 | 721 + IVPU_MMU_CD_0_AA64 | 722 + IVPU_MMU_CD_0_R | 723 + IVPU_MMU_CD_0_ASET; 724 + cd[1] = cd_dma & IVPU_MMU_CD_1_TTB0_MASK; 725 + cd[2] = 0; 726 + cd[3] = 0x0000000000007444; 728 727 729 - /* For global context generate memory fault on VPU */ 730 - if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) 731 - cd[0] |= IVPU_MMU_CD_0_A; 732 - } else { 733 - memset(cd, 0, sizeof(cd)); 734 - } 728 + /* For global context generate memory fault on VPU */ 729 + if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) 730 + cd[0] |= IVPU_MMU_CD_0_A; 731 + 732 + if (valid) 733 + cd[0] |= IVPU_MMU_CD_0_V; 735 734 736 735 WRITE_ONCE(entry[1], cd[1]); 737 736 WRITE_ONCE(entry[2], cd[2]); ··· 740 741 if (!ivpu_is_force_snoop_enabled(vdev)) 741 742 clflush_cache_range(entry, IVPU_MMU_CDTAB_ENT_SIZE); 742 743 743 - ivpu_dbg(vdev, MMU, "CDTAB %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", 744 - cd_dma ? "write" : "clear", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]); 744 + ivpu_dbg(vdev, MMU, "CDTAB set %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", 745 + valid ? "valid" : "invalid", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]); 745 746 746 747 mutex_lock(&mmu->lock); 747 748 if (!mmu->on) ··· 749 750 750 751 ret = ivpu_mmu_cmdq_write_cfgi_all(vdev); 751 752 if (ret) 752 - goto unlock; 753 + goto err_invalidate; 753 754 754 755 ret = ivpu_mmu_cmdq_sync(vdev); 756 + if (ret) 757 + goto err_invalidate; 755 758 unlock: 756 759 mutex_unlock(&mmu->lock); 757 - return ret; 758 - } 760 + return 0; 759 761 760 - static int ivpu_mmu_cd_add_gbl(struct ivpu_device *vdev) 761 - { 762 - int ret; 763 - 764 - ret = ivpu_mmu_cd_add(vdev, 0, vdev->gctx.pgtable.pgd_dma); 765 - if (ret) 766 - ivpu_err(vdev, "Failed to add global CD entry: %d\n", ret); 767 - 768 - return ret; 769 - } 770 - 771 - static int ivpu_mmu_cd_add_user(struct ivpu_device *vdev, u32 ssid, dma_addr_t cd_dma) 772 - { 773 - int ret; 774 - 775 - if (ssid == 0) { 776 - ivpu_err(vdev, "Invalid SSID: %u\n", ssid); 777 - return -EINVAL; 778 - } 779 - 780 - ret = ivpu_mmu_cd_add(vdev, ssid, cd_dma); 781 - if (ret) 782 - ivpu_err(vdev, "Failed to add CD entry SSID=%u: %d\n", ssid, ret); 783 - 762 + err_invalidate: 763 + WRITE_ONCE(entry[0], 0); 764 + mutex_unlock(&mmu->lock); 784 765 return ret; 785 766 } 786 767 ··· 782 803 return ret; 783 804 784 805 ret = ivpu_mmu_strtab_init(vdev); 785 - if (ret) { 786 - ivpu_err(vdev, "Failed to initialize strtab: %d\n", ret); 787 - return ret; 788 - } 789 - 790 - ret = ivpu_mmu_cd_add_gbl(vdev); 791 806 if (ret) { 792 807 ivpu_err(vdev, "Failed to initialize strtab: %d\n", ret); 793 808 return ret; ··· 939 966 REGV_WR32(IVPU_MMU_REG_GERRORN, gerror_val); 940 967 } 941 968 942 - int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable) 969 + int ivpu_mmu_cd_set(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable) 943 970 { 944 - return ivpu_mmu_cd_add_user(vdev, ssid, pgtable->pgd_dma); 971 + return ivpu_mmu_cdtab_entry_set(vdev, ssid, pgtable->pgd_dma, true); 945 972 } 946 973 947 - void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid) 974 + void ivpu_mmu_cd_clear(struct ivpu_device *vdev, int ssid) 948 975 { 949 - ivpu_mmu_cd_add_user(vdev, ssid, 0); /* 0 will clear CD entry */ 976 + ivpu_mmu_cdtab_entry_set(vdev, ssid, 0, false); 950 977 }
+2 -2
drivers/accel/ivpu/ivpu_mmu.h
··· 40 40 int ivpu_mmu_init(struct ivpu_device *vdev); 41 41 void ivpu_mmu_disable(struct ivpu_device *vdev); 42 42 int ivpu_mmu_enable(struct ivpu_device *vdev); 43 - int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable); 44 - void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid); 43 + int ivpu_mmu_cd_set(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable); 44 + void ivpu_mmu_cd_clear(struct ivpu_device *vdev, int ssid); 45 45 int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid); 46 46 47 47 void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev);
+83 -75
drivers/accel/ivpu/ivpu_mmu_context.c
··· 90 90 } 91 91 } 92 92 93 - static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) 94 - { 95 - dma_addr_t pgd_dma; 96 - 97 - pgtable->pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); 98 - if (!pgtable->pgd_dma_ptr) 99 - return -ENOMEM; 100 - 101 - pgtable->pgd_dma = pgd_dma; 102 - 103 - return 0; 104 - } 105 - 106 93 static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) 107 94 { 108 95 int pgd_idx, pud_idx, pmd_idx; ··· 127 140 } 128 141 129 142 ivpu_pgtable_free_page(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); 143 + pgtable->pgd_dma_ptr = NULL; 144 + pgtable->pgd_dma = 0; 145 + } 146 + 147 + static u64* 148 + ivpu_mmu_ensure_pgd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) 149 + { 150 + u64 *pgd_dma_ptr = pgtable->pgd_dma_ptr; 151 + dma_addr_t pgd_dma; 152 + 153 + if (pgd_dma_ptr) 154 + return pgd_dma_ptr; 155 + 156 + pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); 157 + if (!pgd_dma_ptr) 158 + return NULL; 159 + 160 + pgtable->pgd_dma_ptr = pgd_dma_ptr; 161 + pgtable->pgd_dma = pgd_dma; 162 + 163 + return pgd_dma_ptr; 130 164 } 131 165 132 166 static u64* ··· 244 236 int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr); 245 237 int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr); 246 238 int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr); 239 + 240 + drm_WARN_ON(&vdev->drm, ctx->id == IVPU_RESERVED_CONTEXT_MMU_SSID); 241 + 242 + /* Allocate PGD - first level page table if needed */ 243 + if (!ivpu_mmu_ensure_pgd(vdev, &ctx->pgtable)) 244 + return -ENOMEM; 247 245 248 246 /* Allocate PUD - second level page table if needed */ 249 247 if (!ivpu_mmu_ensure_pud(vdev, &ctx->pgtable, pgd_idx)) ··· 432 418 ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, 433 419 u64 vpu_addr, struct sg_table *sgt, bool llc_coherent) 434 420 { 421 + size_t start_vpu_addr = vpu_addr; 435 422 struct scatterlist *sg; 436 423 int ret; 437 424 u64 prot; ··· 463 448 ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot); 464 449 if (ret) { 465 450 ivpu_err(vdev, "Failed to map context pages\n"); 466 - mutex_unlock(&ctx->lock); 467 - return ret; 451 + goto err_unmap_pages; 468 452 } 469 453 vpu_addr += size; 454 + } 455 + 456 + if (!ctx->is_cd_valid) { 457 + ret = ivpu_mmu_cd_set(vdev, ctx->id, &ctx->pgtable); 458 + if (ret) { 459 + ivpu_err(vdev, "Failed to set context descriptor for context %u: %d\n", 460 + ctx->id, ret); 461 + goto err_unmap_pages; 462 + } 463 + ctx->is_cd_valid = true; 470 464 } 471 465 472 466 /* Ensure page table modifications are flushed from wc buffers to memory */ 473 467 wmb(); 474 468 475 - mutex_unlock(&ctx->lock); 476 - 477 469 ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); 478 - if (ret) 470 + if (ret) { 479 471 ivpu_err(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret); 472 + goto err_unmap_pages; 473 + } 474 + 475 + mutex_unlock(&ctx->lock); 476 + return 0; 477 + 478 + err_unmap_pages: 479 + ivpu_mmu_context_unmap_pages(ctx, start_vpu_addr, vpu_addr - start_vpu_addr); 480 + mutex_unlock(&ctx->lock); 480 481 return ret; 481 482 } 482 483 ··· 561 530 mutex_unlock(&ctx->lock); 562 531 } 563 532 564 - static int 565 - ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id) 533 + void ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id) 566 534 { 567 535 u64 start, end; 568 - int ret; 569 536 570 537 mutex_init(&ctx->lock); 571 - 572 - ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable); 573 - if (ret) { 574 - ivpu_err(vdev, "Failed to initialize pgtable for ctx %u: %d\n", context_id, ret); 575 - return ret; 576 - } 577 538 578 539 if (!context_id) { 579 540 start = vdev->hw->ranges.global.start; 580 541 end = vdev->hw->ranges.shave.end; 581 542 } else { 582 - start = vdev->hw->ranges.user.start; 583 - end = vdev->hw->ranges.dma.end; 543 + start = min_t(u64, vdev->hw->ranges.user.start, vdev->hw->ranges.shave.start); 544 + end = max_t(u64, vdev->hw->ranges.user.end, vdev->hw->ranges.dma.end); 584 545 } 585 546 586 547 drm_mm_init(&ctx->mm, start, end - start); 587 548 ctx->id = context_id; 588 - 589 - return 0; 590 549 } 591 550 592 - static void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) 551 + void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) 593 552 { 594 - if (drm_WARN_ON(&vdev->drm, !ctx->pgtable.pgd_dma_ptr)) 595 - return; 553 + if (ctx->is_cd_valid) { 554 + ivpu_mmu_cd_clear(vdev, ctx->id); 555 + ctx->is_cd_valid = false; 556 + } 596 557 597 558 mutex_destroy(&ctx->lock); 598 559 ivpu_mmu_pgtables_free(vdev, &ctx->pgtable); 599 560 drm_mm_takedown(&ctx->mm); 600 - 601 - ctx->pgtable.pgd_dma_ptr = NULL; 602 - ctx->pgtable.pgd_dma = 0; 603 561 } 604 562 605 - int ivpu_mmu_global_context_init(struct ivpu_device *vdev) 563 + void ivpu_mmu_global_context_init(struct ivpu_device *vdev) 606 564 { 607 - return ivpu_mmu_context_init(vdev, &vdev->gctx, IVPU_GLOBAL_CONTEXT_MMU_SSID); 565 + ivpu_mmu_context_init(vdev, &vdev->gctx, IVPU_GLOBAL_CONTEXT_MMU_SSID); 608 566 } 609 567 610 568 void ivpu_mmu_global_context_fini(struct ivpu_device *vdev) 611 569 { 612 - return ivpu_mmu_context_fini(vdev, &vdev->gctx); 570 + ivpu_mmu_context_fini(vdev, &vdev->gctx); 613 571 } 614 572 615 573 int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev) 616 574 { 617 - return ivpu_mmu_user_context_init(vdev, &vdev->rctx, IVPU_RESERVED_CONTEXT_MMU_SSID); 575 + int ret; 576 + 577 + ivpu_mmu_context_init(vdev, &vdev->rctx, IVPU_RESERVED_CONTEXT_MMU_SSID); 578 + 579 + mutex_lock(&vdev->rctx.lock); 580 + 581 + if (!ivpu_mmu_ensure_pgd(vdev, &vdev->rctx.pgtable)) { 582 + ivpu_err(vdev, "Failed to allocate root page table for reserved context\n"); 583 + ret = -ENOMEM; 584 + goto unlock; 585 + } 586 + 587 + ret = ivpu_mmu_cd_set(vdev, vdev->rctx.id, &vdev->rctx.pgtable); 588 + if (ret) { 589 + ivpu_err(vdev, "Failed to set context descriptor for reserved context\n"); 590 + goto unlock; 591 + } 592 + 593 + unlock: 594 + mutex_unlock(&vdev->rctx.lock); 595 + return ret; 618 596 } 619 597 620 598 void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev) 621 599 { 622 - return ivpu_mmu_user_context_fini(vdev, &vdev->rctx); 600 + ivpu_mmu_cd_clear(vdev, vdev->rctx.id); 601 + ivpu_mmu_context_fini(vdev, &vdev->rctx); 623 602 } 624 603 625 604 void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid) ··· 643 602 file_priv->has_mmu_faults = true; 644 603 645 604 xa_unlock(&vdev->context_xa); 646 - } 647 - 648 - int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id) 649 - { 650 - int ret; 651 - 652 - drm_WARN_ON(&vdev->drm, !ctx_id); 653 - 654 - ret = ivpu_mmu_context_init(vdev, ctx, ctx_id); 655 - if (ret) { 656 - ivpu_err(vdev, "Failed to initialize context %u: %d\n", ctx_id, ret); 657 - return ret; 658 - } 659 - 660 - ret = ivpu_mmu_set_pgtable(vdev, ctx_id, &ctx->pgtable); 661 - if (ret) { 662 - ivpu_err(vdev, "Failed to set page table for context %u: %d\n", ctx_id, ret); 663 - goto err_context_fini; 664 - } 665 - 666 - return 0; 667 - 668 - err_context_fini: 669 - ivpu_mmu_context_fini(vdev, ctx); 670 - return ret; 671 - } 672 - 673 - void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) 674 - { 675 - drm_WARN_ON(&vdev->drm, !ctx->id); 676 - 677 - ivpu_mmu_clear_pgtable(vdev, ctx->id); 678 - ivpu_mmu_context_fini(vdev, ctx); 679 605 }
+5 -4
drivers/accel/ivpu/ivpu_mmu_context.h
··· 23 23 }; 24 24 25 25 struct ivpu_mmu_context { 26 - struct mutex lock; /* Protects: mm, pgtable */ 26 + struct mutex lock; /* Protects: mm, pgtable, is_cd_valid */ 27 27 struct drm_mm mm; 28 28 struct ivpu_mmu_pgtable pgtable; 29 + bool is_cd_valid; 29 30 u32 id; 30 31 }; 31 32 32 - int ivpu_mmu_global_context_init(struct ivpu_device *vdev); 33 + void ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id); 34 + void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); 35 + void ivpu_mmu_global_context_init(struct ivpu_device *vdev); 33 36 void ivpu_mmu_global_context_fini(struct ivpu_device *vdev); 34 37 int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev); 35 38 void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev); 36 39 37 - int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id); 38 - void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); 39 40 void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid); 40 41 41 42 int ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range,
+2
drivers/accel/ivpu/ivpu_pm.c
··· 24 24 #include "vpu_boot_api.h" 25 25 26 26 static bool ivpu_disable_recovery; 27 + #if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) 27 28 module_param_named_unsafe(disable_recovery, ivpu_disable_recovery, bool, 0644); 28 29 MODULE_PARM_DESC(disable_recovery, "Disables recovery when NPU hang is detected"); 30 + #endif 29 31 30 32 static unsigned long ivpu_tdr_timeout_ms; 31 33 module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, ulong, 0644);
+2 -2
drivers/accel/qaic/qaic_drv.c
··· 54 54 destroy_workqueue(wq); 55 55 } 56 56 57 - static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt) 57 + static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *name) 58 58 { 59 59 struct workqueue_struct *wq; 60 60 int ret; 61 61 62 - wq = alloc_workqueue(fmt, WQ_UNBOUND, 0); 62 + wq = alloc_workqueue("%s", WQ_UNBOUND, 0, name); 63 63 if (!wq) 64 64 return ERR_PTR(-ENOMEM); 65 65 ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq);
+381 -7
drivers/accel/qaic/sahara.c
··· 2 2 3 3 /* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ 4 4 5 + #include <linux/devcoredump.h> 5 6 #include <linux/firmware.h> 6 7 #include <linux/limits.h> 7 8 #include <linux/mhi.h> ··· 10 9 #include <linux/mod_devicetable.h> 11 10 #include <linux/overflow.h> 12 11 #include <linux/types.h> 12 + #include <linux/vmalloc.h> 13 13 #include <linux/workqueue.h> 14 14 15 15 #include "sahara.h" ··· 38 36 39 37 #define SAHARA_PACKET_MAX_SIZE 0xffffU /* MHI_MAX_MTU */ 40 38 #define SAHARA_TRANSFER_MAX_SIZE 0x80000 39 + #define SAHARA_READ_MAX_SIZE 0xfff0U /* Avoid unaligned requests */ 41 40 #define SAHARA_NUM_TX_BUF DIV_ROUND_UP(SAHARA_TRANSFER_MAX_SIZE,\ 42 41 SAHARA_PACKET_MAX_SIZE) 43 42 #define SAHARA_IMAGE_ID_NONE U32_MAX 44 43 45 44 #define SAHARA_VERSION 2 46 45 #define SAHARA_SUCCESS 0 46 + #define SAHARA_TABLE_ENTRY_STR_LEN 20 47 47 48 48 #define SAHARA_MODE_IMAGE_TX_PENDING 0x0 49 49 #define SAHARA_MODE_IMAGE_TX_COMPLETE 0x1 ··· 57 53 #define SAHARA_END_OF_IMAGE_LENGTH 0x10 58 54 #define SAHARA_DONE_LENGTH 0x8 59 55 #define SAHARA_RESET_LENGTH 0x8 56 + #define SAHARA_MEM_DEBUG64_LENGTH 0x18 57 + #define SAHARA_MEM_READ64_LENGTH 0x18 60 58 61 59 struct sahara_packet { 62 60 __le32 cmd; ··· 86 80 __le32 image; 87 81 __le32 status; 88 82 } end_of_image; 83 + struct { 84 + __le64 table_address; 85 + __le64 table_length; 86 + } memory_debug64; 87 + struct { 88 + __le64 memory_address; 89 + __le64 memory_length; 90 + } memory_read64; 89 91 }; 90 92 }; 93 + 94 + struct sahara_debug_table_entry64 { 95 + __le64 type; 96 + __le64 address; 97 + __le64 length; 98 + char description[SAHARA_TABLE_ENTRY_STR_LEN]; 99 + char filename[SAHARA_TABLE_ENTRY_STR_LEN]; 100 + }; 101 + 102 + struct sahara_dump_table_entry { 103 + u64 type; 104 + u64 address; 105 + u64 length; 106 + char description[SAHARA_TABLE_ENTRY_STR_LEN]; 107 + char filename[SAHARA_TABLE_ENTRY_STR_LEN]; 108 + }; 109 + 110 + #define SAHARA_DUMP_V1_MAGIC 0x1234567890abcdef 111 + #define SAHARA_DUMP_V1_VER 1 112 + struct sahara_memory_dump_meta_v1 { 113 + u64 magic; 114 + u64 version; 115 + u64 dump_size; 116 + u64 table_size; 117 + }; 118 + 119 + /* 120 + * Layout of crashdump provided to user via devcoredump 121 + * +------------------------------------------+ 122 + * | Crashdump Meta structure | 123 + * | type: struct sahara_memory_dump_meta_v1 | 124 + * +------------------------------------------+ 125 + * | Crashdump Table | 126 + * | type: array of struct | 127 + * | sahara_dump_table_entry | 128 + * | | 129 + * | | 130 + * +------------------------------------------+ 131 + * | Crashdump | 132 + * | | 133 + * | | 134 + * | | 135 + * | | 136 + * | | 137 + * +------------------------------------------+ 138 + * 139 + * First is the metadata header. Userspace can use the magic number to verify 140 + * the content type, and then check the version for the rest of the format. 141 + * New versions should keep the magic number location/value, and version 142 + * location, but increment the version value. 143 + * 144 + * For v1, the metadata lists the size of the entire dump (header + table + 145 + * dump) and the size of the table. Then the dump image table, which describes 146 + * the contents of the dump. Finally all the images are listed in order, with 147 + * no deadspace in between. Userspace can use the sizes listed in the image 148 + * table to reconstruct the individual images. 149 + */ 91 150 92 151 struct sahara_context { 93 152 struct sahara_packet *tx[SAHARA_NUM_TX_BUF]; 94 153 struct sahara_packet *rx; 95 - struct work_struct work; 154 + struct work_struct fw_work; 155 + struct work_struct dump_work; 96 156 struct mhi_device *mhi_dev; 97 157 const char **image_table; 98 158 u32 table_size; 99 159 u32 active_image_id; 100 160 const struct firmware *firmware; 161 + u64 dump_table_address; 162 + u64 dump_table_length; 163 + size_t rx_size; 164 + size_t rx_size_requested; 165 + void *mem_dump; 166 + size_t mem_dump_sz; 167 + struct sahara_dump_table_entry *dump_image; 168 + u64 dump_image_offset; 169 + void *mem_dump_freespace; 170 + u64 dump_images_left; 171 + bool is_mem_dump_mode; 101 172 }; 102 173 103 174 static const char *aic100_image_table[] = { ··· 236 153 { 237 154 int ret; 238 155 156 + context->is_mem_dump_mode = false; 157 + 239 158 context->tx[0]->cmd = cpu_to_le32(SAHARA_RESET_CMD); 240 159 context->tx[0]->length = cpu_to_le32(SAHARA_RESET_LENGTH); 241 160 ··· 271 186 } 272 187 273 188 if (le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_PENDING && 274 - le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_COMPLETE) { 189 + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_COMPLETE && 190 + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_MEMORY_DEBUG) { 275 191 dev_err(&context->mhi_dev->dev, "Unsupported hello packet - mode %d\n", 276 192 le32_to_cpu(context->rx->hello.mode)); 277 193 return; ··· 406 320 dev_dbg(&context->mhi_dev->dev, "Unable to send done response %d\n", ret); 407 321 } 408 322 323 + static void sahara_memory_debug64(struct sahara_context *context) 324 + { 325 + int ret; 326 + 327 + dev_dbg(&context->mhi_dev->dev, 328 + "MEMORY DEBUG64 cmd received. length:%d table_address:%#llx table_length:%#llx\n", 329 + le32_to_cpu(context->rx->length), 330 + le64_to_cpu(context->rx->memory_debug64.table_address), 331 + le64_to_cpu(context->rx->memory_debug64.table_length)); 332 + 333 + if (le32_to_cpu(context->rx->length) != SAHARA_MEM_DEBUG64_LENGTH) { 334 + dev_err(&context->mhi_dev->dev, "Malformed memory debug64 packet - length %d\n", 335 + le32_to_cpu(context->rx->length)); 336 + return; 337 + } 338 + 339 + context->dump_table_address = le64_to_cpu(context->rx->memory_debug64.table_address); 340 + context->dump_table_length = le64_to_cpu(context->rx->memory_debug64.table_length); 341 + 342 + if (context->dump_table_length % sizeof(struct sahara_debug_table_entry64) != 0 || 343 + !context->dump_table_length) { 344 + dev_err(&context->mhi_dev->dev, "Malformed memory debug64 packet - table length %lld\n", 345 + context->dump_table_length); 346 + return; 347 + } 348 + 349 + /* 350 + * From this point, the protocol flips. We make memory_read requests to 351 + * the device, and the device responds with the raw data. If the device 352 + * has an error, it will send an End of Image command. First we need to 353 + * request the memory dump table so that we know where all the pieces 354 + * of the dump are that we can consume. 355 + */ 356 + 357 + context->is_mem_dump_mode = true; 358 + 359 + /* 360 + * Assume that the table is smaller than our MTU so that we can read it 361 + * in one shot. The spec does not put an upper limit on the table, but 362 + * no known device will exceed this. 363 + */ 364 + if (context->dump_table_length > SAHARA_PACKET_MAX_SIZE) { 365 + dev_err(&context->mhi_dev->dev, "Memory dump table length %lld exceeds supported size. Discarding dump\n", 366 + context->dump_table_length); 367 + sahara_send_reset(context); 368 + return; 369 + } 370 + 371 + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); 372 + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); 373 + context->tx[0]->memory_read64.memory_address = cpu_to_le64(context->dump_table_address); 374 + context->tx[0]->memory_read64.memory_length = cpu_to_le64(context->dump_table_length); 375 + 376 + context->rx_size_requested = context->dump_table_length; 377 + 378 + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], 379 + SAHARA_MEM_READ64_LENGTH, MHI_EOT); 380 + if (ret) 381 + dev_err(&context->mhi_dev->dev, "Unable to send read for dump table %d\n", ret); 382 + } 383 + 409 384 static void sahara_processing(struct work_struct *work) 410 385 { 411 - struct sahara_context *context = container_of(work, struct sahara_context, work); 386 + struct sahara_context *context = container_of(work, struct sahara_context, fw_work); 412 387 int ret; 413 388 414 389 switch (le32_to_cpu(context->rx->cmd)) { ··· 485 338 case SAHARA_DONE_RESP_CMD: 486 339 /* Intentional do nothing as we don't need to exit an app */ 487 340 break; 341 + case SAHARA_RESET_RESP_CMD: 342 + /* Intentional do nothing as we don't need to exit an app */ 343 + break; 344 + case SAHARA_MEM_DEBUG64_CMD: 345 + sahara_memory_debug64(context); 346 + break; 488 347 default: 489 348 dev_err(&context->mhi_dev->dev, "Unknown command %d\n", 490 349 le32_to_cpu(context->rx->cmd)); ··· 501 348 SAHARA_PACKET_MAX_SIZE, MHI_EOT); 502 349 if (ret) 503 350 dev_err(&context->mhi_dev->dev, "Unable to requeue rx buf %d\n", ret); 351 + } 352 + 353 + static void sahara_parse_dump_table(struct sahara_context *context) 354 + { 355 + struct sahara_dump_table_entry *image_out_table; 356 + struct sahara_debug_table_entry64 *dev_table; 357 + struct sahara_memory_dump_meta_v1 *dump_meta; 358 + u64 table_nents; 359 + u64 dump_length; 360 + int ret; 361 + u64 i; 362 + 363 + table_nents = context->dump_table_length / sizeof(*dev_table); 364 + context->dump_images_left = table_nents; 365 + dump_length = 0; 366 + 367 + dev_table = (struct sahara_debug_table_entry64 *)(context->rx); 368 + for (i = 0; i < table_nents; ++i) { 369 + /* Do not trust the device, ensure the strings are terminated */ 370 + dev_table[i].description[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0; 371 + dev_table[i].filename[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0; 372 + 373 + dump_length = size_add(dump_length, le64_to_cpu(dev_table[i].length)); 374 + if (dump_length == SIZE_MAX) { 375 + /* Discard the dump */ 376 + sahara_send_reset(context); 377 + return; 378 + } 379 + 380 + dev_dbg(&context->mhi_dev->dev, 381 + "Memory dump table entry %lld type: %lld address: %#llx length: %#llx description: \"%s\" filename \"%s\"\n", 382 + i, 383 + le64_to_cpu(dev_table[i].type), 384 + le64_to_cpu(dev_table[i].address), 385 + le64_to_cpu(dev_table[i].length), 386 + dev_table[i].description, 387 + dev_table[i].filename); 388 + } 389 + 390 + dump_length = size_add(dump_length, sizeof(*dump_meta)); 391 + if (dump_length == SIZE_MAX) { 392 + /* Discard the dump */ 393 + sahara_send_reset(context); 394 + return; 395 + } 396 + dump_length = size_add(dump_length, size_mul(sizeof(*image_out_table), table_nents)); 397 + if (dump_length == SIZE_MAX) { 398 + /* Discard the dump */ 399 + sahara_send_reset(context); 400 + return; 401 + } 402 + 403 + context->mem_dump_sz = dump_length; 404 + context->mem_dump = vzalloc(dump_length); 405 + if (!context->mem_dump) { 406 + /* Discard the dump */ 407 + sahara_send_reset(context); 408 + return; 409 + } 410 + 411 + /* Populate the dump metadata and table for userspace */ 412 + dump_meta = context->mem_dump; 413 + dump_meta->magic = SAHARA_DUMP_V1_MAGIC; 414 + dump_meta->version = SAHARA_DUMP_V1_VER; 415 + dump_meta->dump_size = dump_length; 416 + dump_meta->table_size = context->dump_table_length; 417 + 418 + image_out_table = context->mem_dump + sizeof(*dump_meta); 419 + for (i = 0; i < table_nents; ++i) { 420 + image_out_table[i].type = le64_to_cpu(dev_table[i].type); 421 + image_out_table[i].address = le64_to_cpu(dev_table[i].address); 422 + image_out_table[i].length = le64_to_cpu(dev_table[i].length); 423 + strscpy(image_out_table[i].description, dev_table[i].description, 424 + SAHARA_TABLE_ENTRY_STR_LEN); 425 + strscpy(image_out_table[i].filename, 426 + dev_table[i].filename, 427 + SAHARA_TABLE_ENTRY_STR_LEN); 428 + } 429 + 430 + context->mem_dump_freespace = &image_out_table[i]; 431 + 432 + /* Done parsing the table, switch to image dump mode */ 433 + context->dump_table_length = 0; 434 + 435 + /* Request the first chunk of the first image */ 436 + context->dump_image = &image_out_table[0]; 437 + dump_length = min(context->dump_image->length, SAHARA_READ_MAX_SIZE); 438 + /* Avoid requesting EOI sized data so that we can identify errors */ 439 + if (dump_length == SAHARA_END_OF_IMAGE_LENGTH) 440 + dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2; 441 + 442 + context->dump_image_offset = dump_length; 443 + 444 + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); 445 + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); 446 + context->tx[0]->memory_read64.memory_address = cpu_to_le64(context->dump_image->address); 447 + context->tx[0]->memory_read64.memory_length = cpu_to_le64(dump_length); 448 + 449 + context->rx_size_requested = dump_length; 450 + 451 + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], 452 + SAHARA_MEM_READ64_LENGTH, MHI_EOT); 453 + if (ret) 454 + dev_err(&context->mhi_dev->dev, "Unable to send read for dump content %d\n", ret); 455 + } 456 + 457 + static void sahara_parse_dump_image(struct sahara_context *context) 458 + { 459 + u64 dump_length; 460 + int ret; 461 + 462 + memcpy(context->mem_dump_freespace, context->rx, context->rx_size); 463 + context->mem_dump_freespace += context->rx_size; 464 + 465 + if (context->dump_image_offset >= context->dump_image->length) { 466 + /* Need to move to next image */ 467 + context->dump_image++; 468 + context->dump_images_left--; 469 + context->dump_image_offset = 0; 470 + 471 + if (!context->dump_images_left) { 472 + /* Dump done */ 473 + dev_coredumpv(context->mhi_dev->mhi_cntrl->cntrl_dev, 474 + context->mem_dump, 475 + context->mem_dump_sz, 476 + GFP_KERNEL); 477 + context->mem_dump = NULL; 478 + sahara_send_reset(context); 479 + return; 480 + } 481 + } 482 + 483 + /* Get next image chunk */ 484 + dump_length = context->dump_image->length - context->dump_image_offset; 485 + dump_length = min(dump_length, SAHARA_READ_MAX_SIZE); 486 + /* Avoid requesting EOI sized data so that we can identify errors */ 487 + if (dump_length == SAHARA_END_OF_IMAGE_LENGTH) 488 + dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2; 489 + 490 + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); 491 + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); 492 + context->tx[0]->memory_read64.memory_address = 493 + cpu_to_le64(context->dump_image->address + context->dump_image_offset); 494 + context->tx[0]->memory_read64.memory_length = cpu_to_le64(dump_length); 495 + 496 + context->dump_image_offset += dump_length; 497 + context->rx_size_requested = dump_length; 498 + 499 + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], 500 + SAHARA_MEM_READ64_LENGTH, MHI_EOT); 501 + if (ret) 502 + dev_err(&context->mhi_dev->dev, 503 + "Unable to send read for dump content %d\n", ret); 504 + } 505 + 506 + static void sahara_dump_processing(struct work_struct *work) 507 + { 508 + struct sahara_context *context = container_of(work, struct sahara_context, dump_work); 509 + int ret; 510 + 511 + /* 512 + * We should get the expected raw data, but if the device has an error 513 + * it is supposed to send EOI with an error code. 514 + */ 515 + if (context->rx_size != context->rx_size_requested && 516 + context->rx_size != SAHARA_END_OF_IMAGE_LENGTH) { 517 + dev_err(&context->mhi_dev->dev, 518 + "Unexpected response to read_data. Expected size: %#zx got: %#zx\n", 519 + context->rx_size_requested, 520 + context->rx_size); 521 + goto error; 522 + } 523 + 524 + if (context->rx_size == SAHARA_END_OF_IMAGE_LENGTH && 525 + le32_to_cpu(context->rx->cmd) == SAHARA_END_OF_IMAGE_CMD) { 526 + dev_err(&context->mhi_dev->dev, 527 + "Unexpected EOI response to read_data. Status: %d\n", 528 + le32_to_cpu(context->rx->end_of_image.status)); 529 + goto error; 530 + } 531 + 532 + if (context->rx_size == SAHARA_END_OF_IMAGE_LENGTH && 533 + le32_to_cpu(context->rx->cmd) != SAHARA_END_OF_IMAGE_CMD) { 534 + dev_err(&context->mhi_dev->dev, 535 + "Invalid EOI response to read_data. CMD: %d\n", 536 + le32_to_cpu(context->rx->cmd)); 537 + goto error; 538 + } 539 + 540 + /* 541 + * Need to know if we received the dump table, or part of a dump image. 542 + * Since we get raw data, we cannot tell from the data itself. Instead, 543 + * we use the stored dump_table_length, which we zero after we read and 544 + * process the entire table. 545 + */ 546 + if (context->dump_table_length) 547 + sahara_parse_dump_table(context); 548 + else 549 + sahara_parse_dump_image(context); 550 + 551 + ret = mhi_queue_buf(context->mhi_dev, DMA_FROM_DEVICE, context->rx, 552 + SAHARA_PACKET_MAX_SIZE, MHI_EOT); 553 + if (ret) 554 + dev_err(&context->mhi_dev->dev, "Unable to requeue rx buf %d\n", ret); 555 + 556 + return; 557 + 558 + error: 559 + vfree(context->mem_dump); 560 + context->mem_dump = NULL; 561 + sahara_send_reset(context); 504 562 } 505 563 506 564 static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) ··· 746 382 } 747 383 748 384 context->mhi_dev = mhi_dev; 749 - INIT_WORK(&context->work, sahara_processing); 385 + INIT_WORK(&context->fw_work, sahara_processing); 386 + INIT_WORK(&context->dump_work, sahara_dump_processing); 750 387 context->image_table = aic100_image_table; 751 388 context->table_size = ARRAY_SIZE(aic100_image_table); 752 389 context->active_image_id = SAHARA_IMAGE_ID_NONE; ··· 770 405 { 771 406 struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev); 772 407 773 - cancel_work_sync(&context->work); 408 + cancel_work_sync(&context->fw_work); 409 + cancel_work_sync(&context->dump_work); 410 + if (context->mem_dump) 411 + vfree(context->mem_dump); 774 412 sahara_release_image(context); 775 413 mhi_unprepare_from_transfer(mhi_dev); 776 414 } ··· 786 418 { 787 419 struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev); 788 420 789 - if (!mhi_result->transaction_status) 790 - schedule_work(&context->work); 421 + if (!mhi_result->transaction_status) { 422 + context->rx_size = mhi_result->bytes_xferd; 423 + if (context->is_mem_dump_mode) 424 + schedule_work(&context->dump_work); 425 + else 426 + schedule_work(&context->fw_work); 427 + } 428 + 791 429 } 792 430 793 431 static const struct mhi_device_id sahara_mhi_match_table[] = {
+34 -7
drivers/gpu/drm/Kconfig
··· 9 9 tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" 10 10 depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA 11 11 select DRM_PANEL_ORIENTATION_QUIRKS 12 - select DRM_KMS_HELPER if DRM_FBDEV_EMULATION 13 - select FB_CORE if DRM_FBDEV_EMULATION 14 - select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION 15 12 select HDMI 16 13 select I2C 17 14 select DMA_SHARED_BUFFER ··· 208 211 209 212 If in doubt, say "N". 210 213 211 - config DRM_CLIENT_SELECTION 214 + config DRM_CLIENT 212 215 bool 213 216 depends on DRM 214 - select DRM_CLIENT_SETUP if DRM_FBDEV_EMULATION 217 + help 218 + Enables support for DRM clients. DRM drivers that need 219 + struct drm_client_dev and its interfaces should select this 220 + option. Drivers that support the default clients should 221 + select DRM_CLIENT_SELECTION instead. 222 + 223 + config DRM_CLIENT_LIB 224 + tristate 225 + depends on DRM 226 + select DRM_KMS_HELPER if DRM_FBDEV_EMULATION 227 + select FB_CORE if DRM_FBDEV_EMULATION 228 + help 229 + This option enables the DRM client library and selects all 230 + modules and components according to the enabled clients. 231 + 232 + config DRM_CLIENT_SELECTION 233 + tristate 234 + depends on DRM 235 + select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION 215 236 help 216 237 Drivers that support in-kernel DRM clients have to select this 217 238 option. ··· 237 222 config DRM_CLIENT_SETUP 238 223 bool 239 224 depends on DRM_CLIENT_SELECTION 225 + help 226 + Enables the DRM client selection. DRM drivers that support the 227 + default clients should select DRM_CLIENT_SELECTION instead. 228 + 229 + menu "Supported DRM clients" 230 + depends on DRM_CLIENT_SELECTION 240 231 241 232 config DRM_FBDEV_EMULATION 242 233 bool "Enable legacy fbdev support for your modesetting driver" 243 - depends on DRM 234 + depends on DRM_CLIENT_SELECTION 235 + select DRM_CLIENT 236 + select DRM_CLIENT_SETUP 244 237 select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE 245 238 default FB 246 239 help ··· 286 263 287 264 If in doubt, say "N" or spread the word to your closed source 288 265 library vendor. 266 + 267 + endmenu 289 268 290 269 config DRM_LOAD_EDID_FIRMWARE 291 270 bool "Allow to specify an EDID data set instead of probing for it" ··· 358 333 tristate 359 334 depends on DRM 360 335 select DRM_TTM 336 + select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION 361 337 help 362 338 Helpers for ttm-based gem objects 363 339 364 340 config DRM_GEM_DMA_HELPER 365 341 tristate 366 342 depends on DRM 367 - select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION 343 + select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION 368 344 help 369 345 Choose this if you need the GEM DMA helper functions 370 346 371 347 config DRM_GEM_SHMEM_HELPER 372 348 tristate 373 349 depends on DRM && MMU 350 + select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION 374 351 help 375 352 Choose this if you need the GEM shmem helper functions 376 353
+13 -7
drivers/gpu/drm/Makefile
··· 40 40 drm_blend.o \ 41 41 drm_bridge.o \ 42 42 drm_cache.o \ 43 - drm_client.o \ 44 - drm_client_modeset.o \ 45 43 drm_color_mgmt.o \ 46 44 drm_connector.o \ 47 45 drm_crtc.o \ ··· 73 75 drm_vblank_work.o \ 74 76 drm_vma_manager.o \ 75 77 drm_writeback.o 78 + drm-$(CONFIG_DRM_CLIENT) += \ 79 + drm_client.o \ 80 + drm_client_event.o \ 81 + drm_client_modeset.o 76 82 drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o 77 83 drm-$(CONFIG_COMPAT) += drm_ioc32.o 78 84 drm-$(CONFIG_DRM_PANEL) += drm_panel.o ··· 144 142 drm_probe_helper.o \ 145 143 drm_self_refresh_helper.o \ 146 144 drm_simple_kms_helper.o 147 - drm_kms_helper-$(CONFIG_DRM_CLIENT_SETUP) += \ 148 - drm_client_setup.o 149 145 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o 150 - drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += \ 151 - drm_fbdev_client.o \ 152 - drm_fb_helper.o 146 + drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o 153 147 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o 148 + 149 + # 150 + # DRM clients 151 + # 152 + 153 + drm_client_lib-y := drm_client_setup.o 154 + drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o 155 + obj-$(CONFIG_DRM_CLIENT_LIB) += drm_client_lib.o 154 156 155 157 # 156 158 # Drivers and the rest
+1
drivers/gpu/drm/amd/amdgpu/Kconfig
··· 5 5 depends on DRM && PCI && MMU 6 6 depends on !UML 7 7 select FW_LOADER 8 + select DRM_CLIENT 8 9 select DRM_CLIENT_SELECTION 9 10 select DRM_DISPLAY_DP_HELPER 10 11 select DRM_DISPLAY_DSC_HELPER
+11 -11
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
··· 38 38 #include <linux/apple-gmux.h> 39 39 40 40 #include <drm/drm_atomic_helper.h> 41 + #include <drm/drm_client_event.h> 41 42 #include <drm/drm_crtc_helper.h> 42 - #include <drm/drm_fb_helper.h> 43 43 #include <drm/drm_probe_helper.h> 44 44 #include <drm/amdgpu_drm.h> 45 45 #include <linux/device.h> ··· 4793 4793 * amdgpu_device_suspend - initiate device suspend 4794 4794 * 4795 4795 * @dev: drm dev pointer 4796 - * @fbcon : notify the fbdev of suspend 4796 + * @notify_clients: notify in-kernel DRM clients 4797 4797 * 4798 4798 * Puts the hw in the suspend state (all asics). 4799 4799 * Returns 0 for success or an error on failure. 4800 4800 * Called at driver suspend. 4801 4801 */ 4802 - int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) 4802 + int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients) 4803 4803 { 4804 4804 struct amdgpu_device *adev = drm_to_adev(dev); 4805 4805 int r = 0; ··· 4819 4819 if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3)) 4820 4820 DRM_WARN("smart shift update failed\n"); 4821 4821 4822 - if (fbcon) 4823 - drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); 4822 + if (notify_clients) 4823 + drm_client_dev_suspend(adev_to_drm(adev), false); 4824 4824 4825 4825 cancel_delayed_work_sync(&adev->delayed_init_work); 4826 4826 ··· 4855 4855 * amdgpu_device_resume - initiate device resume 4856 4856 * 4857 4857 * @dev: drm dev pointer 4858 - * @fbcon : notify the fbdev of resume 4858 + * @notify_clients: notify in-kernel DRM clients 4859 4859 * 4860 4860 * Bring the hw back to operating state (all asics). 4861 4861 * Returns 0 for success or an error on failure. 4862 4862 * Called at driver resume. 4863 4863 */ 4864 - int amdgpu_device_resume(struct drm_device *dev, bool fbcon) 4864 + int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) 4865 4865 { 4866 4866 struct amdgpu_device *adev = drm_to_adev(dev); 4867 4867 int r = 0; ··· 4917 4917 /* Make sure IB tests flushed */ 4918 4918 flush_delayed_work(&adev->delayed_init_work); 4919 4919 4920 - if (fbcon) 4921 - drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, false); 4920 + if (notify_clients) 4921 + drm_client_dev_resume(adev_to_drm(adev), false); 4922 4922 4923 4923 amdgpu_ras_resume(adev); 4924 4924 ··· 5482 5482 if (r) 5483 5483 goto out; 5484 5484 5485 - drm_fb_helper_set_suspend_unlocked(adev_to_drm(tmp_adev)->fb_helper, false); 5485 + drm_client_dev_resume(adev_to_drm(tmp_adev), false); 5486 5486 5487 5487 /* 5488 5488 * The GPU enters bad state once faulty pages ··· 5842 5842 */ 5843 5843 amdgpu_unregister_gpu_instance(tmp_adev); 5844 5844 5845 - drm_fb_helper_set_suspend_unlocked(adev_to_drm(tmp_adev)->fb_helper, true); 5845 + drm_client_dev_suspend(adev_to_drm(tmp_adev), false); 5846 5846 5847 5847 /* disable ras on ALL IPs */ 5848 5848 if (!need_emergency_restart &&
+4
drivers/gpu/drm/bridge/aux-bridge.c
··· 120 120 data->bridge.funcs = &drm_aux_bridge_funcs; 121 121 data->bridge.of_node = data->dev->of_node; 122 122 123 + /* passthrough data, allow everything */ 124 + data->bridge.interlace_allowed = true; 125 + data->bridge.ycbcr_420_allowed = true; 126 + 123 127 return devm_drm_bridge_add(data->dev, &data->bridge); 124 128 } 125 129
+4
drivers/gpu/drm/bridge/aux-hpd-bridge.c
··· 180 180 data->bridge.ops = DRM_BRIDGE_OP_HPD; 181 181 data->bridge.type = id->driver_data; 182 182 183 + /* passthrough data, allow everything */ 184 + data->bridge.interlace_allowed = true; 185 + data->bridge.ycbcr_420_allowed = true; 186 + 183 187 auxiliary_set_drvdata(auxdev, data); 184 188 185 189 return devm_drm_bridge_add(data->dev, &data->bridge);
+4
drivers/gpu/drm/bridge/display-connector.c
··· 270 270 /* All the supported connector types support interlaced modes. */ 271 271 conn->bridge.interlace_allowed = true; 272 272 273 + if (type == DRM_MODE_CONNECTOR_HDMIA || 274 + type == DRM_MODE_CONNECTOR_DisplayPort) 275 + conn->bridge.ycbcr_420_allowed = true; 276 + 273 277 /* Get the optional connector label. */ 274 278 of_property_read_string(pdev->dev.of_node, "label", &label); 275 279
+1
drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
··· 85 85 EXPORT_SYMBOL_GPL(devm_imx_drm_legacy_bridge); 86 86 87 87 MODULE_LICENSE("GPL"); 88 + MODULE_DESCRIPTION("Freescale i.MX DRM bridge driver for legacy DT bindings");
-2
drivers/gpu/drm/bridge/ite-it66121.c
··· 770 770 771 771 mutex_lock(&ctx->lock); 772 772 773 - hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe); 774 - 775 773 ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ctx->connector, 776 774 adjusted_mode); 777 775 if (ret) {
+23 -1
drivers/gpu/drm/bridge/sii902x.c
··· 180 180 struct gpio_desc *reset_gpio; 181 181 struct i2c_mux_core *i2cmux; 182 182 bool sink_is_hdmi; 183 + u32 bus_width; 184 + 183 185 /* 184 186 * Mutex protects audio and video functions from interfering 185 187 * each other, by keeping their i2c command sequences atomic. ··· 479 477 u32 output_fmt, 480 478 unsigned int *num_input_fmts) 481 479 { 480 + 481 + struct sii902x *sii902x = bridge_to_sii902x(bridge); 482 482 u32 *input_fmts; 483 483 484 484 *num_input_fmts = 0; ··· 489 485 if (!input_fmts) 490 486 return NULL; 491 487 492 - input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 488 + switch (sii902x->bus_width) { 489 + case 16: 490 + input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16; 491 + break; 492 + case 18: 493 + input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18; 494 + break; 495 + case 24: 496 + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 497 + break; 498 + default: 499 + return NULL; 500 + } 501 + 493 502 *num_input_fmts = 1; 494 503 495 504 return input_fmts; ··· 1183 1166 PTR_ERR(sii902x->reset_gpio)); 1184 1167 return PTR_ERR(sii902x->reset_gpio); 1185 1168 } 1169 + 1170 + sii902x->bus_width = 24; 1171 + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); 1172 + if (endpoint) 1173 + of_property_read_u32(endpoint, "bus-width", &sii902x->bus_width); 1186 1174 1187 1175 endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); 1188 1176 if (endpoint) {
+8
drivers/gpu/drm/bridge/synopsys/Kconfig
··· 46 46 Support the CE interface which is part of the Synopsys 47 47 Designware HDMI block. 48 48 49 + config DRM_DW_HDMI_QP 50 + tristate 51 + select DRM_DISPLAY_HDMI_HELPER 52 + select DRM_DISPLAY_HDMI_STATE_HELPER 53 + select DRM_DISPLAY_HELPER 54 + select DRM_KMS_HELPER 55 + select REGMAP_MMIO 56 + 49 57 config DRM_DW_MIPI_DSI 50 58 tristate 51 59 select DRM_KMS_HELPER
+2
drivers/gpu/drm/bridge/synopsys/Makefile
··· 5 5 obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o 6 6 obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o 7 7 8 + obj-$(CONFIG_DRM_DW_HDMI_QP) += dw-hdmi-qp.o 9 + 8 10 obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw-mipi-dsi.o
+647
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. 4 + * Copyright (c) 2024 Collabora Ltd. 5 + * 6 + * Author: Algea Cao <algea.cao@rock-chips.com> 7 + * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> 8 + */ 9 + #include <linux/completion.h> 10 + #include <linux/hdmi.h> 11 + #include <linux/i2c.h> 12 + #include <linux/irq.h> 13 + #include <linux/module.h> 14 + #include <linux/mutex.h> 15 + #include <linux/of.h> 16 + #include <linux/workqueue.h> 17 + 18 + #include <drm/bridge/dw_hdmi_qp.h> 19 + #include <drm/display/drm_hdmi_helper.h> 20 + #include <drm/display/drm_hdmi_state_helper.h> 21 + #include <drm/drm_atomic.h> 22 + #include <drm/drm_atomic_helper.h> 23 + #include <drm/drm_bridge.h> 24 + #include <drm/drm_connector.h> 25 + #include <drm/drm_edid.h> 26 + #include <drm/drm_modes.h> 27 + 28 + #include <sound/hdmi-codec.h> 29 + 30 + #include "dw-hdmi-qp.h" 31 + 32 + #define DDC_CI_ADDR 0x37 33 + #define DDC_SEGMENT_ADDR 0x30 34 + 35 + #define HDMI14_MAX_TMDSCLK 340000000 36 + 37 + #define SCRAMB_POLL_DELAY_MS 3000 38 + 39 + struct dw_hdmi_qp_i2c { 40 + struct i2c_adapter adap; 41 + 42 + struct mutex lock; /* used to serialize data transfers */ 43 + struct completion cmp; 44 + u8 stat; 45 + 46 + u8 slave_reg; 47 + bool is_regaddr; 48 + bool is_segment; 49 + }; 50 + 51 + struct dw_hdmi_qp { 52 + struct drm_bridge bridge; 53 + 54 + struct device *dev; 55 + struct dw_hdmi_qp_i2c *i2c; 56 + 57 + struct { 58 + const struct dw_hdmi_qp_phy_ops *ops; 59 + void *data; 60 + } phy; 61 + 62 + struct regmap *regm; 63 + }; 64 + 65 + static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, 66 + int offset) 67 + { 68 + regmap_write(hdmi->regm, offset, val); 69 + } 70 + 71 + static unsigned int dw_hdmi_qp_read(struct dw_hdmi_qp *hdmi, int offset) 72 + { 73 + unsigned int val = 0; 74 + 75 + regmap_read(hdmi->regm, offset, &val); 76 + 77 + return val; 78 + } 79 + 80 + static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data, 81 + unsigned int mask, unsigned int reg) 82 + { 83 + regmap_update_bits(hdmi->regm, reg, mask, data); 84 + } 85 + 86 + static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, 87 + unsigned char *buf, unsigned int length) 88 + { 89 + struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; 90 + int stat; 91 + 92 + if (!i2c->is_regaddr) { 93 + dev_dbg(hdmi->dev, "set read register address to 0\n"); 94 + i2c->slave_reg = 0x00; 95 + i2c->is_regaddr = true; 96 + } 97 + 98 + while (length--) { 99 + reinit_completion(&i2c->cmp); 100 + 101 + dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, 102 + I2CM_INTERFACE_CONTROL0); 103 + 104 + if (i2c->is_segment) 105 + dw_hdmi_qp_mod(hdmi, I2CM_EXT_READ, I2CM_WR_MASK, 106 + I2CM_INTERFACE_CONTROL0); 107 + else 108 + dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK, 109 + I2CM_INTERFACE_CONTROL0); 110 + 111 + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); 112 + if (!stat) { 113 + dev_err(hdmi->dev, "i2c read timed out\n"); 114 + dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); 115 + return -EAGAIN; 116 + } 117 + 118 + /* Check for error condition on the bus */ 119 + if (i2c->stat & I2CM_NACK_RCVD_IRQ) { 120 + dev_err(hdmi->dev, "i2c read error\n"); 121 + dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); 122 + return -EIO; 123 + } 124 + 125 + *buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; 126 + dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); 127 + } 128 + 129 + i2c->is_segment = false; 130 + 131 + return 0; 132 + } 133 + 134 + static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi, 135 + unsigned char *buf, unsigned int length) 136 + { 137 + struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; 138 + int stat; 139 + 140 + if (!i2c->is_regaddr) { 141 + /* Use the first write byte as register address */ 142 + i2c->slave_reg = buf[0]; 143 + length--; 144 + buf++; 145 + i2c->is_regaddr = true; 146 + } 147 + 148 + while (length--) { 149 + reinit_completion(&i2c->cmp); 150 + 151 + dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3); 152 + dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, 153 + I2CM_INTERFACE_CONTROL0); 154 + dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK, 155 + I2CM_INTERFACE_CONTROL0); 156 + 157 + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); 158 + if (!stat) { 159 + dev_err(hdmi->dev, "i2c write time out!\n"); 160 + dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); 161 + return -EAGAIN; 162 + } 163 + 164 + /* Check for error condition on the bus */ 165 + if (i2c->stat & I2CM_NACK_RCVD_IRQ) { 166 + dev_err(hdmi->dev, "i2c write nack!\n"); 167 + dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); 168 + return -EIO; 169 + } 170 + 171 + dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); 172 + } 173 + 174 + return 0; 175 + } 176 + 177 + static int dw_hdmi_qp_i2c_xfer(struct i2c_adapter *adap, 178 + struct i2c_msg *msgs, int num) 179 + { 180 + struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap); 181 + struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; 182 + u8 addr = msgs[0].addr; 183 + int i, ret = 0; 184 + 185 + if (addr == DDC_CI_ADDR) 186 + /* 187 + * The internal I2C controller does not support the multi-byte 188 + * read and write operations needed for DDC/CI. 189 + * FIXME: Blacklist the DDC/CI address until we filter out 190 + * unsupported I2C operations. 191 + */ 192 + return -EOPNOTSUPP; 193 + 194 + for (i = 0; i < num; i++) { 195 + if (msgs[i].len == 0) { 196 + dev_err(hdmi->dev, 197 + "unsupported transfer %d/%d, no data\n", 198 + i + 1, num); 199 + return -EOPNOTSUPP; 200 + } 201 + } 202 + 203 + guard(mutex)(&i2c->lock); 204 + 205 + /* Unmute DONE and ERROR interrupts */ 206 + dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, 207 + I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, 208 + MAINUNIT_1_INT_MASK_N); 209 + 210 + /* Set slave device address taken from the first I2C message */ 211 + if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1) 212 + addr = DDC_ADDR; 213 + 214 + dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0); 215 + 216 + /* Set slave device register address on transfer */ 217 + i2c->is_regaddr = false; 218 + 219 + /* Set segment pointer for I2C extended read mode operation */ 220 + i2c->is_segment = false; 221 + 222 + for (i = 0; i < num; i++) { 223 + if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { 224 + i2c->is_segment = true; 225 + dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, 226 + I2CM_INTERFACE_CONTROL1); 227 + dw_hdmi_qp_mod(hdmi, *msgs[i].buf << 7, I2CM_SEG_PTR, 228 + I2CM_INTERFACE_CONTROL1); 229 + } else { 230 + if (msgs[i].flags & I2C_M_RD) 231 + ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf, 232 + msgs[i].len); 233 + else 234 + ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf, 235 + msgs[i].len); 236 + } 237 + if (ret < 0) 238 + break; 239 + } 240 + 241 + if (!ret) 242 + ret = num; 243 + 244 + /* Mute DONE and ERROR interrupts */ 245 + dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N, 246 + MAINUNIT_1_INT_MASK_N); 247 + 248 + return ret; 249 + } 250 + 251 + static u32 dw_hdmi_qp_i2c_func(struct i2c_adapter *adapter) 252 + { 253 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 254 + } 255 + 256 + static const struct i2c_algorithm dw_hdmi_qp_algorithm = { 257 + .master_xfer = dw_hdmi_qp_i2c_xfer, 258 + .functionality = dw_hdmi_qp_i2c_func, 259 + }; 260 + 261 + static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi) 262 + { 263 + struct dw_hdmi_qp_i2c *i2c; 264 + struct i2c_adapter *adap; 265 + int ret; 266 + 267 + i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); 268 + if (!i2c) 269 + return ERR_PTR(-ENOMEM); 270 + 271 + mutex_init(&i2c->lock); 272 + init_completion(&i2c->cmp); 273 + 274 + adap = &i2c->adap; 275 + adap->owner = THIS_MODULE; 276 + adap->dev.parent = hdmi->dev; 277 + adap->algo = &dw_hdmi_qp_algorithm; 278 + strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name)); 279 + 280 + i2c_set_adapdata(adap, hdmi); 281 + 282 + ret = devm_i2c_add_adapter(hdmi->dev, adap); 283 + if (ret) { 284 + dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); 285 + devm_kfree(hdmi->dev, i2c); 286 + return ERR_PTR(ret); 287 + } 288 + 289 + hdmi->i2c = i2c; 290 + dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); 291 + 292 + return adap; 293 + } 294 + 295 + static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi, 296 + const u8 *buffer, size_t len) 297 + { 298 + u32 val, i, j; 299 + 300 + if (len != HDMI_INFOFRAME_SIZE(AVI)) { 301 + dev_err(hdmi->dev, "failed to configure avi infoframe\n"); 302 + return -EINVAL; 303 + } 304 + 305 + /* 306 + * DW HDMI QP IP uses a different byte format from standard AVI info 307 + * frames, though generally the bits are in the correct bytes. 308 + */ 309 + val = buffer[1] << 8 | buffer[2] << 16; 310 + dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0); 311 + 312 + for (i = 0; i < 4; i++) { 313 + for (j = 0; j < 4; j++) { 314 + if (i * 4 + j >= 14) 315 + break; 316 + if (!j) 317 + val = buffer[i * 4 + j + 3]; 318 + val |= buffer[i * 4 + j + 3] << (8 * j); 319 + } 320 + 321 + dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4); 322 + } 323 + 324 + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1); 325 + 326 + dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, 327 + PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); 328 + 329 + return 0; 330 + } 331 + 332 + static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi, 333 + const u8 *buffer, size_t len) 334 + { 335 + u32 val, i; 336 + 337 + if (len != HDMI_INFOFRAME_SIZE(DRM)) { 338 + dev_err(hdmi->dev, "failed to configure drm infoframe\n"); 339 + return -EINVAL; 340 + } 341 + 342 + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); 343 + 344 + val = buffer[1] << 8 | buffer[2] << 16; 345 + dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0); 346 + 347 + for (i = 0; i <= buffer[2]; i++) { 348 + if (i % 4 == 0) 349 + val = buffer[3 + i]; 350 + val |= buffer[3 + i] << ((i % 4) * 8); 351 + 352 + if ((i % 4 == 3) || i == buffer[2]) 353 + dw_hdmi_qp_write(hdmi, val, 354 + PKT_DRMI_CONTENTS1 + ((i / 4) * 4)); 355 + } 356 + 357 + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); 358 + dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, 359 + PKTSCHED_PKT_EN); 360 + 361 + return 0; 362 + } 363 + 364 + static int dw_hdmi_qp_bridge_atomic_check(struct drm_bridge *bridge, 365 + struct drm_bridge_state *bridge_state, 366 + struct drm_crtc_state *crtc_state, 367 + struct drm_connector_state *conn_state) 368 + { 369 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 370 + int ret; 371 + 372 + ret = drm_atomic_helper_connector_hdmi_check(conn_state->connector, 373 + conn_state->state); 374 + if (ret) 375 + dev_dbg(hdmi->dev, "%s failed: %d\n", __func__, ret); 376 + 377 + return ret; 378 + } 379 + 380 + static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, 381 + struct drm_bridge_state *old_state) 382 + { 383 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 384 + struct drm_atomic_state *state = old_state->base.state; 385 + struct drm_connector_state *conn_state; 386 + struct drm_connector *connector; 387 + unsigned int op_mode; 388 + 389 + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); 390 + if (WARN_ON(!connector)) 391 + return; 392 + 393 + conn_state = drm_atomic_get_new_connector_state(state, connector); 394 + if (WARN_ON(!conn_state)) 395 + return; 396 + 397 + if (connector->display_info.is_hdmi) { 398 + dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", 399 + __func__, conn_state->hdmi.tmds_char_rate); 400 + op_mode = 0; 401 + } else { 402 + dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); 403 + op_mode = OPMODE_DVI; 404 + } 405 + 406 + hdmi->phy.ops->init(hdmi, hdmi->phy.data); 407 + 408 + dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); 409 + dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0); 410 + 411 + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); 412 + } 413 + 414 + static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, 415 + struct drm_bridge_state *old_state) 416 + { 417 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 418 + 419 + hdmi->phy.ops->disable(hdmi, hdmi->phy.data); 420 + } 421 + 422 + static enum drm_connector_status 423 + dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge) 424 + { 425 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 426 + 427 + return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); 428 + } 429 + 430 + static const struct drm_edid * 431 + dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge, 432 + struct drm_connector *connector) 433 + { 434 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 435 + const struct drm_edid *drm_edid; 436 + 437 + drm_edid = drm_edid_read_ddc(connector, bridge->ddc); 438 + if (!drm_edid) 439 + dev_dbg(hdmi->dev, "failed to get edid\n"); 440 + 441 + return drm_edid; 442 + } 443 + 444 + static enum drm_mode_status 445 + dw_hdmi_qp_bridge_mode_valid(struct drm_bridge *bridge, 446 + const struct drm_display_info *info, 447 + const struct drm_display_mode *mode) 448 + { 449 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 450 + unsigned long long rate; 451 + 452 + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); 453 + if (rate > HDMI14_MAX_TMDSCLK) { 454 + dev_dbg(hdmi->dev, "Unsupported mode clock: %d\n", mode->clock); 455 + return MODE_CLOCK_HIGH; 456 + } 457 + 458 + return MODE_OK; 459 + } 460 + 461 + static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge, 462 + enum hdmi_infoframe_type type) 463 + { 464 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 465 + 466 + switch (type) { 467 + case HDMI_INFOFRAME_TYPE_AVI: 468 + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, 469 + PKTSCHED_PKT_EN); 470 + break; 471 + 472 + case HDMI_INFOFRAME_TYPE_DRM: 473 + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); 474 + break; 475 + 476 + default: 477 + dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); 478 + } 479 + 480 + return 0; 481 + } 482 + 483 + static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge, 484 + enum hdmi_infoframe_type type, 485 + const u8 *buffer, size_t len) 486 + { 487 + struct dw_hdmi_qp *hdmi = bridge->driver_private; 488 + 489 + dw_hdmi_qp_bridge_clear_infoframe(bridge, type); 490 + 491 + switch (type) { 492 + case HDMI_INFOFRAME_TYPE_AVI: 493 + return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len); 494 + 495 + case HDMI_INFOFRAME_TYPE_DRM: 496 + return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); 497 + 498 + default: 499 + dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); 500 + return 0; 501 + } 502 + } 503 + 504 + static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { 505 + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 506 + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 507 + .atomic_reset = drm_atomic_helper_bridge_reset, 508 + .atomic_check = dw_hdmi_qp_bridge_atomic_check, 509 + .atomic_enable = dw_hdmi_qp_bridge_atomic_enable, 510 + .atomic_disable = dw_hdmi_qp_bridge_atomic_disable, 511 + .detect = dw_hdmi_qp_bridge_detect, 512 + .edid_read = dw_hdmi_qp_bridge_edid_read, 513 + .mode_valid = dw_hdmi_qp_bridge_mode_valid, 514 + .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe, 515 + .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe, 516 + }; 517 + 518 + static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) 519 + { 520 + struct dw_hdmi_qp *hdmi = dev_id; 521 + struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; 522 + u32 stat; 523 + 524 + stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS); 525 + 526 + i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | 527 + I2CM_NACK_RCVD_IRQ); 528 + 529 + if (i2c->stat) { 530 + dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); 531 + complete(&i2c->cmp); 532 + } 533 + 534 + if (stat) 535 + return IRQ_HANDLED; 536 + 537 + return IRQ_NONE; 538 + } 539 + 540 + static const struct regmap_config dw_hdmi_qp_regmap_config = { 541 + .reg_bits = 32, 542 + .val_bits = 32, 543 + .reg_stride = 4, 544 + .max_register = EARCRX_1_INT_FORCE, 545 + }; 546 + 547 + static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi) 548 + { 549 + dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N); 550 + dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N); 551 + dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0); 552 + 553 + /* Software reset */ 554 + dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); 555 + 556 + dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); 557 + 558 + dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); 559 + 560 + /* Clear DONE and ERROR interrupts */ 561 + dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, 562 + MAINUNIT_1_INT_CLEAR); 563 + 564 + if (hdmi->phy.ops->setup_hpd) 565 + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); 566 + } 567 + 568 + struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, 569 + struct drm_encoder *encoder, 570 + const struct dw_hdmi_qp_plat_data *plat_data) 571 + { 572 + struct device *dev = &pdev->dev; 573 + struct dw_hdmi_qp *hdmi; 574 + void __iomem *regs; 575 + int ret; 576 + 577 + if (!plat_data->phy_ops || !plat_data->phy_ops->init || 578 + !plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) { 579 + dev_err(dev, "Missing platform PHY ops\n"); 580 + return ERR_PTR(-ENODEV); 581 + } 582 + 583 + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); 584 + if (!hdmi) 585 + return ERR_PTR(-ENOMEM); 586 + 587 + hdmi->dev = dev; 588 + 589 + regs = devm_platform_ioremap_resource(pdev, 0); 590 + if (IS_ERR(regs)) 591 + return ERR_CAST(regs); 592 + 593 + hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config); 594 + if (IS_ERR(hdmi->regm)) { 595 + dev_err(dev, "Failed to configure regmap\n"); 596 + return ERR_CAST(hdmi->regm); 597 + } 598 + 599 + hdmi->phy.ops = plat_data->phy_ops; 600 + hdmi->phy.data = plat_data->phy_data; 601 + 602 + dw_hdmi_qp_init_hw(hdmi); 603 + 604 + ret = devm_request_threaded_irq(dev, plat_data->main_irq, 605 + dw_hdmi_qp_main_hardirq, NULL, 606 + IRQF_SHARED, dev_name(dev), hdmi); 607 + if (ret) 608 + return ERR_PTR(ret); 609 + 610 + hdmi->bridge.driver_private = hdmi; 611 + hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs; 612 + hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | 613 + DRM_BRIDGE_OP_EDID | 614 + DRM_BRIDGE_OP_HDMI | 615 + DRM_BRIDGE_OP_HPD; 616 + hdmi->bridge.of_node = pdev->dev.of_node; 617 + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 618 + hdmi->bridge.vendor = "Synopsys"; 619 + hdmi->bridge.product = "DW HDMI QP TX"; 620 + 621 + hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi); 622 + if (IS_ERR(hdmi->bridge.ddc)) 623 + return ERR_CAST(hdmi->bridge.ddc); 624 + 625 + ret = devm_drm_bridge_add(dev, &hdmi->bridge); 626 + if (ret) 627 + return ERR_PTR(ret); 628 + 629 + ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 630 + DRM_BRIDGE_ATTACH_NO_CONNECTOR); 631 + if (ret) 632 + return ERR_PTR(ret); 633 + 634 + return hdmi; 635 + } 636 + EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); 637 + 638 + void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) 639 + { 640 + dw_hdmi_qp_init_hw(hdmi); 641 + } 642 + EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); 643 + 644 + MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>"); 645 + MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@collabora.com>"); 646 + MODULE_DESCRIPTION("DW HDMI QP transmitter library"); 647 + MODULE_LICENSE("GPL");
+834
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) Rockchip Electronics Co.Ltd 4 + * Author: 5 + * Algea Cao <algea.cao@rock-chips.com> 6 + */ 7 + #ifndef __DW_HDMI_QP_H__ 8 + #define __DW_HDMI_QP_H__ 9 + 10 + #include <linux/bits.h> 11 + 12 + /* Main Unit Registers */ 13 + #define CORE_ID 0x0 14 + #define VER_NUMBER 0x4 15 + #define VER_TYPE 0x8 16 + #define CONFIG_REG 0xc 17 + #define CONFIG_CEC BIT(28) 18 + #define CONFIG_AUD_UD BIT(23) 19 + #define CORE_TIMESTAMP_HHMM 0x14 20 + #define CORE_TIMESTAMP_MMDD 0x18 21 + #define CORE_TIMESTAMP_YYYY 0x1c 22 + /* Reset Manager Registers */ 23 + #define GLOBAL_SWRESET_REQUEST 0x40 24 + #define EARCRX_CMDC_SWINIT_P BIT(27) 25 + #define AVP_DATAPATH_PACKET_AUDIO_SWINIT_P BIT(10) 26 + #define GLOBAL_SWDISABLE 0x44 27 + #define CEC_SWDISABLE BIT(17) 28 + #define AVP_DATAPATH_PACKET_AUDIO_SWDISABLE BIT(10) 29 + #define AVP_DATAPATH_VIDEO_SWDISABLE BIT(6) 30 + #define RESET_MANAGER_CONFIG0 0x48 31 + #define RESET_MANAGER_STATUS0 0x50 32 + #define RESET_MANAGER_STATUS1 0x54 33 + #define RESET_MANAGER_STATUS2 0x58 34 + /* Timer Base Registers */ 35 + #define TIMER_BASE_CONFIG0 0x80 36 + #define TIMER_BASE_STATUS0 0x84 37 + /* CMU Registers */ 38 + #define CMU_CONFIG0 0xa0 39 + #define CMU_CONFIG1 0xa4 40 + #define CMU_CONFIG2 0xa8 41 + #define CMU_CONFIG3 0xac 42 + #define CMU_STATUS 0xb0 43 + #define DISPLAY_CLK_MONITOR 0x3f 44 + #define DISPLAY_CLK_LOCKED 0X15 45 + #define EARC_BPCLK_OFF BIT(9) 46 + #define AUDCLK_OFF BIT(7) 47 + #define LINKQPCLK_OFF BIT(5) 48 + #define VIDQPCLK_OFF BIT(3) 49 + #define IPI_CLK_OFF BIT(1) 50 + #define CMU_IPI_CLK_FREQ 0xb4 51 + #define CMU_VIDQPCLK_FREQ 0xb8 52 + #define CMU_LINKQPCLK_FREQ 0xbc 53 + #define CMU_AUDQPCLK_FREQ 0xc0 54 + #define CMU_EARC_BPCLK_FREQ 0xc4 55 + /* I2CM Registers */ 56 + #define I2CM_SM_SCL_CONFIG0 0xe0 57 + #define I2CM_FM_SCL_CONFIG0 0xe4 58 + #define I2CM_CONFIG0 0xe8 59 + #define I2CM_CONTROL0 0xec 60 + #define I2CM_STATUS0 0xf0 61 + #define I2CM_INTERFACE_CONTROL0 0xf4 62 + #define I2CM_ADDR 0xff000 63 + #define I2CM_SLVADDR 0xfe0 64 + #define I2CM_WR_MASK 0x1e 65 + #define I2CM_EXT_READ BIT(4) 66 + #define I2CM_SHORT_READ BIT(3) 67 + #define I2CM_FM_READ BIT(2) 68 + #define I2CM_FM_WRITE BIT(1) 69 + #define I2CM_FM_EN BIT(0) 70 + #define I2CM_INTERFACE_CONTROL1 0xf8 71 + #define I2CM_SEG_PTR 0x7f80 72 + #define I2CM_SEG_ADDR 0x7f 73 + #define I2CM_INTERFACE_WRDATA_0_3 0xfc 74 + #define I2CM_INTERFACE_WRDATA_4_7 0x100 75 + #define I2CM_INTERFACE_WRDATA_8_11 0x104 76 + #define I2CM_INTERFACE_WRDATA_12_15 0x108 77 + #define I2CM_INTERFACE_RDDATA_0_3 0x10c 78 + #define I2CM_INTERFACE_RDDATA_4_7 0x110 79 + #define I2CM_INTERFACE_RDDATA_8_11 0x114 80 + #define I2CM_INTERFACE_RDDATA_12_15 0x118 81 + /* SCDC Registers */ 82 + #define SCDC_CONFIG0 0x140 83 + #define SCDC_I2C_FM_EN BIT(12) 84 + #define SCDC_UPD_FLAGS_AUTO_CLR BIT(6) 85 + #define SCDC_UPD_FLAGS_POLL_EN BIT(4) 86 + #define SCDC_CONTROL0 0x148 87 + #define SCDC_STATUS0 0x150 88 + #define STATUS_UPDATE BIT(0) 89 + #define FRL_START BIT(4) 90 + #define FLT_UPDATE BIT(5) 91 + /* FLT Registers */ 92 + #define FLT_CONFIG0 0x160 93 + #define FLT_CONFIG1 0x164 94 + #define FLT_CONFIG2 0x168 95 + #define FLT_CONTROL0 0x170 96 + /* Main Unit 2 Registers */ 97 + #define MAINUNIT_STATUS0 0x180 98 + /* Video Interface Registers */ 99 + #define VIDEO_INTERFACE_CONFIG0 0x800 100 + #define VIDEO_INTERFACE_CONFIG1 0x804 101 + #define VIDEO_INTERFACE_CONFIG2 0x808 102 + #define VIDEO_INTERFACE_CONTROL0 0x80c 103 + #define VIDEO_INTERFACE_STATUS0 0x814 104 + /* Video Packing Registers */ 105 + #define VIDEO_PACKING_CONFIG0 0x81c 106 + /* Audio Interface Registers */ 107 + #define AUDIO_INTERFACE_CONFIG0 0x820 108 + #define AUD_IF_SEL_MSK 0x3 109 + #define AUD_IF_SPDIF 0x2 110 + #define AUD_IF_I2S 0x1 111 + #define AUD_IF_PAI 0x0 112 + #define AUD_FIFO_INIT_ON_OVF_MSK BIT(2) 113 + #define AUD_FIFO_INIT_ON_OVF_EN BIT(2) 114 + #define I2S_LINES_EN_MSK GENMASK(7, 4) 115 + #define I2S_LINES_EN(x) BIT((x) + 4) 116 + #define I2S_BPCUV_RCV_MSK BIT(12) 117 + #define I2S_BPCUV_RCV_EN BIT(12) 118 + #define I2S_BPCUV_RCV_DIS 0 119 + #define SPDIF_LINES_EN GENMASK(19, 16) 120 + #define AUD_FORMAT_MSK GENMASK(26, 24) 121 + #define AUD_3DOBA (0x7 << 24) 122 + #define AUD_3DASP (0x6 << 24) 123 + #define AUD_MSOBA (0x5 << 24) 124 + #define AUD_MSASP (0x4 << 24) 125 + #define AUD_HBR (0x3 << 24) 126 + #define AUD_DST (0x2 << 24) 127 + #define AUD_OBA (0x1 << 24) 128 + #define AUD_ASP (0x0 << 24) 129 + #define AUDIO_INTERFACE_CONFIG1 0x824 130 + #define AUDIO_INTERFACE_CONTROL0 0x82c 131 + #define AUDIO_FIFO_CLR_P BIT(0) 132 + #define AUDIO_INTERFACE_STATUS0 0x834 133 + /* Frame Composer Registers */ 134 + #define FRAME_COMPOSER_CONFIG0 0x840 135 + #define FRAME_COMPOSER_CONFIG1 0x844 136 + #define FRAME_COMPOSER_CONFIG2 0x848 137 + #define FRAME_COMPOSER_CONFIG3 0x84c 138 + #define FRAME_COMPOSER_CONFIG4 0x850 139 + #define FRAME_COMPOSER_CONFIG5 0x854 140 + #define FRAME_COMPOSER_CONFIG6 0x858 141 + #define FRAME_COMPOSER_CONFIG7 0x85c 142 + #define FRAME_COMPOSER_CONFIG8 0x860 143 + #define FRAME_COMPOSER_CONFIG9 0x864 144 + #define FRAME_COMPOSER_CONTROL0 0x86c 145 + /* Video Monitor Registers */ 146 + #define VIDEO_MONITOR_CONFIG0 0x880 147 + #define VIDEO_MONITOR_STATUS0 0x884 148 + #define VIDEO_MONITOR_STATUS1 0x888 149 + #define VIDEO_MONITOR_STATUS2 0x88c 150 + #define VIDEO_MONITOR_STATUS3 0x890 151 + #define VIDEO_MONITOR_STATUS4 0x894 152 + #define VIDEO_MONITOR_STATUS5 0x898 153 + #define VIDEO_MONITOR_STATUS6 0x89c 154 + /* HDCP2 Logic Registers */ 155 + #define HDCP2LOGIC_CONFIG0 0x8e0 156 + #define HDCP2_BYPASS BIT(0) 157 + #define HDCP2LOGIC_ESM_GPIO_IN 0x8e4 158 + #define HDCP2LOGIC_ESM_GPIO_OUT 0x8e8 159 + /* HDCP14 Registers */ 160 + #define HDCP14_CONFIG0 0x900 161 + #define HDCP14_CONFIG1 0x904 162 + #define HDCP14_CONFIG2 0x908 163 + #define HDCP14_CONFIG3 0x90c 164 + #define HDCP14_KEY_SEED 0x914 165 + #define HDCP14_KEY_H 0x918 166 + #define HDCP14_KEY_L 0x91c 167 + #define HDCP14_KEY_STATUS 0x920 168 + #define HDCP14_AKSV_H 0x924 169 + #define HDCP14_AKSV_L 0x928 170 + #define HDCP14_AN_H 0x92c 171 + #define HDCP14_AN_L 0x930 172 + #define HDCP14_STATUS0 0x934 173 + #define HDCP14_STATUS1 0x938 174 + /* Scrambler Registers */ 175 + #define SCRAMB_CONFIG0 0x960 176 + /* Video Configuration Registers */ 177 + #define LINK_CONFIG0 0x968 178 + #define OPMODE_FRL_4LANES BIT(8) 179 + #define OPMODE_DVI BIT(4) 180 + #define OPMODE_FRL BIT(0) 181 + /* TMDS FIFO Registers */ 182 + #define TMDS_FIFO_CONFIG0 0x970 183 + #define TMDS_FIFO_CONTROL0 0x974 184 + /* FRL RSFEC Registers */ 185 + #define FRL_RSFEC_CONFIG0 0xa20 186 + #define FRL_RSFEC_STATUS0 0xa30 187 + /* FRL Packetizer Registers */ 188 + #define FRL_PKTZ_CONFIG0 0xa40 189 + #define FRL_PKTZ_CONTROL0 0xa44 190 + #define FRL_PKTZ_CONTROL1 0xa50 191 + #define FRL_PKTZ_STATUS1 0xa54 192 + /* Packet Scheduler Registers */ 193 + #define PKTSCHED_CONFIG0 0xa80 194 + #define PKTSCHED_PRQUEUE0_CONFIG0 0xa84 195 + #define PKTSCHED_PRQUEUE1_CONFIG0 0xa88 196 + #define PKTSCHED_PRQUEUE2_CONFIG0 0xa8c 197 + #define PKTSCHED_PRQUEUE2_CONFIG1 0xa90 198 + #define PKTSCHED_PRQUEUE2_CONFIG2 0xa94 199 + #define PKTSCHED_PKT_CONFIG0 0xa98 200 + #define PKTSCHED_PKT_CONFIG1 0xa9c 201 + #define PKTSCHED_DRMI_FIELDRATE BIT(13) 202 + #define PKTSCHED_AVI_FIELDRATE BIT(12) 203 + #define PKTSCHED_PKT_CONFIG2 0xaa0 204 + #define PKTSCHED_PKT_CONFIG3 0xaa4 205 + #define PKTSCHED_PKT_EN 0xaa8 206 + #define PKTSCHED_DRMI_TX_EN BIT(17) 207 + #define PKTSCHED_AUDI_TX_EN BIT(15) 208 + #define PKTSCHED_AVI_TX_EN BIT(13) 209 + #define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) 210 + #define PKTSCHED_AMD_TX_EN BIT(8) 211 + #define PKTSCHED_GCP_TX_EN BIT(3) 212 + #define PKTSCHED_AUDS_TX_EN BIT(2) 213 + #define PKTSCHED_ACR_TX_EN BIT(1) 214 + #define PKTSCHED_NULL_TX_EN BIT(0) 215 + #define PKTSCHED_PKT_CONTROL0 0xaac 216 + #define PKTSCHED_PKT_SEND 0xab0 217 + #define PKTSCHED_PKT_STATUS0 0xab4 218 + #define PKTSCHED_PKT_STATUS1 0xab8 219 + #define PKT_NULL_CONTENTS0 0xb00 220 + #define PKT_NULL_CONTENTS1 0xb04 221 + #define PKT_NULL_CONTENTS2 0xb08 222 + #define PKT_NULL_CONTENTS3 0xb0c 223 + #define PKT_NULL_CONTENTS4 0xb10 224 + #define PKT_NULL_CONTENTS5 0xb14 225 + #define PKT_NULL_CONTENTS6 0xb18 226 + #define PKT_NULL_CONTENTS7 0xb1c 227 + #define PKT_ACP_CONTENTS0 0xb20 228 + #define PKT_ACP_CONTENTS1 0xb24 229 + #define PKT_ACP_CONTENTS2 0xb28 230 + #define PKT_ACP_CONTENTS3 0xb2c 231 + #define PKT_ACP_CONTENTS4 0xb30 232 + #define PKT_ACP_CONTENTS5 0xb34 233 + #define PKT_ACP_CONTENTS6 0xb38 234 + #define PKT_ACP_CONTENTS7 0xb3c 235 + #define PKT_ISRC1_CONTENTS0 0xb40 236 + #define PKT_ISRC1_CONTENTS1 0xb44 237 + #define PKT_ISRC1_CONTENTS2 0xb48 238 + #define PKT_ISRC1_CONTENTS3 0xb4c 239 + #define PKT_ISRC1_CONTENTS4 0xb50 240 + #define PKT_ISRC1_CONTENTS5 0xb54 241 + #define PKT_ISRC1_CONTENTS6 0xb58 242 + #define PKT_ISRC1_CONTENTS7 0xb5c 243 + #define PKT_ISRC2_CONTENTS0 0xb60 244 + #define PKT_ISRC2_CONTENTS1 0xb64 245 + #define PKT_ISRC2_CONTENTS2 0xb68 246 + #define PKT_ISRC2_CONTENTS3 0xb6c 247 + #define PKT_ISRC2_CONTENTS4 0xb70 248 + #define PKT_ISRC2_CONTENTS5 0xb74 249 + #define PKT_ISRC2_CONTENTS6 0xb78 250 + #define PKT_ISRC2_CONTENTS7 0xb7c 251 + #define PKT_GMD_CONTENTS0 0xb80 252 + #define PKT_GMD_CONTENTS1 0xb84 253 + #define PKT_GMD_CONTENTS2 0xb88 254 + #define PKT_GMD_CONTENTS3 0xb8c 255 + #define PKT_GMD_CONTENTS4 0xb90 256 + #define PKT_GMD_CONTENTS5 0xb94 257 + #define PKT_GMD_CONTENTS6 0xb98 258 + #define PKT_GMD_CONTENTS7 0xb9c 259 + #define PKT_AMD_CONTENTS0 0xba0 260 + #define PKT_AMD_CONTENTS1 0xba4 261 + #define PKT_AMD_CONTENTS2 0xba8 262 + #define PKT_AMD_CONTENTS3 0xbac 263 + #define PKT_AMD_CONTENTS4 0xbb0 264 + #define PKT_AMD_CONTENTS5 0xbb4 265 + #define PKT_AMD_CONTENTS6 0xbb8 266 + #define PKT_AMD_CONTENTS7 0xbbc 267 + #define PKT_VSI_CONTENTS0 0xbc0 268 + #define PKT_VSI_CONTENTS1 0xbc4 269 + #define PKT_VSI_CONTENTS2 0xbc8 270 + #define PKT_VSI_CONTENTS3 0xbcc 271 + #define PKT_VSI_CONTENTS4 0xbd0 272 + #define PKT_VSI_CONTENTS5 0xbd4 273 + #define PKT_VSI_CONTENTS6 0xbd8 274 + #define PKT_VSI_CONTENTS7 0xbdc 275 + #define PKT_AVI_CONTENTS0 0xbe0 276 + #define HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT BIT(4) 277 + #define HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR 0x04 278 + #define HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR 0x08 279 + #define HDMI_FC_AVICONF2_IT_CONTENT_VALID 0x80 280 + #define PKT_AVI_CONTENTS1 0xbe4 281 + #define PKT_AVI_CONTENTS2 0xbe8 282 + #define PKT_AVI_CONTENTS3 0xbec 283 + #define PKT_AVI_CONTENTS4 0xbf0 284 + #define PKT_AVI_CONTENTS5 0xbf4 285 + #define PKT_AVI_CONTENTS6 0xbf8 286 + #define PKT_AVI_CONTENTS7 0xbfc 287 + #define PKT_SPDI_CONTENTS0 0xc00 288 + #define PKT_SPDI_CONTENTS1 0xc04 289 + #define PKT_SPDI_CONTENTS2 0xc08 290 + #define PKT_SPDI_CONTENTS3 0xc0c 291 + #define PKT_SPDI_CONTENTS4 0xc10 292 + #define PKT_SPDI_CONTENTS5 0xc14 293 + #define PKT_SPDI_CONTENTS6 0xc18 294 + #define PKT_SPDI_CONTENTS7 0xc1c 295 + #define PKT_AUDI_CONTENTS0 0xc20 296 + #define PKT_AUDI_CONTENTS1 0xc24 297 + #define PKT_AUDI_CONTENTS2 0xc28 298 + #define PKT_AUDI_CONTENTS3 0xc2c 299 + #define PKT_AUDI_CONTENTS4 0xc30 300 + #define PKT_AUDI_CONTENTS5 0xc34 301 + #define PKT_AUDI_CONTENTS6 0xc38 302 + #define PKT_AUDI_CONTENTS7 0xc3c 303 + #define PKT_NVI_CONTENTS0 0xc40 304 + #define PKT_NVI_CONTENTS1 0xc44 305 + #define PKT_NVI_CONTENTS2 0xc48 306 + #define PKT_NVI_CONTENTS3 0xc4c 307 + #define PKT_NVI_CONTENTS4 0xc50 308 + #define PKT_NVI_CONTENTS5 0xc54 309 + #define PKT_NVI_CONTENTS6 0xc58 310 + #define PKT_NVI_CONTENTS7 0xc5c 311 + #define PKT_DRMI_CONTENTS0 0xc60 312 + #define PKT_DRMI_CONTENTS1 0xc64 313 + #define PKT_DRMI_CONTENTS2 0xc68 314 + #define PKT_DRMI_CONTENTS3 0xc6c 315 + #define PKT_DRMI_CONTENTS4 0xc70 316 + #define PKT_DRMI_CONTENTS5 0xc74 317 + #define PKT_DRMI_CONTENTS6 0xc78 318 + #define PKT_DRMI_CONTENTS7 0xc7c 319 + #define PKT_GHDMI1_CONTENTS0 0xc80 320 + #define PKT_GHDMI1_CONTENTS1 0xc84 321 + #define PKT_GHDMI1_CONTENTS2 0xc88 322 + #define PKT_GHDMI1_CONTENTS3 0xc8c 323 + #define PKT_GHDMI1_CONTENTS4 0xc90 324 + #define PKT_GHDMI1_CONTENTS5 0xc94 325 + #define PKT_GHDMI1_CONTENTS6 0xc98 326 + #define PKT_GHDMI1_CONTENTS7 0xc9c 327 + #define PKT_GHDMI2_CONTENTS0 0xca0 328 + #define PKT_GHDMI2_CONTENTS1 0xca4 329 + #define PKT_GHDMI2_CONTENTS2 0xca8 330 + #define PKT_GHDMI2_CONTENTS3 0xcac 331 + #define PKT_GHDMI2_CONTENTS4 0xcb0 332 + #define PKT_GHDMI2_CONTENTS5 0xcb4 333 + #define PKT_GHDMI2_CONTENTS6 0xcb8 334 + #define PKT_GHDMI2_CONTENTS7 0xcbc 335 + /* EMP Packetizer Registers */ 336 + #define PKT_EMP_CONFIG0 0xce0 337 + #define PKT_EMP_CONTROL0 0xcec 338 + #define PKT_EMP_CONTROL1 0xcf0 339 + #define PKT_EMP_CONTROL2 0xcf4 340 + #define PKT_EMP_VTEM_CONTENTS0 0xd00 341 + #define PKT_EMP_VTEM_CONTENTS1 0xd04 342 + #define PKT_EMP_VTEM_CONTENTS2 0xd08 343 + #define PKT_EMP_VTEM_CONTENTS3 0xd0c 344 + #define PKT_EMP_VTEM_CONTENTS4 0xd10 345 + #define PKT_EMP_VTEM_CONTENTS5 0xd14 346 + #define PKT_EMP_VTEM_CONTENTS6 0xd18 347 + #define PKT_EMP_VTEM_CONTENTS7 0xd1c 348 + #define PKT0_EMP_CVTEM_CONTENTS0 0xd20 349 + #define PKT0_EMP_CVTEM_CONTENTS1 0xd24 350 + #define PKT0_EMP_CVTEM_CONTENTS2 0xd28 351 + #define PKT0_EMP_CVTEM_CONTENTS3 0xd2c 352 + #define PKT0_EMP_CVTEM_CONTENTS4 0xd30 353 + #define PKT0_EMP_CVTEM_CONTENTS5 0xd34 354 + #define PKT0_EMP_CVTEM_CONTENTS6 0xd38 355 + #define PKT0_EMP_CVTEM_CONTENTS7 0xd3c 356 + #define PKT1_EMP_CVTEM_CONTENTS0 0xd40 357 + #define PKT1_EMP_CVTEM_CONTENTS1 0xd44 358 + #define PKT1_EMP_CVTEM_CONTENTS2 0xd48 359 + #define PKT1_EMP_CVTEM_CONTENTS3 0xd4c 360 + #define PKT1_EMP_CVTEM_CONTENTS4 0xd50 361 + #define PKT1_EMP_CVTEM_CONTENTS5 0xd54 362 + #define PKT1_EMP_CVTEM_CONTENTS6 0xd58 363 + #define PKT1_EMP_CVTEM_CONTENTS7 0xd5c 364 + #define PKT2_EMP_CVTEM_CONTENTS0 0xd60 365 + #define PKT2_EMP_CVTEM_CONTENTS1 0xd64 366 + #define PKT2_EMP_CVTEM_CONTENTS2 0xd68 367 + #define PKT2_EMP_CVTEM_CONTENTS3 0xd6c 368 + #define PKT2_EMP_CVTEM_CONTENTS4 0xd70 369 + #define PKT2_EMP_CVTEM_CONTENTS5 0xd74 370 + #define PKT2_EMP_CVTEM_CONTENTS6 0xd78 371 + #define PKT2_EMP_CVTEM_CONTENTS7 0xd7c 372 + #define PKT3_EMP_CVTEM_CONTENTS0 0xd80 373 + #define PKT3_EMP_CVTEM_CONTENTS1 0xd84 374 + #define PKT3_EMP_CVTEM_CONTENTS2 0xd88 375 + #define PKT3_EMP_CVTEM_CONTENTS3 0xd8c 376 + #define PKT3_EMP_CVTEM_CONTENTS4 0xd90 377 + #define PKT3_EMP_CVTEM_CONTENTS5 0xd94 378 + #define PKT3_EMP_CVTEM_CONTENTS6 0xd98 379 + #define PKT3_EMP_CVTEM_CONTENTS7 0xd9c 380 + #define PKT4_EMP_CVTEM_CONTENTS0 0xda0 381 + #define PKT4_EMP_CVTEM_CONTENTS1 0xda4 382 + #define PKT4_EMP_CVTEM_CONTENTS2 0xda8 383 + #define PKT4_EMP_CVTEM_CONTENTS3 0xdac 384 + #define PKT4_EMP_CVTEM_CONTENTS4 0xdb0 385 + #define PKT4_EMP_CVTEM_CONTENTS5 0xdb4 386 + #define PKT4_EMP_CVTEM_CONTENTS6 0xdb8 387 + #define PKT4_EMP_CVTEM_CONTENTS7 0xdbc 388 + #define PKT5_EMP_CVTEM_CONTENTS0 0xdc0 389 + #define PKT5_EMP_CVTEM_CONTENTS1 0xdc4 390 + #define PKT5_EMP_CVTEM_CONTENTS2 0xdc8 391 + #define PKT5_EMP_CVTEM_CONTENTS3 0xdcc 392 + #define PKT5_EMP_CVTEM_CONTENTS4 0xdd0 393 + #define PKT5_EMP_CVTEM_CONTENTS5 0xdd4 394 + #define PKT5_EMP_CVTEM_CONTENTS6 0xdd8 395 + #define PKT5_EMP_CVTEM_CONTENTS7 0xddc 396 + /* Audio Packetizer Registers */ 397 + #define AUDPKT_CONTROL0 0xe20 398 + #define AUDPKT_PBIT_FORCE_EN_MASK BIT(12) 399 + #define AUDPKT_PBIT_FORCE_EN BIT(12) 400 + #define AUDPKT_CHSTATUS_OVR_EN_MASK BIT(0) 401 + #define AUDPKT_CHSTATUS_OVR_EN BIT(0) 402 + #define AUDPKT_CONTROL1 0xe24 403 + #define AUDPKT_ACR_CONTROL0 0xe40 404 + #define AUDPKT_ACR_N_VALUE 0xfffff 405 + #define AUDPKT_ACR_CONTROL1 0xe44 406 + #define AUDPKT_ACR_CTS_OVR_VAL_MSK GENMASK(23, 4) 407 + #define AUDPKT_ACR_CTS_OVR_VAL(x) ((x) << 4) 408 + #define AUDPKT_ACR_CTS_OVR_EN_MSK BIT(1) 409 + #define AUDPKT_ACR_CTS_OVR_EN BIT(1) 410 + #define AUDPKT_ACR_STATUS0 0xe4c 411 + #define AUDPKT_CHSTATUS_OVR0 0xe60 412 + #define AUDPKT_CHSTATUS_OVR1 0xe64 413 + /* IEC60958 Byte 3: Sampleing frenuency Bits 24 to 27 */ 414 + #define AUDPKT_CHSTATUS_SR_MASK GENMASK(3, 0) 415 + #define AUDPKT_CHSTATUS_SR_22050 0x4 416 + #define AUDPKT_CHSTATUS_SR_24000 0x6 417 + #define AUDPKT_CHSTATUS_SR_32000 0x3 418 + #define AUDPKT_CHSTATUS_SR_44100 0x0 419 + #define AUDPKT_CHSTATUS_SR_48000 0x2 420 + #define AUDPKT_CHSTATUS_SR_88200 0x8 421 + #define AUDPKT_CHSTATUS_SR_96000 0xa 422 + #define AUDPKT_CHSTATUS_SR_176400 0xc 423 + #define AUDPKT_CHSTATUS_SR_192000 0xe 424 + #define AUDPKT_CHSTATUS_SR_768000 0x9 425 + #define AUDPKT_CHSTATUS_SR_NOT_INDICATED 0x1 426 + /* IEC60958 Byte 4: Original Sampleing frenuency Bits 36 to 39 */ 427 + #define AUDPKT_CHSTATUS_0SR_MASK GENMASK(15, 12) 428 + #define AUDPKT_CHSTATUS_OSR_8000 0x6 429 + #define AUDPKT_CHSTATUS_OSR_11025 0xa 430 + #define AUDPKT_CHSTATUS_OSR_12000 0x2 431 + #define AUDPKT_CHSTATUS_OSR_16000 0x8 432 + #define AUDPKT_CHSTATUS_OSR_22050 0xb 433 + #define AUDPKT_CHSTATUS_OSR_24000 0x9 434 + #define AUDPKT_CHSTATUS_OSR_32000 0xc 435 + #define AUDPKT_CHSTATUS_OSR_44100 0xf 436 + #define AUDPKT_CHSTATUS_OSR_48000 0xd 437 + #define AUDPKT_CHSTATUS_OSR_88200 0x7 438 + #define AUDPKT_CHSTATUS_OSR_96000 0x5 439 + #define AUDPKT_CHSTATUS_OSR_176400 0x3 440 + #define AUDPKT_CHSTATUS_OSR_192000 0x1 441 + #define AUDPKT_CHSTATUS_OSR_NOT_INDICATED 0x0 442 + #define AUDPKT_CHSTATUS_OVR2 0xe68 443 + #define AUDPKT_CHSTATUS_OVR3 0xe6c 444 + #define AUDPKT_CHSTATUS_OVR4 0xe70 445 + #define AUDPKT_CHSTATUS_OVR5 0xe74 446 + #define AUDPKT_CHSTATUS_OVR6 0xe78 447 + #define AUDPKT_CHSTATUS_OVR7 0xe7c 448 + #define AUDPKT_CHSTATUS_OVR8 0xe80 449 + #define AUDPKT_CHSTATUS_OVR9 0xe84 450 + #define AUDPKT_CHSTATUS_OVR10 0xe88 451 + #define AUDPKT_CHSTATUS_OVR11 0xe8c 452 + #define AUDPKT_CHSTATUS_OVR12 0xe90 453 + #define AUDPKT_CHSTATUS_OVR13 0xe94 454 + #define AUDPKT_CHSTATUS_OVR14 0xe98 455 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC0 0xea0 456 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC1 0xea4 457 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC2 0xea8 458 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC3 0xeac 459 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC4 0xeb0 460 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC5 0xeb4 461 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC6 0xeb8 462 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC7 0xebc 463 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC8 0xec0 464 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC9 0xec4 465 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC10 0xec8 466 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC11 0xecc 467 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC12 0xed0 468 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC13 0xed4 469 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC14 0xed8 470 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC15 0xedc 471 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC16 0xee0 472 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC17 0xee4 473 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC18 0xee8 474 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC19 0xeec 475 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC20 0xef0 476 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC21 0xef4 477 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC22 0xef8 478 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC23 0xefc 479 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC24 0xf00 480 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC25 0xf04 481 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC26 0xf08 482 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC27 0xf0c 483 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC28 0xf10 484 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC29 0xf14 485 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC30 0xf18 486 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC31 0xf1c 487 + #define AUDPKT_USRDATA_OVR_MSG_GENERIC32 0xf20 488 + #define AUDPKT_VBIT_OVR0 0xf24 489 + /* CEC Registers */ 490 + #define CEC_TX_CONTROL 0x1000 491 + #define CEC_STATUS 0x1004 492 + #define CEC_CONFIG 0x1008 493 + #define CEC_ADDR 0x100c 494 + #define CEC_TX_COUNT 0x1020 495 + #define CEC_TX_DATA3_0 0x1024 496 + #define CEC_TX_DATA7_4 0x1028 497 + #define CEC_TX_DATA11_8 0x102c 498 + #define CEC_TX_DATA15_12 0x1030 499 + #define CEC_RX_COUNT_STATUS 0x1040 500 + #define CEC_RX_DATA3_0 0x1044 501 + #define CEC_RX_DATA7_4 0x1048 502 + #define CEC_RX_DATA11_8 0x104c 503 + #define CEC_RX_DATA15_12 0x1050 504 + #define CEC_LOCK_CONTROL 0x1054 505 + #define CEC_RXQUAL_BITTIME_CONFIG 0x1060 506 + #define CEC_RX_BITTIME_CONFIG 0x1064 507 + #define CEC_TX_BITTIME_CONFIG 0x1068 508 + /* eARC RX CMDC Registers */ 509 + #define EARCRX_CMDC_CONFIG0 0x1800 510 + #define EARCRX_XACTREAD_STOP_CFG BIT(26) 511 + #define EARCRX_XACTREAD_RETRY_CFG BIT(25) 512 + #define EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 BIT(24) 513 + #define EARCRX_CMDC_XACT_RESTART_EN BIT(18) 514 + #define EARCRX_CMDC_CONFIG1 0x1804 515 + #define EARCRX_CMDC_CONTROL 0x1808 516 + #define EARCRX_CMDC_HEARTBEAT_LOSS_EN BIT(4) 517 + #define EARCRX_CMDC_DISCOVERY_EN BIT(3) 518 + #define EARCRX_CONNECTOR_HPD BIT(1) 519 + #define EARCRX_CMDC_WHITELIST0_CONFIG 0x180c 520 + #define EARCRX_CMDC_WHITELIST1_CONFIG 0x1810 521 + #define EARCRX_CMDC_WHITELIST2_CONFIG 0x1814 522 + #define EARCRX_CMDC_WHITELIST3_CONFIG 0x1818 523 + #define EARCRX_CMDC_STATUS 0x181c 524 + #define EARCRX_CMDC_XACT_INFO 0x1820 525 + #define EARCRX_CMDC_XACT_ACTION 0x1824 526 + #define EARCRX_CMDC_HEARTBEAT_RXSTAT_SE 0x1828 527 + #define EARCRX_CMDC_HEARTBEAT_STATUS 0x182c 528 + #define EARCRX_CMDC_XACT_WR0 0x1840 529 + #define EARCRX_CMDC_XACT_WR1 0x1844 530 + #define EARCRX_CMDC_XACT_WR2 0x1848 531 + #define EARCRX_CMDC_XACT_WR3 0x184c 532 + #define EARCRX_CMDC_XACT_WR4 0x1850 533 + #define EARCRX_CMDC_XACT_WR5 0x1854 534 + #define EARCRX_CMDC_XACT_WR6 0x1858 535 + #define EARCRX_CMDC_XACT_WR7 0x185c 536 + #define EARCRX_CMDC_XACT_WR8 0x1860 537 + #define EARCRX_CMDC_XACT_WR9 0x1864 538 + #define EARCRX_CMDC_XACT_WR10 0x1868 539 + #define EARCRX_CMDC_XACT_WR11 0x186c 540 + #define EARCRX_CMDC_XACT_WR12 0x1870 541 + #define EARCRX_CMDC_XACT_WR13 0x1874 542 + #define EARCRX_CMDC_XACT_WR14 0x1878 543 + #define EARCRX_CMDC_XACT_WR15 0x187c 544 + #define EARCRX_CMDC_XACT_WR16 0x1880 545 + #define EARCRX_CMDC_XACT_WR17 0x1884 546 + #define EARCRX_CMDC_XACT_WR18 0x1888 547 + #define EARCRX_CMDC_XACT_WR19 0x188c 548 + #define EARCRX_CMDC_XACT_WR20 0x1890 549 + #define EARCRX_CMDC_XACT_WR21 0x1894 550 + #define EARCRX_CMDC_XACT_WR22 0x1898 551 + #define EARCRX_CMDC_XACT_WR23 0x189c 552 + #define EARCRX_CMDC_XACT_WR24 0x18a0 553 + #define EARCRX_CMDC_XACT_WR25 0x18a4 554 + #define EARCRX_CMDC_XACT_WR26 0x18a8 555 + #define EARCRX_CMDC_XACT_WR27 0x18ac 556 + #define EARCRX_CMDC_XACT_WR28 0x18b0 557 + #define EARCRX_CMDC_XACT_WR29 0x18b4 558 + #define EARCRX_CMDC_XACT_WR30 0x18b8 559 + #define EARCRX_CMDC_XACT_WR31 0x18bc 560 + #define EARCRX_CMDC_XACT_WR32 0x18c0 561 + #define EARCRX_CMDC_XACT_WR33 0x18c4 562 + #define EARCRX_CMDC_XACT_WR34 0x18c8 563 + #define EARCRX_CMDC_XACT_WR35 0x18cc 564 + #define EARCRX_CMDC_XACT_WR36 0x18d0 565 + #define EARCRX_CMDC_XACT_WR37 0x18d4 566 + #define EARCRX_CMDC_XACT_WR38 0x18d8 567 + #define EARCRX_CMDC_XACT_WR39 0x18dc 568 + #define EARCRX_CMDC_XACT_WR40 0x18e0 569 + #define EARCRX_CMDC_XACT_WR41 0x18e4 570 + #define EARCRX_CMDC_XACT_WR42 0x18e8 571 + #define EARCRX_CMDC_XACT_WR43 0x18ec 572 + #define EARCRX_CMDC_XACT_WR44 0x18f0 573 + #define EARCRX_CMDC_XACT_WR45 0x18f4 574 + #define EARCRX_CMDC_XACT_WR46 0x18f8 575 + #define EARCRX_CMDC_XACT_WR47 0x18fc 576 + #define EARCRX_CMDC_XACT_WR48 0x1900 577 + #define EARCRX_CMDC_XACT_WR49 0x1904 578 + #define EARCRX_CMDC_XACT_WR50 0x1908 579 + #define EARCRX_CMDC_XACT_WR51 0x190c 580 + #define EARCRX_CMDC_XACT_WR52 0x1910 581 + #define EARCRX_CMDC_XACT_WR53 0x1914 582 + #define EARCRX_CMDC_XACT_WR54 0x1918 583 + #define EARCRX_CMDC_XACT_WR55 0x191c 584 + #define EARCRX_CMDC_XACT_WR56 0x1920 585 + #define EARCRX_CMDC_XACT_WR57 0x1924 586 + #define EARCRX_CMDC_XACT_WR58 0x1928 587 + #define EARCRX_CMDC_XACT_WR59 0x192c 588 + #define EARCRX_CMDC_XACT_WR60 0x1930 589 + #define EARCRX_CMDC_XACT_WR61 0x1934 590 + #define EARCRX_CMDC_XACT_WR62 0x1938 591 + #define EARCRX_CMDC_XACT_WR63 0x193c 592 + #define EARCRX_CMDC_XACT_WR64 0x1940 593 + #define EARCRX_CMDC_XACT_RD0 0x1960 594 + #define EARCRX_CMDC_XACT_RD1 0x1964 595 + #define EARCRX_CMDC_XACT_RD2 0x1968 596 + #define EARCRX_CMDC_XACT_RD3 0x196c 597 + #define EARCRX_CMDC_XACT_RD4 0x1970 598 + #define EARCRX_CMDC_XACT_RD5 0x1974 599 + #define EARCRX_CMDC_XACT_RD6 0x1978 600 + #define EARCRX_CMDC_XACT_RD7 0x197c 601 + #define EARCRX_CMDC_XACT_RD8 0x1980 602 + #define EARCRX_CMDC_XACT_RD9 0x1984 603 + #define EARCRX_CMDC_XACT_RD10 0x1988 604 + #define EARCRX_CMDC_XACT_RD11 0x198c 605 + #define EARCRX_CMDC_XACT_RD12 0x1990 606 + #define EARCRX_CMDC_XACT_RD13 0x1994 607 + #define EARCRX_CMDC_XACT_RD14 0x1998 608 + #define EARCRX_CMDC_XACT_RD15 0x199c 609 + #define EARCRX_CMDC_XACT_RD16 0x19a0 610 + #define EARCRX_CMDC_XACT_RD17 0x19a4 611 + #define EARCRX_CMDC_XACT_RD18 0x19a8 612 + #define EARCRX_CMDC_XACT_RD19 0x19ac 613 + #define EARCRX_CMDC_XACT_RD20 0x19b0 614 + #define EARCRX_CMDC_XACT_RD21 0x19b4 615 + #define EARCRX_CMDC_XACT_RD22 0x19b8 616 + #define EARCRX_CMDC_XACT_RD23 0x19bc 617 + #define EARCRX_CMDC_XACT_RD24 0x19c0 618 + #define EARCRX_CMDC_XACT_RD25 0x19c4 619 + #define EARCRX_CMDC_XACT_RD26 0x19c8 620 + #define EARCRX_CMDC_XACT_RD27 0x19cc 621 + #define EARCRX_CMDC_XACT_RD28 0x19d0 622 + #define EARCRX_CMDC_XACT_RD29 0x19d4 623 + #define EARCRX_CMDC_XACT_RD30 0x19d8 624 + #define EARCRX_CMDC_XACT_RD31 0x19dc 625 + #define EARCRX_CMDC_XACT_RD32 0x19e0 626 + #define EARCRX_CMDC_XACT_RD33 0x19e4 627 + #define EARCRX_CMDC_XACT_RD34 0x19e8 628 + #define EARCRX_CMDC_XACT_RD35 0x19ec 629 + #define EARCRX_CMDC_XACT_RD36 0x19f0 630 + #define EARCRX_CMDC_XACT_RD37 0x19f4 631 + #define EARCRX_CMDC_XACT_RD38 0x19f8 632 + #define EARCRX_CMDC_XACT_RD39 0x19fc 633 + #define EARCRX_CMDC_XACT_RD40 0x1a00 634 + #define EARCRX_CMDC_XACT_RD41 0x1a04 635 + #define EARCRX_CMDC_XACT_RD42 0x1a08 636 + #define EARCRX_CMDC_XACT_RD43 0x1a0c 637 + #define EARCRX_CMDC_XACT_RD44 0x1a10 638 + #define EARCRX_CMDC_XACT_RD45 0x1a14 639 + #define EARCRX_CMDC_XACT_RD46 0x1a18 640 + #define EARCRX_CMDC_XACT_RD47 0x1a1c 641 + #define EARCRX_CMDC_XACT_RD48 0x1a20 642 + #define EARCRX_CMDC_XACT_RD49 0x1a24 643 + #define EARCRX_CMDC_XACT_RD50 0x1a28 644 + #define EARCRX_CMDC_XACT_RD51 0x1a2c 645 + #define EARCRX_CMDC_XACT_RD52 0x1a30 646 + #define EARCRX_CMDC_XACT_RD53 0x1a34 647 + #define EARCRX_CMDC_XACT_RD54 0x1a38 648 + #define EARCRX_CMDC_XACT_RD55 0x1a3c 649 + #define EARCRX_CMDC_XACT_RD56 0x1a40 650 + #define EARCRX_CMDC_XACT_RD57 0x1a44 651 + #define EARCRX_CMDC_XACT_RD58 0x1a48 652 + #define EARCRX_CMDC_XACT_RD59 0x1a4c 653 + #define EARCRX_CMDC_XACT_RD60 0x1a50 654 + #define EARCRX_CMDC_XACT_RD61 0x1a54 655 + #define EARCRX_CMDC_XACT_RD62 0x1a58 656 + #define EARCRX_CMDC_XACT_RD63 0x1a5c 657 + #define EARCRX_CMDC_XACT_RD64 0x1a60 658 + #define EARCRX_CMDC_SYNC_CONFIG 0x1b00 659 + /* eARC RX DMAC Registers */ 660 + #define EARCRX_DMAC_PHY_CONTROL 0x1c00 661 + #define EARCRX_DMAC_CONFIG 0x1c08 662 + #define EARCRX_DMAC_CONTROL0 0x1c0c 663 + #define EARCRX_DMAC_AUDIO_EN BIT(1) 664 + #define EARCRX_DMAC_EN BIT(0) 665 + #define EARCRX_DMAC_CONTROL1 0x1c10 666 + #define EARCRX_DMAC_STATUS 0x1c14 667 + #define EARCRX_DMAC_CHSTATUS0 0x1c18 668 + #define EARCRX_DMAC_CHSTATUS1 0x1c1c 669 + #define EARCRX_DMAC_CHSTATUS2 0x1c20 670 + #define EARCRX_DMAC_CHSTATUS3 0x1c24 671 + #define EARCRX_DMAC_CHSTATUS4 0x1c28 672 + #define EARCRX_DMAC_CHSTATUS5 0x1c2c 673 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC0 0x1c30 674 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC1 0x1c34 675 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC2 0x1c38 676 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC3 0x1c3c 677 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC4 0x1c40 678 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC5 0x1c44 679 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC6 0x1c48 680 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC7 0x1c4c 681 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC8 0x1c50 682 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC9 0x1c54 683 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC10 0x1c58 684 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_AC11 0x1c5c 685 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT0 0x1c60 686 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT1 0x1c64 687 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT2 0x1c68 688 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT3 0x1c6c 689 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT4 0x1c70 690 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT5 0x1c74 691 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT6 0x1c78 692 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT7 0x1c7c 693 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT8 0x1c80 694 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT9 0x1c84 695 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT10 0x1c88 696 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT11 0x1c8c 697 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT0 0x1c90 698 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT1 0x1c94 699 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT2 0x1c98 700 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT3 0x1c9c 701 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT4 0x1ca0 702 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT5 0x1ca4 703 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT6 0x1ca8 704 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT7 0x1cac 705 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT8 0x1cb0 706 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT9 0x1cb4 707 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT10 0x1cb8 708 + #define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT11 0x1cbc 709 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC0 0x1cc0 710 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC1 0x1cc4 711 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC2 0x1cc8 712 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC3 0x1ccc 713 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC4 0x1cd0 714 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC5 0x1cd4 715 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC6 0x1cd8 716 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC7 0x1cdc 717 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC8 0x1ce0 718 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC9 0x1ce4 719 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC10 0x1ce8 720 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC11 0x1cec 721 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC12 0x1cf0 722 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC13 0x1cf4 723 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC14 0x1cf8 724 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC15 0x1cfc 725 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC16 0x1d00 726 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC17 0x1d04 727 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC18 0x1d08 728 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC19 0x1d0c 729 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC20 0x1d10 730 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC21 0x1d14 731 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC22 0x1d18 732 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC23 0x1d1c 733 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC24 0x1d20 734 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC25 0x1d24 735 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC26 0x1d28 736 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC27 0x1d2c 737 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC28 0x1d30 738 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC29 0x1d34 739 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC30 0x1d38 740 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC31 0x1d3c 741 + #define EARCRX_DMAC_USRDATA_MSG_GENERIC32 0x1d40 742 + #define EARCRX_DMAC_CHSTATUS_STREAMER0 0x1d44 743 + #define EARCRX_DMAC_CHSTATUS_STREAMER1 0x1d48 744 + #define EARCRX_DMAC_CHSTATUS_STREAMER2 0x1d4c 745 + #define EARCRX_DMAC_CHSTATUS_STREAMER3 0x1d50 746 + #define EARCRX_DMAC_CHSTATUS_STREAMER4 0x1d54 747 + #define EARCRX_DMAC_CHSTATUS_STREAMER5 0x1d58 748 + #define EARCRX_DMAC_CHSTATUS_STREAMER6 0x1d5c 749 + #define EARCRX_DMAC_CHSTATUS_STREAMER7 0x1d60 750 + #define EARCRX_DMAC_CHSTATUS_STREAMER8 0x1d64 751 + #define EARCRX_DMAC_CHSTATUS_STREAMER9 0x1d68 752 + #define EARCRX_DMAC_CHSTATUS_STREAMER10 0x1d6c 753 + #define EARCRX_DMAC_CHSTATUS_STREAMER11 0x1d70 754 + #define EARCRX_DMAC_CHSTATUS_STREAMER12 0x1d74 755 + #define EARCRX_DMAC_CHSTATUS_STREAMER13 0x1d78 756 + #define EARCRX_DMAC_CHSTATUS_STREAMER14 0x1d7c 757 + #define EARCRX_DMAC_USRDATA_STREAMER0 0x1d80 758 + /* Main Unit Interrupt Registers */ 759 + #define MAIN_INTVEC_INDEX 0x3000 760 + #define MAINUNIT_0_INT_STATUS 0x3010 761 + #define MAINUNIT_0_INT_MASK_N 0x3014 762 + #define MAINUNIT_0_INT_CLEAR 0x3018 763 + #define MAINUNIT_0_INT_FORCE 0x301c 764 + #define MAINUNIT_1_INT_STATUS 0x3020 765 + #define FLT_EXIT_TO_LTSL_IRQ BIT(22) 766 + #define FLT_EXIT_TO_LTS4_IRQ BIT(21) 767 + #define FLT_EXIT_TO_LTSP_IRQ BIT(20) 768 + #define SCDC_NACK_RCVD_IRQ BIT(12) 769 + #define SCDC_RR_REPLY_STOP_IRQ BIT(11) 770 + #define SCDC_UPD_FLAGS_CLR_IRQ BIT(10) 771 + #define SCDC_UPD_FLAGS_CHG_IRQ BIT(9) 772 + #define SCDC_UPD_FLAGS_RD_IRQ BIT(8) 773 + #define I2CM_NACK_RCVD_IRQ BIT(2) 774 + #define I2CM_READ_REQUEST_IRQ BIT(1) 775 + #define I2CM_OP_DONE_IRQ BIT(0) 776 + #define MAINUNIT_1_INT_MASK_N 0x3024 777 + #define I2CM_NACK_RCVD_MASK_N BIT(2) 778 + #define I2CM_READ_REQUEST_MASK_N BIT(1) 779 + #define I2CM_OP_DONE_MASK_N BIT(0) 780 + #define MAINUNIT_1_INT_CLEAR 0x3028 781 + #define I2CM_NACK_RCVD_CLEAR BIT(2) 782 + #define I2CM_READ_REQUEST_CLEAR BIT(1) 783 + #define I2CM_OP_DONE_CLEAR BIT(0) 784 + #define MAINUNIT_1_INT_FORCE 0x302c 785 + /* AVPUNIT Interrupt Registers */ 786 + #define AVP_INTVEC_INDEX 0x3800 787 + #define AVP_0_INT_STATUS 0x3810 788 + #define AVP_0_INT_MASK_N 0x3814 789 + #define AVP_0_INT_CLEAR 0x3818 790 + #define AVP_0_INT_FORCE 0x381c 791 + #define AVP_1_INT_STATUS 0x3820 792 + #define AVP_1_INT_MASK_N 0x3824 793 + #define HDCP14_AUTH_CHG_MASK_N BIT(6) 794 + #define AVP_1_INT_CLEAR 0x3828 795 + #define AVP_1_INT_FORCE 0x382c 796 + #define AVP_2_INT_STATUS 0x3830 797 + #define AVP_2_INT_MASK_N 0x3834 798 + #define AVP_2_INT_CLEAR 0x3838 799 + #define AVP_2_INT_FORCE 0x383c 800 + #define AVP_3_INT_STATUS 0x3840 801 + #define AVP_3_INT_MASK_N 0x3844 802 + #define AVP_3_INT_CLEAR 0x3848 803 + #define AVP_3_INT_FORCE 0x384c 804 + #define AVP_4_INT_STATUS 0x3850 805 + #define AVP_4_INT_MASK_N 0x3854 806 + #define AVP_4_INT_CLEAR 0x3858 807 + #define AVP_4_INT_FORCE 0x385c 808 + #define AVP_5_INT_STATUS 0x3860 809 + #define AVP_5_INT_MASK_N 0x3864 810 + #define AVP_5_INT_CLEAR 0x3868 811 + #define AVP_5_INT_FORCE 0x386c 812 + #define AVP_6_INT_STATUS 0x3870 813 + #define AVP_6_INT_MASK_N 0x3874 814 + #define AVP_6_INT_CLEAR 0x3878 815 + #define AVP_6_INT_FORCE 0x387c 816 + /* CEC Interrupt Registers */ 817 + #define CEC_INT_STATUS 0x4000 818 + #define CEC_INT_MASK_N 0x4004 819 + #define CEC_INT_CLEAR 0x4008 820 + #define CEC_INT_FORCE 0x400c 821 + /* eARC RX Interrupt Registers */ 822 + #define EARCRX_INTVEC_INDEX 0x4800 823 + #define EARCRX_0_INT_STATUS 0x4810 824 + #define EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ BIT(9) 825 + #define EARCRX_CMDC_DISCOVERY_DONE_IRQ BIT(8) 826 + #define EARCRX_0_INT_MASK_N 0x4814 827 + #define EARCRX_0_INT_CLEAR 0x4818 828 + #define EARCRX_0_INT_FORCE 0x481c 829 + #define EARCRX_1_INT_STATUS 0x4820 830 + #define EARCRX_1_INT_MASK_N 0x4824 831 + #define EARCRX_1_INT_CLEAR 0x4828 832 + #define EARCRX_1_INT_FORCE 0x482c 833 + 834 + #endif /* __DW_HDMI_QP_H__ */
+3
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 3503 3503 hdmi->bridge.of_node = pdev->dev.of_node; 3504 3504 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 3505 3505 3506 + if (hdmi->version >= 0x200a) 3507 + hdmi->bridge.ycbcr_420_allowed = plat_data->ycbcr_420_allowed; 3508 + 3506 3509 memset(&pdevinfo, 0, sizeof(pdevinfo)); 3507 3510 pdevinfo.parent = dev; 3508 3511 pdevinfo.id = PLATFORM_DEVID_AUTO;
+1 -1
drivers/gpu/drm/bridge/tc358767.c
··· 1707 1707 { 1708 1708 struct tc_data *tc = bridge_to_tc(bridge); 1709 1709 1710 - drm_mode_copy(&tc->mode, mode); 1710 + drm_mode_copy(&tc->mode, adj); 1711 1711 } 1712 1712 1713 1713 static const struct drm_edid *tc_edid_read(struct drm_bridge *bridge,
+3 -1
drivers/gpu/drm/bridge/tc358768.c
··· 443 443 ret = -EINVAL; 444 444 ep = of_graph_get_endpoint_by_regs(host->dev->of_node, 0, 0); 445 445 if (ep) { 446 - ret = of_property_read_u32(ep, "data-lines", &priv->pd_lines); 446 + ret = of_property_read_u32(ep, "bus-width", &priv->pd_lines); 447 + if (ret) 448 + ret = of_property_read_u32(ep, "data-lines", &priv->pd_lines); 447 449 448 450 of_node_put(ep); 449 451 }
+1 -1
drivers/gpu/drm/bridge/ti-dlpc3433.c
··· 94 94 .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges), 95 95 }; 96 96 97 - static struct regmap_config dlpc_regmap_config = { 97 + static const struct regmap_config dlpc_regmap_config = { 98 98 .reg_bits = 8, 99 99 .val_bits = 8, 100 100 .max_register = WR_DSI_PORT_EN,
+6 -1
drivers/gpu/drm/ci/arm64.config
··· 90 90 CONFIG_USB_ONBOARD_DEV=y 91 91 CONFIG_NVMEM_QCOM_QFPROM=y 92 92 CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y 93 - 93 + CONFIG_REGULATOR_QCOM_REFGEN=y 94 + CONFIG_TYPEC_MUX_FSA4480=y 95 + CONFIG_QCOM_PMIC_GLINK=y 96 + CONFIG_UCSI_PMIC_GLINK=y 97 + CONFIG_QRTR=y 98 + CONFIG_QRTR_SMD=y 94 99 95 100 # db410c ethernet 96 101 CONFIG_USB_RTL8152=y
+1
drivers/gpu/drm/ci/build.sh
··· 30 30 DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dtb" 31 31 DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r5.dtb" 32 32 DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtb" 33 + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sm8350-hdk.dtb" 33 34 elif [[ "$KERNEL_ARCH" = "arm" ]]; then 34 35 GCC_ARCH="arm-linux-gnueabihf" 35 36 DEBIAN_ARCH="armhf"
+25
drivers/gpu/drm/ci/test.yml
··· 162 162 script: 163 163 - ./install/bare-metal/cros-servo.sh 164 164 165 + msm:sm8350-hdk: 166 + extends: 167 + - .lava-igt:arm64 168 + stage: msm 169 + parallel: 4 170 + variables: 171 + BOOT_METHOD: fastboot 172 + DEVICE_TYPE: sm8350-hdk 173 + DRIVER_NAME: msm 174 + DTB: ${DEVICE_TYPE} 175 + FARM: collabora 176 + GPU_VERSION: ${DEVICE_TYPE} 177 + KERNEL_IMAGE_NAME: "Image.gz" 178 + KERNEL_IMAGE_TYPE: "" 179 + RUNNER_TAG: mesa-ci-x86-64-lava-sm8350-hdk 180 + 165 181 .rockchip-device: 166 182 variables: 167 183 DTB: ${DEVICE_TYPE} ··· 301 285 DEVICE_TYPE: acer-cp514-2h-1130g7-volteer 302 286 GPU_VERSION: tgl 303 287 RUNNER_TAG: mesa-ci-x86-64-lava-acer-cp514-2h-1130g7-volteer 288 + 289 + i915:jsl: 290 + extends: 291 + - .i915 292 + parallel: 4 293 + variables: 294 + DEVICE_TYPE: acer-cb317-1h-c3z6-dedede 295 + GPU_VERSION: jsl 296 + RUNNER_TAG: mesa-ci-x86-64-lava-acer-cb317-1h-c3z6-dedede 304 297 305 298 .amdgpu: 306 299 extends:
+51
drivers/gpu/drm/ci/xfails/i915-jsl-fails.txt
··· 1 + core_setmaster@master-drop-set-user,Fail 2 + i915_module_load@load,Fail 3 + i915_module_load@reload,Fail 4 + i915_module_load@reload-no-display,Fail 5 + i915_module_load@resize-bar,Fail 6 + i915_pm_rpm@gem-execbuf-stress,Timeout 7 + i915_pm_rpm@module-reload,Fail 8 + kms_flip@plain-flip-fb-recreate,Fail 9 + kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail 10 + kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail 11 + kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,Fail 12 + kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail 13 + kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail 14 + kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail 15 + kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail 16 + kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail 17 + kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail 18 + kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail 19 + kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail 20 + kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail 21 + kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling,Fail 22 + kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail 23 + kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail 24 + kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail 25 + kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail 26 + kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail 27 + kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail 28 + kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail 29 + kms_lease@lease-uevent,Fail 30 + kms_pm_rpm@legacy-planes,Timeout 31 + kms_pm_rpm@legacy-planes-dpms,Timeout 32 + kms_pm_rpm@modeset-stress-extra-wait,Timeout 33 + kms_pm_rpm@universal-planes,Timeout 34 + kms_pm_rpm@universal-planes-dpms,Timeout 35 + kms_rotation_crc@multiplane-rotation,Fail 36 + kms_rotation_crc@multiplane-rotation-cropping-bottom,Fail 37 + kms_rotation_crc@multiplane-rotation-cropping-top,Fail 38 + perf@i915-ref-count,Fail 39 + perf_pmu@busy-accuracy-50,Fail 40 + perf_pmu@module-unload,Fail 41 + perf_pmu@most-busy-idle-check-all,Fail 42 + perf_pmu@rc6,Crash 43 + sysfs_heartbeat_interval@long,Timeout 44 + sysfs_heartbeat_interval@off,Timeout 45 + sysfs_preempt_timeout@off,Timeout 46 + sysfs_timeslice_duration@off,Timeout 47 + xe_module_load@force-load,Fail 48 + xe_module_load@load,Fail 49 + xe_module_load@many-reload,Fail 50 + xe_module_load@reload,Fail 51 + xe_module_load@reload-no-display,Fail
+13
drivers/gpu/drm/ci/xfails/i915-jsl-flakes.txt
··· 1 + # Board Name: acer-cb317-1h-c3z6-dedede 2 + # Bug Report: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12475 3 + # Failure Rate: 100 4 + # IGT Version: 1.28-ga73311079 5 + # Linux Version: 6.12.0-rc1 6 + kms_flip@flip-vs-panning-interruptible 7 + 8 + # Board Name: acer-cb317-1h-c3z6-dedede 9 + # Bug Report: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12476 10 + # Failure Rate: 100 11 + # IGT Version: 1.28-ga73311079 12 + # Linux Version: 6.12.0-rc1 13 + kms_universal_plane@cursor-fb-leak
+20
drivers/gpu/drm/ci/xfails/i915-jsl-skips.txt
··· 1 + # Suspend to RAM seems to be broken on this machine 2 + .*suspend.* 3 + 4 + # Skip driver specific tests 5 + ^amdgpu.* 6 + ^msm.* 7 + nouveau_.* 8 + ^panfrost.* 9 + ^v3d.* 10 + ^vc4.* 11 + ^vmwgfx* 12 + 13 + # GEM tests takes ~1000 hours, so skip it 14 + gem_.* 15 + 16 + # trap_err 17 + i915_pm_rc6_residency.* 18 + 19 + # Hangs the machine and timeout occurs 20 + i915_pm_rpm@system-hibernate*
+15
drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-fails.txt
··· 1 + kms_3d,Fail 2 + kms_cursor_legacy@forked-bo,Fail 3 + kms_cursor_legacy@forked-move,Fail 4 + kms_cursor_legacy@single-bo,Fail 5 + kms_cursor_legacy@single-move,Fail 6 + kms_cursor_legacy@torture-bo,Fail 7 + kms_cursor_legacy@torture-move,Fail 8 + kms_hdmi_inject@inject-4k,Fail 9 + kms_lease@lease-uevent,Fail 10 + kms_plane_alpha_blend@alpha-7efc,Fail 11 + kms_plane_alpha_blend@alpha-basic,Fail 12 + kms_plane_alpha_blend@alpha-opaque-fb,Fail 13 + kms_plane_alpha_blend@alpha-transparent-fb,Fail 14 + kms_plane_alpha_blend@constant-alpha-max,Fail 15 + msm/msm_recovery@gpu-fault-parallel,Fail
+6
drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-flakes.txt
··· 1 + # Board Name: sm8350-hdk 2 + # Bug Report: https://gitlab.freedesktop.org/drm/msm/-/issues/65 3 + # Failure Rate: 100 4 + # IGT Version: 1.28-ga73311079 5 + # Linux Version: 6.12.0-rc1 6 + msm/msm_recovery@gpu-fault
+211
drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-skips.txt
··· 1 + # Skip driver specific tests 2 + ^amdgpu.* 3 + nouveau_.* 4 + ^panfrost.* 5 + ^v3d.* 6 + ^vc4.* 7 + ^vmwgfx* 8 + 9 + # Skip intel specific tests 10 + gem_.* 11 + i915_.* 12 + tools_test.* 13 + 14 + # Currently fails and causes coverage loss for other tests 15 + # since core_getversion also fails. 16 + core_hotunplug.* 17 + 18 + # Kernel panic 19 + msm/msm_mapping@ring 20 + # DEBUG - Begin test msm/msm_mapping@ring 21 + # [ 200.874157] [IGT] msm_mapping: executing 22 + # [ 200.880236] [IGT] msm_mapping: starting subtest ring 23 + # [ 200.895243] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=PERMISSION source=CP (0,0,0,1) 24 + # [ 200.906885] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 25 + # [ 200.917625] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 26 + # [ 200.928353] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 27 + # [ 200.939084] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 28 + # [ 200.949815] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 29 + # [ 200.950227] platform 3d6a000.gmu: [drm:a6xx_hfi_send_msg.constprop.0] *ERROR* Message HFI_H2F_MSG_GX_BW_PERF_VOTE id 25 timed out waiting for response 30 + # [ 200.960467] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 31 + # [ 200.960500] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 32 + # [ 200.995966] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 33 + # [ 201.006702] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 34 + # [ 204.213387] platform 3d6a000.gmu: GMU watchdog expired 35 + # [ 205.909103] adreno_fault_handler: 224274 callbacks suppressed 36 + # [ 205.909108] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 37 + # [ 205.925794] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 38 + # [ 205.936529] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 39 + # [ 205.947263] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 40 + # [ 205.957997] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 41 + # [ 205.968731] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 42 + # [ 205.979465] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 43 + # [ 205.990199] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 44 + # [ 206.000932] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 45 + # [ 206.011666] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 46 + # [ 210.925090] adreno_fault_handler: 224511 callbacks suppressed 47 + # [ 210.925096] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 48 + # [ 210.941781] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 49 + # [ 210.952517] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 50 + # [ 210.963250] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 51 + # [ 210.973985] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 52 + # [ 210.984719] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 53 + # [ 210.995452] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 54 + # [ 211.006186] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 55 + # [ 211.016921] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 56 + # [ 211.027655] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 57 + # [ 215.937100] adreno_fault_handler: 223760 callbacks suppressed 58 + # [ 215.937106] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 59 + # [ 215.953824] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 60 + # [ 215.964573] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 61 + # [ 215.975321] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 62 + # [ 215.986067] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 63 + # [ 215.996815] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 64 + # [ 216.007563] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 65 + # [ 216.018310] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 66 + # [ 216.029057] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 67 + # [ 216.039805] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 68 + # [ 220.945182] adreno_fault_handler: 222822 callbacks suppressed 69 + # [ 220.945188] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 70 + # [ 220.961897] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 71 + # [ 220.972645] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 72 + # [ 220.983392] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 73 + # [ 220.994140] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 74 + # [ 221.004889] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 75 + # [ 221.015636] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 76 + # [ 221.026383] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 77 + # [ 221.037130] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 78 + # [ 221.047879] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 79 + # [ 225.953179] adreno_fault_handler: 223373 callbacks suppressed 80 + # [ 225.953184] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 81 + # [ 225.969883] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 82 + # [ 225.980617] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 83 + # [ 225.991350] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 84 + # [ 226.002084] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 85 + # [ 226.012818] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 86 + # [ 226.023551] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 87 + # [ 226.034285] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 88 + # [ 226.045019] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 89 + # [ 226.055753] *** gpu fault: ttbr0=00000001160d6000 iova=0001000000001000 dir=WRITE type=UNKNOWN source=CP (0,0,0,1) 90 + # [ 228.001087] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: 91 + # [ 228.007412] rcu: 0-....: (524 ticks this GP) idle=4ffc/1/0x4000000000000000 softirq=9367/9368 fqs=29 92 + # [ 228.017097] rcu: (detected by 1, t=6504 jiffies, g=29837, q=6 ncpus=8) 93 + # [ 228.023959] Sending NMI from CPU 1 to CPUs 0: 94 + # [ 228.161164] watchdog: BUG: soft lockup - CPU#0 stuck for 26s! [gpu-worker:150] 95 + # [ 228.173169] Modules linked in: 96 + # [ 228.176361] irq event stamp: 2809595 97 + # [ 228.180083] hardirqs last enabled at (2809594): [<ffffd3bc52cb91ac>] exit_to_kernel_mode+0x38/0x130 98 + # [ 228.189547] hardirqs last disabled at (2809595): [<ffffd3bc52cb92c8>] el1_interrupt+0x24/0x64 99 + # [ 228.198377] softirqs last enabled at (1669060): [<ffffd3bc51936f98>] handle_softirqs+0x4a4/0x4bc 100 + # [ 228.207565] softirqs last disabled at (1669063): [<ffffd3bc518905a4>] __do_softirq+0x14/0x20 101 + # [ 228.216316] CPU: 0 UID: 0 PID: 150 Comm: gpu-worker Not tainted 6.12.0-rc1-g685d530dc83a #1 102 + # [ 228.224966] Hardware name: Qualcomm Technologies, Inc. SM8350 HDK (DT) 103 + # [ 228.231730] pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) 104 + # [ 228.238948] pc : tcp_fastretrans_alert+0x0/0x884 105 + # [ 228.243751] lr : tcp_ack+0x9d4/0x1238 106 + # [ 228.247562] sp : ffff8000800036d0 107 + # [ 228.251011] x29: ffff8000800036d0 x28: 000000000000000c x27: 0000000000000001 108 + # [ 228.258421] x26: ffff704683cd8000 x25: 0000000000000403 x24: ffff70468b7e7c00 109 + # [ 228.265829] x23: 0000000000000000 x22: 0000000000000004 x21: 000000000000140f 110 + # [ 228.273237] x20: 00000000f1de79f7 x19: 00000000f1de7a5f x18: 0000000000000001 111 + # [ 228.280644] x17: 00000000302d6762 x16: 632d6b64682d3035 x15: ffff704683c39000 112 + # [ 228.288051] x14: 00000000000e2000 x13: ffff704683df6000 x12: 0000000000000000 113 + # [ 228.295458] x11: 00000000000000a0 x10: 0000000000000000 x9 : ffffd3bc551a9a20 114 + # [ 228.302865] x8 : ffff800080003640 x7 : 0000000000040faa x6 : 00000000ffff9634 115 + # [ 228.310271] x5 : 00000000000005a8 x4 : ffff800080003788 x3 : ffff80008000377c 116 + # [ 228.317679] x2 : 0000000000000000 x1 : 00000000f1de79f7 x0 : ffff704683cd8000 117 + # [ 228.325087] Call trace: 118 + # [ 228.327640] tcp_fastretrans_alert+0x0/0x884 119 + # [ 228.332082] tcp_rcv_established+0x7c4/0x8bc 120 + # [ 228.336523] tcp_v4_do_rcv+0x244/0x31c 121 + # [ 228.340429] tcp_v4_rcv+0xcc4/0x1084 122 + # [ 228.344155] ip_protocol_deliver_rcu+0x64/0x218 123 + # [ 228.348862] ip_local_deliver_finish+0xb8/0x1ac 124 + # [ 228.353566] ip_local_deliver+0x84/0x254 125 + # [ 228.357651] ip_sublist_rcv_finish+0x84/0xb8 126 + # [ 228.362092] ip_sublist_rcv+0x11c/0x2f0 127 + # [ 228.366081] ip_list_rcv+0xfc/0x190 128 + # [ 228.369711] __netif_receive_skb_list_core+0x174/0x208 129 + # [ 228.375050] netif_receive_skb_list_internal+0x204/0x3ac 130 + # [ 228.380564] napi_complete_done+0x64/0x1d0 131 + # [ 228.384826] lan78xx_poll+0x71c/0x9cc 132 + # [ 228.388638] __napi_poll.constprop.0+0x3c/0x254 133 + # [ 228.393341] net_rx_action+0x164/0x2d4 134 + # [ 228.397244] handle_softirqs+0x128/0x4bc 135 + # [ 228.401329] __do_softirq+0x14/0x20 136 + # [ 228.404958] ____do_softirq+0x10/0x1c 137 + # [ 228.408769] call_on_irq_stack+0x24/0x4c 138 + # [ 228.412854] do_softirq_own_stack+0x1c/0x28 139 + # [ 228.417199] __irq_exit_rcu+0x124/0x164 140 + # [ 228.421188] irq_exit_rcu+0x10/0x38 141 + # [ 228.424819] el1_interrupt+0x38/0x64 142 + # [ 228.428546] el1h_64_irq_handler+0x18/0x24 143 + # [ 228.432807] el1h_64_irq+0x64/0x68 144 + # [ 228.436354] lock_acquire+0x214/0x32c 145 + # [ 228.440166] __mutex_lock+0x98/0x3d0 146 + # [ 228.443893] mutex_lock_nested+0x24/0x30 147 + # [ 228.447978] fault_worker+0x58/0x184 148 + # [ 228.451704] kthread_worker_fn+0xf4/0x320 149 + # [ 228.455873] kthread+0x114/0x118 150 + # [ 228.459243] ret_from_fork+0x10/0x20 151 + # [ 228.462970] Kernel panic - not syncing: softlockup: hung tasks 152 + # [ 228.469018] CPU: 0 UID: 0 PID: 150 Comm: gpu-worker Tainted: G L 6.12.0-rc1-g685d530dc83a #1 153 + # [ 228.479190] Tainted: [L]=SOFTLOCKUP 154 + # [ 228.482815] Hardware name: Qualcomm Technologies, Inc. SM8350 HDK (DT) 155 + # [ 228.489574] Call trace: 156 + # [ 228.492125] dump_backtrace+0x98/0xf0 157 + # [ 228.495931] show_stack+0x18/0x24 158 + # [ 228.499380] dump_stack_lvl+0x38/0xd0 159 + # [ 228.503189] dump_stack+0x18/0x24 160 + # [ 228.506639] panic+0x3bc/0x41c 161 + # [ 228.509826] watchdog_timer_fn+0x254/0x2e4 162 + # [ 228.514087] __hrtimer_run_queues+0x3b0/0x40c 163 + # [ 228.518612] hrtimer_interrupt+0xe8/0x248 164 + # [ 228.522777] arch_timer_handler_virt+0x2c/0x44 165 + # [ 228.527399] handle_percpu_devid_irq+0xa8/0x2c4 166 + # [ 228.532103] generic_handle_domain_irq+0x2c/0x44 167 + # [ 228.536902] gic_handle_irq+0x4c/0x11c 168 + # [ 228.540802] do_interrupt_handler+0x50/0x84 169 + # [ 228.545146] el1_interrupt+0x34/0x64 170 + # [ 228.548870] el1h_64_irq_handler+0x18/0x24 171 + # [ 228.553128] el1h_64_irq+0x64/0x68 172 + # [ 228.556672] tcp_fastretrans_alert+0x0/0x884 173 + # [ 228.561110] tcp_rcv_established+0x7c4/0x8bc 174 + # [ 228.565548] tcp_v4_do_rcv+0x244/0x31c 175 + # [ 228.569449] tcp_v4_rcv+0xcc4/0x1084 176 + # [ 228.573171] ip_protocol_deliver_rcu+0x64/0x218 177 + # [ 228.577873] ip_local_deliver_finish+0xb8/0x1ac 178 + # [ 228.582574] ip_local_deliver+0x84/0x254 179 + # [ 228.586655] ip_sublist_rcv_finish+0x84/0xb8 180 + # [ 228.591092] ip_sublist_rcv+0x11c/0x2f0 181 + # [ 228.595079] ip_list_rcv+0xfc/0x190 182 + # [ 228.598706] __netif_receive_skb_list_core+0x174/0x208 183 + # [ 228.604039] netif_receive_skb_list_internal+0x204/0x3ac 184 + # [ 228.609549] napi_complete_done+0x64/0x1d0 185 + # [ 228.613808] lan78xx_poll+0x71c/0x9cc 186 + # [ 228.617614] __napi_poll.constprop.0+0x3c/0x254 187 + # [ 228.622314] net_rx_action+0x164/0x2d4 188 + # [ 228.626214] handle_softirqs+0x128/0x4bc 189 + # [ 228.630297] __do_softirq+0x14/0x20 190 + # [ 228.633923] ____do_softirq+0x10/0x1c 191 + # [ 228.637729] call_on_irq_stack+0x24/0x4c 192 + # [ 228.641811] do_softirq_own_stack+0x1c/0x28 193 + # [ 228.646152] __irq_exit_rcu+0x124/0x164 194 + # [ 228.650139] irq_exit_rcu+0x10/0x38 195 + # [ 228.653768] el1_interrupt+0x38/0x64 196 + # [ 228.657491] el1h_64_irq_handler+0x18/0x24 197 + # [ 228.661750] el1h_64_irq+0x64/0x68 198 + # [ 228.665293] lock_acquire+0x214/0x32c 199 + # [ 228.669098] __mutex_lock+0x98/0x3d0 200 + # [ 228.672821] mutex_lock_nested+0x24/0x30 201 + # [ 228.676903] fault_worker+0x58/0x184 202 + # [ 228.680626] kthread_worker_fn+0xf4/0x320 203 + # [ 228.684790] kthread+0x114/0x118 204 + # [ 228.688156] ret_from_fork+0x10/0x20 205 + # [ 228.691882] SMP: stopping secondary CPUs 206 + # [ 229.736843] SMP: failed to stop secondary CPUs 1,4 207 + # [ 229.741827] Kernel Offset: 0x53bbd1880000 from 0xffff800080000000 208 + # [ 229.748159] PHYS_OFFSET: 0xfff08fba80000000 209 + # [ 229.752499] CPU features: 0x18,00000017,00200928,4200720b 210 + # [ 229.758095] Memory Limit: none 211 + # [ 229.761291] ---[ end Kernel panic - not syncing: softlockup: hung tasks ]---
+1 -1
drivers/gpu/drm/display/Kconfig
··· 3 3 config DRM_DISPLAY_DP_AUX_BUS 4 4 tristate 5 5 depends on DRM 6 - depends on OF || COMPILE_TEST 6 + depends on OF 7 7 8 8 config DRM_DISPLAY_HELPER 9 9 tristate
+4 -2
drivers/gpu/drm/display/drm_bridge_connector.c
··· 397 397 bridge_connector->encoder = encoder; 398 398 399 399 /* 400 - * TODO: Handle doublescan_allowed, stereo_allowed and 401 - * ycbcr_420_allowed. 400 + * TODO: Handle doublescan_allowed and stereo_allowed. 402 401 */ 403 402 connector = &bridge_connector->base; 404 403 connector->interlace_allowed = true; 404 + connector->ycbcr_420_allowed = true; 405 405 406 406 /* 407 407 * Initialise connector status handling. First locate the furthest ··· 414 414 drm_for_each_bridge_in_chain(encoder, bridge) { 415 415 if (!bridge->interlace_allowed) 416 416 connector->interlace_allowed = false; 417 + if (!bridge->ycbcr_420_allowed) 418 + connector->ycbcr_420_allowed = false; 417 419 418 420 if (bridge->ops & DRM_BRIDGE_OP_EDID) 419 421 bridge_connector->bridge_edid = bridge;
+2
drivers/gpu/drm/drm_atomic.c
··· 1132 1132 drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); 1133 1133 drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 1134 1134 drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); 1135 + drm_printf(p, "\tinterlace_allowed=%d\n", connector->interlace_allowed); 1136 + drm_printf(p, "\tycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed); 1135 1137 drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); 1136 1138 drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); 1137 1139
-121
drivers/gpu/drm/drm_client.c
··· 10 10 #include <linux/slab.h> 11 11 12 12 #include <drm/drm_client.h> 13 - #include <drm/drm_debugfs.h> 14 13 #include <drm/drm_device.h> 15 14 #include <drm/drm_drv.h> 16 15 #include <drm/drm_file.h> ··· 170 171 drm_dev_put(dev); 171 172 } 172 173 EXPORT_SYMBOL(drm_client_release); 173 - 174 - /** 175 - * drm_client_dev_unregister - Unregister clients 176 - * @dev: DRM device 177 - * 178 - * This function releases all clients by calling each client's 179 - * &drm_client_funcs.unregister callback. The callback function 180 - * is responsibe for releaseing all resources including the client 181 - * itself. 182 - * 183 - * The helper drm_dev_unregister() calls this function. Drivers 184 - * that use it don't need to call this function themselves. 185 - */ 186 - void drm_client_dev_unregister(struct drm_device *dev) 187 - { 188 - struct drm_client_dev *client, *tmp; 189 - 190 - if (!drm_core_check_feature(dev, DRIVER_MODESET)) 191 - return; 192 - 193 - mutex_lock(&dev->clientlist_mutex); 194 - list_for_each_entry_safe(client, tmp, &dev->clientlist, list) { 195 - list_del(&client->list); 196 - if (client->funcs && client->funcs->unregister) { 197 - client->funcs->unregister(client); 198 - } else { 199 - drm_client_release(client); 200 - kfree(client); 201 - } 202 - } 203 - mutex_unlock(&dev->clientlist_mutex); 204 - } 205 - EXPORT_SYMBOL(drm_client_dev_unregister); 206 - 207 - /** 208 - * drm_client_dev_hotplug - Send hotplug event to clients 209 - * @dev: DRM device 210 - * 211 - * This function calls the &drm_client_funcs.hotplug callback on the attached clients. 212 - * 213 - * drm_kms_helper_hotplug_event() calls this function, so drivers that use it 214 - * don't need to call this function themselves. 215 - */ 216 - void drm_client_dev_hotplug(struct drm_device *dev) 217 - { 218 - struct drm_client_dev *client; 219 - int ret; 220 - 221 - if (!drm_core_check_feature(dev, DRIVER_MODESET)) 222 - return; 223 - 224 - if (!dev->mode_config.num_connector) { 225 - drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n"); 226 - return; 227 - } 228 - 229 - mutex_lock(&dev->clientlist_mutex); 230 - list_for_each_entry(client, &dev->clientlist, list) { 231 - if (!client->funcs || !client->funcs->hotplug) 232 - continue; 233 - 234 - if (client->hotplug_failed) 235 - continue; 236 - 237 - ret = client->funcs->hotplug(client); 238 - drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 239 - if (ret) 240 - client->hotplug_failed = true; 241 - } 242 - mutex_unlock(&dev->clientlist_mutex); 243 - } 244 - EXPORT_SYMBOL(drm_client_dev_hotplug); 245 - 246 - void drm_client_dev_restore(struct drm_device *dev) 247 - { 248 - struct drm_client_dev *client; 249 - int ret; 250 - 251 - if (!drm_core_check_feature(dev, DRIVER_MODESET)) 252 - return; 253 - 254 - mutex_lock(&dev->clientlist_mutex); 255 - list_for_each_entry(client, &dev->clientlist, list) { 256 - if (!client->funcs || !client->funcs->restore) 257 - continue; 258 - 259 - ret = client->funcs->restore(client); 260 - drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 261 - if (!ret) /* The first one to return zero gets the privilege to restore */ 262 - break; 263 - } 264 - mutex_unlock(&dev->clientlist_mutex); 265 - } 266 174 267 175 static void drm_client_buffer_delete(struct drm_client_buffer *buffer) 268 176 { ··· 490 584 0, 0, NULL, 0); 491 585 } 492 586 EXPORT_SYMBOL(drm_client_framebuffer_flush); 493 - 494 - #ifdef CONFIG_DEBUG_FS 495 - static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data) 496 - { 497 - struct drm_debugfs_entry *entry = m->private; 498 - struct drm_device *dev = entry->dev; 499 - struct drm_printer p = drm_seq_file_printer(m); 500 - struct drm_client_dev *client; 501 - 502 - mutex_lock(&dev->clientlist_mutex); 503 - list_for_each_entry(client, &dev->clientlist, list) 504 - drm_printf(&p, "%s\n", client->name); 505 - mutex_unlock(&dev->clientlist_mutex); 506 - 507 - return 0; 508 - } 509 - 510 - static const struct drm_debugfs_info drm_client_debugfs_list[] = { 511 - { "internal_clients", drm_client_debugfs_internal_clients, 0 }, 512 - }; 513 - 514 - void drm_client_debugfs_init(struct drm_device *dev) 515 - { 516 - drm_debugfs_add_files(dev, drm_client_debugfs_list, 517 - ARRAY_SIZE(drm_client_debugfs_list)); 518 - } 519 - #endif
+197
drivers/gpu/drm/drm_client_event.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* 3 + * Copyright 2018 Noralf Trønnes 4 + */ 5 + 6 + #include <linux/list.h> 7 + #include <linux/mutex.h> 8 + #include <linux/seq_file.h> 9 + 10 + #include <drm/drm_client.h> 11 + #include <drm/drm_client_event.h> 12 + #include <drm/drm_debugfs.h> 13 + #include <drm/drm_device.h> 14 + #include <drm/drm_drv.h> 15 + #include <drm/drm_print.h> 16 + 17 + #include "drm_internal.h" 18 + 19 + /** 20 + * drm_client_dev_unregister - Unregister clients 21 + * @dev: DRM device 22 + * 23 + * This function releases all clients by calling each client's 24 + * &drm_client_funcs.unregister callback. The callback function 25 + * is responsibe for releaseing all resources including the client 26 + * itself. 27 + * 28 + * The helper drm_dev_unregister() calls this function. Drivers 29 + * that use it don't need to call this function themselves. 30 + */ 31 + void drm_client_dev_unregister(struct drm_device *dev) 32 + { 33 + struct drm_client_dev *client, *tmp; 34 + 35 + if (!drm_core_check_feature(dev, DRIVER_MODESET)) 36 + return; 37 + 38 + mutex_lock(&dev->clientlist_mutex); 39 + list_for_each_entry_safe(client, tmp, &dev->clientlist, list) { 40 + list_del(&client->list); 41 + if (client->funcs && client->funcs->unregister) { 42 + client->funcs->unregister(client); 43 + } else { 44 + drm_client_release(client); 45 + kfree(client); 46 + } 47 + } 48 + mutex_unlock(&dev->clientlist_mutex); 49 + } 50 + EXPORT_SYMBOL(drm_client_dev_unregister); 51 + 52 + /** 53 + * drm_client_dev_hotplug - Send hotplug event to clients 54 + * @dev: DRM device 55 + * 56 + * This function calls the &drm_client_funcs.hotplug callback on the attached clients. 57 + * 58 + * drm_kms_helper_hotplug_event() calls this function, so drivers that use it 59 + * don't need to call this function themselves. 60 + */ 61 + void drm_client_dev_hotplug(struct drm_device *dev) 62 + { 63 + struct drm_client_dev *client; 64 + int ret; 65 + 66 + if (!drm_core_check_feature(dev, DRIVER_MODESET)) 67 + return; 68 + 69 + if (!dev->mode_config.num_connector) { 70 + drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n"); 71 + return; 72 + } 73 + 74 + mutex_lock(&dev->clientlist_mutex); 75 + list_for_each_entry(client, &dev->clientlist, list) { 76 + if (!client->funcs || !client->funcs->hotplug) 77 + continue; 78 + 79 + if (client->hotplug_failed) 80 + continue; 81 + 82 + ret = client->funcs->hotplug(client); 83 + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 84 + if (ret) 85 + client->hotplug_failed = true; 86 + } 87 + mutex_unlock(&dev->clientlist_mutex); 88 + } 89 + EXPORT_SYMBOL(drm_client_dev_hotplug); 90 + 91 + void drm_client_dev_restore(struct drm_device *dev) 92 + { 93 + struct drm_client_dev *client; 94 + int ret; 95 + 96 + if (!drm_core_check_feature(dev, DRIVER_MODESET)) 97 + return; 98 + 99 + mutex_lock(&dev->clientlist_mutex); 100 + list_for_each_entry(client, &dev->clientlist, list) { 101 + if (!client->funcs || !client->funcs->restore) 102 + continue; 103 + 104 + ret = client->funcs->restore(client); 105 + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 106 + if (!ret) /* The first one to return zero gets the privilege to restore */ 107 + break; 108 + } 109 + mutex_unlock(&dev->clientlist_mutex); 110 + } 111 + 112 + static int drm_client_suspend(struct drm_client_dev *client, bool holds_console_lock) 113 + { 114 + struct drm_device *dev = client->dev; 115 + int ret = 0; 116 + 117 + if (drm_WARN_ON_ONCE(dev, client->suspended)) 118 + return 0; 119 + 120 + if (client->funcs && client->funcs->suspend) 121 + ret = client->funcs->suspend(client, holds_console_lock); 122 + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 123 + 124 + client->suspended = true; 125 + 126 + return ret; 127 + } 128 + 129 + void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock) 130 + { 131 + struct drm_client_dev *client; 132 + 133 + mutex_lock(&dev->clientlist_mutex); 134 + list_for_each_entry(client, &dev->clientlist, list) { 135 + if (!client->suspended) 136 + drm_client_suspend(client, holds_console_lock); 137 + } 138 + mutex_unlock(&dev->clientlist_mutex); 139 + } 140 + EXPORT_SYMBOL(drm_client_dev_suspend); 141 + 142 + static int drm_client_resume(struct drm_client_dev *client, bool holds_console_lock) 143 + { 144 + struct drm_device *dev = client->dev; 145 + int ret = 0; 146 + 147 + if (drm_WARN_ON_ONCE(dev, !client->suspended)) 148 + return 0; 149 + 150 + if (client->funcs && client->funcs->resume) 151 + ret = client->funcs->resume(client, holds_console_lock); 152 + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); 153 + 154 + client->suspended = false; 155 + 156 + return ret; 157 + } 158 + 159 + void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock) 160 + { 161 + struct drm_client_dev *client; 162 + 163 + mutex_lock(&dev->clientlist_mutex); 164 + list_for_each_entry(client, &dev->clientlist, list) { 165 + if (client->suspended) 166 + drm_client_resume(client, holds_console_lock); 167 + } 168 + mutex_unlock(&dev->clientlist_mutex); 169 + } 170 + EXPORT_SYMBOL(drm_client_dev_resume); 171 + 172 + #ifdef CONFIG_DEBUG_FS 173 + static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data) 174 + { 175 + struct drm_debugfs_entry *entry = m->private; 176 + struct drm_device *dev = entry->dev; 177 + struct drm_printer p = drm_seq_file_printer(m); 178 + struct drm_client_dev *client; 179 + 180 + mutex_lock(&dev->clientlist_mutex); 181 + list_for_each_entry(client, &dev->clientlist, list) 182 + drm_printf(&p, "%s\n", client->name); 183 + mutex_unlock(&dev->clientlist_mutex); 184 + 185 + return 0; 186 + } 187 + 188 + static const struct drm_debugfs_info drm_client_debugfs_list[] = { 189 + { "internal_clients", drm_client_debugfs_internal_clients, 0 }, 190 + }; 191 + 192 + void drm_client_debugfs_init(struct drm_device *dev) 193 + { 194 + drm_debugfs_add_files(dev, drm_client_debugfs_list, 195 + ARRAY_SIZE(drm_client_debugfs_list)); 196 + } 197 + #endif
+3
drivers/gpu/drm/drm_client_setup.c
··· 64 64 drm_client_setup_with_fourcc(dev, fourcc); 65 65 } 66 66 EXPORT_SYMBOL(drm_client_setup_with_color_mode); 67 + 68 + MODULE_DESCRIPTION("In-kernel DRM clients"); 69 + MODULE_LICENSE("GPL and additional rights");
-1
drivers/gpu/drm/drm_debugfs.c
··· 32 32 #include <drm/drm_atomic.h> 33 33 #include <drm/drm_auth.h> 34 34 #include <drm/drm_bridge.h> 35 - #include <drm/drm_client.h> 36 35 #include <drm/drm_debugfs.h> 37 36 #include <drm/drm_device.h> 38 37 #include <drm/drm_drv.h>
+1 -1
drivers/gpu/drm/drm_drv.c
··· 38 38 39 39 #include <drm/drm_accel.h> 40 40 #include <drm/drm_cache.h> 41 - #include <drm/drm_client.h> 41 + #include <drm/drm_client_event.h> 42 42 #include <drm/drm_color_mgmt.h> 43 43 #include <drm/drm_drv.h> 44 44 #include <drm/drm_file.h>
+2
drivers/gpu/drm/drm_fb_helper.c
··· 697 697 } 698 698 EXPORT_SYMBOL(drm_fb_helper_damage_area); 699 699 700 + #ifdef CONFIG_FB_DEFERRED_IO 700 701 /** 701 702 * drm_fb_helper_deferred_io() - fbdev deferred_io callback function 702 703 * @info: fb_info struct pointer ··· 741 740 } 742 741 } 743 742 EXPORT_SYMBOL(drm_fb_helper_deferred_io); 743 + #endif 744 744 745 745 /** 746 746 * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
+28 -2
drivers/gpu/drm/drm_fbdev_client.c
··· 61 61 return ret; 62 62 } 63 63 64 + static int drm_fbdev_client_suspend(struct drm_client_dev *client, bool holds_console_lock) 65 + { 66 + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); 67 + 68 + if (holds_console_lock) 69 + drm_fb_helper_set_suspend(fb_helper, true); 70 + else 71 + drm_fb_helper_set_suspend_unlocked(fb_helper, true); 72 + 73 + return 0; 74 + } 75 + 76 + static int drm_fbdev_client_resume(struct drm_client_dev *client, bool holds_console_lock) 77 + { 78 + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); 79 + 80 + if (holds_console_lock) 81 + drm_fb_helper_set_suspend(fb_helper, false); 82 + else 83 + drm_fb_helper_set_suspend_unlocked(fb_helper, false); 84 + 85 + return 0; 86 + } 87 + 64 88 static const struct drm_client_funcs drm_fbdev_client_funcs = { 65 89 .owner = THIS_MODULE, 66 90 .unregister = drm_fbdev_client_unregister, 67 91 .restore = drm_fbdev_client_restore, 68 92 .hotplug = drm_fbdev_client_hotplug, 93 + .suspend = drm_fbdev_client_suspend, 94 + .resume = drm_fbdev_client_resume, 69 95 }; 70 96 71 97 /** ··· 102 76 * 103 77 * This function sets up fbdev emulation. Restore, hotplug events and 104 78 * teardown are all taken care of. Drivers that do suspend/resume need 105 - * to call drm_fb_helper_set_suspend_unlocked() themselves. Simple 106 - * drivers might use drm_mode_config_helper_suspend(). 79 + * to call drm_client_dev_suspend() and drm_client_dev_resume() by 80 + * themselves. Simple drivers might use drm_mode_config_helper_suspend(). 107 81 * 108 82 * This function is safe to call even when there are no connectors present. 109 83 * Setup will be retried on the next hotplug event.
+1 -1
drivers/gpu/drm/drm_file.c
··· 40 40 #include <linux/slab.h> 41 41 #include <linux/vga_switcheroo.h> 42 42 43 - #include <drm/drm_client.h> 43 + #include <drm/drm_client_event.h> 44 44 #include <drm/drm_drv.h> 45 45 #include <drm/drm_file.h> 46 46 #include <drm/drm_gem.h>
+8
drivers/gpu/drm/drm_internal.h
··· 48 48 struct drm_printer; 49 49 struct drm_vblank_crtc; 50 50 51 + /* drm_client_event.c */ 52 + #if defined(CONFIG_DRM_CLIENT) 53 + void drm_client_debugfs_init(struct drm_device *dev); 54 + #else 55 + static inline void drm_client_debugfs_init(struct drm_device *dev) 56 + { } 57 + #endif 58 + 51 59 /* drm_file.c */ 52 60 extern struct mutex drm_global_mutex; 53 61 bool drm_dev_needs_global_mutex(struct drm_device *dev);
+8 -6
drivers/gpu/drm/drm_modeset_helper.c
··· 21 21 */ 22 22 23 23 #include <drm/drm_atomic_helper.h> 24 - #include <drm/drm_fb_helper.h> 24 + #include <drm/drm_client_event.h> 25 25 #include <drm/drm_fourcc.h> 26 26 #include <drm/drm_framebuffer.h> 27 27 #include <drm/drm_modeset_helper.h> ··· 185 185 * Zero on success, negative error code on error. 186 186 * 187 187 * See also: 188 - * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked(). 188 + * drm_kms_helper_poll_disable() and drm_client_dev_suspend(). 189 189 */ 190 190 int drm_mode_config_helper_suspend(struct drm_device *dev) 191 191 { ··· 199 199 if (dev->mode_config.poll_enabled) 200 200 drm_kms_helper_poll_disable(dev); 201 201 202 - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1); 202 + drm_client_dev_suspend(dev, false); 203 203 state = drm_atomic_helper_suspend(dev); 204 204 if (IS_ERR(state)) { 205 - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0); 205 + drm_client_dev_resume(dev, false); 206 + 206 207 /* 207 208 * Don't enable polling if it was never initialized 208 209 */ ··· 231 230 * Zero on success, negative error code on error. 232 231 * 233 232 * See also: 234 - * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable(). 233 + * drm_client_dev_resume() and drm_kms_helper_poll_enable(). 235 234 */ 236 235 int drm_mode_config_helper_resume(struct drm_device *dev) 237 236 { ··· 248 247 DRM_ERROR("Failed to resume (%d)\n", ret); 249 248 dev->mode_config.suspend_state = NULL; 250 249 251 - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0); 250 + drm_client_dev_resume(dev, false); 251 + 252 252 /* 253 253 * Don't enable polling if it is not initialized 254 254 */
+1 -1
drivers/gpu/drm/drm_probe_helper.c
··· 33 33 #include <linux/moduleparam.h> 34 34 35 35 #include <drm/drm_bridge.h> 36 - #include <drm/drm_client.h> 36 + #include <drm/drm_client_event.h> 37 37 #include <drm/drm_crtc.h> 38 38 #include <drm/drm_edid.h> 39 39 #include <drm/drm_fourcc.h>
+1
drivers/gpu/drm/fsl-dcu/Kconfig
··· 9 9 select DRM_PANEL 10 10 select REGMAP_MMIO 11 11 select VIDEOMODE_HELPERS 12 + select MFD_SYSCON if SOC_LS1021A 12 13 help 13 14 Choose this option if you have an Freescale DCU chipset. 14 15 If M is selected the module will be called fsl-dcu-drm.
+17 -6
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
··· 101 101 static int fsl_dcu_load(struct drm_device *dev, unsigned long flags) 102 102 { 103 103 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 104 + struct regmap *scfg; 104 105 int ret; 105 106 106 107 ret = fsl_dcu_drm_modeset_init(fsl_dev); 107 - if (ret < 0) { 108 - dev_err(dev->dev, "failed to initialize mode setting\n"); 109 - return ret; 108 + if (ret < 0) 109 + return dev_err_probe(dev->dev, ret, "failed to initialize mode setting\n"); 110 + 111 + scfg = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg"); 112 + if (PTR_ERR(scfg) != -ENODEV) { 113 + /* 114 + * For simplicity, enable the PIXCLK unconditionally, 115 + * resulting in increased power consumption. Disabling 116 + * the clock in PM or on unload could be implemented as 117 + * a future improvement. 118 + */ 119 + ret = regmap_update_bits(scfg, SCFG_PIXCLKCR, SCFG_PIXCLKCR_PXCEN, 120 + SCFG_PIXCLKCR_PXCEN); 121 + if (ret < 0) 122 + return dev_err_probe(dev->dev, ret, "failed to enable pixclk\n"); 110 123 } 111 124 112 125 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ··· 287 274 } 288 275 289 276 fsl_dev->irq = platform_get_irq(pdev, 0); 290 - if (fsl_dev->irq < 0) { 291 - dev_err(dev, "failed to get irq\n"); 277 + if (fsl_dev->irq < 0) 292 278 return fsl_dev->irq; 293 - } 294 279 295 280 fsl_dev->regmap = devm_regmap_init_mmio(dev, base, 296 281 &fsl_dcu_regmap_config);
+3
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
··· 160 160 #define FSL_DCU_ARGB4444 12 161 161 #define FSL_DCU_YUV422 14 162 162 163 + #define SCFG_PIXCLKCR 0x28 164 + #define SCFG_PIXCLKCR_PXCEN BIT(31) 165 + 163 166 #define VF610_LAYER_REG_NUM 9 164 167 #define LS1021A_LAYER_REG_NUM 10 165 168
+1 -1
drivers/gpu/drm/fsl-dcu/fsl_tcon.c
··· 29 29 FSL_TCON_CTRL1_TCON_BYPASS); 30 30 } 31 31 32 - static struct regmap_config fsl_tcon_regmap_config = { 32 + static const struct regmap_config fsl_tcon_regmap_config = { 33 33 .reg_bits = 32, 34 34 .reg_stride = 4, 35 35 .val_bits = 32,
+1
drivers/gpu/drm/i915/Kconfig
··· 10 10 # the shmem_readpage() which depends upon tmpfs 11 11 select SHMEM 12 12 select TMPFS 13 + select DRM_CLIENT_SELECTION 13 14 select DRM_DISPLAY_DP_HELPER 14 15 select DRM_DISPLAY_DSC_HELPER 15 16 select DRM_DISPLAY_HDCP_HELPER
+1 -1
drivers/gpu/drm/i915/display/intel_display_driver.c
··· 11 11 #include <acpi/video.h> 12 12 #include <drm/display/drm_dp_mst_helper.h> 13 13 #include <drm/drm_atomic_helper.h> 14 - #include <drm/drm_client.h> 14 + #include <drm/drm_client_event.h> 15 15 #include <drm/drm_mode_config.h> 16 16 #include <drm/drm_privacy_screen_consumer.h> 17 17 #include <drm/drm_probe_helper.h>
+1 -1
drivers/gpu/drm/imx/dcss/Kconfig
··· 7 7 select DRM_BRIDGE_CONNECTOR 8 8 select DRM_GEM_DMA_HELPER 9 9 select VIDEOMODE_HELPERS 10 - depends on DRM && ARCH_MXC && ARM64 10 + depends on DRM && ((ARCH_MXC && ARM64) || COMPILE_TEST) 11 11 help 12 12 Choose this if you have a NXP i.MX8MQ based system and want to use the 13 13 Display Controller Subsystem. This option enables DCSS support.
+2 -2
drivers/gpu/drm/imx/dcss/dcss-scaler.c
··· 136 136 else 137 137 temp -= B / 2; 138 138 139 - result = (int)(temp / B); 139 + result = div_s64(temp, B); 140 140 return result; 141 141 } 142 142 ··· 239 239 ll_temp = coef[phase][i]; 240 240 ll_temp <<= PSC_COEFF_PRECISION; 241 241 ll_temp += sum >> 1; 242 - ll_temp /= sum; 242 + ll_temp = div_s64(ll_temp, sum); 243 243 coef[phase][i] = (int)ll_temp; 244 244 } 245 245 }
+1
drivers/gpu/drm/imx/ipuv3/Kconfig
··· 15 15 depends on DRM_IMX 16 16 select DRM_BRIDGE 17 17 select DRM_BRIDGE_CONNECTOR 18 + select DRM_IMX_LEGACY_BRIDGE 18 19 select DRM_PANEL_BRIDGE 19 20 select VIDEOMODE_HELPERS 20 21
+2 -2
drivers/gpu/drm/mediatek/Kconfig
··· 2 2 config DRM_MEDIATEK 3 3 tristate "DRM Support for Mediatek SoCs" 4 4 depends on DRM 5 - depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST) 5 + depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST 6 6 depends on COMMON_CLK 7 - depends on HAVE_ARM_SMCCC 7 + depends on HAVE_ARM_SMCCC || COMPILE_TEST 8 8 depends on OF 9 9 depends on MTK_MMSYS 10 10 select DRM_CLIENT_SELECTION
+1 -1
drivers/gpu/drm/mediatek/mtk_dp.c
··· 311 311 }, 312 312 }; 313 313 314 - static struct regmap_config mtk_dp_regmap_config = { 314 + static const struct regmap_config mtk_dp_regmap_config = { 315 315 .reg_bits = 32, 316 316 .val_bits = 32, 317 317 .reg_stride = 4,
+1 -1
drivers/gpu/drm/meson/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config DRM_MESON 3 3 tristate "DRM Support for Amlogic Meson Display Controller" 4 - depends on DRM && OF && (ARM || ARM64) 4 + depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST) 5 5 depends on ARCH_MESON || COMPILE_TEST 6 6 select DRM_CLIENT_SELECTION 7 7 select DRM_KMS_HELPER
+1 -1
drivers/gpu/drm/meson/meson_drv.c
··· 128 128 return false; 129 129 } 130 130 131 - static struct regmap_config meson_regmap_config = { 131 + static const struct regmap_config meson_regmap_config = { 132 132 .reg_bits = 32, 133 133 .val_bits = 32, 134 134 .reg_stride = 4,
-14
drivers/gpu/drm/meson/meson_dw_hdmi.c
··· 272 272 writeb(data, dw_hdmi->hdmitx + addr); 273 273 } 274 274 275 - /* Helper to change specific bits in controller registers */ 276 - static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, 277 - unsigned int addr, 278 - unsigned int mask, 279 - unsigned int val) 280 - { 281 - unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); 282 - 283 - data &= ~mask; 284 - data |= val; 285 - 286 - dw_hdmi->data->dwc_write(dw_hdmi, addr, data); 287 - } 288 - 289 275 /* Bridge */ 290 276 291 277 /* Setup PHY bandwidth modes */
+1
drivers/gpu/drm/msm/Kconfig
··· 6 6 depends on ARCH_QCOM || SOC_IMX5 || COMPILE_TEST 7 7 depends on COMMON_CLK 8 8 depends on IOMMU_SUPPORT 9 + depends on OF 9 10 depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n 10 11 depends on QCOM_OCMEM || QCOM_OCMEM=n 11 12 depends on QCOM_LLCC || QCOM_LLCC=n
+2 -2
drivers/gpu/drm/msm/dp/dp_display.c
··· 1467 1467 1468 1468 dp_priv = container_of(dp_display, struct dp_display_private, dp_display); 1469 1469 1470 - ret = dp_bridge_init(dp_display, dev, encoder); 1470 + ret = dp_bridge_init(dp_display, dev, encoder, yuv_supported); 1471 1471 if (ret) { 1472 1472 DRM_DEV_ERROR(dev->dev, 1473 1473 "failed to create dp bridge: %d\n", ret); 1474 1474 return ret; 1475 1475 } 1476 1476 1477 - dp_display->connector = dp_drm_connector_init(dp_display, encoder, yuv_supported); 1477 + dp_display->connector = dp_drm_connector_init(dp_display, encoder); 1478 1478 if (IS_ERR(dp_display->connector)) { 1479 1479 ret = PTR_ERR(dp_display->connector); 1480 1480 DRM_DEV_ERROR(dev->dev,
+4 -6
drivers/gpu/drm/msm/dp/dp_drm.c
··· 289 289 }; 290 290 291 291 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, 292 - struct drm_encoder *encoder) 292 + struct drm_encoder *encoder, bool yuv_supported) 293 293 { 294 294 int rc; 295 295 struct msm_dp_bridge *dp_bridge; ··· 304 304 bridge = &dp_bridge->bridge; 305 305 bridge->funcs = dp_display->is_edp ? &edp_bridge_ops : &dp_bridge_ops; 306 306 bridge->type = dp_display->connector_type; 307 + bridge->ycbcr_420_allowed = yuv_supported; 307 308 308 309 /* 309 310 * Many ops only make sense for DP. Why? ··· 352 351 } 353 352 354 353 /* connector initialization */ 355 - struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder, 356 - bool yuv_supported) 354 + struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, 355 + struct drm_encoder *encoder) 357 356 { 358 357 struct drm_connector *connector = NULL; 359 358 ··· 363 362 364 363 if (!dp_display->is_edp) 365 364 drm_connector_attach_dp_subconnector_property(connector); 366 - 367 - if (yuv_supported) 368 - connector->ycbcr_420_allowed = true; 369 365 370 366 drm_connector_attach_encoder(connector, encoder); 371 367
+4 -3
drivers/gpu/drm/msm/dp/dp_drm.h
··· 19 19 20 20 #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge) 21 21 22 - struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder, 23 - bool yuv_supported); 22 + struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, 23 + struct drm_encoder *encoder); 24 24 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, 25 - struct drm_encoder *encoder); 25 + struct drm_encoder *encoder, 26 + bool yuv_supported); 26 27 27 28 void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, 28 29 struct drm_bridge_state *old_bridge_state);
+3 -5
drivers/gpu/drm/nouveau/nouveau_display.c
··· 28 28 29 29 #include <drm/drm_atomic.h> 30 30 #include <drm/drm_atomic_helper.h> 31 + #include <drm/drm_client_event.h> 31 32 #include <drm/drm_crtc_helper.h> 32 - #include <drm/drm_fb_helper.h> 33 33 #include <drm/drm_fourcc.h> 34 34 #include <drm/drm_gem_framebuffer_helper.h> 35 35 #include <drm/drm_probe_helper.h> ··· 804 804 { 805 805 struct nouveau_display *disp = nouveau_display(dev); 806 806 807 - /* Disable console. */ 808 - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true); 807 + drm_client_dev_suspend(dev, false); 809 808 810 809 if (drm_drv_uses_atomic_modeset(dev)) { 811 810 if (!runtime) { ··· 835 836 } 836 837 } 837 838 838 - /* Enable console. */ 839 - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false); 839 + drm_client_dev_resume(dev, false); 840 840 } 841 841 842 842 int
+1 -1
drivers/gpu/drm/nouveau/nouveau_vga.c
··· 2 2 #include <linux/vgaarb.h> 3 3 #include <linux/vga_switcheroo.h> 4 4 5 - #include <drm/drm_fb_helper.h> 5 + #include <drm/drm_client_event.h> 6 6 7 7 #include "nouveau_drv.h" 8 8 #include "nouveau_acpi.h"
+1
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
··· 443 443 ret = gf100_grctx_generate(gr, chan, fifoch->inst); 444 444 if (ret) { 445 445 nvkm_error(&base->engine.subdev, "failed to construct context\n"); 446 + mutex_unlock(&gr->fecs.mutex); 446 447 return ret; 447 448 } 448 449 }
-146
drivers/gpu/drm/omapdrm/dss/dispc.c
··· 691 691 return mgr_desc[channel].sync_lost_irq; 692 692 } 693 693 694 - u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) 695 - { 696 - return DISPC_IRQ_FRAMEDONEWB; 697 - } 698 - 699 694 void dispc_mgr_enable(struct dispc_device *dispc, 700 695 enum omap_channel channel, bool enable) 701 696 { ··· 719 724 DSSDBG("GO %s\n", mgr_desc[channel].name); 720 725 721 726 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); 722 - } 723 - 724 - bool dispc_wb_go_busy(struct dispc_device *dispc) 725 - { 726 - return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; 727 - } 728 - 729 - void dispc_wb_go(struct dispc_device *dispc) 730 - { 731 - enum omap_plane_id plane = OMAP_DSS_WB; 732 - bool enable, go; 733 - 734 - enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; 735 - 736 - if (!enable) 737 - return; 738 - 739 - go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; 740 - if (go) { 741 - DSSERR("GO bit not down for WB\n"); 742 - return; 743 - } 744 - 745 - REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6); 746 727 } 747 728 748 729 static void dispc_ovl_write_firh_reg(struct dispc_device *dispc, ··· 1467 1496 dispc->feat->set_max_preload && plane != OMAP_DSS_WB) 1468 1497 dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane), 1469 1498 min(high, 0xfffu)); 1470 - } 1471 - 1472 - void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable) 1473 - { 1474 - if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) { 1475 - WARN_ON(enable); 1476 - return; 1477 - } 1478 - 1479 - DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); 1480 - REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14); 1481 1499 } 1482 1500 1483 1501 void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, ··· 2774 2814 return r; 2775 2815 } 2776 2816 2777 - int dispc_wb_setup(struct dispc_device *dispc, 2778 - const struct omap_dss_writeback_info *wi, 2779 - bool mem_to_mem, const struct videomode *vm, 2780 - enum dss_writeback_channel channel_in) 2781 - { 2782 - int r; 2783 - u32 l; 2784 - enum omap_plane_id plane = OMAP_DSS_WB; 2785 - const int pos_x = 0, pos_y = 0; 2786 - const u8 zorder = 0, global_alpha = 0; 2787 - const bool replication = true; 2788 - bool truncation; 2789 - int in_width = vm->hactive; 2790 - int in_height = vm->vactive; 2791 - enum omap_overlay_caps caps = 2792 - OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; 2793 - 2794 - if (vm->flags & DISPLAY_FLAGS_INTERLACED) 2795 - in_height /= 2; 2796 - 2797 - DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " 2798 - "rot %d\n", wi->paddr, wi->p_uv_addr, in_width, 2799 - in_height, wi->width, wi->height, wi->fourcc, wi->rotation); 2800 - 2801 - r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr, 2802 - wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, 2803 - wi->height, wi->fourcc, wi->rotation, zorder, 2804 - wi->pre_mult_alpha, global_alpha, wi->rotation_type, 2805 - replication, vm, mem_to_mem, DRM_COLOR_YCBCR_BT601, 2806 - DRM_COLOR_YCBCR_LIMITED_RANGE); 2807 - if (r) 2808 - return r; 2809 - 2810 - switch (wi->fourcc) { 2811 - case DRM_FORMAT_RGB565: 2812 - case DRM_FORMAT_RGB888: 2813 - case DRM_FORMAT_ARGB4444: 2814 - case DRM_FORMAT_RGBA4444: 2815 - case DRM_FORMAT_RGBX4444: 2816 - case DRM_FORMAT_ARGB1555: 2817 - case DRM_FORMAT_XRGB1555: 2818 - case DRM_FORMAT_XRGB4444: 2819 - truncation = true; 2820 - break; 2821 - default: 2822 - truncation = false; 2823 - break; 2824 - } 2825 - 2826 - /* setup extra DISPC_WB_ATTRIBUTES */ 2827 - l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 2828 - l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ 2829 - l = FLD_MOD(l, channel_in, 18, 16); /* CHANNELIN */ 2830 - l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ 2831 - if (mem_to_mem) 2832 - l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */ 2833 - else 2834 - l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */ 2835 - dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); 2836 - 2837 - if (mem_to_mem) { 2838 - /* WBDELAYCOUNT */ 2839 - REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); 2840 - } else { 2841 - u32 wbdelay; 2842 - 2843 - if (channel_in == DSS_WB_TV_MGR) 2844 - wbdelay = vm->vsync_len + vm->vback_porch; 2845 - else 2846 - wbdelay = vm->vfront_porch + vm->vsync_len + 2847 - vm->vback_porch; 2848 - 2849 - if (vm->flags & DISPLAY_FLAGS_INTERLACED) 2850 - wbdelay /= 2; 2851 - 2852 - wbdelay = min(wbdelay, 255u); 2853 - 2854 - /* WBDELAYCOUNT */ 2855 - REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); 2856 - } 2857 - 2858 - return 0; 2859 - } 2860 - 2861 - bool dispc_has_writeback(struct dispc_device *dispc) 2862 - { 2863 - return dispc->feat->has_writeback; 2864 - } 2865 - 2866 2817 int dispc_ovl_enable(struct dispc_device *dispc, 2867 2818 enum omap_plane_id plane, bool enable) 2868 2819 { ··· 3611 3740 3612 3741 dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div, 3613 3742 cinfo->pck_div); 3614 - } 3615 - 3616 - int dispc_mgr_get_clock_div(struct dispc_device *dispc, 3617 - enum omap_channel channel, 3618 - struct dispc_clock_info *cinfo) 3619 - { 3620 - unsigned long fck; 3621 - 3622 - fck = dispc_fclk_rate(dispc); 3623 - 3624 - cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); 3625 - cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0); 3626 - 3627 - cinfo->lck = fck / cinfo->lck_div; 3628 - cinfo->pck = cinfo->lck / cinfo->pck_div; 3629 - 3630 - return 0; 3631 3743 } 3632 3744 3633 3745 u32 dispc_read_irqstatus(struct dispc_device *dispc)
-13
drivers/gpu/drm/omapdrm/dss/dss.h
··· 416 416 enum omap_channel channel); 417 417 u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, 418 418 enum omap_channel channel); 419 - u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc); 420 419 421 420 u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc); 422 421 ··· 457 458 int dispc_ovl_enable(struct dispc_device *dispc, 458 459 enum omap_plane_id plane, bool enable); 459 460 460 - bool dispc_has_writeback(struct dispc_device *dispc); 461 - int dispc_wb_setup(struct dispc_device *dispc, 462 - const struct omap_dss_writeback_info *wi, 463 - bool mem_to_mem, const struct videomode *vm, 464 - enum dss_writeback_channel channel_in); 465 - bool dispc_wb_go_busy(struct dispc_device *dispc); 466 - void dispc_wb_go(struct dispc_device *dispc); 467 - 468 461 void dispc_enable_sidle(struct dispc_device *dispc); 469 462 void dispc_disable_sidle(struct dispc_device *dispc); 470 463 471 464 void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable); 472 465 void dispc_pck_free_enable(struct dispc_device *dispc, bool enable); 473 - void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable); 474 466 475 467 typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, 476 468 unsigned long pck, void *data); ··· 484 494 void dispc_mgr_set_clock_div(struct dispc_device *dispc, 485 495 enum omap_channel channel, 486 496 const struct dispc_clock_info *cinfo); 487 - int dispc_mgr_get_clock_div(struct dispc_device *dispc, 488 - enum omap_channel channel, 489 - struct dispc_clock_info *cinfo); 490 497 void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk); 491 498 492 499 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+10
drivers/gpu/drm/panel/Kconfig
··· 632 632 Say Y or M here if you want to enable support for the 633 633 Samsung AMS639RQ08 FHD Plus (2340x1080@60Hz) CMD mode panel. 634 634 635 + config DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24 636 + tristate "Samsung AMS427AP24 panel with S6E88A0 controller" 637 + depends on GPIOLIB && OF && REGULATOR 638 + depends on DRM_MIPI_DSI 639 + depends on BACKLIGHT_CLASS_DEVICE 640 + help 641 + Say Y here if you want to enable support for Samsung AMS427AP24 panel 642 + with S6E88A0 controller (found in Samsung Galaxy S4 Mini Value Edition 643 + GT-I9195I). To compile this driver as a module, choose M here. 644 + 635 645 config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 636 646 tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" 637 647 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 77 77 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o 78 78 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o 79 79 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o 80 + obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24) += panel-samsung-s6e88a0-ams427ap24.o 80 81 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o 81 82 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o 82 83 obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o
+1 -1
drivers/gpu/drm/panel/panel-ilitek-ili9322.c
··· 318 318 return spi_write_then_read(spi, buf, 1, val, 1); 319 319 } 320 320 321 - static struct regmap_bus ili9322_regmap_bus = { 321 + static const struct regmap_bus ili9322_regmap_bus = { 322 322 .write = ili9322_regmap_spi_write, 323 323 .read = ili9322_regmap_spi_read, 324 324 .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+131 -208
drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
··· 26 26 struct ltk050h3146w_desc { 27 27 const unsigned long mode_flags; 28 28 const struct drm_display_mode *mode; 29 - int (*init)(struct ltk050h3146w *ctx); 29 + void (*init)(struct mipi_dsi_multi_context *dsi_ctx); 30 30 }; 31 31 32 32 struct ltk050h3146w { ··· 243 243 return container_of(panel, struct ltk050h3146w, panel); 244 244 } 245 245 246 - static int ltk050h3148w_init_sequence(struct ltk050h3146w *ctx) 246 + static void ltk050h3148w_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 247 247 { 248 - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 249 - int ret; 250 - 251 248 /* 252 249 * Init sequence was supplied by the panel vendor without much 253 250 * documentation. 254 251 */ 255 - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0xff, 0x83, 0x94); 256 - mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, 257 - 0x71, 0x31, 0x55, 0x2f); 258 - mipi_dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 259 - mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x88); 260 - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07); 261 - mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70, 262 - 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74, 263 - 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86); 264 - mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e, 265 - 0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54, 266 - 0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05, 267 - 0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07, 268 - 0x17, 0x11, 0x40); 269 - mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 270 - 0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 271 - 0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23, 272 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 273 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 274 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 275 - mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 276 - 0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 277 - 0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20, 278 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 279 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 280 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 281 - mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14, 282 - 0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c, 283 - 0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58, 284 - 0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00, 285 - 0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e, 286 - 0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88, 287 - 0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b, 288 - 0x5d, 0x61, 0x65, 0x7f); 289 - mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x0b); 290 - mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31); 291 - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0xc4, 0xc4); 292 - mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x01); 293 - mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00); 294 - mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x00); 295 - mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xef); 296 - mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x02); 252 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0xff, 0x83, 0x94); 253 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, 254 + 0x71, 0x31, 0x55, 0x2f); 255 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 256 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x88); 257 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07); 258 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70, 259 + 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74, 260 + 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86); 261 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e, 262 + 0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54, 263 + 0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05, 264 + 0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07, 265 + 0x17, 0x11, 0x40); 266 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 267 + 0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 268 + 0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23, 269 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 270 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 271 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 272 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 273 + 0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 274 + 0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20, 275 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 276 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 277 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 278 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14, 279 + 0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c, 280 + 0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58, 281 + 0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00, 282 + 0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e, 283 + 0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88, 284 + 0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b, 285 + 0x5d, 0x61, 0x65, 0x7f); 286 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcc, 0x0b); 287 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x1f, 0x31); 288 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb6, 0xc4, 0xc4); 289 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 290 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x00); 291 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 292 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc6, 0xef); 293 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd4, 0x02); 297 294 298 - ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 299 - if (ret < 0) { 300 - dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 301 - return ret; 302 - } 303 - 304 - msleep(60); 305 - 306 - return 0; 295 + mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 1); 296 + mipi_dsi_msleep(dsi_ctx, 60); 307 297 } 308 298 309 299 static const struct drm_display_mode ltk050h3148w_mode = { ··· 317 327 MIPI_DSI_MODE_VIDEO_BURST, 318 328 }; 319 329 320 - static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) 330 + static void ltk050h3146w_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 321 331 { 322 - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 323 - int ret; 324 - 325 332 /* 326 333 * Init sequence was supplied by the panel vendor without much 327 334 * documentation. 328 335 */ 329 - mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8); 330 - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06, 331 - 0x01); 332 - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5); 333 - mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5); 334 - mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00); 336 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xdf, 0x93, 0x65, 0xf8); 337 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06, 338 + 0x01); 339 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x00, 0xb5); 340 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb3, 0x00, 0xb5); 341 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00); 335 342 336 - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07); 337 - mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f, 338 - 0x28, 0x04, 0xcc, 0xcc, 0xcc); 339 - mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04); 340 - mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2); 341 - mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03); 342 - mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12); 343 - mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80, 344 - 0x80); 345 - mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f, 346 - 0x16, 0x00, 0x00); 347 - mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50, 348 - 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f, 349 - 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67, 350 - 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55, 351 - 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08); 352 - mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a, 353 - 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f, 354 - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 355 - mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b, 356 - 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f, 357 - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 358 - mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05, 359 - 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f, 360 - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 361 - mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04, 362 - 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f, 363 - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 364 - mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20, 365 - 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03, 366 - 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08); 367 - mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00, 368 - 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05, 369 - 0x21, 0x00, 0x60); 370 - mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00); 371 - mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02); 372 - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c); 373 - mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04); 374 - mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11); 375 - mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37); 376 - mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84); 377 - mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00); 343 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0xc4, 0x23, 0x07); 344 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f, 345 + 0x28, 0x04, 0xcc, 0xcc, 0xcc); 346 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbc, 0x0f, 0x04); 347 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x1e, 0xf2); 348 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x26, 0x03); 349 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc1, 0x00, 0x12); 350 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80, 351 + 0x80); 352 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f, 353 + 0x16, 0x00, 0x00); 354 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50, 355 + 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f, 356 + 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67, 357 + 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55, 358 + 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08); 359 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a, 360 + 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f, 361 + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 362 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b, 363 + 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f, 364 + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 365 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05, 366 + 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f, 367 + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 368 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04, 369 + 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f, 370 + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 371 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20, 372 + 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03, 373 + 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08); 374 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00, 375 + 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05, 376 + 0x21, 0x00, 0x60); 377 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xdd, 0x2c, 0xa3, 0x00); 378 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xde, 0x02); 379 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x32, 0x1c); 380 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb7, 0x3b, 0x70, 0x00, 0x04); 381 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc1, 0x11); 382 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37); 383 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc2, 0x20, 0x38, 0x1e, 0x84); 384 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xde, 0x00); 378 385 379 - ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 380 - if (ret < 0) { 381 - dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 382 - return ret; 383 - } 384 - 385 - msleep(60); 386 - 387 - return 0; 386 + mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 1); 387 + mipi_dsi_msleep(dsi_ctx, 60); 388 388 } 389 389 390 390 static const struct drm_display_mode ltk050h3146w_mode = { ··· 398 418 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, 399 419 }; 400 420 401 - static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page) 421 + static void ltk050h3146w_a2_select_page(struct mipi_dsi_multi_context *dsi_ctx, int page) 402 422 { 403 - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 404 - u8 d[3] = { 0x98, 0x81, page }; 423 + u8 d[4] = { 0xff, 0x98, 0x81, page }; 405 424 406 - return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d)); 425 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, d, ARRAY_SIZE(d)); 407 426 } 408 427 409 - static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, 428 + static void ltk050h3146w_a2_write_page(struct mipi_dsi_multi_context *dsi_ctx, int page, 410 429 const struct ltk050h3146w_cmd *cmds, 411 430 int num) 412 431 { 413 - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 414 - int i, ret; 432 + ltk050h3146w_a2_select_page(dsi_ctx, page); 415 433 416 - ret = ltk050h3146w_a2_select_page(ctx, page); 417 - if (ret < 0) { 418 - dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret); 419 - return ret; 420 - } 421 - 422 - for (i = 0; i < num; i++) { 423 - ret = mipi_dsi_generic_write(dsi, &cmds[i], 434 + for (int i = 0; i < num; i++) 435 + mipi_dsi_generic_write_multi(dsi_ctx, &cmds[i], 424 436 sizeof(struct ltk050h3146w_cmd)); 425 - if (ret < 0) { 426 - dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret); 427 - return ret; 428 - } 429 - } 430 - 431 - return 0; 432 437 } 433 438 434 - static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx) 439 + static void ltk050h3146w_a2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 435 440 { 436 - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 437 - int ret; 438 - 439 441 /* 440 442 * Init sequence was supplied by the panel vendor without much 441 443 * documentation. 442 444 */ 443 - ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds, 445 + ltk050h3146w_a2_write_page(dsi_ctx, 3, page3_cmds, 444 446 ARRAY_SIZE(page3_cmds)); 445 - if (ret < 0) 446 - return ret; 447 - 448 - ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds, 447 + ltk050h3146w_a2_write_page(dsi_ctx, 4, page4_cmds, 449 448 ARRAY_SIZE(page4_cmds)); 450 - if (ret < 0) 451 - return ret; 452 - 453 - ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds, 449 + ltk050h3146w_a2_write_page(dsi_ctx, 1, page1_cmds, 454 450 ARRAY_SIZE(page1_cmds)); 455 - if (ret < 0) 456 - return ret; 457 - 458 - ret = ltk050h3146w_a2_select_page(ctx, 0); 459 - if (ret < 0) { 460 - dev_err(ctx->dev, "failed to select page 0: %d\n", ret); 461 - return ret; 462 - } 451 + ltk050h3146w_a2_select_page(dsi_ctx, 0); 463 452 464 453 /* vendor code called this without param, where there should be one */ 465 - ret = mipi_dsi_dcs_set_tear_on(dsi, 0); 466 - if (ret < 0) { 467 - dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 468 - return ret; 469 - } 454 + mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 0); 470 455 471 - msleep(60); 472 - 473 - return 0; 456 + mipi_dsi_msleep(dsi_ctx, 60); 474 457 } 475 458 476 459 static const struct drm_display_mode ltk050h3146w_a2_mode = { ··· 461 518 { 462 519 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 463 520 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 464 - int ret; 521 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 465 522 466 - ret = mipi_dsi_dcs_set_display_off(dsi); 467 - if (ret < 0) { 468 - dev_err(ctx->dev, "failed to set display off: %d\n", ret); 469 - return ret; 470 - } 471 - 472 - mipi_dsi_dcs_enter_sleep_mode(dsi); 473 - if (ret < 0) { 474 - dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); 475 - return ret; 476 - } 523 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 524 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 525 + if (dsi_ctx.accum_err) 526 + return dsi_ctx.accum_err; 477 527 478 528 regulator_disable(ctx->iovcc); 479 529 regulator_disable(ctx->vci); ··· 478 542 { 479 543 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 480 544 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 481 - int ret; 545 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 482 546 483 547 dev_dbg(ctx->dev, "Resetting the panel\n"); 484 - ret = regulator_enable(ctx->vci); 485 - if (ret < 0) { 486 - dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); 487 - return ret; 548 + dsi_ctx.accum_err = regulator_enable(ctx->vci); 549 + if (dsi_ctx.accum_err) { 550 + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", dsi_ctx.accum_err); 551 + return dsi_ctx.accum_err; 488 552 } 489 - ret = regulator_enable(ctx->iovcc); 490 - if (ret < 0) { 491 - dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 553 + dsi_ctx.accum_err = regulator_enable(ctx->iovcc); 554 + if (dsi_ctx.accum_err) { 555 + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", dsi_ctx.accum_err); 492 556 goto disable_vci; 493 557 } 494 558 ··· 497 561 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 498 562 msleep(20); 499 563 500 - ret = ctx->panel_desc->init(ctx); 501 - if (ret < 0) { 502 - dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); 503 - goto disable_iovcc; 504 - } 505 - 506 - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 507 - if (ret < 0) { 508 - dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); 509 - goto disable_iovcc; 510 - } 511 - 564 + ctx->panel_desc->init(&dsi_ctx); 565 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 512 566 /* T9: 120ms */ 513 - msleep(120); 567 + mipi_dsi_msleep(&dsi_ctx, 120); 568 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 569 + mipi_dsi_msleep(&dsi_ctx, 50); 514 570 515 - ret = mipi_dsi_dcs_set_display_on(dsi); 516 - if (ret < 0) { 517 - dev_err(ctx->dev, "Failed to set display on: %d\n", ret); 571 + if (dsi_ctx.accum_err) 518 572 goto disable_iovcc; 519 - } 520 - 521 - msleep(50); 522 573 523 574 return 0; 524 575 ··· 513 590 regulator_disable(ctx->iovcc); 514 591 disable_vci: 515 592 regulator_disable(ctx->vci); 516 - return ret; 593 + return dsi_ctx.accum_err; 517 594 } 518 595 519 596 static int ltk050h3146w_get_modes(struct drm_panel *panel,
+1 -1
drivers/gpu/drm/panel/panel-newvision-nv3052c.c
··· 917 917 static const struct spi_device_id nv3052c_ids[] = { 918 918 { "ltk035c5444t", }, 919 919 { "fs035vg158", }, 920 - { "wl-355608-a8", }, 920 + { "rg35xx-plus-panel", }, 921 921 { /* sentinel */ } 922 922 }; 923 923 MODULE_DEVICE_TABLE(spi, nv3052c_ids);
+1 -1
drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c
··· 24 24 struct regulator_bulk_data *supplies; 25 25 }; 26 26 27 - const struct regulator_bulk_data s6e3ha8_supplies[] = { 27 + static const struct regulator_bulk_data s6e3ha8_supplies[] = { 28 28 { .supply = "vdd3" }, 29 29 { .supply = "vci" }, 30 30 { .supply = "vddr" },
+766
drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Samsung AMS427AP24 panel with S6E88A0 controller 4 + * Copyright (c) 2024 Jakob Hauser <jahau@rocketmail.com> 5 + */ 6 + 7 + #include <linux/backlight.h> 8 + #include <linux/delay.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/module.h> 11 + #include <linux/regulator/consumer.h> 12 + 13 + #include <video/mipi_display.h> 14 + 15 + #include <drm/drm_mipi_dsi.h> 16 + #include <drm/drm_modes.h> 17 + #include <drm/drm_panel.h> 18 + #include <drm/drm_probe_helper.h> 19 + 20 + #define NUM_STEPS_CANDELA 54 21 + #define NUM_STEPS_AID 39 22 + #define NUM_STEPS_ELVSS 17 23 + 24 + /* length of the payload data, thereof fixed and variable */ 25 + #define FIX_LEN_AID 4 26 + #define FIX_LEN_ELVSS 2 27 + #define FIX_LEN_GAMMA 1 28 + #define VAR_LEN_AID 2 29 + #define VAR_LEN_ELVSS 1 30 + #define VAR_LEN_GAMMA 33 31 + #define LEN_AID (FIX_LEN_AID + VAR_LEN_AID) 32 + #define LEN_ELVSS (FIX_LEN_ELVSS + VAR_LEN_ELVSS) 33 + #define LEN_GAMMA (FIX_LEN_GAMMA + VAR_LEN_GAMMA) 34 + 35 + struct s6e88a0_ams427ap24 { 36 + struct drm_panel panel; 37 + struct backlight_device *bl_dev; 38 + struct mipi_dsi_device *dsi; 39 + struct regulator_bulk_data *supplies; 40 + struct gpio_desc *reset_gpio; 41 + bool flip_horizontal; 42 + }; 43 + 44 + static const struct regulator_bulk_data s6e88a0_ams427ap24_supplies[] = { 45 + { .supply = "vdd3" }, 46 + { .supply = "vci" }, 47 + }; 48 + 49 + static inline 50 + struct s6e88a0_ams427ap24 *to_s6e88a0_ams427ap24(struct drm_panel *panel) 51 + { 52 + return container_of(panel, struct s6e88a0_ams427ap24, panel); 53 + } 54 + 55 + enum candela { 56 + CANDELA_10CD, /* 0 */ 57 + CANDELA_11CD, 58 + CANDELA_12CD, 59 + CANDELA_13CD, 60 + CANDELA_14CD, 61 + CANDELA_15CD, 62 + CANDELA_16CD, 63 + CANDELA_17CD, 64 + CANDELA_19CD, 65 + CANDELA_20CD, 66 + CANDELA_21CD, 67 + CANDELA_22CD, 68 + CANDELA_24CD, 69 + CANDELA_25CD, 70 + CANDELA_27CD, 71 + CANDELA_29CD, 72 + CANDELA_30CD, 73 + CANDELA_32CD, 74 + CANDELA_34CD, 75 + CANDELA_37CD, 76 + CANDELA_39CD, 77 + CANDELA_41CD, 78 + CANDELA_44CD, 79 + CANDELA_47CD, 80 + CANDELA_50CD, 81 + CANDELA_53CD, 82 + CANDELA_56CD, 83 + CANDELA_60CD, 84 + CANDELA_64CD, 85 + CANDELA_68CD, 86 + CANDELA_72CD, 87 + CANDELA_77CD, 88 + CANDELA_82CD, 89 + CANDELA_87CD, 90 + CANDELA_93CD, 91 + CANDELA_98CD, 92 + CANDELA_105CD, 93 + CANDELA_111CD, 94 + CANDELA_119CD, 95 + CANDELA_126CD, 96 + CANDELA_134CD, 97 + CANDELA_143CD, 98 + CANDELA_152CD, 99 + CANDELA_162CD, 100 + CANDELA_172CD, 101 + CANDELA_183CD, 102 + CANDELA_195CD, 103 + CANDELA_207CD, 104 + CANDELA_220CD, 105 + CANDELA_234CD, 106 + CANDELA_249CD, 107 + CANDELA_265CD, 108 + CANDELA_282CD, 109 + CANDELA_300CD, /* 53 */ 110 + }; 111 + 112 + static const int s6e88a0_ams427ap24_br_to_cd[NUM_STEPS_CANDELA] = { 113 + /* columns: brightness from, brightness till, candela */ 114 + /* 0 */ 10, /* 10CD */ 115 + /* 11 */ 11, /* 11CD */ 116 + /* 12 */ 12, /* 12CD */ 117 + /* 13 */ 13, /* 13CD */ 118 + /* 14 */ 14, /* 14CD */ 119 + /* 15 */ 15, /* 15CD */ 120 + /* 16 */ 16, /* 16CD */ 121 + /* 17 */ 17, /* 17CD */ 122 + /* 18 */ 18, /* 19CD */ 123 + /* 19 */ 19, /* 20CD */ 124 + /* 20 */ 20, /* 21CD */ 125 + /* 21 */ 21, /* 22CD */ 126 + /* 22 */ 22, /* 24CD */ 127 + /* 23 */ 23, /* 25CD */ 128 + /* 24 */ 24, /* 27CD */ 129 + /* 25 */ 25, /* 29CD */ 130 + /* 26 */ 26, /* 30CD */ 131 + /* 27 */ 27, /* 32CD */ 132 + /* 28 */ 28, /* 34CD */ 133 + /* 29 */ 29, /* 37CD */ 134 + /* 30 */ 30, /* 39CD */ 135 + /* 31 */ 32, /* 41CD */ 136 + /* 33 */ 34, /* 44CD */ 137 + /* 35 */ 36, /* 47CD */ 138 + /* 37 */ 38, /* 50CD */ 139 + /* 39 */ 40, /* 53CD */ 140 + /* 41 */ 43, /* 56CD */ 141 + /* 44 */ 46, /* 60CD */ 142 + /* 47 */ 49, /* 64CD */ 143 + /* 50 */ 52, /* 68CD */ 144 + /* 53 */ 56, /* 72CD */ 145 + /* 57 */ 59, /* 77CD */ 146 + /* 60 */ 63, /* 82CD */ 147 + /* 64 */ 67, /* 87CD */ 148 + /* 68 */ 71, /* 93CD */ 149 + /* 72 */ 76, /* 98CD */ 150 + /* 77 */ 80, /* 105CD */ 151 + /* 81 */ 86, /* 111CD */ 152 + /* 87 */ 91, /* 119CD */ 153 + /* 92 */ 97, /* 126CD */ 154 + /* 98 */ 104, /* 134CD */ 155 + /* 105 */ 110, /* 143CD */ 156 + /* 111 */ 118, /* 152CD */ 157 + /* 119 */ 125, /* 162CD */ 158 + /* 126 */ 133, /* 172CD */ 159 + /* 134 */ 142, /* 183CD */ 160 + /* 143 */ 150, /* 195CD */ 161 + /* 151 */ 160, /* 207CD */ 162 + /* 161 */ 170, /* 220CD */ 163 + /* 171 */ 181, /* 234CD */ 164 + /* 182 */ 205, /* 249CD */ 165 + /* 206 */ 234, /* 265CD */ 166 + /* 235 */ 254, /* 282CD */ 167 + /* 255 */ 255, /* 300CD */ 168 + }; 169 + 170 + static const u8 s6e88a0_ams427ap24_aid[NUM_STEPS_AID][VAR_LEN_AID] = { 171 + { 0x03, 0x77 }, /* AOR 90.9%, 10CD */ 172 + { 0x03, 0x73 }, /* AOR 90.5%, 11CD */ 173 + { 0x03, 0x69 }, /* AOR 89.4%, 12CD */ 174 + { 0x03, 0x65 }, /* AOR 89.0%, 13CD */ 175 + { 0x03, 0x61 }, /* AOR 88.6%, 14CD */ 176 + { 0x03, 0x55 }, /* AOR 87.4%, 15CD */ 177 + { 0x03, 0x50 }, /* AOR 86.9%, 16CD */ 178 + { 0x03, 0x45 }, /* AOR 85.8%, 17CD */ 179 + { 0x03, 0x35 }, /* AOR 84.1%, 19CD */ 180 + { 0x03, 0x27 }, /* AOR 82.7%, 20CD */ 181 + { 0x03, 0x23 }, /* AOR 82.3%, 21CD */ 182 + { 0x03, 0x17 }, /* AOR 81.0%, 22CD */ 183 + { 0x03, 0x11 }, /* AOR 80.4%, 24CD */ 184 + { 0x03, 0x04 }, /* AOR 79.1%, 25CD */ 185 + { 0x02, 0xf4 }, /* AOR 77.5%, 27CD */ 186 + { 0x02, 0xe3 }, /* AOR 75.7%, 29CD */ 187 + { 0x02, 0xd7 }, /* AOR 74.5%, 30CD */ 188 + { 0x02, 0xc6 }, /* AOR 72.7%, 32CD */ 189 + { 0x02, 0xb7 }, /* AOR 71.2%, 34CD */ 190 + { 0x02, 0xa1 }, /* AOR 69.0%, 37CD */ 191 + { 0x02, 0x91 }, /* AOR 67.3%, 39CD */ 192 + { 0x02, 0x78 }, /* AOR 64.8%, 41CD */ 193 + { 0x02, 0x62 }, /* AOR 62.5%, 44CD */ 194 + { 0x02, 0x45 }, /* AOR 59.5%, 47CD */ 195 + { 0x02, 0x30 }, /* AOR 57.4%, 50CD */ 196 + { 0x02, 0x13 }, /* AOR 54.4%, 53CD */ 197 + { 0x01, 0xf5 }, /* AOR 51.3%, 56CD */ 198 + { 0x01, 0xd3 }, /* AOR 47.8%, 60CD */ 199 + { 0x01, 0xb1 }, /* AOR 44.4%, 64CD */ 200 + { 0x01, 0x87 }, /* AOR 40.1%, 68CD */ 201 + { 0x01, 0x63 }, /* AOR 36.6%, 72CD */ 202 + { 0x01, 0x35 }, /* AOR 31.7%, 77CD */ 203 + { 0x01, 0x05 }, /* AOR 26.9%, 82CD */ 204 + { 0x00, 0xd5 }, /* AOR 21.8%, 87CD */ 205 + { 0x00, 0xa1 }, /* AOR 16.5%, 93CD */ 206 + { 0x00, 0x6f }, /* AOR 11.4%, 98CD */ 207 + { 0x00, 0x31 }, /* AOR 5.0%, 105CD */ 208 + { 0x01, 0x86 }, /* AOR 40.0%, 111CD ~ 172CD */ 209 + { 0x00, 0x08 }, /* AOR 0.6%, 183CD ~ 300CD */ 210 + }; 211 + 212 + static const u8 s6e88a0_ams427ap24_elvss[NUM_STEPS_ELVSS][VAR_LEN_ELVSS] = { 213 + { 0x14 }, /* 10CD ~ 111CD */ 214 + { 0x13 }, /* 119CD */ 215 + { 0x12 }, /* 126CD */ 216 + { 0x12 }, /* 134CD */ 217 + { 0x11 }, /* 143CD */ 218 + { 0x10 }, /* 152CD */ 219 + { 0x0f }, /* 162CD */ 220 + { 0x0e }, /* 172CD */ 221 + { 0x11 }, /* 183CD */ 222 + { 0x11 }, /* 195CD */ 223 + { 0x10 }, /* 207CD */ 224 + { 0x0f }, /* 220CD */ 225 + { 0x0f }, /* 234CD */ 226 + { 0x0e }, /* 249CD */ 227 + { 0x0d }, /* 265CD */ 228 + { 0x0c }, /* 282CD */ 229 + { 0x0b }, /* 300CD */ 230 + }; 231 + 232 + static const u8 s6e88a0_ams427ap24_gamma[NUM_STEPS_CANDELA][VAR_LEN_GAMMA] = { 233 + /* 10CD */ 234 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8b, 235 + 0x8c, 0x87, 0x89, 0x89, 0x88, 0x87, 0x8c, 0x80, 0x82, 0x88, 0x7b, 236 + 0x72, 0x8c, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 237 + /* 11CD */ 238 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8b, 239 + 0x8c, 0x87, 0x89, 0x89, 0x88, 0x87, 0x8c, 0x80, 0x82, 0x88, 0x7b, 240 + 0x72, 0x8c, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 241 + /* 12CD */ 242 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8b, 0x8b, 243 + 0x8c, 0x88, 0x89, 0x8a, 0x88, 0x87, 0x8c, 0x81, 0x82, 0x87, 0x7a, 244 + 0x72, 0x8b, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 245 + /* 13CD */ 246 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8b, 0x8b, 247 + 0x8c, 0x88, 0x89, 0x8a, 0x88, 0x87, 0x8c, 0x81, 0x82, 0x87, 0x7a, 248 + 0x72, 0x8b, 0x61, 0x69, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 249 + /* 14CD */ 250 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 251 + 0x8c, 0x88, 0x89, 0x8a, 0x87, 0x86, 0x8a, 0x82, 0x82, 0x87, 0x79, 252 + 0x71, 0x89, 0x63, 0x6c, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 253 + /* 15CD */ 254 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8c, 255 + 0x8c, 0x86, 0x87, 0x88, 0x85, 0x85, 0x8a, 0x83, 0x83, 0x88, 0x78, 256 + 0x72, 0x89, 0x64, 0x6c, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 257 + /* 16CD */ 258 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 259 + 0x8c, 0x86, 0x88, 0x88, 0x86, 0x86, 0x8a, 0x84, 0x84, 0x88, 0x78, 260 + 0x72, 0x89, 0x5d, 0x67, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 261 + /* 17CD */ 262 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 263 + 0x8b, 0x87, 0x89, 0x89, 0x86, 0x86, 0x8a, 0x84, 0x83, 0x87, 0x78, 264 + 0x73, 0x89, 0x64, 0x6e, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 265 + /* 19CD */ 266 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 267 + 0x8b, 0x87, 0x89, 0x89, 0x86, 0x86, 0x89, 0x84, 0x84, 0x87, 0x77, 268 + 0x72, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 269 + /* 20CD */ 270 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 271 + 0x8b, 0x88, 0x89, 0x89, 0x85, 0x85, 0x88, 0x82, 0x83, 0x85, 0x79, 272 + 0x73, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 273 + /* 21CD */ 274 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 275 + 0x8b, 0x88, 0x89, 0x89, 0x85, 0x85, 0x88, 0x82, 0x83, 0x85, 0x79, 276 + 0x74, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 277 + /* 22CD */ 278 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 279 + 0x8c, 0x86, 0x88, 0x87, 0x86, 0x86, 0x89, 0x82, 0x83, 0x85, 0x7c, 280 + 0x75, 0x87, 0x65, 0x6f, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 281 + /* 24CD */ 282 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 283 + 0x8c, 0x86, 0x88, 0x87, 0x86, 0x86, 0x89, 0x82, 0x83, 0x85, 0x7c, 284 + 0x76, 0x86, 0x66, 0x6f, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 285 + /* 25CD */ 286 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 287 + 0x8b, 0x86, 0x89, 0x88, 0x87, 0x87, 0x89, 0x82, 0x82, 0x84, 0x7f, 288 + 0x7a, 0x89, 0x6b, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 289 + /* 27CD */ 290 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 291 + 0x8b, 0x86, 0x89, 0x88, 0x87, 0x87, 0x89, 0x82, 0x82, 0x84, 0x7f, 292 + 0x7a, 0x89, 0x6b, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 293 + /* 29CD */ 294 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 295 + 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 296 + 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 297 + /* 30CD */ 298 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 299 + 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 300 + 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 301 + /* 32CD */ 302 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 303 + 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 304 + 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 305 + /* 34CD */ 306 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 307 + 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x83, 0x84, 0x84, 0x7f, 308 + 0x79, 0x86, 0x6c, 0x76, 0x91, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 309 + /* 37CD */ 310 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 311 + 0x8b, 0x86, 0x88, 0x88, 0x87, 0x86, 0x87, 0x83, 0x84, 0x84, 0x7f, 312 + 0x79, 0x86, 0x6c, 0x76, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 313 + /* 39CD */ 314 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 315 + 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x83, 0x85, 0x85, 0x80, 316 + 0x79, 0x85, 0x6c, 0x76, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 317 + /* 41CD */ 318 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 319 + 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x81, 0x84, 0x83, 0x7f, 320 + 0x79, 0x84, 0x6e, 0x79, 0x93, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 321 + /* 44CD */ 322 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 323 + 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x81, 0x84, 0x83, 0x7f, 324 + 0x79, 0x84, 0x6e, 0x79, 0x92, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 325 + /* 47CD */ 326 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 327 + 0x8b, 0x86, 0x88, 0x87, 0x84, 0x85, 0x86, 0x81, 0x84, 0x83, 0x7f, 328 + 0x79, 0x83, 0x6f, 0x79, 0x91, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 329 + /* 50CD */ 330 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 331 + 0x8b, 0x86, 0x88, 0x87, 0x84, 0x85, 0x86, 0x82, 0x84, 0x83, 0x7f, 332 + 0x79, 0x83, 0x6f, 0x79, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 333 + /* 53CD */ 334 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 335 + 0x8b, 0x86, 0x88, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x85, 0x7f, 336 + 0x79, 0x83, 0x70, 0x79, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 337 + /* 56CD */ 338 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 339 + 0x8a, 0x87, 0x89, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x84, 0x7f, 340 + 0x79, 0x82, 0x70, 0x7a, 0x8e, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 341 + /* 60CD */ 342 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 343 + 0x8a, 0x87, 0x89, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x84, 0x7e, 344 + 0x79, 0x82, 0x71, 0x7a, 0x8d, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 345 + /* 64CD */ 346 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 347 + 0x8a, 0x86, 0x88, 0x86, 0x84, 0x84, 0x86, 0x82, 0x83, 0x82, 0x80, 348 + 0x7a, 0x84, 0x71, 0x7a, 0x8c, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 349 + /* 68CD */ 350 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 351 + 0x8a, 0x86, 0x88, 0x86, 0x84, 0x84, 0x86, 0x82, 0x84, 0x82, 0x81, 352 + 0x7b, 0x83, 0x72, 0x7b, 0x8b, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 353 + /* 72CD */ 354 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 355 + 0x8a, 0x86, 0x88, 0x86, 0x85, 0x85, 0x86, 0x82, 0x84, 0x82, 0x81, 356 + 0x7b, 0x83, 0x72, 0x7c, 0x8a, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 357 + /* 77CD */ 358 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 359 + 0x8a, 0x85, 0x87, 0x85, 0x85, 0x87, 0x87, 0x82, 0x84, 0x82, 0x81, 360 + 0x7c, 0x82, 0x72, 0x7c, 0x89, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 361 + /* 82CD */ 362 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 363 + 0x8a, 0x85, 0x87, 0x85, 0x85, 0x87, 0x87, 0x82, 0x84, 0x82, 0x81, 364 + 0x7c, 0x82, 0x73, 0x7c, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 365 + /* 87CD */ 366 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 367 + 0x8a, 0x85, 0x87, 0x85, 0x84, 0x84, 0x86, 0x80, 0x84, 0x81, 0x80, 368 + 0x7a, 0x82, 0x76, 0x7f, 0x89, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 369 + /* 93CD */ 370 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8b, 0x8a, 371 + 0x8a, 0x86, 0x87, 0x85, 0x84, 0x85, 0x86, 0x80, 0x84, 0x80, 0x80, 372 + 0x7a, 0x82, 0x76, 0x80, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 373 + /* 98CD */ 374 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8b, 0x8a, 375 + 0x8a, 0x86, 0x87, 0x85, 0x85, 0x85, 0x86, 0x80, 0x84, 0x80, 0x80, 376 + 0x7a, 0x82, 0x76, 0x80, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 377 + /* 105CD */ 378 + { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x89, 0x88, 0x88, 0x8b, 0x8a, 379 + 0x8a, 0x84, 0x87, 0x85, 0x85, 0x85, 0x85, 0x80, 0x84, 0x80, 0x7f, 380 + 0x79, 0x81, 0x71, 0x7d, 0x87, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 381 + /* 111CD */ 382 + { 0x00, 0xdf, 0x00, 0xde, 0x00, 0xde, 0x85, 0x85, 0x84, 0x87, 0x86, 383 + 0x87, 0x85, 0x86, 0x85, 0x83, 0x83, 0x83, 0x81, 0x82, 0x82, 0x80, 384 + 0x7d, 0x82, 0x75, 0x7f, 0x86, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 385 + /* 119CD */ 386 + { 0x00, 0xe3, 0x00, 0xe1, 0x00, 0xe2, 0x85, 0x85, 0x84, 0x86, 0x85, 387 + 0x85, 0x84, 0x85, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x7e, 388 + 0x7b, 0x81, 0x75, 0x7f, 0x86, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 389 + /* 126CD */ 390 + { 0x00, 0xe6, 0x00, 0xe5, 0x00, 0xe5, 0x85, 0x84, 0x84, 0x85, 0x85, 391 + 0x85, 0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x80, 0x81, 0x81, 0x80, 392 + 0x7f, 0x83, 0x73, 0x7c, 0x84, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 393 + /* 134CD */ 394 + { 0x00, 0xe9, 0x00, 0xe8, 0x00, 0xe8, 0x84, 0x84, 0x83, 0x85, 0x85, 395 + 0x85, 0x84, 0x84, 0x83, 0x81, 0x82, 0x82, 0x81, 0x81, 0x81, 0x7f, 396 + 0x7d, 0x81, 0x73, 0x7c, 0x83, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 397 + /* 143CD */ 398 + { 0x00, 0xed, 0x00, 0xec, 0x00, 0xec, 0x84, 0x83, 0x83, 0x84, 0x84, 399 + 0x84, 0x84, 0x84, 0x83, 0x82, 0x83, 0x83, 0x81, 0x80, 0x81, 0x7f, 400 + 0x7e, 0x81, 0x70, 0x79, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 401 + /* 152CD */ 402 + { 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x83, 0x83, 0x83, 0x83, 0x83, 403 + 0x83, 0x84, 0x84, 0x83, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 404 + 0x80, 0x82, 0x6f, 0x78, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 405 + /* 162CD */ 406 + { 0x00, 0xf4, 0x00, 0xf3, 0x00, 0xf4, 0x83, 0x83, 0x83, 0x83, 0x83, 407 + 0x83, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 408 + 0x7f, 0x82, 0x6f, 0x78, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 409 + /* 172CD */ 410 + { 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf8, 0x82, 0x82, 0x82, 0x82, 0x82, 411 + 0x82, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 412 + 0x80, 0x83, 0x6d, 0x76, 0x7d, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 413 + /* 183CD */ 414 + { 0x00, 0xe0, 0x00, 0xdf, 0x00, 0xdf, 0x84, 0x84, 0x83, 0x86, 0x86, 415 + 0x86, 0x83, 0x84, 0x83, 0x82, 0x82, 0x82, 0x81, 0x83, 0x81, 0x81, 416 + 0x7e, 0x81, 0x80, 0x82, 0x84, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 417 + /* 195CD */ 418 + { 0x00, 0xe4, 0x00, 0xe3, 0x00, 0xe3, 0x84, 0x83, 0x83, 0x85, 0x85, 419 + 0x85, 0x83, 0x84, 0x83, 0x81, 0x82, 0x82, 0x82, 0x83, 0x81, 0x81, 420 + 0x80, 0x82, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 421 + /* 207CD */ 422 + { 0x00, 0xe7, 0x00, 0xe6, 0x00, 0xe6, 0x83, 0x82, 0x82, 0x85, 0x85, 423 + 0x85, 0x82, 0x83, 0x83, 0x82, 0x82, 0x82, 0x80, 0x81, 0x80, 0x81, 424 + 0x80, 0x82, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 425 + /* 220CD */ 426 + { 0x00, 0xeb, 0x00, 0xea, 0x00, 0xea, 0x83, 0x83, 0x82, 0x84, 0x84, 427 + 0x84, 0x82, 0x83, 0x82, 0x81, 0x81, 0x82, 0x81, 0x82, 0x81, 0x80, 428 + 0x7e, 0x80, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 429 + /* 234CD */ 430 + { 0x00, 0xef, 0x00, 0xee, 0x00, 0xee, 0x83, 0x82, 0x82, 0x83, 0x83, 431 + 0x83, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 432 + 0x80, 0x81, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 433 + /* 249CD */ 434 + { 0x00, 0xf3, 0x00, 0xf2, 0x00, 0xf2, 0x82, 0x81, 0x81, 0x83, 0x83, 435 + 0x83, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x81, 0x80, 0x7f, 436 + 0x7e, 0x7f, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 437 + /* 265CD */ 438 + { 0x00, 0xf7, 0x00, 0xf7, 0x00, 0xf7, 0x81, 0x81, 0x80, 0x82, 0x82, 439 + 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 440 + 0x7e, 0x7f, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 441 + /* 282CD */ 442 + { 0x00, 0xfb, 0x00, 0xfb, 0x00, 0xfb, 0x80, 0x80, 0x80, 0x81, 0x81, 443 + 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 444 + 0x7f, 0x7f, 0x78, 0x79, 0x7d, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 445 + /* 300CD */ 446 + { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 447 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 448 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00 }, 449 + }; 450 + 451 + static int s6e88a0_ams427ap24_set_brightness(struct backlight_device *bd) 452 + { 453 + struct s6e88a0_ams427ap24 *ctx = bl_get_data(bd); 454 + struct mipi_dsi_device *dsi = ctx->dsi; 455 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 456 + struct device *dev = &dsi->dev; 457 + int brightness = bd->props.brightness; 458 + int candela_enum; 459 + u8 b2[LEN_AID] = { 0xb2, 0x40, 0x08, 0x20, 0x00, 0x00 }; 460 + u8 b6[LEN_ELVSS] = { 0xb6, 0x28, 0x00 }; 461 + u8 ca[LEN_GAMMA]; 462 + 463 + /* get candela enum from brightness */ 464 + for (candela_enum = 0; candela_enum < NUM_STEPS_CANDELA; candela_enum++) 465 + if (brightness <= s6e88a0_ams427ap24_br_to_cd[candela_enum]) 466 + break; 467 + 468 + /* get aid */ 469 + switch (candela_enum) { 470 + case CANDELA_10CD ... CANDELA_105CD: 471 + memcpy(&b2[FIX_LEN_AID], 472 + s6e88a0_ams427ap24_aid[candela_enum], 473 + VAR_LEN_AID); 474 + break; 475 + case CANDELA_111CD ... CANDELA_172CD: 476 + memcpy(&b2[FIX_LEN_AID], 477 + s6e88a0_ams427ap24_aid[CANDELA_111CD], 478 + VAR_LEN_AID); 479 + break; 480 + case CANDELA_183CD ... CANDELA_300CD: 481 + memcpy(&b2[FIX_LEN_AID], 482 + s6e88a0_ams427ap24_aid[CANDELA_111CD + 1], 483 + VAR_LEN_AID); 484 + break; 485 + default: 486 + dev_err(dev, "Failed to get aid data\n"); 487 + return -EINVAL; 488 + } 489 + 490 + /* get elvss */ 491 + if (candela_enum <= CANDELA_111CD) { 492 + memcpy(&b6[FIX_LEN_ELVSS], 493 + s6e88a0_ams427ap24_elvss[0], 494 + VAR_LEN_ELVSS); 495 + } else { 496 + memcpy(&b6[FIX_LEN_ELVSS], 497 + s6e88a0_ams427ap24_elvss[candela_enum - CANDELA_111CD], 498 + VAR_LEN_ELVSS); 499 + } 500 + 501 + /* get gamma */ 502 + ca[0] = 0xca; 503 + memcpy(&ca[FIX_LEN_GAMMA], 504 + s6e88a0_ams427ap24_gamma[candela_enum], 505 + VAR_LEN_GAMMA); 506 + 507 + /* write data */ 508 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); // level 1 key on 509 + mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, b2, ARRAY_SIZE(b2)); // set aid 510 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x00); // acl off 511 + mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, b6, ARRAY_SIZE(b6)); // set elvss 512 + mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, ca, ARRAY_SIZE(ca)); // set gamma 513 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf7, 0x03); // gamma update 514 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); // level 1 key off 515 + 516 + return dsi_ctx.accum_err; 517 + } 518 + 519 + static void s6e88a0_ams427ap24_reset(struct s6e88a0_ams427ap24 *ctx) 520 + { 521 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 522 + usleep_range(5000, 6000); 523 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 524 + usleep_range(1000, 2000); 525 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 526 + usleep_range(18000, 19000); 527 + } 528 + 529 + static int s6e88a0_ams427ap24_on(struct s6e88a0_ams427ap24 *ctx) 530 + { 531 + struct mipi_dsi_device *dsi = ctx->dsi; 532 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 533 + struct device *dev = &dsi->dev; 534 + int ret; 535 + 536 + dsi->mode_flags |= MIPI_DSI_MODE_LPM; 537 + 538 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); // level 1 key on 539 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x5a, 0x5a); // level 2 key on 540 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x11); // src latch set global 1 541 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x11); // src latch set 1 542 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x13); // src latch set global 2 543 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x18); // src latch set 2 544 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x02); // avdd set 1 545 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x30); // avdd set 2 546 + 547 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 548 + mipi_dsi_msleep(&dsi_ctx, 20); 549 + 550 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x5a, 0x5a); // level 3 key on 551 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, 0x4c); // pixel clock divider pol. 552 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x03, 0x0d); // unknown 553 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0xa5, 0xa5); // level 3 key off 554 + 555 + if (ctx->flip_horizontal) 556 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, 0x0e); // flip display 557 + 558 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); // level 1 key off 559 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0xa5, 0xa5); // level 2 key off 560 + 561 + ret = s6e88a0_ams427ap24_set_brightness(ctx->bl_dev); 562 + if (ret < 0) { 563 + dev_err(dev, "Failed to set brightness: %d\n", ret); 564 + return ret; 565 + } 566 + 567 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 568 + 569 + return dsi_ctx.accum_err; 570 + } 571 + 572 + static int s6e88a0_ams427ap24_off(struct s6e88a0_ams427ap24 *ctx) 573 + { 574 + struct mipi_dsi_device *dsi = ctx->dsi; 575 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 576 + 577 + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 578 + 579 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 580 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 581 + mipi_dsi_msleep(&dsi_ctx, 120); 582 + 583 + return dsi_ctx.accum_err; 584 + } 585 + 586 + static int s6e88a0_ams427ap24_prepare(struct drm_panel *panel) 587 + { 588 + struct s6e88a0_ams427ap24 *ctx = to_s6e88a0_ams427ap24(panel); 589 + struct device *dev = &ctx->dsi->dev; 590 + int ret; 591 + 592 + ret = regulator_bulk_enable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 593 + ctx->supplies); 594 + if (ret < 0) { 595 + dev_err(dev, "Failed to enable regulators: %d\n", ret); 596 + return ret; 597 + } 598 + 599 + s6e88a0_ams427ap24_reset(ctx); 600 + 601 + ret = s6e88a0_ams427ap24_on(ctx); 602 + if (ret < 0) { 603 + dev_err(dev, "Failed to initialize panel: %d\n", ret); 604 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 605 + regulator_bulk_disable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 606 + ctx->supplies); 607 + return ret; 608 + } 609 + 610 + return 0; 611 + } 612 + 613 + static int s6e88a0_ams427ap24_unprepare(struct drm_panel *panel) 614 + { 615 + struct s6e88a0_ams427ap24 *ctx = to_s6e88a0_ams427ap24(panel); 616 + struct device *dev = &ctx->dsi->dev; 617 + int ret; 618 + 619 + ret = s6e88a0_ams427ap24_off(ctx); 620 + if (ret < 0) 621 + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 622 + 623 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 624 + regulator_bulk_disable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 625 + ctx->supplies); 626 + 627 + return 0; 628 + } 629 + 630 + static const struct drm_display_mode s6e88a0_ams427ap24_mode = { 631 + .clock = (540 + 94 + 4 + 18) * (960 + 12 + 1 + 3) * 60 / 1000, 632 + .hdisplay = 540, 633 + .hsync_start = 540 + 94, 634 + .hsync_end = 540 + 94 + 4, 635 + .htotal = 540 + 94 + 4 + 18, 636 + .vdisplay = 960, 637 + .vsync_start = 960 + 12, 638 + .vsync_end = 960 + 12 + 1, 639 + .vtotal = 960 + 12 + 1 + 3, 640 + .width_mm = 55, 641 + .height_mm = 95, 642 + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 643 + }; 644 + 645 + static int s6e88a0_ams427ap24_get_modes(struct drm_panel *panel, 646 + struct drm_connector *connector) 647 + { 648 + return drm_connector_helper_get_modes_fixed(connector, 649 + &s6e88a0_ams427ap24_mode); 650 + } 651 + 652 + static const struct drm_panel_funcs s6e88a0_ams427ap24_panel_funcs = { 653 + .prepare = s6e88a0_ams427ap24_prepare, 654 + .unprepare = s6e88a0_ams427ap24_unprepare, 655 + .get_modes = s6e88a0_ams427ap24_get_modes, 656 + }; 657 + 658 + static const struct backlight_ops s6e88a0_ams427ap24_bl_ops = { 659 + .update_status = s6e88a0_ams427ap24_set_brightness, 660 + }; 661 + 662 + static int s6e88a0_ams427ap24_register_backlight(struct s6e88a0_ams427ap24 *ctx) 663 + { 664 + struct backlight_properties props = { 665 + .type = BACKLIGHT_RAW, 666 + .brightness = 180, 667 + .max_brightness = 255, 668 + }; 669 + struct mipi_dsi_device *dsi = ctx->dsi; 670 + struct device *dev = &dsi->dev; 671 + int ret = 0; 672 + 673 + ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev), dev, ctx, 674 + &s6e88a0_ams427ap24_bl_ops, 675 + &props); 676 + if (IS_ERR(ctx->bl_dev)) { 677 + ret = PTR_ERR(ctx->bl_dev); 678 + dev_err(dev, "error registering backlight device (%d)\n", ret); 679 + } 680 + 681 + return ret; 682 + } 683 + 684 + static int s6e88a0_ams427ap24_probe(struct mipi_dsi_device *dsi) 685 + { 686 + struct device *dev = &dsi->dev; 687 + struct s6e88a0_ams427ap24 *ctx; 688 + int ret; 689 + 690 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 691 + if (!ctx) 692 + return -ENOMEM; 693 + 694 + ret = devm_regulator_bulk_get_const(dev, 695 + ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 696 + s6e88a0_ams427ap24_supplies, 697 + &ctx->supplies); 698 + if (ret < 0) 699 + return ret; 700 + 701 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 702 + if (IS_ERR(ctx->reset_gpio)) 703 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 704 + "Failed to get reset-gpios\n"); 705 + 706 + ctx->dsi = dsi; 707 + mipi_dsi_set_drvdata(dsi, ctx); 708 + 709 + dsi->lanes = 2; 710 + dsi->format = MIPI_DSI_FMT_RGB888; 711 + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 712 + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_NO_HFP; 713 + 714 + drm_panel_init(&ctx->panel, dev, &s6e88a0_ams427ap24_panel_funcs, 715 + DRM_MODE_CONNECTOR_DSI); 716 + ctx->panel.prepare_prev_first = true; 717 + 718 + ctx->flip_horizontal = device_property_read_bool(dev, "flip-horizontal"); 719 + 720 + ret = s6e88a0_ams427ap24_register_backlight(ctx); 721 + if (ret < 0) 722 + return ret; 723 + 724 + drm_panel_add(&ctx->panel); 725 + 726 + ret = mipi_dsi_attach(dsi); 727 + if (ret < 0) { 728 + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 729 + drm_panel_remove(&ctx->panel); 730 + return ret; 731 + } 732 + 733 + return 0; 734 + } 735 + 736 + static void s6e88a0_ams427ap24_remove(struct mipi_dsi_device *dsi) 737 + { 738 + struct s6e88a0_ams427ap24 *ctx = mipi_dsi_get_drvdata(dsi); 739 + int ret; 740 + 741 + ret = mipi_dsi_detach(dsi); 742 + if (ret < 0) 743 + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 744 + 745 + drm_panel_remove(&ctx->panel); 746 + } 747 + 748 + static const struct of_device_id s6e88a0_ams427ap24_of_match[] = { 749 + { .compatible = "samsung,s6e88a0-ams427ap24" }, 750 + { /* sentinel */ }, 751 + }; 752 + MODULE_DEVICE_TABLE(of, s6e88a0_ams427ap24_of_match); 753 + 754 + static struct mipi_dsi_driver s6e88a0_ams427ap24_driver = { 755 + .probe = s6e88a0_ams427ap24_probe, 756 + .remove = s6e88a0_ams427ap24_remove, 757 + .driver = { 758 + .name = "panel-s6e88a0-ams427ap24", 759 + .of_match_table = s6e88a0_ams427ap24_of_match, 760 + }, 761 + }; 762 + module_mipi_dsi_driver(s6e88a0_ams427ap24_driver); 763 + 764 + MODULE_AUTHOR("Jakob Hauser <jahau@rocketmail.com>"); 765 + MODULE_DESCRIPTION("Samsung AMS427AP24 panel with S6E88A0 controller"); 766 + MODULE_LICENSE("GPL v2");
+28
drivers/gpu/drm/panel/panel-simple.c
··· 4565 4565 .connector_type = DRM_MODE_CONNECTOR_LVDS, 4566 4566 }; 4567 4567 4568 + static const struct drm_display_mode mchp_ac69t88a_mode = { 4569 + .clock = 25000, 4570 + .hdisplay = 800, 4571 + .hsync_start = 800 + 88, 4572 + .hsync_end = 800 + 88 + 5, 4573 + .htotal = 800 + 88 + 5 + 40, 4574 + .vdisplay = 480, 4575 + .vsync_start = 480 + 23, 4576 + .vsync_end = 480 + 23 + 5, 4577 + .vtotal = 480 + 23 + 5 + 1, 4578 + }; 4579 + 4580 + static const struct panel_desc mchp_ac69t88a = { 4581 + .modes = &mchp_ac69t88a_mode, 4582 + .num_modes = 1, 4583 + .bpc = 8, 4584 + .size = { 4585 + .width = 108, 4586 + .height = 65, 4587 + }, 4588 + .bus_flags = DRM_BUS_FLAG_DE_HIGH, 4589 + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 4590 + .connector_type = DRM_MODE_CONNECTOR_LVDS, 4591 + }; 4592 + 4568 4593 static const struct drm_display_mode arm_rtsm_mode[] = { 4569 4594 { 4570 4595 .clock = 65000, ··· 5073 5048 }, { 5074 5049 .compatible = "yes-optoelectronics,ytc700tlag-05-201c", 5075 5050 .data = &yes_optoelectronics_ytc700tlag_05_201c, 5051 + }, { 5052 + .compatible = "microchip,ac69t88a", 5053 + .data = &mchp_ac69t88a, 5076 5054 }, { 5077 5055 /* Must be the last entry */ 5078 5056 .compatible = "panel-dpi",
-1
drivers/gpu/drm/panfrost/panfrost_gpu.c
··· 177 177 struct panfrost_model { 178 178 const char *name; 179 179 u32 id; 180 - u32 id_mask; 181 180 u64 features; 182 181 u64 issues; 183 182 struct {
+10 -9
drivers/gpu/drm/radeon/radeon_device.c
··· 35 35 #include <linux/vgaarb.h> 36 36 37 37 #include <drm/drm_cache.h> 38 + #include <drm/drm_client_event.h> 38 39 #include <drm/drm_crtc_helper.h> 39 40 #include <drm/drm_device.h> 40 41 #include <drm/drm_file.h> ··· 1543 1542 * Called at driver suspend. 1544 1543 */ 1545 1544 int radeon_suspend_kms(struct drm_device *dev, bool suspend, 1546 - bool fbcon, bool freeze) 1545 + bool notify_clients, bool freeze) 1547 1546 { 1548 1547 struct radeon_device *rdev; 1549 1548 struct pci_dev *pdev; ··· 1635 1634 pci_set_power_state(pdev, PCI_D3hot); 1636 1635 } 1637 1636 1638 - if (fbcon) { 1637 + if (notify_clients) { 1639 1638 console_lock(); 1640 - radeon_fbdev_set_suspend(rdev, 1); 1639 + drm_client_dev_suspend(dev, true); 1641 1640 console_unlock(); 1642 1641 } 1643 1642 return 0; ··· 1650 1649 * Returns 0 for success or an error on failure. 1651 1650 * Called at driver resume. 1652 1651 */ 1653 - int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) 1652 + int radeon_resume_kms(struct drm_device *dev, bool resume, bool notify_clients) 1654 1653 { 1655 1654 struct drm_connector *connector; 1656 1655 struct radeon_device *rdev = dev->dev_private; ··· 1661 1660 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1662 1661 return 0; 1663 1662 1664 - if (fbcon) { 1663 + if (notify_clients) { 1665 1664 console_lock(); 1666 1665 } 1667 1666 if (resume) { 1668 1667 pci_set_power_state(pdev, PCI_D0); 1669 1668 pci_restore_state(pdev); 1670 1669 if (pci_enable_device(pdev)) { 1671 - if (fbcon) 1670 + if (notify_clients) 1672 1671 console_unlock(); 1673 1672 return -1; 1674 1673 } ··· 1731 1730 /* reset hpd state */ 1732 1731 radeon_hpd_init(rdev); 1733 1732 /* blat the mode back in */ 1734 - if (fbcon) { 1733 + if (notify_clients) { 1735 1734 drm_helper_resume_force_mode(dev); 1736 1735 /* turn on display hw */ 1737 1736 drm_modeset_lock_all(dev); ··· 1747 1746 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1748 1747 radeon_pm_compute_clocks(rdev); 1749 1748 1750 - if (fbcon) { 1751 - radeon_fbdev_set_suspend(rdev, 0); 1749 + if (notify_clients) { 1750 + drm_client_dev_resume(dev, true); 1752 1751 console_unlock(); 1753 1752 } 1754 1753
-6
drivers/gpu/drm/radeon/radeon_fbdev.c
··· 288 288 return ret; 289 289 } 290 290 291 - void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) 292 - { 293 - if (rdev_to_drm(rdev)->fb_helper) 294 - drm_fb_helper_set_suspend(rdev_to_drm(rdev)->fb_helper, state); 295 - } 296 - 297 291 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) 298 292 { 299 293 struct drm_fb_helper *fb_helper = rdev_to_drm(rdev)->fb_helper;
-3
drivers/gpu/drm/radeon/radeon_mode.h
··· 942 942 struct drm_fb_helper_surface_size *sizes); 943 943 #define RADEON_FBDEV_DRIVER_OPS \ 944 944 .fbdev_probe = radeon_fbdev_driver_fbdev_probe 945 - void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); 946 945 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); 947 946 #else 948 947 #define RADEON_FBDEV_DRIVER_OPS \ 949 948 .fbdev_probe = NULL 950 - static inline void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) 951 - { } 952 949 static inline bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) 953 950 { 954 951 return false;
+9
drivers/gpu/drm/rockchip/Kconfig
··· 9 9 select VIDEOMODE_HELPERS 10 10 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP 11 11 select DRM_DW_HDMI if ROCKCHIP_DW_HDMI 12 + select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP 12 13 select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI 13 14 select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI 14 15 select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI ··· 64 63 for the Synopsys DesignWare HDMI driver. If you want to 65 64 enable HDMI on RK3288 or RK3399 based SoC, you should select 66 65 this option. 66 + 67 + config ROCKCHIP_DW_HDMI_QP 68 + bool "Rockchip specific extensions for Synopsys DW HDMI QP" 69 + select DRM_BRIDGE_CONNECTOR 70 + help 71 + This selects support for Rockchip SoC specific extensions 72 + for the Synopsys DesignWare HDMI QP driver. If you want to 73 + enable HDMI on RK3588 based SoC, you should select this option. 67 74 68 75 config ROCKCHIP_DW_MIPI_DSI 69 76 bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
+1
drivers/gpu/drm/rockchip/Makefile
··· 11 11 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o 12 12 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o 13 13 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o 14 + rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o 14 15 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o 15 16 rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o 16 17 rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
+424
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. 4 + * Copyright (c) 2024 Collabora Ltd. 5 + * 6 + * Author: Algea Cao <algea.cao@rock-chips.com> 7 + * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> 8 + */ 9 + 10 + #include <linux/clk.h> 11 + #include <linux/gpio/consumer.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/module.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/phy/phy.h> 16 + #include <linux/regmap.h> 17 + #include <linux/workqueue.h> 18 + 19 + #include <drm/bridge/dw_hdmi_qp.h> 20 + #include <drm/display/drm_hdmi_helper.h> 21 + #include <drm/drm_bridge_connector.h> 22 + #include <drm/drm_of.h> 23 + #include <drm/drm_probe_helper.h> 24 + #include <drm/drm_simple_kms_helper.h> 25 + 26 + #include "rockchip_drm_drv.h" 27 + 28 + #define RK3588_GRF_SOC_CON2 0x0308 29 + #define RK3588_HDMI0_HPD_INT_MSK BIT(13) 30 + #define RK3588_HDMI0_HPD_INT_CLR BIT(12) 31 + #define RK3588_GRF_SOC_CON7 0x031c 32 + #define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12) 33 + #define RK3588_GRF_SOC_STATUS1 0x0384 34 + #define RK3588_HDMI0_LEVEL_INT BIT(16) 35 + #define RK3588_GRF_VO1_CON3 0x000c 36 + #define RK3588_SCLIN_MASK BIT(9) 37 + #define RK3588_SDAIN_MASK BIT(10) 38 + #define RK3588_MODE_MASK BIT(11) 39 + #define RK3588_I2S_SEL_MASK BIT(13) 40 + #define RK3588_GRF_VO1_CON9 0x0024 41 + #define RK3588_HDMI0_GRANT_SEL BIT(10) 42 + 43 + #define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) 44 + #define HOTPLUG_DEBOUNCE_MS 150 45 + 46 + struct rockchip_hdmi_qp { 47 + struct device *dev; 48 + struct regmap *regmap; 49 + struct regmap *vo_regmap; 50 + struct rockchip_encoder encoder; 51 + struct clk *ref_clk; 52 + struct dw_hdmi_qp *hdmi; 53 + struct phy *phy; 54 + struct gpio_desc *enable_gpio; 55 + struct delayed_work hpd_work; 56 + }; 57 + 58 + static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder) 59 + { 60 + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 61 + 62 + return container_of(rkencoder, struct rockchip_hdmi_qp, encoder); 63 + } 64 + 65 + static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) 66 + { 67 + struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); 68 + struct drm_crtc *crtc = encoder->crtc; 69 + unsigned long long rate; 70 + 71 + /* Unconditionally switch to TMDS as FRL is not yet supported */ 72 + gpiod_set_value(hdmi->enable_gpio, 1); 73 + 74 + if (crtc && crtc->state) { 75 + rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode, 76 + 8, HDMI_COLORSPACE_RGB); 77 + clk_set_rate(hdmi->ref_clk, rate); 78 + /* 79 + * FIXME: Temporary workaround to pass pixel clock rate 80 + * to the PHY driver until phy_configure_opts_hdmi 81 + * becomes available in the PHY API. See also the related 82 + * comment in rk_hdptx_phy_power_on() from 83 + * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c 84 + */ 85 + phy_set_bus_width(hdmi->phy, rate / 100); 86 + } 87 + } 88 + 89 + static int 90 + dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, 91 + struct drm_crtc_state *crtc_state, 92 + struct drm_connector_state *conn_state) 93 + { 94 + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 95 + 96 + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 97 + s->output_type = DRM_MODE_CONNECTOR_HDMIA; 98 + 99 + return 0; 100 + } 101 + 102 + static const struct 103 + drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = { 104 + .enable = dw_hdmi_qp_rockchip_encoder_enable, 105 + .atomic_check = dw_hdmi_qp_rockchip_encoder_atomic_check, 106 + }; 107 + 108 + static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data) 109 + { 110 + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 111 + 112 + return phy_power_on(hdmi->phy); 113 + } 114 + 115 + static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi, 116 + void *data) 117 + { 118 + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 119 + 120 + phy_power_off(hdmi->phy); 121 + } 122 + 123 + static enum drm_connector_status 124 + dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) 125 + { 126 + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 127 + u32 val; 128 + 129 + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); 130 + 131 + return val & RK3588_HDMI0_LEVEL_INT ? 132 + connector_status_connected : connector_status_disconnected; 133 + } 134 + 135 + static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) 136 + { 137 + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; 138 + 139 + regmap_write(hdmi->regmap, 140 + RK3588_GRF_SOC_CON2, 141 + HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, 142 + RK3588_HDMI0_HPD_INT_CLR | 143 + RK3588_HDMI0_HPD_INT_MSK)); 144 + } 145 + 146 + static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = { 147 + .init = dw_hdmi_qp_rk3588_phy_init, 148 + .disable = dw_hdmi_qp_rk3588_phy_disable, 149 + .read_hpd = dw_hdmi_qp_rk3588_read_hpd, 150 + .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd, 151 + }; 152 + 153 + static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work) 154 + { 155 + struct rockchip_hdmi_qp *hdmi = container_of(work, 156 + struct rockchip_hdmi_qp, 157 + hpd_work.work); 158 + struct drm_device *drm = hdmi->encoder.encoder.dev; 159 + bool changed; 160 + 161 + if (drm) { 162 + changed = drm_helper_hpd_irq_event(drm); 163 + if (changed) 164 + drm_dbg(hdmi, "connector status changed\n"); 165 + } 166 + } 167 + 168 + static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id) 169 + { 170 + struct rockchip_hdmi_qp *hdmi = dev_id; 171 + u32 intr_stat, val; 172 + 173 + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); 174 + 175 + if (intr_stat) { 176 + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, 177 + RK3588_HDMI0_HPD_INT_MSK); 178 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 179 + return IRQ_WAKE_THREAD; 180 + } 181 + 182 + return IRQ_NONE; 183 + } 184 + 185 + static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) 186 + { 187 + struct rockchip_hdmi_qp *hdmi = dev_id; 188 + u32 intr_stat, val; 189 + 190 + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); 191 + if (!intr_stat) 192 + return IRQ_NONE; 193 + 194 + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, 195 + RK3588_HDMI0_HPD_INT_CLR); 196 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 197 + 198 + mod_delayed_work(system_wq, &hdmi->hpd_work, 199 + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); 200 + 201 + val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); 202 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 203 + 204 + return IRQ_HANDLED; 205 + } 206 + 207 + static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = { 208 + { .compatible = "rockchip,rk3588-dw-hdmi-qp", 209 + .data = &rk3588_hdmi_phy_ops }, 210 + {}, 211 + }; 212 + MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids); 213 + 214 + static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, 215 + void *data) 216 + { 217 + static const char * const clk_names[] = { 218 + "pclk", "earc", "aud", "hdp", "hclk_vo1", 219 + "ref" /* keep "ref" last */ 220 + }; 221 + struct platform_device *pdev = to_platform_device(dev); 222 + struct dw_hdmi_qp_plat_data plat_data; 223 + struct drm_device *drm = data; 224 + struct drm_connector *connector; 225 + struct drm_encoder *encoder; 226 + struct rockchip_hdmi_qp *hdmi; 227 + struct clk *clk; 228 + int ret, irq, i; 229 + u32 val; 230 + 231 + if (!pdev->dev.of_node) 232 + return -ENODEV; 233 + 234 + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 235 + if (!hdmi) 236 + return -ENOMEM; 237 + 238 + plat_data.phy_ops = of_device_get_match_data(dev); 239 + if (!plat_data.phy_ops) 240 + return -ENODEV; 241 + 242 + plat_data.phy_data = hdmi; 243 + hdmi->dev = &pdev->dev; 244 + 245 + encoder = &hdmi->encoder.encoder; 246 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 247 + 248 + rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, 249 + dev->of_node, 0, 0); 250 + /* 251 + * If we failed to find the CRTC(s) which this encoder is 252 + * supposed to be connected to, it's because the CRTC has 253 + * not been registered yet. Defer probing, and hope that 254 + * the required CRTC is added later. 255 + */ 256 + if (encoder->possible_crtcs == 0) 257 + return -EPROBE_DEFER; 258 + 259 + hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 260 + "rockchip,grf"); 261 + if (IS_ERR(hdmi->regmap)) { 262 + drm_err(hdmi, "Unable to get rockchip,grf\n"); 263 + return PTR_ERR(hdmi->regmap); 264 + } 265 + 266 + hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 267 + "rockchip,vo-grf"); 268 + if (IS_ERR(hdmi->vo_regmap)) { 269 + drm_err(hdmi, "Unable to get rockchip,vo-grf\n"); 270 + return PTR_ERR(hdmi->vo_regmap); 271 + } 272 + 273 + for (i = 0; i < ARRAY_SIZE(clk_names); i++) { 274 + clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]); 275 + 276 + if (IS_ERR(clk)) { 277 + ret = PTR_ERR(clk); 278 + if (ret != -EPROBE_DEFER) 279 + drm_err(hdmi, "Failed to get %s clock: %d\n", 280 + clk_names[i], ret); 281 + return ret; 282 + } 283 + } 284 + hdmi->ref_clk = clk; 285 + 286 + hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", 287 + GPIOD_OUT_HIGH); 288 + if (IS_ERR(hdmi->enable_gpio)) { 289 + ret = PTR_ERR(hdmi->enable_gpio); 290 + drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret); 291 + return ret; 292 + } 293 + 294 + hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); 295 + if (IS_ERR(hdmi->phy)) { 296 + ret = PTR_ERR(hdmi->phy); 297 + if (ret != -EPROBE_DEFER) 298 + drm_err(hdmi, "failed to get phy: %d\n", ret); 299 + return ret; 300 + } 301 + 302 + val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | 303 + HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | 304 + HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | 305 + HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); 306 + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); 307 + 308 + val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, 309 + RK3588_SET_HPD_PATH_MASK); 310 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); 311 + 312 + val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, 313 + RK3588_HDMI0_GRANT_SEL); 314 + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); 315 + 316 + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); 317 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 318 + 319 + INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work); 320 + 321 + plat_data.main_irq = platform_get_irq_byname(pdev, "main"); 322 + if (plat_data.main_irq < 0) 323 + return plat_data.main_irq; 324 + 325 + irq = platform_get_irq_byname(pdev, "hpd"); 326 + if (irq < 0) 327 + return irq; 328 + 329 + ret = devm_request_threaded_irq(hdmi->dev, irq, 330 + dw_hdmi_qp_rk3588_hardirq, 331 + dw_hdmi_qp_rk3588_irq, 332 + IRQF_SHARED, "dw-hdmi-qp-hpd", 333 + hdmi); 334 + if (ret) 335 + return ret; 336 + 337 + drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs); 338 + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); 339 + 340 + platform_set_drvdata(pdev, hdmi); 341 + 342 + hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); 343 + if (IS_ERR(hdmi->hdmi)) { 344 + ret = PTR_ERR(hdmi->hdmi); 345 + drm_encoder_cleanup(encoder); 346 + return ret; 347 + } 348 + 349 + connector = drm_bridge_connector_init(drm, encoder); 350 + if (IS_ERR(connector)) { 351 + ret = PTR_ERR(connector); 352 + drm_err(hdmi, "failed to init bridge connector: %d\n", ret); 353 + return ret; 354 + } 355 + 356 + return drm_connector_attach_encoder(connector, encoder); 357 + } 358 + 359 + static void dw_hdmi_qp_rockchip_unbind(struct device *dev, 360 + struct device *master, 361 + void *data) 362 + { 363 + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); 364 + 365 + cancel_delayed_work_sync(&hdmi->hpd_work); 366 + 367 + drm_encoder_cleanup(&hdmi->encoder.encoder); 368 + } 369 + 370 + static const struct component_ops dw_hdmi_qp_rockchip_ops = { 371 + .bind = dw_hdmi_qp_rockchip_bind, 372 + .unbind = dw_hdmi_qp_rockchip_unbind, 373 + }; 374 + 375 + static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev) 376 + { 377 + return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops); 378 + } 379 + 380 + static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) 381 + { 382 + component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); 383 + } 384 + 385 + static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) 386 + { 387 + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); 388 + u32 val; 389 + 390 + val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | 391 + HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | 392 + HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | 393 + HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); 394 + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); 395 + 396 + val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, 397 + RK3588_SET_HPD_PATH_MASK); 398 + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); 399 + 400 + val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, 401 + RK3588_HDMI0_GRANT_SEL); 402 + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); 403 + 404 + dw_hdmi_qp_resume(dev, hdmi->hdmi); 405 + 406 + if (hdmi->encoder.encoder.dev) 407 + drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev); 408 + 409 + return 0; 410 + } 411 + 412 + static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { 413 + SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) 414 + }; 415 + 416 + struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { 417 + .probe = dw_hdmi_qp_rockchip_probe, 418 + .remove = dw_hdmi_qp_rockchip_remove, 419 + .driver = { 420 + .name = "dwhdmiqp-rockchip", 421 + .pm = &dw_hdmi_qp_rockchip_pm, 422 + .of_match_table = dw_hdmi_qp_rockchip_dt_ids, 423 + }, 424 + };
+2
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
··· 532 532 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); 533 533 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, 534 534 CONFIG_ROCKCHIP_DW_HDMI); 535 + ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver, 536 + CONFIG_ROCKCHIP_DW_HDMI_QP); 535 537 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver, 536 538 CONFIG_ROCKCHIP_DW_MIPI_DSI); 537 539 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
+1
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
··· 88 88 int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); 89 89 extern struct platform_driver cdn_dp_driver; 90 90 extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; 91 + extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver; 91 92 extern struct platform_driver dw_mipi_dsi_rockchip_driver; 92 93 extern struct platform_driver inno_hdmi_driver; 93 94 extern struct platform_driver rockchip_dp_driver;
+19 -1
drivers/gpu/drm/scheduler/sched_main.c
··· 593 593 * callers responsibility to release it manually if it's not part of the 594 594 * pending list any more. 595 595 * 596 + * This function is typically used for reset recovery (see the docu of 597 + * drm_sched_backend_ops.timedout_job() for details). Do not call it for 598 + * scheduler teardown, i.e., before calling drm_sched_fini(). 596 599 */ 597 600 void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) 598 601 { ··· 668 665 */ 669 666 cancel_delayed_work(&sched->work_tdr); 670 667 } 671 - 672 668 EXPORT_SYMBOL(drm_sched_stop); 673 669 674 670 /** ··· 676 674 * @sched: scheduler instance 677 675 * @errno: error to set on the pending fences 678 676 * 677 + * This function is typically used for reset recovery (see the docu of 678 + * drm_sched_backend_ops.timedout_job() for details). Do not call it for 679 + * scheduler startup. The scheduler itself is fully operational after 680 + * drm_sched_init() succeeded. 679 681 */ 680 682 void drm_sched_start(struct drm_gpu_scheduler *sched, int errno) 681 683 { ··· 777 771 * Drivers must make sure drm_sched_job_cleanup() if this function returns 778 772 * successfully, even when @job is aborted before drm_sched_job_arm() is called. 779 773 * 774 + * Note that this function does not assign a valid value to each struct member 775 + * of struct drm_sched_job. Take a look at that struct's documentation to see 776 + * who sets which struct member with what lifetime. 777 + * 780 778 * WARNING: amdgpu abuses &drm_sched.ready to signal when the hardware 781 779 * has died, which can mean that there's no valid runqueue for a @entity. 782 780 * This function returns -ENOENT in this case (which probably should be -EIO as ··· 805 795 pr_err("*ERROR* %s: credits cannot be 0!\n", __func__); 806 796 return -EINVAL; 807 797 } 798 + 799 + /* 800 + * We don't know for sure how the user has allocated. Thus, zero the 801 + * struct so that unallowed (i.e., too early) usage of pointers that 802 + * this function does not set is guaranteed to lead to a NULL pointer 803 + * exception instead of UB. 804 + */ 805 + memset(job, 0, sizeof(*job)); 808 806 809 807 job->entity = entity; 810 808 job->credits = credits;
+1 -1
drivers/gpu/drm/sprd/sprd_dsi.c
··· 209 209 return 0; 210 210 } 211 211 212 - static struct regmap_bus regmap_tst_io = { 212 + static const struct regmap_bus regmap_tst_io = { 213 213 .reg_write = regmap_tst_io_write, 214 214 .reg_read = regmap_tst_io_read, 215 215 };
+21
drivers/gpu/drm/tiny/Kconfig
··· 198 198 199 199 If M is selected the module will be called repaper. 200 200 201 + config TINYDRM_SHARP_MEMORY 202 + tristate "DRM support for Sharp Memory LCD panels" 203 + depends on DRM && SPI 204 + select DRM_CLIENT_SELECTION 205 + select DRM_GEM_DMA_HELPER 206 + select DRM_KMS_HELPER 207 + help 208 + DRM Driver for the following Sharp Memory Panels: 209 + * 1.00" Sharp Memory LCD (LS010B7DH04) 210 + * 1.10" Sharp Memory LCD (LS011B7DH03) 211 + * 1.20" Sharp Memory LCD (LS012B7DD01) 212 + * 1.28" Sharp Memory LCD (LS013B7DH03) 213 + * 1.26" Sharp Memory LCD (LS013B7DH05) 214 + * 1.80" Sharp Memory LCD (LS018B7DH02) 215 + * 2.70" Sharp Memory LCD (LS027B7DH01) 216 + * 2.70" Sharp Memory LCD (LS027B7DH01A) 217 + * 3.20" Sharp Memory LCD (LS032B7DD02) 218 + * 4.40" Sharp Memory LCD (LS044Q7DH01) 219 + 220 + If M is selected the module will be called sharp_memory. 221 + 201 222 config TINYDRM_ST7586 202 223 tristate "DRM support for Sitronix ST7586 display panels" 203 224 depends on DRM && SPI
+1
drivers/gpu/drm/tiny/Makefile
··· 14 14 obj-$(CONFIG_TINYDRM_ILI9486) += ili9486.o 15 15 obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o 16 16 obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o 17 + obj-$(CONFIG_TINYDRM_SHARP_MEMORY) += sharp-memory.o 17 18 obj-$(CONFIG_TINYDRM_ST7586) += st7586.o 18 19 obj-$(CONFIG_TINYDRM_ST7735R) += st7735r.o
+671
drivers/gpu/drm/tiny/sharp-memory.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + 3 + #include <drm/drm_atomic.h> 4 + #include <drm/drm_atomic_helper.h> 5 + #include <drm/drm_client_setup.h> 6 + #include <drm/drm_connector.h> 7 + #include <drm/drm_damage_helper.h> 8 + #include <drm/drm_drv.h> 9 + #include <drm/drm_fb_dma_helper.h> 10 + #include <drm/drm_fbdev_dma.h> 11 + #include <drm/drm_format_helper.h> 12 + #include <drm/drm_framebuffer.h> 13 + #include <drm/drm_gem_atomic_helper.h> 14 + #include <drm/drm_gem_dma_helper.h> 15 + #include <drm/drm_gem_framebuffer_helper.h> 16 + #include <drm/drm_managed.h> 17 + #include <drm/drm_modes.h> 18 + #include <drm/drm_probe_helper.h> 19 + #include <drm/drm_rect.h> 20 + #include <linux/bitrev.h> 21 + #include <linux/delay.h> 22 + #include <linux/gpio/consumer.h> 23 + #include <linux/kthread.h> 24 + #include <linux/mod_devicetable.h> 25 + #include <linux/module.h> 26 + #include <linux/mutex.h> 27 + #include <linux/pwm.h> 28 + #include <linux/spi/spi.h> 29 + 30 + #define SHARP_MODE_PERIOD 8 31 + #define SHARP_ADDR_PERIOD 8 32 + #define SHARP_DUMMY_PERIOD 8 33 + 34 + #define SHARP_MEMORY_DISPLAY_MAINTAIN_MODE 0 35 + #define SHARP_MEMORY_DISPLAY_UPDATE_MODE 1 36 + #define SHARP_MEMORY_DISPLAY_CLEAR_MODE 4 37 + 38 + enum sharp_memory_model { 39 + LS010B7DH04, 40 + LS011B7DH03, 41 + LS012B7DD01, 42 + LS013B7DH03, 43 + LS013B7DH05, 44 + LS018B7DH02, 45 + LS027B7DH01, 46 + LS027B7DH01A, 47 + LS032B7DD02, 48 + LS044Q7DH01, 49 + }; 50 + 51 + enum sharp_memory_vcom_mode { 52 + SHARP_MEMORY_SOFTWARE_VCOM, 53 + SHARP_MEMORY_EXTERNAL_VCOM, 54 + SHARP_MEMORY_PWM_VCOM 55 + }; 56 + 57 + struct sharp_memory_device { 58 + struct drm_device drm; 59 + struct spi_device *spi; 60 + 61 + const struct drm_display_mode *mode; 62 + 63 + struct drm_crtc crtc; 64 + struct drm_plane plane; 65 + struct drm_encoder encoder; 66 + struct drm_connector connector; 67 + 68 + struct gpio_desc *enable_gpio; 69 + 70 + struct task_struct *sw_vcom_signal; 71 + struct pwm_device *pwm_vcom_signal; 72 + 73 + enum sharp_memory_vcom_mode vcom_mode; 74 + u8 vcom; 75 + 76 + u32 pitch; 77 + u32 tx_buffer_size; 78 + u8 *tx_buffer; 79 + 80 + /* When vcom_mode == "software" a kthread is used to periodically send a 81 + * 'maintain display' message over spi. This mutex ensures tx_buffer access 82 + * and spi bus usage is synchronized in this case. 83 + */ 84 + struct mutex tx_mutex; 85 + }; 86 + 87 + static inline int sharp_memory_spi_write(struct spi_device *spi, void *buf, size_t len) 88 + { 89 + /* Reverse the bit order */ 90 + for (u8 *b = buf; b < ((u8 *)buf) + len; ++b) 91 + *b = bitrev8(*b); 92 + 93 + return spi_write(spi, buf, len); 94 + } 95 + 96 + static inline struct sharp_memory_device *drm_to_sharp_memory_device(struct drm_device *drm) 97 + { 98 + return container_of(drm, struct sharp_memory_device, drm); 99 + } 100 + 101 + DEFINE_DRM_GEM_DMA_FOPS(sharp_memory_fops); 102 + 103 + static const struct drm_driver sharp_memory_drm_driver = { 104 + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 105 + .fops = &sharp_memory_fops, 106 + DRM_GEM_DMA_DRIVER_OPS_VMAP, 107 + DRM_FBDEV_DMA_DRIVER_OPS, 108 + .name = "sharp_memory_display", 109 + .desc = "Sharp Display Memory LCD", 110 + .date = "20231129", 111 + .major = 1, 112 + .minor = 0, 113 + }; 114 + 115 + static inline void sharp_memory_set_tx_buffer_mode(u8 *buffer, u8 mode, u8 vcom) 116 + { 117 + *buffer = mode | (vcom << 1); 118 + } 119 + 120 + static inline void sharp_memory_set_tx_buffer_addresses(u8 *buffer, 121 + struct drm_rect clip, 122 + u32 pitch) 123 + { 124 + for (u32 line = 0; line < clip.y2; ++line) 125 + buffer[line * pitch] = line + 1; 126 + } 127 + 128 + static void sharp_memory_set_tx_buffer_data(u8 *buffer, 129 + struct drm_framebuffer *fb, 130 + struct drm_rect clip, 131 + u32 pitch, 132 + struct drm_format_conv_state *fmtcnv_state) 133 + { 134 + int ret; 135 + struct iosys_map dst, vmap; 136 + struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); 137 + 138 + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); 139 + if (ret) 140 + return; 141 + 142 + iosys_map_set_vaddr(&dst, buffer); 143 + iosys_map_set_vaddr(&vmap, dma_obj->vaddr); 144 + 145 + drm_fb_xrgb8888_to_mono(&dst, &pitch, &vmap, fb, &clip, fmtcnv_state); 146 + 147 + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); 148 + } 149 + 150 + static int sharp_memory_update_display(struct sharp_memory_device *smd, 151 + struct drm_framebuffer *fb, 152 + struct drm_rect clip, 153 + struct drm_format_conv_state *fmtcnv_state) 154 + { 155 + int ret; 156 + u32 pitch = smd->pitch; 157 + u8 vcom = smd->vcom; 158 + u8 *tx_buffer = smd->tx_buffer; 159 + u32 tx_buffer_size = smd->tx_buffer_size; 160 + 161 + mutex_lock(&smd->tx_mutex); 162 + 163 + /* Populate the transmit buffer with frame data */ 164 + sharp_memory_set_tx_buffer_mode(&tx_buffer[0], 165 + SHARP_MEMORY_DISPLAY_UPDATE_MODE, vcom); 166 + sharp_memory_set_tx_buffer_addresses(&tx_buffer[1], clip, pitch); 167 + sharp_memory_set_tx_buffer_data(&tx_buffer[2], fb, clip, pitch, fmtcnv_state); 168 + 169 + ret = sharp_memory_spi_write(smd->spi, tx_buffer, tx_buffer_size); 170 + 171 + mutex_unlock(&smd->tx_mutex); 172 + 173 + return ret; 174 + } 175 + 176 + static int sharp_memory_maintain_display(struct sharp_memory_device *smd) 177 + { 178 + int ret; 179 + u8 vcom = smd->vcom; 180 + u8 *tx_buffer = smd->tx_buffer; 181 + 182 + mutex_lock(&smd->tx_mutex); 183 + 184 + sharp_memory_set_tx_buffer_mode(&tx_buffer[0], SHARP_MEMORY_DISPLAY_MAINTAIN_MODE, vcom); 185 + tx_buffer[1] = 0; /* Write dummy data */ 186 + ret = sharp_memory_spi_write(smd->spi, tx_buffer, 2); 187 + 188 + mutex_unlock(&smd->tx_mutex); 189 + 190 + return ret; 191 + } 192 + 193 + static int sharp_memory_clear_display(struct sharp_memory_device *smd) 194 + { 195 + int ret; 196 + u8 vcom = smd->vcom; 197 + u8 *tx_buffer = smd->tx_buffer; 198 + 199 + mutex_lock(&smd->tx_mutex); 200 + 201 + sharp_memory_set_tx_buffer_mode(&tx_buffer[0], SHARP_MEMORY_DISPLAY_CLEAR_MODE, vcom); 202 + tx_buffer[1] = 0; /* write dummy data */ 203 + ret = sharp_memory_spi_write(smd->spi, tx_buffer, 2); 204 + 205 + mutex_unlock(&smd->tx_mutex); 206 + 207 + return ret; 208 + } 209 + 210 + static void sharp_memory_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect, 211 + struct drm_format_conv_state *fmtconv_state) 212 + { 213 + struct drm_rect clip; 214 + struct sharp_memory_device *smd = drm_to_sharp_memory_device(fb->dev); 215 + 216 + /* Always update a full line regardless of what is dirty */ 217 + clip.x1 = 0; 218 + clip.x2 = fb->width; 219 + clip.y1 = rect->y1; 220 + clip.y2 = rect->y2; 221 + 222 + sharp_memory_update_display(smd, fb, clip, fmtconv_state); 223 + } 224 + 225 + static int sharp_memory_plane_atomic_check(struct drm_plane *plane, 226 + struct drm_atomic_state *state) 227 + { 228 + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); 229 + struct sharp_memory_device *smd; 230 + struct drm_crtc_state *crtc_state; 231 + 232 + smd = container_of(plane, struct sharp_memory_device, plane); 233 + crtc_state = drm_atomic_get_new_crtc_state(state, &smd->crtc); 234 + 235 + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, 236 + DRM_PLANE_NO_SCALING, 237 + DRM_PLANE_NO_SCALING, 238 + false, false); 239 + } 240 + 241 + static void sharp_memory_plane_atomic_update(struct drm_plane *plane, 242 + struct drm_atomic_state *state) 243 + { 244 + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); 245 + struct drm_plane_state *plane_state = plane->state; 246 + struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; 247 + struct sharp_memory_device *smd; 248 + struct drm_rect rect; 249 + 250 + smd = container_of(plane, struct sharp_memory_device, plane); 251 + if (!smd->crtc.state->active) 252 + return; 253 + 254 + if (drm_atomic_helper_damage_merged(old_state, plane_state, &rect)) 255 + sharp_memory_fb_dirty(plane_state->fb, &rect, &fmtcnv_state); 256 + 257 + drm_format_conv_state_release(&fmtcnv_state); 258 + } 259 + 260 + static const struct drm_plane_helper_funcs sharp_memory_plane_helper_funcs = { 261 + .prepare_fb = drm_gem_plane_helper_prepare_fb, 262 + .atomic_check = sharp_memory_plane_atomic_check, 263 + .atomic_update = sharp_memory_plane_atomic_update, 264 + }; 265 + 266 + static bool sharp_memory_format_mod_supported(struct drm_plane *plane, 267 + u32 format, 268 + u64 modifier) 269 + { 270 + return modifier == DRM_FORMAT_MOD_LINEAR; 271 + } 272 + 273 + static const struct drm_plane_funcs sharp_memory_plane_funcs = { 274 + .update_plane = drm_atomic_helper_update_plane, 275 + .disable_plane = drm_atomic_helper_disable_plane, 276 + .destroy = drm_plane_cleanup, 277 + .reset = drm_atomic_helper_plane_reset, 278 + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 279 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 280 + .format_mod_supported = sharp_memory_format_mod_supported, 281 + }; 282 + 283 + static enum drm_mode_status sharp_memory_crtc_mode_valid(struct drm_crtc *crtc, 284 + const struct drm_display_mode *mode) 285 + { 286 + struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev); 287 + 288 + return drm_crtc_helper_mode_valid_fixed(crtc, mode, smd->mode); 289 + } 290 + 291 + static int sharp_memory_crtc_check(struct drm_crtc *crtc, 292 + struct drm_atomic_state *state) 293 + { 294 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 295 + int ret; 296 + 297 + if (!crtc_state->enable) 298 + goto out; 299 + 300 + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); 301 + if (ret) 302 + return ret; 303 + 304 + out: 305 + return drm_atomic_add_affected_planes(state, crtc); 306 + } 307 + 308 + static int sharp_memory_sw_vcom_signal_thread(void *data) 309 + { 310 + struct sharp_memory_device *smd = data; 311 + 312 + while (!kthread_should_stop()) { 313 + smd->vcom ^= 1; /* Toggle vcom */ 314 + sharp_memory_maintain_display(smd); 315 + msleep(1000); 316 + } 317 + 318 + return 0; 319 + } 320 + 321 + static void sharp_memory_crtc_enable(struct drm_crtc *crtc, 322 + struct drm_atomic_state *state) 323 + { 324 + struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev); 325 + 326 + sharp_memory_clear_display(smd); 327 + 328 + if (smd->enable_gpio) 329 + gpiod_set_value(smd->enable_gpio, 1); 330 + } 331 + 332 + static void sharp_memory_crtc_disable(struct drm_crtc *crtc, 333 + struct drm_atomic_state *state) 334 + { 335 + struct sharp_memory_device *smd = drm_to_sharp_memory_device(crtc->dev); 336 + 337 + sharp_memory_clear_display(smd); 338 + 339 + if (smd->enable_gpio) 340 + gpiod_set_value(smd->enable_gpio, 0); 341 + } 342 + 343 + static const struct drm_crtc_helper_funcs sharp_memory_crtc_helper_funcs = { 344 + .mode_valid = sharp_memory_crtc_mode_valid, 345 + .atomic_check = sharp_memory_crtc_check, 346 + .atomic_enable = sharp_memory_crtc_enable, 347 + .atomic_disable = sharp_memory_crtc_disable, 348 + }; 349 + 350 + static const struct drm_crtc_funcs sharp_memory_crtc_funcs = { 351 + .reset = drm_atomic_helper_crtc_reset, 352 + .destroy = drm_crtc_cleanup, 353 + .set_config = drm_atomic_helper_set_config, 354 + .page_flip = drm_atomic_helper_page_flip, 355 + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 356 + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 357 + }; 358 + 359 + static const struct drm_encoder_funcs sharp_memory_encoder_funcs = { 360 + .destroy = drm_encoder_cleanup, 361 + }; 362 + 363 + static int sharp_memory_connector_get_modes(struct drm_connector *connector) 364 + { 365 + struct sharp_memory_device *smd = drm_to_sharp_memory_device(connector->dev); 366 + 367 + return drm_connector_helper_get_modes_fixed(connector, smd->mode); 368 + } 369 + 370 + static const struct drm_connector_helper_funcs sharp_memory_connector_hfuncs = { 371 + .get_modes = sharp_memory_connector_get_modes, 372 + }; 373 + 374 + static const struct drm_connector_funcs sharp_memory_connector_funcs = { 375 + .reset = drm_atomic_helper_connector_reset, 376 + .fill_modes = drm_helper_probe_single_connector_modes, 377 + .destroy = drm_connector_cleanup, 378 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 379 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 380 + 381 + }; 382 + 383 + static const struct drm_mode_config_funcs sharp_memory_mode_config_funcs = { 384 + .fb_create = drm_gem_fb_create_with_dirty, 385 + .atomic_check = drm_atomic_helper_check, 386 + .atomic_commit = drm_atomic_helper_commit, 387 + }; 388 + 389 + static const struct drm_display_mode sharp_memory_ls010b7dh04_mode = { 390 + DRM_SIMPLE_MODE(128, 128, 18, 18), 391 + }; 392 + 393 + static const struct drm_display_mode sharp_memory_ls011b7dh03_mode = { 394 + DRM_SIMPLE_MODE(160, 68, 25, 10), 395 + }; 396 + 397 + static const struct drm_display_mode sharp_memory_ls012b7dd01_mode = { 398 + DRM_SIMPLE_MODE(184, 38, 29, 6), 399 + }; 400 + 401 + static const struct drm_display_mode sharp_memory_ls013b7dh03_mode = { 402 + DRM_SIMPLE_MODE(128, 128, 23, 23), 403 + }; 404 + 405 + static const struct drm_display_mode sharp_memory_ls013b7dh05_mode = { 406 + DRM_SIMPLE_MODE(144, 168, 20, 24), 407 + }; 408 + 409 + static const struct drm_display_mode sharp_memory_ls018b7dh02_mode = { 410 + DRM_SIMPLE_MODE(230, 303, 27, 36), 411 + }; 412 + 413 + static const struct drm_display_mode sharp_memory_ls027b7dh01_mode = { 414 + DRM_SIMPLE_MODE(400, 240, 58, 35), 415 + }; 416 + 417 + static const struct drm_display_mode sharp_memory_ls032b7dd02_mode = { 418 + DRM_SIMPLE_MODE(336, 536, 42, 68), 419 + }; 420 + 421 + static const struct drm_display_mode sharp_memory_ls044q7dh01_mode = { 422 + DRM_SIMPLE_MODE(320, 240, 89, 67), 423 + }; 424 + 425 + static const struct spi_device_id sharp_memory_ids[] = { 426 + {"ls010b7dh04", (kernel_ulong_t)&sharp_memory_ls010b7dh04_mode}, 427 + {"ls011b7dh03", (kernel_ulong_t)&sharp_memory_ls011b7dh03_mode}, 428 + {"ls012b7dd01", (kernel_ulong_t)&sharp_memory_ls012b7dd01_mode}, 429 + {"ls013b7dh03", (kernel_ulong_t)&sharp_memory_ls013b7dh03_mode}, 430 + {"ls013b7dh05", (kernel_ulong_t)&sharp_memory_ls013b7dh05_mode}, 431 + {"ls018b7dh02", (kernel_ulong_t)&sharp_memory_ls018b7dh02_mode}, 432 + {"ls027b7dh01", (kernel_ulong_t)&sharp_memory_ls027b7dh01_mode}, 433 + {"ls027b7dh01a", (kernel_ulong_t)&sharp_memory_ls027b7dh01_mode}, 434 + {"ls032b7dd02", (kernel_ulong_t)&sharp_memory_ls032b7dd02_mode}, 435 + {"ls044q7dh01", (kernel_ulong_t)&sharp_memory_ls044q7dh01_mode}, 436 + {}, 437 + }; 438 + MODULE_DEVICE_TABLE(spi, sharp_memory_ids); 439 + 440 + static const struct of_device_id sharp_memory_of_match[] = { 441 + {.compatible = "sharp,ls010b7dh04", &sharp_memory_ls010b7dh04_mode}, 442 + {.compatible = "sharp,ls011b7dh03", &sharp_memory_ls011b7dh03_mode}, 443 + {.compatible = "sharp,ls012b7dd01", &sharp_memory_ls012b7dd01_mode}, 444 + {.compatible = "sharp,ls013b7dh03", &sharp_memory_ls013b7dh03_mode}, 445 + {.compatible = "sharp,ls013b7dh05", &sharp_memory_ls013b7dh05_mode}, 446 + {.compatible = "sharp,ls018b7dh02", &sharp_memory_ls018b7dh02_mode}, 447 + {.compatible = "sharp,ls027b7dh01", &sharp_memory_ls027b7dh01_mode}, 448 + {.compatible = "sharp,ls027b7dh01a", &sharp_memory_ls027b7dh01_mode}, 449 + {.compatible = "sharp,ls032b7dd02", &sharp_memory_ls032b7dd02_mode}, 450 + {.compatible = "sharp,ls044q7dh01", &sharp_memory_ls044q7dh01_mode}, 451 + {}, 452 + }; 453 + MODULE_DEVICE_TABLE(of, sharp_memory_of_match); 454 + 455 + static const u32 sharp_memory_formats[] = { 456 + DRM_FORMAT_XRGB8888, 457 + }; 458 + 459 + static int sharp_memory_pipe_init(struct drm_device *dev, 460 + struct sharp_memory_device *smd, 461 + const u32 *formats, unsigned int format_count, 462 + const u64 *format_modifiers) 463 + { 464 + int ret; 465 + struct drm_encoder *encoder = &smd->encoder; 466 + struct drm_plane *plane = &smd->plane; 467 + struct drm_crtc *crtc = &smd->crtc; 468 + struct drm_connector *connector = &smd->connector; 469 + 470 + drm_plane_helper_add(plane, &sharp_memory_plane_helper_funcs); 471 + ret = drm_universal_plane_init(dev, plane, 0, 472 + &sharp_memory_plane_funcs, 473 + formats, format_count, 474 + format_modifiers, 475 + DRM_PLANE_TYPE_PRIMARY, NULL); 476 + if (ret) 477 + return ret; 478 + 479 + drm_crtc_helper_add(crtc, &sharp_memory_crtc_helper_funcs); 480 + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 481 + &sharp_memory_crtc_funcs, NULL); 482 + if (ret) 483 + return ret; 484 + 485 + encoder->possible_crtcs = drm_crtc_mask(crtc); 486 + ret = drm_encoder_init(dev, encoder, &sharp_memory_encoder_funcs, 487 + DRM_MODE_ENCODER_NONE, NULL); 488 + if (ret) 489 + return ret; 490 + 491 + ret = drm_connector_init(&smd->drm, &smd->connector, 492 + &sharp_memory_connector_funcs, 493 + DRM_MODE_CONNECTOR_SPI); 494 + if (ret) 495 + return ret; 496 + 497 + drm_connector_helper_add(&smd->connector, 498 + &sharp_memory_connector_hfuncs); 499 + 500 + return drm_connector_attach_encoder(connector, encoder); 501 + } 502 + 503 + static int sharp_memory_init_pwm_vcom_signal(struct sharp_memory_device *smd) 504 + { 505 + int ret; 506 + struct device *dev = &smd->spi->dev; 507 + struct pwm_state pwm_state; 508 + 509 + smd->pwm_vcom_signal = devm_pwm_get(dev, NULL); 510 + if (IS_ERR(smd->pwm_vcom_signal)) 511 + return dev_err_probe(dev, PTR_ERR(smd->pwm_vcom_signal), 512 + "Could not get pwm device\n"); 513 + 514 + pwm_init_state(smd->pwm_vcom_signal, &pwm_state); 515 + pwm_set_relative_duty_cycle(&pwm_state, 1, 10); 516 + pwm_state.enabled = true; 517 + ret = pwm_apply_might_sleep(smd->pwm_vcom_signal, &pwm_state); 518 + if (ret) 519 + return dev_err_probe(dev, -EINVAL, "Could not apply pwm state\n"); 520 + 521 + return 0; 522 + } 523 + 524 + static int sharp_memory_probe(struct spi_device *spi) 525 + { 526 + int ret; 527 + struct device *dev; 528 + struct sharp_memory_device *smd; 529 + struct drm_device *drm; 530 + const char *vcom_mode_str; 531 + 532 + dev = &spi->dev; 533 + 534 + ret = spi_setup(spi); 535 + if (ret < 0) 536 + return dev_err_probe(dev, ret, "Failed to setup spi device\n"); 537 + 538 + if (!dev->coherent_dma_mask) { 539 + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); 540 + if (ret) 541 + return dev_err_probe(dev, ret, "Failed to set dma mask\n"); 542 + } 543 + 544 + smd = devm_drm_dev_alloc(dev, &sharp_memory_drm_driver, 545 + struct sharp_memory_device, drm); 546 + if (!smd) 547 + return -ENOMEM; 548 + 549 + spi_set_drvdata(spi, smd); 550 + 551 + smd->spi = spi; 552 + drm = &smd->drm; 553 + ret = drmm_mode_config_init(drm); 554 + if (ret) 555 + return dev_err_probe(dev, ret, "Failed to initialize drm config\n"); 556 + 557 + smd->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); 558 + if (!smd->enable_gpio) 559 + dev_warn(dev, "Enable gpio not defined\n"); 560 + 561 + drm->mode_config.funcs = &sharp_memory_mode_config_funcs; 562 + smd->mode = spi_get_device_match_data(spi); 563 + 564 + smd->pitch = (SHARP_ADDR_PERIOD + smd->mode->hdisplay + SHARP_DUMMY_PERIOD) / 8; 565 + smd->tx_buffer_size = (SHARP_MODE_PERIOD + 566 + (SHARP_ADDR_PERIOD + (smd->mode->hdisplay) + SHARP_DUMMY_PERIOD) * 567 + smd->mode->vdisplay) / 8; 568 + 569 + smd->tx_buffer = devm_kzalloc(dev, smd->tx_buffer_size, GFP_KERNEL); 570 + if (!smd->tx_buffer) 571 + return -ENOMEM; 572 + 573 + mutex_init(&smd->tx_mutex); 574 + 575 + /* 576 + * VCOM is a signal that prevents DC bias from being built up in 577 + * the panel resulting in pixels being forever stuck in one state. 578 + * 579 + * This driver supports three different methods to generate this 580 + * signal depending on EXTMODE pin: 581 + * 582 + * software (EXTMODE = L) - This mode uses a kthread to 583 + * periodically send a "maintain display" message to the display, 584 + * toggling the vcom bit on and off with each message 585 + * 586 + * external (EXTMODE = H) - This mode relies on an external 587 + * clock to generate the signal on the EXTCOMM pin 588 + * 589 + * pwm (EXTMODE = H) - This mode uses a pwm device to generate 590 + * the signal on the EXTCOMM pin 591 + * 592 + */ 593 + if (device_property_read_string(dev, "sharp,vcom-mode", &vcom_mode_str)) 594 + return dev_err_probe(dev, -EINVAL, 595 + "Unable to find sharp,vcom-mode node in device tree\n"); 596 + 597 + if (!strcmp("software", vcom_mode_str)) { 598 + smd->vcom_mode = SHARP_MEMORY_SOFTWARE_VCOM; 599 + smd->sw_vcom_signal = kthread_run(sharp_memory_sw_vcom_signal_thread, 600 + smd, "sw_vcom_signal"); 601 + 602 + } else if (!strcmp("external", vcom_mode_str)) { 603 + smd->vcom_mode = SHARP_MEMORY_EXTERNAL_VCOM; 604 + 605 + } else if (!strcmp("pwm", vcom_mode_str)) { 606 + smd->vcom_mode = SHARP_MEMORY_PWM_VCOM; 607 + ret = sharp_memory_init_pwm_vcom_signal(smd); 608 + if (ret) 609 + return ret; 610 + } else { 611 + return dev_err_probe(dev, -EINVAL, "Invalid value set for vcom-mode\n"); 612 + } 613 + 614 + drm->mode_config.min_width = smd->mode->hdisplay; 615 + drm->mode_config.max_width = smd->mode->hdisplay; 616 + drm->mode_config.min_height = smd->mode->vdisplay; 617 + drm->mode_config.max_height = smd->mode->vdisplay; 618 + 619 + ret = sharp_memory_pipe_init(drm, smd, sharp_memory_formats, 620 + ARRAY_SIZE(sharp_memory_formats), 621 + NULL); 622 + if (ret) 623 + return dev_err_probe(dev, ret, "Failed to initialize display pipeline.\n"); 624 + 625 + drm_plane_enable_fb_damage_clips(&smd->plane); 626 + drm_mode_config_reset(drm); 627 + 628 + ret = drm_dev_register(drm, 0); 629 + if (ret) 630 + return dev_err_probe(dev, ret, "Failed to register drm device.\n"); 631 + 632 + drm_client_setup(drm, NULL); 633 + 634 + return 0; 635 + } 636 + 637 + static void sharp_memory_remove(struct spi_device *spi) 638 + { 639 + struct sharp_memory_device *smd = spi_get_drvdata(spi); 640 + 641 + drm_dev_unplug(&smd->drm); 642 + drm_atomic_helper_shutdown(&smd->drm); 643 + 644 + switch (smd->vcom_mode) { 645 + case SHARP_MEMORY_SOFTWARE_VCOM: 646 + kthread_stop(smd->sw_vcom_signal); 647 + break; 648 + 649 + case SHARP_MEMORY_EXTERNAL_VCOM: 650 + break; 651 + 652 + case SHARP_MEMORY_PWM_VCOM: 653 + pwm_disable(smd->pwm_vcom_signal); 654 + break; 655 + } 656 + } 657 + 658 + static struct spi_driver sharp_memory_spi_driver = { 659 + .driver = { 660 + .name = "sharp_memory", 661 + .of_match_table = sharp_memory_of_match, 662 + }, 663 + .probe = sharp_memory_probe, 664 + .remove = sharp_memory_remove, 665 + .id_table = sharp_memory_ids, 666 + }; 667 + module_spi_driver(sharp_memory_spi_driver); 668 + 669 + MODULE_AUTHOR("Alex Lanzano <lanzano.alex@gmail.com>"); 670 + MODULE_DESCRIPTION("SPI Protocol driver for the sharp_memory display"); 671 + MODULE_LICENSE("GPL");
+2 -7
drivers/gpu/drm/v3d/v3d_bo.c
··· 157 157 struct v3d_bo *bo; 158 158 int ret; 159 159 160 - /* Let the user opt out of allocating the BOs with THP */ 161 - if (v3d->gemfs) 162 - shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size, 163 - v3d->gemfs); 164 - else 165 - shmem_obj = drm_gem_shmem_create(dev, unaligned_size); 166 - 160 + shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size, 161 + v3d->gemfs); 167 162 if (IS_ERR(shmem_obj)) 168 163 return ERR_CAST(shmem_obj); 169 164 bo = to_v3d_bo(&shmem_obj->base);
+1
drivers/gpu/drm/xe/Kconfig
··· 8 8 select SHMEM 9 9 select TMPFS 10 10 select DRM_BUDDY 11 + select DRM_CLIENT_SELECTION 11 12 select DRM_EXEC 12 13 select DRM_KMS_HELPER 13 14 select DRM_KUNIT_TEST_HELPERS if DRM_XE_KUNIT_TEST != n
+3
drivers/gpu/drm/xlnx/zynqmp_disp.c
··· 1200 1200 { 1201 1201 unsigned int i; 1202 1202 1203 + if (!layer->info) 1204 + return; 1205 + 1203 1206 for (i = 0; i < layer->info->num_channels; i++) { 1204 1207 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; 1205 1208
+796 -47
drivers/gpu/drm/xlnx/zynqmp_dp.c
··· 18 18 #include <drm/drm_modes.h> 19 19 #include <drm/drm_of.h> 20 20 21 + #include <linux/bitfield.h> 21 22 #include <linux/clk.h> 23 + #include <linux/debugfs.h> 22 24 #include <linux/delay.h> 23 25 #include <linux/device.h> 24 26 #include <linux/io.h> ··· 53 51 #define ZYNQMP_DP_LANE_COUNT_SET 0x4 54 52 #define ZYNQMP_DP_ENHANCED_FRAME_EN 0x8 55 53 #define ZYNQMP_DP_TRAINING_PATTERN_SET 0xc 54 + #define ZYNQMP_DP_LINK_QUAL_PATTERN_SET 0x10 56 55 #define ZYNQMP_DP_SCRAMBLING_DISABLE 0x14 57 56 #define ZYNQMP_DP_DOWNSPREAD_CTL 0x18 58 57 #define ZYNQMP_DP_SOFTWARE_RESET 0x1c ··· 67 64 ZYNQMP_DP_SOFTWARE_RESET_STREAM3 | \ 68 65 ZYNQMP_DP_SOFTWARE_RESET_STREAM4 | \ 69 66 ZYNQMP_DP_SOFTWARE_RESET_AUX) 67 + #define ZYNQMP_DP_COMP_PATTERN_80BIT_1 0x20 68 + #define ZYNQMP_DP_COMP_PATTERN_80BIT_2 0x24 69 + #define ZYNQMP_DP_COMP_PATTERN_80BIT_3 0x28 70 70 71 71 /* Core enable registers */ 72 72 #define ZYNQMP_DP_TRANSMITTER_ENABLE 0x80 ··· 213 207 #define ZYNQMP_DP_TX_PHY_POWER_DOWN_LANE_2 BIT(2) 214 208 #define ZYNQMP_DP_TX_PHY_POWER_DOWN_LANE_3 BIT(3) 215 209 #define ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL 0xf 210 + #define ZYNQMP_DP_TRANSMIT_PRBS7 0x230 216 211 #define ZYNQMP_DP_PHY_PRECURSOR_LANE_0 0x23c 217 212 #define ZYNQMP_DP_PHY_PRECURSOR_LANE_1 0x240 218 213 #define ZYNQMP_DP_PHY_PRECURSOR_LANE_2 0x244 ··· 282 275 }; 283 276 284 277 /** 278 + * enum test_pattern - Test patterns for test testing 279 + * @TEST_VIDEO: Use regular video input 280 + * @TEST_SYMBOL_ERROR: Symbol error measurement pattern 281 + * @TEST_PRBS7: Output of the PRBS7 (x^7 + x^6 + 1) polynomial 282 + * @TEST_80BIT_CUSTOM: A custom 80-bit pattern 283 + * @TEST_CP2520: HBR2 compliance eye pattern 284 + * @TEST_TPS1: Link training symbol pattern TPS1 (/D10.2/) 285 + * @TEST_TPS2: Link training symbol pattern TPS2 286 + * @TEST_TPS3: Link training symbol pattern TPS3 (for HBR2) 287 + */ 288 + enum test_pattern { 289 + TEST_VIDEO, 290 + TEST_TPS1, 291 + TEST_TPS2, 292 + TEST_TPS3, 293 + TEST_SYMBOL_ERROR, 294 + TEST_PRBS7, 295 + TEST_80BIT_CUSTOM, 296 + TEST_CP2520, 297 + }; 298 + 299 + static const char *const test_pattern_str[] = { 300 + [TEST_VIDEO] = "video", 301 + [TEST_TPS1] = "tps1", 302 + [TEST_TPS2] = "tps2", 303 + [TEST_TPS3] = "tps3", 304 + [TEST_SYMBOL_ERROR] = "symbol-error", 305 + [TEST_PRBS7] = "prbs7", 306 + [TEST_80BIT_CUSTOM] = "80bit-custom", 307 + [TEST_CP2520] = "cp2520", 308 + }; 309 + 310 + /** 311 + * struct zynqmp_dp_test - Configuration for test mode 312 + * @pattern: The test pattern 313 + * @enhanced: Use enhanced framing 314 + * @downspread: Use SSC 315 + * @active: Whether test mode is active 316 + * @custom: Custom pattern for %TEST_80BIT_CUSTOM 317 + * @train_set: Voltage/preemphasis settings 318 + * @bw_code: Bandwidth code for the link 319 + * @link_cnt: Number of lanes 320 + */ 321 + struct zynqmp_dp_test { 322 + enum test_pattern pattern; 323 + bool enhanced, downspread, active; 324 + u8 custom[10]; 325 + u8 train_set[ZYNQMP_DP_MAX_LANES]; 326 + u8 bw_code; 327 + u8 link_cnt; 328 + }; 329 + 330 + /** 331 + * struct zynqmp_dp_train_set_priv - Private data for train_set debugfs files 332 + * @dp: DisplayPort IP core structure 333 + * @lane: The lane for this file 334 + */ 335 + struct zynqmp_dp_train_set_priv { 336 + struct zynqmp_dp *dp; 337 + int lane; 338 + }; 339 + 340 + /** 285 341 * struct zynqmp_dp - Xilinx DisplayPort core 286 342 * @dev: device structure 287 343 * @dpsub: Display subsystem 288 344 * @iomem: device I/O memory for register access 289 345 * @reset: reset controller 346 + * @lock: Mutex protecting this struct and register access (but not AUX) 290 347 * @irq: irq 291 348 * @bridge: DRM bridge for the DP encoder 292 349 * @next_bridge: The downstream bridge 350 + * @test: Configuration for test mode 293 351 * @config: IP core configuration from DTS 294 352 * @aux: aux channel 353 + * @aux_done: Completed when we get an AUX reply or timeout 354 + * @ignore_aux_errors: If set, AUX errors are suppressed 295 355 * @phy: PHY handles for DP lanes 296 356 * @num_lanes: number of enabled phy lanes 297 357 * @hpd_work: hot plug detection worker 358 + * @hpd_irq_work: hot plug detection IRQ worker 359 + * @ignore_hpd: If set, HPD events and IRQs are ignored 298 360 * @status: connection status 299 361 * @enabled: flag to indicate if the device is enabled 300 362 * @dpcd: DP configuration data from currently connected sink device 301 363 * @link_config: common link configuration between IP core and sink device 302 364 * @mode: current mode between IP core and sink device 303 365 * @train_set: set of training data 366 + * @debugfs_train_set: Debugfs private data for @train_set 367 + * 368 + * @lock covers the link configuration in this struct and the device's 369 + * registers. It does not cover @aux or @ignore_aux_errors. It is not strictly 370 + * required for any of the members which are only modified at probe/remove time 371 + * (e.g. @dev). 304 372 */ 305 373 struct zynqmp_dp { 306 374 struct drm_dp_aux aux; 307 375 struct drm_bridge bridge; 308 376 struct work_struct hpd_work; 377 + struct work_struct hpd_irq_work; 378 + struct completion aux_done; 379 + struct mutex lock; 309 380 310 381 struct drm_bridge *next_bridge; 311 382 struct device *dev; ··· 395 310 enum drm_connector_status status; 396 311 int irq; 397 312 bool enabled; 313 + bool ignore_aux_errors; 314 + bool ignore_hpd; 398 315 316 + struct zynqmp_dp_train_set_priv debugfs_train_set[ZYNQMP_DP_MAX_LANES]; 399 317 struct zynqmp_dp_mode mode; 400 318 struct zynqmp_dp_link_config link_config; 319 + struct zynqmp_dp_test test; 401 320 struct zynqmp_dp_config config; 402 321 u8 dpcd[DP_RECEIVER_CAP_SIZE]; 403 322 u8 train_set[ZYNQMP_DP_MAX_LANES]; ··· 715 626 /** 716 627 * zynqmp_dp_update_vs_emph - Update the training values 717 628 * @dp: DisplayPort IP core structure 629 + * @train_set: A set of training values 718 630 * 719 631 * Update the training values based on the request from sink. The mapped values 720 632 * are predefined, and values(vs, pe, pc) are from the device manual. ··· 723 633 * Return: 0 if vs and emph are updated successfully, or the error code returned 724 634 * by drm_dp_dpcd_write(). 725 635 */ 726 - static int zynqmp_dp_update_vs_emph(struct zynqmp_dp *dp) 636 + static int zynqmp_dp_update_vs_emph(struct zynqmp_dp *dp, u8 *train_set) 727 637 { 728 638 unsigned int i; 729 639 int ret; 730 640 731 - ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->train_set, 641 + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, 732 642 dp->mode.lane_cnt); 733 643 if (ret < 0) 734 644 return ret; ··· 736 646 for (i = 0; i < dp->mode.lane_cnt; i++) { 737 647 u32 reg = ZYNQMP_DP_SUB_TX_PHY_PRECURSOR_LANE_0 + i * 4; 738 648 union phy_configure_opts opts = { 0 }; 739 - u8 train = dp->train_set[i]; 649 + u8 train = train_set[i]; 740 650 741 651 opts.dp.voltage[0] = (train & DP_TRAIN_VOLTAGE_SWING_MASK) 742 652 >> DP_TRAIN_VOLTAGE_SWING_SHIFT; ··· 780 690 * So, This loop should exit before 512 iterations 781 691 */ 782 692 for (max_tries = 0; max_tries < 512; max_tries++) { 783 - ret = zynqmp_dp_update_vs_emph(dp); 693 + ret = zynqmp_dp_update_vs_emph(dp, dp->train_set); 784 694 if (ret) 785 695 return ret; 786 696 ··· 845 755 return ret; 846 756 847 757 for (tries = 0; tries < DP_MAX_TRAINING_TRIES; tries++) { 848 - ret = zynqmp_dp_update_vs_emph(dp); 758 + ret = zynqmp_dp_update_vs_emph(dp, dp->train_set); 849 759 if (ret) 850 760 return ret; 851 761 ··· 868 778 } 869 779 870 780 /** 871 - * zynqmp_dp_train - Train the link 781 + * zynqmp_dp_setup() - Set up major link parameters 872 782 * @dp: DisplayPort IP core structure 783 + * @bw_code: The link bandwidth as a multiple of 270 MHz 784 + * @lane_cnt: The number of lanes to use 785 + * @enhanced: Use enhanced framing 786 + * @downspread: Enable spread-spectrum clocking 873 787 * 874 - * Return: 0 if all trains are done successfully, or corresponding error code. 788 + * Return: 0 on success, or -errno on failure 875 789 */ 876 - static int zynqmp_dp_train(struct zynqmp_dp *dp) 790 + static int zynqmp_dp_setup(struct zynqmp_dp *dp, u8 bw_code, u8 lane_cnt, 791 + bool enhanced, bool downspread) 877 792 { 878 793 u32 reg; 879 - u8 bw_code = dp->mode.bw_code; 880 - u8 lane_cnt = dp->mode.lane_cnt; 881 794 u8 aux_lane_cnt = lane_cnt; 882 - bool enhanced; 883 795 int ret; 884 796 885 797 zynqmp_dp_write(dp, ZYNQMP_DP_LANE_COUNT_SET, lane_cnt); 886 - enhanced = drm_dp_enhanced_frame_cap(dp->dpcd); 887 798 if (enhanced) { 888 799 zynqmp_dp_write(dp, ZYNQMP_DP_ENHANCED_FRAME_EN, 1); 889 800 aux_lane_cnt |= DP_LANE_COUNT_ENHANCED_FRAME_EN; 890 801 } 891 802 892 - if (dp->dpcd[3] & 0x1) { 803 + if (downspread) { 893 804 zynqmp_dp_write(dp, ZYNQMP_DP_DOWNSPREAD_CTL, 1); 894 805 drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, 895 806 DP_SPREAD_AMP_0_5); ··· 933 842 } 934 843 935 844 zynqmp_dp_write(dp, ZYNQMP_DP_PHY_CLOCK_SELECT, reg); 936 - ret = zynqmp_dp_phy_ready(dp); 937 - if (ret < 0) 845 + return zynqmp_dp_phy_ready(dp); 846 + } 847 + 848 + /** 849 + * zynqmp_dp_train - Train the link 850 + * @dp: DisplayPort IP core structure 851 + * 852 + * Return: 0 if all trains are done successfully, or corresponding error code. 853 + */ 854 + static int zynqmp_dp_train(struct zynqmp_dp *dp) 855 + { 856 + int ret; 857 + 858 + ret = zynqmp_dp_setup(dp, dp->mode.bw_code, dp->mode.lane_cnt, 859 + drm_dp_enhanced_frame_cap(dp->dpcd), 860 + dp->dpcd[DP_MAX_DOWNSPREAD] & 861 + DP_MAX_DOWNSPREAD_0_5); 862 + if (ret) 938 863 return ret; 939 864 940 865 zynqmp_dp_write(dp, ZYNQMP_DP_SCRAMBLING_DISABLE, 1); ··· 1041 934 u8 *buf, u8 bytes, u8 *reply) 1042 935 { 1043 936 bool is_read = (cmd & AUX_READ_BIT) ? true : false; 937 + unsigned long time_left; 1044 938 u32 reg, i; 1045 939 1046 940 reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); 1047 941 if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REQUEST) 1048 942 return -EBUSY; 943 + 944 + reinit_completion(&dp->aux_done); 1049 945 1050 946 zynqmp_dp_write(dp, ZYNQMP_DP_AUX_ADDRESS, addr); 1051 947 if (!is_read) ··· 1064 954 zynqmp_dp_write(dp, ZYNQMP_DP_AUX_COMMAND, reg); 1065 955 1066 956 /* Wait for reply to be delivered upto 2ms */ 1067 - for (i = 0; ; i++) { 1068 - reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); 1069 - if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY) 1070 - break; 957 + time_left = wait_for_completion_timeout(&dp->aux_done, 958 + msecs_to_jiffies(2)); 959 + if (!time_left) 960 + return -ETIMEDOUT; 1071 961 1072 - if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT || 1073 - i == 2) 1074 - return -ETIMEDOUT; 1075 - 1076 - usleep_range(1000, 1100); 1077 - } 962 + reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); 963 + if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT) 964 + return -ETIMEDOUT; 1078 965 1079 966 reg = zynqmp_dp_read(dp, ZYNQMP_DP_AUX_REPLY_CODE); 1080 967 if (reply) ··· 1113 1006 1114 1007 if (dp->status == connector_status_disconnected) { 1115 1008 dev_dbg(dp->dev, "no connected aux device\n"); 1009 + if (dp->ignore_aux_errors) 1010 + goto fake_response; 1116 1011 return -ENODEV; 1117 1012 } 1118 1013 ··· 1123 1014 1124 1015 dev_dbg(dp->dev, "failed to do aux transfer (%d)\n", ret); 1125 1016 1126 - return ret; 1017 + if (!dp->ignore_aux_errors) 1018 + return ret; 1019 + 1020 + fake_response: 1021 + msg->reply = DP_AUX_NATIVE_REPLY_ACK; 1022 + memset(msg->buffer, 0, msg->size); 1023 + return msg->size; 1127 1024 } 1128 1025 1129 1026 /** ··· 1163 1048 (w << ZYNQMP_DP_AUX_CLK_DIVIDER_AUX_FILTER_SHIFT) | 1164 1049 (rate / (1000 * 1000))); 1165 1050 1051 + zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_REPLY_RECEIVED | 1052 + ZYNQMP_DP_INT_REPLY_TIMEOUT); 1053 + 1166 1054 dp->aux.name = "ZynqMP DP AUX"; 1167 1055 dp->aux.dev = dp->dev; 1168 1056 dp->aux.drm_dev = dp->bridge.dev; ··· 1183 1065 static void zynqmp_dp_aux_cleanup(struct zynqmp_dp *dp) 1184 1066 { 1185 1067 drm_dp_aux_unregister(&dp->aux); 1068 + 1069 + zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_REPLY_RECEIVED | 1070 + ZYNQMP_DP_INT_REPLY_TIMEOUT); 1186 1071 } 1187 1072 1188 1073 /* ----------------------------------------------------------------------------- ··· 1507 1386 } 1508 1387 1509 1388 /* Check with link rate and lane count */ 1389 + mutex_lock(&dp->lock); 1510 1390 rate = zynqmp_dp_max_rate(dp->link_config.max_rate, 1511 1391 dp->link_config.max_lanes, dp->config.bpp); 1392 + mutex_unlock(&dp->lock); 1512 1393 if (mode->clock > rate) { 1513 1394 dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n", 1514 1395 mode->name); ··· 1537 1414 1538 1415 pm_runtime_get_sync(dp->dev); 1539 1416 1417 + mutex_lock(&dp->lock); 1540 1418 zynqmp_dp_disp_enable(dp, old_bridge_state); 1541 1419 1542 1420 /* ··· 1598 1474 zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET, 1599 1475 ZYNQMP_DP_SOFTWARE_RESET_ALL); 1600 1476 zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); 1477 + mutex_unlock(&dp->lock); 1601 1478 } 1602 1479 1603 1480 static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, ··· 1606 1481 { 1607 1482 struct zynqmp_dp *dp = bridge_to_dp(bridge); 1608 1483 1484 + mutex_lock(&dp->lock); 1609 1485 dp->enabled = false; 1610 1486 cancel_work(&dp->hpd_work); 1611 1487 zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); ··· 1617 1491 zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); 1618 1492 1619 1493 zynqmp_dp_disp_disable(dp, old_bridge_state); 1494 + mutex_unlock(&dp->lock); 1620 1495 1621 1496 pm_runtime_put_sync(dp->dev); 1622 1497 } ··· 1653 1526 return 0; 1654 1527 } 1655 1528 1656 - static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge) 1529 + static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp) 1657 1530 { 1658 - struct zynqmp_dp *dp = bridge_to_dp(bridge); 1659 1531 struct zynqmp_dp_link_config *link_config = &dp->link_config; 1660 1532 u32 state, i; 1661 1533 int ret; 1534 + 1535 + lockdep_assert_held(&dp->lock); 1662 1536 1663 1537 /* 1664 1538 * This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to ··· 1694 1566 disconnected: 1695 1567 dp->status = connector_status_disconnected; 1696 1568 return connector_status_disconnected; 1569 + } 1570 + 1571 + static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge) 1572 + { 1573 + struct zynqmp_dp *dp = bridge_to_dp(bridge); 1574 + enum drm_connector_status ret; 1575 + 1576 + mutex_lock(&dp->lock); 1577 + ret = __zynqmp_dp_bridge_detect(dp); 1578 + mutex_unlock(&dp->lock); 1579 + 1580 + return ret; 1697 1581 } 1698 1582 1699 1583 static const struct drm_edid *zynqmp_dp_bridge_edid_read(struct drm_bridge *bridge, ··· 1745 1605 return zynqmp_dp_bridge_default_bus_fmts(num_input_fmts); 1746 1606 } 1747 1607 1608 + /* ----------------------------------------------------------------------------- 1609 + * debugfs 1610 + */ 1611 + 1612 + /** 1613 + * zynqmp_dp_set_test_pattern() - Configure the link for a test pattern 1614 + * @dp: DisplayPort IP core structure 1615 + * @pattern: The test pattern to configure 1616 + * @custom: The custom pattern to use if @pattern is %TEST_80BIT_CUSTOM 1617 + * 1618 + * Return: 0 on success, or negative errno on (DPCD) failure 1619 + */ 1620 + static int zynqmp_dp_set_test_pattern(struct zynqmp_dp *dp, 1621 + enum test_pattern pattern, 1622 + u8 *const custom) 1623 + { 1624 + bool scramble = false; 1625 + u32 train_pattern = 0; 1626 + u32 link_pattern = 0; 1627 + u8 dpcd_train = 0; 1628 + u8 dpcd_link = 0; 1629 + int ret; 1630 + 1631 + switch (pattern) { 1632 + case TEST_TPS1: 1633 + train_pattern = 1; 1634 + break; 1635 + case TEST_TPS2: 1636 + train_pattern = 2; 1637 + break; 1638 + case TEST_TPS3: 1639 + train_pattern = 3; 1640 + break; 1641 + case TEST_SYMBOL_ERROR: 1642 + scramble = true; 1643 + link_pattern = DP_PHY_TEST_PATTERN_ERROR_COUNT; 1644 + break; 1645 + case TEST_PRBS7: 1646 + /* We use a dedicated register to enable PRBS7 */ 1647 + dpcd_link = DP_LINK_QUAL_PATTERN_ERROR_RATE; 1648 + break; 1649 + case TEST_80BIT_CUSTOM: { 1650 + const u8 *p = custom; 1651 + 1652 + link_pattern = DP_LINK_QUAL_PATTERN_80BIT_CUSTOM; 1653 + 1654 + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_1, 1655 + (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); 1656 + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_2, 1657 + (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]); 1658 + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_3, 1659 + (p[9] << 8) | p[8]); 1660 + break; 1661 + } 1662 + case TEST_CP2520: 1663 + link_pattern = DP_LINK_QUAL_PATTERN_CP2520_PAT_1; 1664 + break; 1665 + default: 1666 + WARN_ON_ONCE(1); 1667 + fallthrough; 1668 + case TEST_VIDEO: 1669 + scramble = true; 1670 + } 1671 + 1672 + zynqmp_dp_write(dp, ZYNQMP_DP_SCRAMBLING_DISABLE, !scramble); 1673 + zynqmp_dp_write(dp, ZYNQMP_DP_TRAINING_PATTERN_SET, train_pattern); 1674 + zynqmp_dp_write(dp, ZYNQMP_DP_LINK_QUAL_PATTERN_SET, link_pattern); 1675 + zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMIT_PRBS7, pattern == TEST_PRBS7); 1676 + 1677 + dpcd_link = dpcd_link ?: link_pattern; 1678 + dpcd_train = train_pattern; 1679 + if (!scramble) 1680 + dpcd_train |= DP_LINK_SCRAMBLING_DISABLE; 1681 + 1682 + if (dp->dpcd[DP_DPCD_REV] < 0x12) { 1683 + if (pattern == TEST_CP2520) 1684 + dev_warn(dp->dev, 1685 + "can't set sink link quality pattern to CP2520 for DPCD < r1.2; error counters will be invalid\n"); 1686 + else 1687 + dpcd_train |= FIELD_PREP(DP_LINK_QUAL_PATTERN_11_MASK, 1688 + dpcd_link); 1689 + } else { 1690 + u8 dpcd_link_lane[ZYNQMP_DP_MAX_LANES]; 1691 + 1692 + memset(dpcd_link_lane, dpcd_link, ZYNQMP_DP_MAX_LANES); 1693 + ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_QUAL_LANE0_SET, 1694 + dpcd_link_lane, ZYNQMP_DP_MAX_LANES); 1695 + if (ret < 0) 1696 + return ret; 1697 + } 1698 + 1699 + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, dpcd_train); 1700 + return ret < 0 ? ret : 0; 1701 + } 1702 + 1703 + static int zynqmp_dp_test_setup(struct zynqmp_dp *dp) 1704 + { 1705 + return zynqmp_dp_setup(dp, dp->test.bw_code, dp->test.link_cnt, 1706 + dp->test.enhanced, dp->test.downspread); 1707 + } 1708 + 1709 + static ssize_t zynqmp_dp_pattern_read(struct file *file, char __user *user_buf, 1710 + size_t count, loff_t *ppos) 1711 + { 1712 + struct dentry *dentry = file->f_path.dentry; 1713 + struct zynqmp_dp *dp = file->private_data; 1714 + char buf[16]; 1715 + ssize_t ret; 1716 + 1717 + ret = debugfs_file_get(dentry); 1718 + if (unlikely(ret)) 1719 + return ret; 1720 + 1721 + mutex_lock(&dp->lock); 1722 + ret = snprintf(buf, sizeof(buf), "%s\n", 1723 + test_pattern_str[dp->test.pattern]); 1724 + mutex_unlock(&dp->lock); 1725 + 1726 + debugfs_file_put(dentry); 1727 + return simple_read_from_buffer(user_buf, count, ppos, buf, ret); 1728 + } 1729 + 1730 + static ssize_t zynqmp_dp_pattern_write(struct file *file, 1731 + const char __user *user_buf, 1732 + size_t count, loff_t *ppos) 1733 + { 1734 + struct dentry *dentry = file->f_path.dentry; 1735 + struct zynqmp_dp *dp = file->private_data; 1736 + char buf[16]; 1737 + ssize_t ret; 1738 + int pattern; 1739 + 1740 + ret = debugfs_file_get(dentry); 1741 + if (unlikely(ret)) 1742 + return ret; 1743 + 1744 + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, 1745 + count); 1746 + if (ret < 0) 1747 + goto out; 1748 + buf[ret] = '\0'; 1749 + 1750 + pattern = sysfs_match_string(test_pattern_str, buf); 1751 + if (pattern < 0) { 1752 + ret = -EINVAL; 1753 + goto out; 1754 + } 1755 + 1756 + mutex_lock(&dp->lock); 1757 + dp->test.pattern = pattern; 1758 + if (dp->test.active) 1759 + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, 1760 + dp->test.custom) ?: ret; 1761 + mutex_unlock(&dp->lock); 1762 + 1763 + out: 1764 + debugfs_file_put(dentry); 1765 + return ret; 1766 + } 1767 + 1768 + static const struct file_operations fops_zynqmp_dp_pattern = { 1769 + .read = zynqmp_dp_pattern_read, 1770 + .write = zynqmp_dp_pattern_write, 1771 + .open = simple_open, 1772 + .llseek = noop_llseek, 1773 + }; 1774 + 1775 + static int zynqmp_dp_enhanced_get(void *data, u64 *val) 1776 + { 1777 + struct zynqmp_dp *dp = data; 1778 + 1779 + mutex_lock(&dp->lock); 1780 + *val = dp->test.enhanced; 1781 + mutex_unlock(&dp->lock); 1782 + return 0; 1783 + } 1784 + 1785 + static int zynqmp_dp_enhanced_set(void *data, u64 val) 1786 + { 1787 + struct zynqmp_dp *dp = data; 1788 + int ret = 0; 1789 + 1790 + mutex_lock(&dp->lock); 1791 + dp->test.enhanced = val; 1792 + if (dp->test.active) 1793 + ret = zynqmp_dp_test_setup(dp); 1794 + mutex_unlock(&dp->lock); 1795 + 1796 + return ret; 1797 + } 1798 + 1799 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_enhanced, zynqmp_dp_enhanced_get, 1800 + zynqmp_dp_enhanced_set, "%llu\n"); 1801 + 1802 + static int zynqmp_dp_downspread_get(void *data, u64 *val) 1803 + { 1804 + struct zynqmp_dp *dp = data; 1805 + 1806 + mutex_lock(&dp->lock); 1807 + *val = dp->test.downspread; 1808 + mutex_unlock(&dp->lock); 1809 + return 0; 1810 + } 1811 + 1812 + static int zynqmp_dp_downspread_set(void *data, u64 val) 1813 + { 1814 + struct zynqmp_dp *dp = data; 1815 + int ret = 0; 1816 + 1817 + mutex_lock(&dp->lock); 1818 + dp->test.downspread = val; 1819 + if (dp->test.active) 1820 + ret = zynqmp_dp_test_setup(dp); 1821 + mutex_unlock(&dp->lock); 1822 + 1823 + return ret; 1824 + } 1825 + 1826 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_downspread, zynqmp_dp_downspread_get, 1827 + zynqmp_dp_downspread_set, "%llu\n"); 1828 + 1829 + static int zynqmp_dp_active_get(void *data, u64 *val) 1830 + { 1831 + struct zynqmp_dp *dp = data; 1832 + 1833 + mutex_lock(&dp->lock); 1834 + *val = dp->test.active; 1835 + mutex_unlock(&dp->lock); 1836 + return 0; 1837 + } 1838 + 1839 + static int zynqmp_dp_active_set(void *data, u64 val) 1840 + { 1841 + struct zynqmp_dp *dp = data; 1842 + int ret = 0; 1843 + 1844 + mutex_lock(&dp->lock); 1845 + if (val) { 1846 + if (val < 2) { 1847 + ret = zynqmp_dp_test_setup(dp); 1848 + if (ret) 1849 + goto out; 1850 + } 1851 + 1852 + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, 1853 + dp->test.custom); 1854 + if (ret) 1855 + goto out; 1856 + 1857 + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); 1858 + if (ret) 1859 + goto out; 1860 + 1861 + dp->test.active = true; 1862 + } else { 1863 + int err; 1864 + 1865 + dp->test.active = false; 1866 + err = zynqmp_dp_set_test_pattern(dp, TEST_VIDEO, NULL); 1867 + if (err) 1868 + dev_warn(dp->dev, "could not clear test pattern: %d\n", 1869 + err); 1870 + zynqmp_dp_train_loop(dp); 1871 + } 1872 + out: 1873 + mutex_unlock(&dp->lock); 1874 + 1875 + return ret; 1876 + } 1877 + 1878 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_active, zynqmp_dp_active_get, 1879 + zynqmp_dp_active_set, "%llu\n"); 1880 + 1881 + static ssize_t zynqmp_dp_custom_read(struct file *file, char __user *user_buf, 1882 + size_t count, loff_t *ppos) 1883 + { 1884 + struct dentry *dentry = file->f_path.dentry; 1885 + struct zynqmp_dp *dp = file->private_data; 1886 + ssize_t ret; 1887 + 1888 + ret = debugfs_file_get(dentry); 1889 + if (unlikely(ret)) 1890 + return ret; 1891 + 1892 + mutex_lock(&dp->lock); 1893 + ret = simple_read_from_buffer(user_buf, count, ppos, &dp->test.custom, 1894 + sizeof(dp->test.custom)); 1895 + mutex_unlock(&dp->lock); 1896 + 1897 + debugfs_file_put(dentry); 1898 + return ret; 1899 + } 1900 + 1901 + static ssize_t zynqmp_dp_custom_write(struct file *file, 1902 + const char __user *user_buf, 1903 + size_t count, loff_t *ppos) 1904 + { 1905 + struct dentry *dentry = file->f_path.dentry; 1906 + struct zynqmp_dp *dp = file->private_data; 1907 + ssize_t ret; 1908 + char buf[sizeof(dp->test.custom)]; 1909 + 1910 + ret = debugfs_file_get(dentry); 1911 + if (unlikely(ret)) 1912 + return ret; 1913 + 1914 + ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); 1915 + if (ret < 0) 1916 + goto out; 1917 + 1918 + mutex_lock(&dp->lock); 1919 + memcpy(dp->test.custom, buf, ret); 1920 + if (dp->test.active) 1921 + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, 1922 + dp->test.custom) ?: ret; 1923 + mutex_unlock(&dp->lock); 1924 + 1925 + out: 1926 + debugfs_file_put(dentry); 1927 + return ret; 1928 + } 1929 + 1930 + static const struct file_operations fops_zynqmp_dp_custom = { 1931 + .read = zynqmp_dp_custom_read, 1932 + .write = zynqmp_dp_custom_write, 1933 + .open = simple_open, 1934 + .llseek = noop_llseek, 1935 + }; 1936 + 1937 + static int zynqmp_dp_swing_get(void *data, u64 *val) 1938 + { 1939 + struct zynqmp_dp_train_set_priv *priv = data; 1940 + struct zynqmp_dp *dp = priv->dp; 1941 + 1942 + mutex_lock(&dp->lock); 1943 + *val = dp->test.train_set[priv->lane] & DP_TRAIN_VOLTAGE_SWING_MASK; 1944 + mutex_unlock(&dp->lock); 1945 + return 0; 1946 + } 1947 + 1948 + static int zynqmp_dp_swing_set(void *data, u64 val) 1949 + { 1950 + struct zynqmp_dp_train_set_priv *priv = data; 1951 + struct zynqmp_dp *dp = priv->dp; 1952 + u8 *train_set = &dp->test.train_set[priv->lane]; 1953 + int ret = 0; 1954 + 1955 + if (val > 3) 1956 + return -EINVAL; 1957 + 1958 + mutex_lock(&dp->lock); 1959 + *train_set &= ~(DP_TRAIN_MAX_SWING_REACHED | 1960 + DP_TRAIN_VOLTAGE_SWING_MASK); 1961 + *train_set |= val; 1962 + if (val == 3) 1963 + *train_set |= DP_TRAIN_MAX_SWING_REACHED; 1964 + 1965 + if (dp->test.active) 1966 + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); 1967 + mutex_unlock(&dp->lock); 1968 + 1969 + return ret; 1970 + } 1971 + 1972 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_swing, zynqmp_dp_swing_get, 1973 + zynqmp_dp_swing_set, "%llu\n"); 1974 + 1975 + static int zynqmp_dp_preemphasis_get(void *data, u64 *val) 1976 + { 1977 + struct zynqmp_dp_train_set_priv *priv = data; 1978 + struct zynqmp_dp *dp = priv->dp; 1979 + 1980 + mutex_lock(&dp->lock); 1981 + *val = FIELD_GET(DP_TRAIN_PRE_EMPHASIS_MASK, 1982 + dp->test.train_set[priv->lane]); 1983 + mutex_unlock(&dp->lock); 1984 + return 0; 1985 + } 1986 + 1987 + static int zynqmp_dp_preemphasis_set(void *data, u64 val) 1988 + { 1989 + struct zynqmp_dp_train_set_priv *priv = data; 1990 + struct zynqmp_dp *dp = priv->dp; 1991 + u8 *train_set = &dp->test.train_set[priv->lane]; 1992 + int ret = 0; 1993 + 1994 + if (val > 2) 1995 + return -EINVAL; 1996 + 1997 + mutex_lock(&dp->lock); 1998 + *train_set &= ~(DP_TRAIN_MAX_PRE_EMPHASIS_REACHED | 1999 + DP_TRAIN_PRE_EMPHASIS_MASK); 2000 + *train_set |= val; 2001 + if (val == 2) 2002 + *train_set |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 2003 + 2004 + if (dp->test.active) 2005 + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); 2006 + mutex_unlock(&dp->lock); 2007 + 2008 + return ret; 2009 + } 2010 + 2011 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_preemphasis, zynqmp_dp_preemphasis_get, 2012 + zynqmp_dp_preemphasis_set, "%llu\n"); 2013 + 2014 + static int zynqmp_dp_lanes_get(void *data, u64 *val) 2015 + { 2016 + struct zynqmp_dp *dp = data; 2017 + 2018 + mutex_lock(&dp->lock); 2019 + *val = dp->test.link_cnt; 2020 + mutex_unlock(&dp->lock); 2021 + return 0; 2022 + } 2023 + 2024 + static int zynqmp_dp_lanes_set(void *data, u64 val) 2025 + { 2026 + struct zynqmp_dp *dp = data; 2027 + int ret = 0; 2028 + 2029 + if (val > ZYNQMP_DP_MAX_LANES) 2030 + return -EINVAL; 2031 + 2032 + mutex_lock(&dp->lock); 2033 + if (val > dp->num_lanes) { 2034 + ret = -EINVAL; 2035 + } else { 2036 + dp->test.link_cnt = val; 2037 + if (dp->test.active) 2038 + ret = zynqmp_dp_test_setup(dp); 2039 + } 2040 + mutex_unlock(&dp->lock); 2041 + 2042 + return ret; 2043 + } 2044 + 2045 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_lanes, zynqmp_dp_lanes_get, 2046 + zynqmp_dp_lanes_set, "%llu\n"); 2047 + 2048 + static int zynqmp_dp_rate_get(void *data, u64 *val) 2049 + { 2050 + struct zynqmp_dp *dp = data; 2051 + 2052 + mutex_lock(&dp->lock); 2053 + *val = drm_dp_bw_code_to_link_rate(dp->test.bw_code) * 10000; 2054 + mutex_unlock(&dp->lock); 2055 + return 0; 2056 + } 2057 + 2058 + static int zynqmp_dp_rate_set(void *data, u64 val) 2059 + { 2060 + struct zynqmp_dp *dp = data; 2061 + int link_rate; 2062 + int ret = 0; 2063 + u8 bw_code; 2064 + 2065 + if (do_div(val, 10000)) 2066 + return -EINVAL; 2067 + 2068 + bw_code = drm_dp_link_rate_to_bw_code(val); 2069 + link_rate = drm_dp_bw_code_to_link_rate(bw_code); 2070 + if (val != link_rate) 2071 + return -EINVAL; 2072 + 2073 + if (bw_code != DP_LINK_BW_1_62 && bw_code != DP_LINK_BW_2_7 && 2074 + bw_code != DP_LINK_BW_5_4) 2075 + return -EINVAL; 2076 + 2077 + mutex_lock(&dp->lock); 2078 + dp->test.bw_code = bw_code; 2079 + if (dp->test.active) 2080 + ret = zynqmp_dp_test_setup(dp); 2081 + mutex_unlock(&dp->lock); 2082 + 2083 + return ret; 2084 + } 2085 + 2086 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_rate, zynqmp_dp_rate_get, 2087 + zynqmp_dp_rate_set, "%llu\n"); 2088 + 2089 + static int zynqmp_dp_ignore_aux_errors_get(void *data, u64 *val) 2090 + { 2091 + struct zynqmp_dp *dp = data; 2092 + 2093 + mutex_lock(&dp->aux.hw_mutex); 2094 + *val = dp->ignore_aux_errors; 2095 + mutex_unlock(&dp->aux.hw_mutex); 2096 + return 0; 2097 + } 2098 + 2099 + static int zynqmp_dp_ignore_aux_errors_set(void *data, u64 val) 2100 + { 2101 + struct zynqmp_dp *dp = data; 2102 + 2103 + if (val != !!val) 2104 + return -EINVAL; 2105 + 2106 + mutex_lock(&dp->aux.hw_mutex); 2107 + dp->ignore_aux_errors = val; 2108 + mutex_unlock(&dp->aux.hw_mutex); 2109 + return 0; 2110 + } 2111 + 2112 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_ignore_aux_errors, 2113 + zynqmp_dp_ignore_aux_errors_get, 2114 + zynqmp_dp_ignore_aux_errors_set, "%llu\n"); 2115 + 2116 + static int zynqmp_dp_ignore_hpd_get(void *data, u64 *val) 2117 + { 2118 + struct zynqmp_dp *dp = data; 2119 + 2120 + mutex_lock(&dp->lock); 2121 + *val = dp->ignore_hpd; 2122 + mutex_unlock(&dp->lock); 2123 + return 0; 2124 + } 2125 + 2126 + static int zynqmp_dp_ignore_hpd_set(void *data, u64 val) 2127 + { 2128 + struct zynqmp_dp *dp = data; 2129 + 2130 + if (val != !!val) 2131 + return -EINVAL; 2132 + 2133 + mutex_lock(&dp->lock); 2134 + dp->ignore_hpd = val; 2135 + mutex_lock(&dp->lock); 2136 + return 0; 2137 + } 2138 + 2139 + DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_ignore_hpd, zynqmp_dp_ignore_hpd_get, 2140 + zynqmp_dp_ignore_hpd_set, "%llu\n"); 2141 + 2142 + static void zynqmp_dp_bridge_debugfs_init(struct drm_bridge *bridge, 2143 + struct dentry *root) 2144 + { 2145 + struct zynqmp_dp *dp = bridge_to_dp(bridge); 2146 + struct dentry *test; 2147 + int i; 2148 + 2149 + dp->test.bw_code = DP_LINK_BW_5_4; 2150 + dp->test.link_cnt = dp->num_lanes; 2151 + 2152 + test = debugfs_create_dir("test", root); 2153 + #define CREATE_FILE(name) \ 2154 + debugfs_create_file(#name, 0600, test, dp, &fops_zynqmp_dp_##name) 2155 + CREATE_FILE(pattern); 2156 + CREATE_FILE(enhanced); 2157 + CREATE_FILE(downspread); 2158 + CREATE_FILE(active); 2159 + CREATE_FILE(custom); 2160 + CREATE_FILE(rate); 2161 + CREATE_FILE(lanes); 2162 + CREATE_FILE(ignore_aux_errors); 2163 + CREATE_FILE(ignore_hpd); 2164 + 2165 + for (i = 0; i < dp->num_lanes; i++) { 2166 + static const char fmt[] = "lane%d_preemphasis"; 2167 + char name[sizeof(fmt)]; 2168 + 2169 + dp->debugfs_train_set[i].dp = dp; 2170 + dp->debugfs_train_set[i].lane = i; 2171 + 2172 + snprintf(name, sizeof(name), fmt, i); 2173 + debugfs_create_file(name, 0600, test, 2174 + &dp->debugfs_train_set[i], 2175 + &fops_zynqmp_dp_preemphasis); 2176 + 2177 + snprintf(name, sizeof(name), "lane%d_swing", i); 2178 + debugfs_create_file(name, 0600, test, 2179 + &dp->debugfs_train_set[i], 2180 + &fops_zynqmp_dp_swing); 2181 + } 2182 + } 2183 + 1748 2184 static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { 1749 2185 .attach = zynqmp_dp_bridge_attach, 1750 2186 .detach = zynqmp_dp_bridge_detach, ··· 2334 1618 .detect = zynqmp_dp_bridge_detect, 2335 1619 .edid_read = zynqmp_dp_bridge_edid_read, 2336 1620 .atomic_get_input_bus_fmts = zynqmp_dp_bridge_get_input_bus_fmts, 1621 + .debugfs_init = zynqmp_dp_bridge_debugfs_init, 2337 1622 }; 2338 1623 2339 1624 /* ----------------------------------------------------------------------------- ··· 2368 1651 struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, hpd_work); 2369 1652 enum drm_connector_status status; 2370 1653 2371 - status = zynqmp_dp_bridge_detect(&dp->bridge); 1654 + mutex_lock(&dp->lock); 1655 + if (dp->ignore_hpd) { 1656 + mutex_unlock(&dp->lock); 1657 + return; 1658 + } 1659 + 1660 + status = __zynqmp_dp_bridge_detect(dp); 1661 + mutex_unlock(&dp->lock); 1662 + 2372 1663 drm_bridge_hpd_notify(&dp->bridge, status); 1664 + } 1665 + 1666 + static void zynqmp_dp_hpd_irq_work_func(struct work_struct *work) 1667 + { 1668 + struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, 1669 + hpd_irq_work); 1670 + u8 status[DP_LINK_STATUS_SIZE + 2]; 1671 + int err; 1672 + 1673 + mutex_lock(&dp->lock); 1674 + if (dp->ignore_hpd) { 1675 + mutex_unlock(&dp->lock); 1676 + return; 1677 + } 1678 + 1679 + err = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, 1680 + DP_LINK_STATUS_SIZE + 2); 1681 + if (err < 0) { 1682 + dev_dbg_ratelimited(dp->dev, 1683 + "could not read sink status: %d\n", err); 1684 + } else { 1685 + if (status[4] & DP_LINK_STATUS_UPDATED || 1686 + !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || 1687 + !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { 1688 + zynqmp_dp_train_loop(dp); 1689 + } 1690 + } 1691 + mutex_unlock(&dp->lock); 2373 1692 } 2374 1693 2375 1694 static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) ··· 2439 1686 if (status & ZYNQMP_DP_INT_HPD_EVENT) 2440 1687 schedule_work(&dp->hpd_work); 2441 1688 2442 - if (status & ZYNQMP_DP_INT_HPD_IRQ) { 2443 - int ret; 2444 - u8 status[DP_LINK_STATUS_SIZE + 2]; 1689 + if (status & ZYNQMP_DP_INT_HPD_IRQ) 1690 + schedule_work(&dp->hpd_irq_work); 2445 1691 2446 - ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, 2447 - DP_LINK_STATUS_SIZE + 2); 2448 - if (ret < 0) 2449 - goto handled; 1692 + if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY) 1693 + complete(&dp->aux_done); 2450 1694 2451 - if (status[4] & DP_LINK_STATUS_UPDATED || 2452 - !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || 2453 - !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { 2454 - zynqmp_dp_train_loop(dp); 2455 - } 2456 - } 1695 + if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT) 1696 + complete(&dp->aux_done); 2457 1697 2458 - handled: 2459 1698 return IRQ_HANDLED; 2460 1699 } 2461 1700 ··· 2470 1725 dp->dev = &pdev->dev; 2471 1726 dp->dpsub = dpsub; 2472 1727 dp->status = connector_status_disconnected; 1728 + mutex_init(&dp->lock); 1729 + init_completion(&dp->aux_done); 2473 1730 2474 1731 INIT_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func); 1732 + INIT_WORK(&dp->hpd_irq_work, zynqmp_dp_hpd_irq_work_func); 2475 1733 2476 1734 /* Acquire all resources (IOMEM, IRQ and PHYs). */ 2477 1735 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp"); ··· 2550 1802 * Now that the hardware is initialized and won't generate spurious 2551 1803 * interrupts, request the IRQ. 2552 1804 */ 2553 - ret = devm_request_threaded_irq(dp->dev, dp->irq, NULL, 2554 - zynqmp_dp_irq_handler, IRQF_ONESHOT, 2555 - dev_name(dp->dev), dp); 1805 + ret = devm_request_irq(dp->dev, dp->irq, zynqmp_dp_irq_handler, 1806 + IRQF_SHARED, dev_name(dp->dev), dp); 2556 1807 if (ret < 0) 2557 1808 goto err_phy_exit; 2558 1809 ··· 2576 1829 struct zynqmp_dp *dp = dpsub->dp; 2577 1830 2578 1831 zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL); 2579 - disable_irq(dp->irq); 1832 + devm_free_irq(dp->dev, dp->irq, dp); 2580 1833 1834 + cancel_work_sync(&dp->hpd_irq_work); 2581 1835 cancel_work_sync(&dp->hpd_work); 2582 1836 2583 1837 zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0); ··· 2586 1838 2587 1839 zynqmp_dp_phy_exit(dp); 2588 1840 zynqmp_dp_reset(dp, true); 1841 + mutex_destroy(&dp->lock); 2589 1842 }
+3 -3
drivers/gpu/drm/xlnx/zynqmp_kms.c
··· 511 511 if (ret) 512 512 return ret; 513 513 514 - drm_kms_helper_poll_init(drm); 515 - 516 514 ret = zynqmp_dpsub_kms_init(dpsub); 517 515 if (ret < 0) 518 516 goto err_poll_fini; 517 + 518 + drm_kms_helper_poll_init(drm); 519 519 520 520 /* Reset all components and register the DRM device. */ 521 521 drm_mode_config_reset(drm); ··· 538 538 { 539 539 struct drm_device *drm = &dpsub->drm->dev; 540 540 541 - drm_dev_unregister(drm); 541 + drm_dev_unplug(drm); 542 542 drm_atomic_helper_shutdown(drm); 543 543 drm_encoder_cleanup(&dpsub->drm->encoder); 544 544 drm_kms_helper_poll_fini(drm);
+32
include/drm/bridge/dw_hdmi_qp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. 4 + * Copyright (c) 2024 Collabora Ltd. 5 + */ 6 + 7 + #ifndef __DW_HDMI_QP__ 8 + #define __DW_HDMI_QP__ 9 + 10 + struct device; 11 + struct drm_encoder; 12 + struct dw_hdmi_qp; 13 + struct platform_device; 14 + 15 + struct dw_hdmi_qp_phy_ops { 16 + int (*init)(struct dw_hdmi_qp *hdmi, void *data); 17 + void (*disable)(struct dw_hdmi_qp *hdmi, void *data); 18 + enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data); 19 + void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data); 20 + }; 21 + 22 + struct dw_hdmi_qp_plat_data { 23 + const struct dw_hdmi_qp_phy_ops *phy_ops; 24 + void *phy_data; 25 + int main_irq; 26 + }; 27 + 28 + struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, 29 + struct drm_encoder *encoder, 30 + const struct dw_hdmi_qp_plat_data *plat_data); 31 + void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi); 32 + #endif /* __DW_HDMI_QP__ */
+5
include/drm/drm_bridge.h
··· 803 803 */ 804 804 bool interlace_allowed; 805 805 /** 806 + * @ycbcr_420_allowed: Indicate that the bridge can handle YCbCr 420 807 + * output. 808 + */ 809 + bool ycbcr_420_allowed; 810 + /** 806 811 * @pre_enable_prev_first: The bridge requires that the prev 807 812 * bridge @pre_enable function is called before its @pre_enable, 808 813 * and conversely for post_disable. This is most frequently a
+35 -6
include/drm/drm_client.h
··· 63 63 * This callback is optional. 64 64 */ 65 65 int (*hotplug)(struct drm_client_dev *client); 66 + 67 + /** 68 + * @suspend: 69 + * 70 + * Called when suspending the device. 71 + * 72 + * This callback is optional. 73 + * 74 + * FIXME: Some callers hold the console lock when invoking this 75 + * function. This interferes with fbdev emulation, which 76 + * also tries to acquire the lock. Push the console lock 77 + * into the callback and remove 'holds_console_lock'. 78 + */ 79 + int (*suspend)(struct drm_client_dev *client, bool holds_console_lock); 80 + 81 + /** 82 + * @resume: 83 + * 84 + * Called when resuming the device from suspend. 85 + * 86 + * This callback is optional. 87 + * 88 + * FIXME: Some callers hold the console lock when invoking this 89 + * function. This interferes with fbdev emulation, which 90 + * also tries to acquire the lock. Push the console lock 91 + * into the callback and remove 'holds_console_lock'. 92 + */ 93 + int (*resume)(struct drm_client_dev *client, bool holds_console_lock); 66 94 }; 67 95 68 96 /** ··· 136 108 struct drm_mode_set *modesets; 137 109 138 110 /** 111 + * @suspended: 112 + * 113 + * The client has been suspended. 114 + */ 115 + bool suspended; 116 + 117 + /** 139 118 * @hotplug_failed: 140 119 * 141 120 * Set by client hotplug helpers if the hotplugging failed ··· 155 120 const char *name, const struct drm_client_funcs *funcs); 156 121 void drm_client_release(struct drm_client_dev *client); 157 122 void drm_client_register(struct drm_client_dev *client); 158 - 159 - void drm_client_dev_unregister(struct drm_device *dev); 160 - void drm_client_dev_hotplug(struct drm_device *dev); 161 - void drm_client_dev_restore(struct drm_device *dev); 162 123 163 124 /** 164 125 * struct drm_client_buffer - DRM client buffer ··· 235 204 #define drm_client_for_each_connector_iter(connector, iter) \ 236 205 drm_for_each_connector_iter(connector, iter) \ 237 206 if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) 238 - 239 - void drm_client_debugfs_init(struct drm_device *dev); 240 207 241 208 #endif
+27
include/drm/drm_client_event.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + 3 + #ifndef _DRM_CLIENT_EVENT_H_ 4 + #define _DRM_CLIENT_EVENT_H_ 5 + 6 + struct drm_device; 7 + 8 + #if defined(CONFIG_DRM_CLIENT) 9 + void drm_client_dev_unregister(struct drm_device *dev); 10 + void drm_client_dev_hotplug(struct drm_device *dev); 11 + void drm_client_dev_restore(struct drm_device *dev); 12 + void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock); 13 + void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock); 14 + #else 15 + static inline void drm_client_dev_unregister(struct drm_device *dev) 16 + { } 17 + static inline void drm_client_dev_hotplug(struct drm_device *dev) 18 + { } 19 + static inline void drm_client_dev_restore(struct drm_device *dev) 20 + { } 21 + static inline void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock) 22 + { } 23 + static inline void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock) 24 + { } 25 + #endif 26 + 27 + #endif
+4
include/drm/drm_fb_helper.h
··· 256 256 void drm_fb_helper_damage_range(struct fb_info *info, off_t off, size_t len); 257 257 void drm_fb_helper_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height); 258 258 259 + #ifdef CONFIG_FB_DEFERRED_IO 259 260 void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist); 261 + #endif 260 262 261 263 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend); 262 264 void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, ··· 363 361 return 0; 364 362 } 365 363 364 + #ifdef CONFIG_FB_DEFERRED_IO 366 365 static inline void drm_fb_helper_deferred_io(struct fb_info *info, 367 366 struct list_head *pagelist) 368 367 { 369 368 } 369 + #endif 370 370 371 371 static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, 372 372 bool suspend)
+8
include/drm/gpu_scheduler.h
··· 340 340 struct drm_sched_job { 341 341 struct spsc_node queue_node; 342 342 struct list_head list; 343 + 344 + /** 345 + * @sched: 346 + * 347 + * The scheduler this job is or will be scheduled on. Gets set by 348 + * drm_sched_job_arm(). Valid until drm_sched_backend_ops.free_job() 349 + * has finished. 350 + */ 343 351 struct drm_gpu_scheduler *sched; 344 352 struct drm_sched_fence *s_fence; 345 353
+1 -5
include/uapi/drm/ivpu_accel.h
··· 258 258 259 259 /* drm_ivpu_submit engines */ 260 260 #define DRM_IVPU_ENGINE_COMPUTE 0 261 - #define DRM_IVPU_ENGINE_COPY 1 261 + #define DRM_IVPU_ENGINE_COPY 1 /* Deprecated */ 262 262 263 263 /** 264 264 * struct drm_ivpu_submit - Submit commands to the VPU ··· 289 289 * %DRM_IVPU_ENGINE_COMPUTE: 290 290 * 291 291 * Performs Deep Learning Neural Compute Inference Operations 292 - * 293 - * %DRM_IVPU_ENGINE_COPY: 294 - * 295 - * Performs memory copy operations to/from system memory allocated for VPU 296 292 */ 297 293 __u32 engine; 298 294