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

Configure Feed

Select the types of activity you want to include in your feed.

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

drm-misc-next for v6.12:

UAPI Changes:

devfs:
- support device numbers up to MINORBITS limit

Core Changes:

ci:
- increase job timeout

devfs:
- use XArray for minor ids

displayport:
- mst: GUID improvements

docs:
- add fixes and cleanups

panic:
- optionally display QR code

Driver Changes:

amdgpu:
- faster vblank disabling
- GUID improvements

gm12u320
- convert to struct drm_edid

host1x:
- fix syncpoint IRQ during resume
- use iommu_paging_domain_alloc()

imx:
- ipuv3: convert to struct drm_edid

omapdrm:
- improve error handling

panel:
- add support for BOE TV101WUM-LL2 plus DT bindings
- novatek-nt35950: improve error handling
- nv3051d: improve error handling
- panel-edp: add support for BOE NE140WUM-N6G; revert support for
SDC ATNA45AF01
- visionox-vtdr6130: improve error handling; use
devm_regulator_bulk_get_const()

renesas:
- rz-du: add support for RZ/G2UL plus DT bindings

sti:
- convert to struct drm_edid

tegra:
- gr3d: improve PM domain handling
- convert to struct drm_edid

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20240829144654.GA145538@linux.fritz.box

+2364 -872
+63
Documentation/devicetree/bindings/display/panel/boe,tv101wum-ll2.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/boe,tv101wum-ll2.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: BOE TV101WUM-LL2 DSI Display Panel 8 + 9 + maintainers: 10 + - Neil Armstrong <neil.armstrong@linaro.org> 11 + 12 + allOf: 13 + - $ref: panel-common.yaml# 14 + 15 + properties: 16 + compatible: 17 + const: boe,tv101wum-ll2 18 + 19 + reg: 20 + maxItems: 1 21 + description: DSI virtual channel 22 + 23 + backlight: true 24 + reset-gpios: true 25 + vsp-supply: true 26 + vsn-supply: true 27 + port: true 28 + rotation: true 29 + 30 + required: 31 + - compatible 32 + - reg 33 + - reset-gpios 34 + - vsp-supply 35 + - vsn-supply 36 + - port 37 + 38 + additionalProperties: false 39 + 40 + examples: 41 + - | 42 + #include <dt-bindings/gpio/gpio.h> 43 + dsi { 44 + #address-cells = <1>; 45 + #size-cells = <0>; 46 + panel@0 { 47 + compatible = "boe,tv101wum-ll2"; 48 + reg = <0>; 49 + 50 + vsn-supply = <&vsn_lcd>; 51 + vsp-supply = <&vsp_lcd>; 52 + 53 + reset-gpios = <&pio 45 GPIO_ACTIVE_LOW>; 54 + 55 + port { 56 + panel_in: endpoint { 57 + remote-endpoint = <&dsi_out>; 58 + }; 59 + }; 60 + }; 61 + }; 62 + 63 + ...
+29 -3
Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
··· 18 18 compatible: 19 19 oneOf: 20 20 - enum: 21 + - renesas,r9a07g043u-du # RZ/G2UL 21 22 - renesas,r9a07g044-du # RZ/G2{L,LC} 22 23 - items: 23 24 - enum: ··· 61 60 $ref: /schemas/graph.yaml#/properties/port 62 61 unevaluatedProperties: false 63 62 64 - required: 65 - - port@0 66 - 67 63 unevaluatedProperties: false 68 64 69 65 renesas,vsps: ··· 85 87 - renesas,vsps 86 88 87 89 additionalProperties: false 90 + 91 + allOf: 92 + - if: 93 + properties: 94 + compatible: 95 + contains: 96 + const: renesas,r9a07g043u-du 97 + then: 98 + properties: 99 + ports: 100 + properties: 101 + port@0: 102 + description: DPI 103 + 104 + required: 105 + - port@0 106 + else: 107 + properties: 108 + ports: 109 + properties: 110 + port@0: 111 + description: DSI 112 + port@1: 113 + description: DPI 114 + 115 + required: 116 + - port@0 117 + - port@1 88 118 89 119 examples: 90 120 # RZ/G2L DU
+1 -1
MAINTAINERS
··· 7343 7343 7344 7344 DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) 7345 7345 M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> 7346 - M: Melissa Wen <melissa.srw@gmail.com> 7347 7346 M: Maíra Canal <mairacanal@riseup.net> 7348 7347 R: Haneen Mohammed <hamohammed.sa@gmail.com> 7349 7348 R: Daniel Vetter <daniel@ffwll.ch> 7349 + R: Melissa Wen <melissa.srw@gmail.com> 7350 7350 L: dri-devel@lists.freedesktop.org 7351 7351 S: Maintained 7352 7352 T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+7 -103
drivers/accel/drm_accel.c
··· 8 8 9 9 #include <linux/debugfs.h> 10 10 #include <linux/device.h> 11 - #include <linux/idr.h> 11 + #include <linux/xarray.h> 12 12 13 13 #include <drm/drm_accel.h> 14 14 #include <drm/drm_auth.h> ··· 18 18 #include <drm/drm_ioctl.h> 19 19 #include <drm/drm_print.h> 20 20 21 - static DEFINE_SPINLOCK(accel_minor_lock); 22 - static struct idr accel_minors_idr; 21 + DEFINE_XARRAY_ALLOC(accel_minors_xa); 23 22 24 23 static struct dentry *accel_debugfs_root; 25 24 ··· 117 118 } 118 119 119 120 /** 120 - * accel_minor_alloc() - Allocates a new accel minor 121 - * 122 - * This function access the accel minors idr and allocates from it 123 - * a new id to represent a new accel minor 124 - * 125 - * Return: A new id on success or error code in case idr_alloc failed 126 - */ 127 - int accel_minor_alloc(void) 128 - { 129 - unsigned long flags; 130 - int r; 131 - 132 - spin_lock_irqsave(&accel_minor_lock, flags); 133 - r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT); 134 - spin_unlock_irqrestore(&accel_minor_lock, flags); 135 - 136 - return r; 137 - } 138 - 139 - /** 140 - * accel_minor_remove() - Remove an accel minor 141 - * @index: The minor id to remove. 142 - * 143 - * This function access the accel minors idr and removes from 144 - * it the member with the id that is passed to this function. 145 - */ 146 - void accel_minor_remove(int index) 147 - { 148 - unsigned long flags; 149 - 150 - spin_lock_irqsave(&accel_minor_lock, flags); 151 - idr_remove(&accel_minors_idr, index); 152 - spin_unlock_irqrestore(&accel_minor_lock, flags); 153 - } 154 - 155 - /** 156 - * accel_minor_replace() - Replace minor pointer in accel minors idr. 157 - * @minor: Pointer to the new minor. 158 - * @index: The minor id to replace. 159 - * 160 - * This function access the accel minors idr structure and replaces the pointer 161 - * that is associated with an existing id. Because the minor pointer can be 162 - * NULL, we need to explicitly pass the index. 163 - * 164 - * Return: 0 for success, negative value for error 165 - */ 166 - void accel_minor_replace(struct drm_minor *minor, int index) 167 - { 168 - unsigned long flags; 169 - 170 - spin_lock_irqsave(&accel_minor_lock, flags); 171 - idr_replace(&accel_minors_idr, minor, index); 172 - spin_unlock_irqrestore(&accel_minor_lock, flags); 173 - } 174 - 175 - /* 176 - * Looks up the given minor-ID and returns the respective DRM-minor object. The 177 - * refence-count of the underlying device is increased so you must release this 178 - * object with accel_minor_release(). 179 - * 180 - * The object can be only a drm_minor that represents an accel device. 181 - * 182 - * As long as you hold this minor, it is guaranteed that the object and the 183 - * minor->dev pointer will stay valid! However, the device may get unplugged and 184 - * unregistered while you hold the minor. 185 - */ 186 - static struct drm_minor *accel_minor_acquire(unsigned int minor_id) 187 - { 188 - struct drm_minor *minor; 189 - unsigned long flags; 190 - 191 - spin_lock_irqsave(&accel_minor_lock, flags); 192 - minor = idr_find(&accel_minors_idr, minor_id); 193 - if (minor) 194 - drm_dev_get(minor->dev); 195 - spin_unlock_irqrestore(&accel_minor_lock, flags); 196 - 197 - if (!minor) { 198 - return ERR_PTR(-ENODEV); 199 - } else if (drm_dev_is_unplugged(minor->dev)) { 200 - drm_dev_put(minor->dev); 201 - return ERR_PTR(-ENODEV); 202 - } 203 - 204 - return minor; 205 - } 206 - 207 - static void accel_minor_release(struct drm_minor *minor) 208 - { 209 - drm_dev_put(minor->dev); 210 - } 211 - 212 - /** 213 121 * accel_open - open method for ACCEL file 214 122 * @inode: device inode 215 123 * @filp: file pointer. ··· 133 227 struct drm_minor *minor; 134 228 int retcode; 135 229 136 - minor = accel_minor_acquire(iminor(inode)); 230 + minor = drm_minor_acquire(&accel_minors_xa, iminor(inode)); 137 231 if (IS_ERR(minor)) 138 232 return PTR_ERR(minor); 139 233 ··· 152 246 153 247 err_undo: 154 248 atomic_dec(&dev->open_count); 155 - accel_minor_release(minor); 249 + drm_minor_release(minor); 156 250 return retcode; 157 251 } 158 252 EXPORT_SYMBOL_GPL(accel_open); ··· 163 257 struct drm_minor *minor; 164 258 int err; 165 259 166 - minor = accel_minor_acquire(iminor(inode)); 260 + minor = drm_minor_acquire(&accel_minors_xa, iminor(inode)); 167 261 if (IS_ERR(minor)) 168 262 return PTR_ERR(minor); 169 263 ··· 180 274 err = 0; 181 275 182 276 out: 183 - accel_minor_release(minor); 277 + drm_minor_release(minor); 184 278 185 279 return err; 186 280 } ··· 196 290 unregister_chrdev(ACCEL_MAJOR, "accel"); 197 291 debugfs_remove(accel_debugfs_root); 198 292 accel_sysfs_destroy(); 199 - idr_destroy(&accel_minors_idr); 293 + WARN_ON(!xa_empty(&accel_minors_xa)); 200 294 } 201 295 202 296 int __init accel_core_init(void) 203 297 { 204 298 int ret; 205 - 206 - idr_init(&accel_minors_idr); 207 299 208 300 ret = accel_sysfs_init(); 209 301 if (ret < 0) {
+31
drivers/gpu/drm/Kconfig
··· 149 149 or by writing to /sys/module/drm/parameters/panic_screen sysfs entry 150 150 Default is "user" 151 151 152 + config DRM_PANIC_SCREEN_QR_CODE 153 + bool "Add a panic screen with a QR code" 154 + depends on DRM_PANIC && RUST 155 + help 156 + This option adds a QR code generator, and a panic screen with a QR 157 + code. The QR code will contain the last lines of kmsg and other debug 158 + information. This should be easier for the user to report a kernel 159 + panic, with all debug information available. 160 + To use this panic screen, also set DRM_PANIC_SCREEN to "qr_code" 161 + 162 + config DRM_PANIC_SCREEN_QR_CODE_URL 163 + string "Base URL of the QR code in the panic screen" 164 + depends on DRM_PANIC_SCREEN_QR_CODE 165 + help 166 + This option sets the base URL to report the kernel panic. If it's set 167 + the QR code will contain the URL and the kmsg compressed with zlib as 168 + a URL parameter. If it's empty, the QR code will contain the kmsg as 169 + uncompressed text only. 170 + There is a demo code in javascript, to decode and uncompress the kmsg 171 + data from the URL parameter at https://github.com/kdj0c/panic_report 172 + 173 + config DRM_PANIC_SCREEN_QR_VERSION 174 + int "Maximum version (size) of the QR code." 175 + depends on DRM_PANIC_SCREEN_QR_CODE 176 + default 40 177 + help 178 + This option limits the version (or size) of the QR code. QR code 179 + version ranges from Version 1 (21x21) to Version 40 (177x177). 180 + Smaller QR code are easier to read, but will contain less debugging 181 + data. Default is 40. 182 + 152 183 config DRM_DEBUG_DP_MST_TOPOLOGY_REFS 153 184 bool "Enable refcount backtrace history in the DP MST helpers" 154 185 depends on STACKTRACE_SUPPORT
+1
drivers/gpu/drm/Makefile
··· 89 89 drm_privacy_screen_x86.o 90 90 drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o 91 91 drm-$(CONFIG_DRM_PANIC) += drm_panic.o 92 + drm-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_qr.o 92 93 obj-$(CONFIG_DRM) += drm.o 93 94 94 95 obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
+72 -23
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 2579 2579 2580 2580 static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr) 2581 2581 { 2582 + u8 buf[UUID_SIZE]; 2583 + guid_t guid; 2582 2584 int ret; 2583 - u8 guid[16]; 2584 - u64 tmp64; 2585 2585 2586 2586 mutex_lock(&mgr->lock); 2587 2587 if (!mgr->mst_primary) ··· 2602 2602 } 2603 2603 2604 2604 /* Some hubs forget their guids after they resume */ 2605 - ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); 2606 - if (ret != 16) { 2605 + ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf)); 2606 + if (ret != sizeof(buf)) { 2607 2607 drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); 2608 2608 goto out_fail; 2609 2609 } 2610 2610 2611 - if (memchr_inv(guid, 0, 16) == NULL) { 2612 - tmp64 = get_jiffies_64(); 2613 - memcpy(&guid[0], &tmp64, sizeof(u64)); 2614 - memcpy(&guid[8], &tmp64, sizeof(u64)); 2611 + import_guid(&guid, buf); 2615 2612 2616 - ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, guid, 16); 2613 + if (guid_is_null(&guid)) { 2614 + guid_gen(&guid); 2615 + export_guid(buf, &guid); 2617 2616 2618 - if (ret != 16) { 2617 + ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, buf, sizeof(buf)); 2618 + 2619 + if (ret != sizeof(buf)) { 2619 2620 drm_dbg_kms(mgr->dev, "check mstb guid failed - undocked during suspend?\n"); 2620 2621 goto out_fail; 2621 2622 } 2622 2623 } 2623 2624 2624 - memcpy(mgr->mst_primary->guid, guid, 16); 2625 + guid_copy(&mgr->mst_primary->guid, &guid); 2625 2626 2626 2627 out_fail: 2627 2628 mutex_unlock(&mgr->lock); ··· 4948 4947 4949 4948 if (psr_feature_enabled) 4950 4949 amdgpu_dm_set_psr_caps(link); 4951 - 4952 - /* TODO: Fix vblank control helpers to delay PSR entry to allow this when 4953 - * PSR is also supported. 4954 - */ 4955 - if (link->psr_settings.psr_feature_enabled) 4956 - adev_to_drm(adev)->vblank_disable_immediate = false; 4957 4950 } 4958 4951 } 4959 4952 amdgpu_set_panel_orientation(&aconnector->base); ··· 8243 8248 8244 8249 static void manage_dm_interrupts(struct amdgpu_device *adev, 8245 8250 struct amdgpu_crtc *acrtc, 8246 - bool enable) 8251 + struct dm_crtc_state *acrtc_state) 8247 8252 { 8248 - if (enable) 8249 - drm_crtc_vblank_on(&acrtc->base); 8250 - else 8253 + /* 8254 + * We have no guarantee that the frontend index maps to the same 8255 + * backend index - some even map to more than one. 8256 + * 8257 + * TODO: Use a different interrupt or check DC itself for the mapping. 8258 + */ 8259 + int irq_type = 8260 + amdgpu_display_crtc_idx_to_irq_type( 8261 + adev, 8262 + acrtc->crtc_id); 8263 + struct drm_vblank_crtc_config config = {0}; 8264 + struct dc_crtc_timing *timing; 8265 + int offdelay; 8266 + 8267 + if (acrtc_state) { 8268 + if (amdgpu_ip_version(adev, DCE_HWIP, 0) < 8269 + IP_VERSION(3, 5, 0) || 8270 + acrtc_state->stream->link->psr_settings.psr_version < 8271 + DC_PSR_VERSION_UNSUPPORTED) { 8272 + timing = &acrtc_state->stream->timing; 8273 + 8274 + /* at least 2 frames */ 8275 + offdelay = DIV64_U64_ROUND_UP((u64)20 * 8276 + timing->v_total * 8277 + timing->h_total, 8278 + timing->pix_clk_100hz); 8279 + 8280 + config.offdelay_ms = offdelay ?: 30; 8281 + } else { 8282 + config.disable_immediate = true; 8283 + } 8284 + 8285 + drm_crtc_vblank_on_config(&acrtc->base, 8286 + &config); 8287 + 8288 + amdgpu_irq_get( 8289 + adev, 8290 + &adev->pageflip_irq, 8291 + irq_type); 8292 + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) 8293 + amdgpu_irq_get( 8294 + adev, 8295 + &adev->vline0_irq, 8296 + irq_type); 8297 + #endif 8298 + } else { 8299 + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) 8300 + amdgpu_irq_put( 8301 + adev, 8302 + &adev->vline0_irq, 8303 + irq_type); 8304 + #endif 8305 + amdgpu_irq_put( 8306 + adev, 8307 + &adev->pageflip_irq, 8308 + irq_type); 8251 8309 drm_crtc_vblank_off(&acrtc->base); 8310 + } 8252 8311 } 8253 8312 8254 8313 static void dm_update_pflip_irq_state(struct amdgpu_device *adev, ··· 9354 9305 if (old_crtc_state->active && 9355 9306 (!new_crtc_state->active || 9356 9307 drm_atomic_crtc_needs_modeset(new_crtc_state))) { 9357 - manage_dm_interrupts(adev, acrtc, false); 9308 + manage_dm_interrupts(adev, acrtc, NULL); 9358 9309 dc_stream_release(dm_old_crtc_state->stream); 9359 9310 } 9360 9311 } ··· 9870 9821 drm_atomic_crtc_needs_modeset(new_crtc_state))) { 9871 9822 dc_stream_retain(dm_new_crtc_state->stream); 9872 9823 acrtc->dm_irq_params.stream = dm_new_crtc_state->stream; 9873 - manage_dm_interrupts(adev, acrtc, true); 9824 + manage_dm_interrupts(adev, acrtc, dm_new_crtc_state); 9874 9825 } 9875 9826 /* Handle vrr on->off / off->on transitions */ 9876 9827 amdgpu_dm_handle_vrr_transition(dm_old_crtc_state, dm_new_crtc_state);
+4 -1
drivers/gpu/drm/ci/test.yml
··· 10 10 .lava-test: 11 11 extends: 12 12 - .test-rules 13 + timeout: "1h30m" 13 14 script: 14 15 # Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY 15 16 - rm -rf install ··· 72 71 - .baremetal-test-arm64 73 72 - .use-debian/baremetal_arm64_test 74 73 - .test-rules 74 + timeout: "1h30m" 75 75 variables: 76 76 FDO_CI_CONCURRENT: 10 77 77 HWCI_TEST_SCRIPT: "/install/igt_runner.sh" ··· 217 215 extends: 218 216 - .lava-igt:x86_64 219 217 stage: i915 220 - timeout: "1h30m" 221 218 variables: 222 219 DRIVER_NAME: i915 223 220 DTB: "" ··· 415 414 416 415 virtio_gpu:none: 417 416 stage: software-driver 417 + timeout: "1h30m" 418 418 variables: 419 419 CROSVM_GALLIUM_DRIVER: llvmpipe 420 420 DRIVER_NAME: virtio_gpu ··· 438 436 439 437 vkms:none: 440 438 stage: software-driver 439 + timeout: "1h30m" 441 440 variables: 442 441 DRIVER_NAME: vkms 443 442 GPU_VERSION: none
+34 -37
drivers/gpu/drm/display/drm_dp_mst_topology.c
··· 89 89 struct drm_dp_mst_branch *mstb, 90 90 struct drm_dp_mst_port *port); 91 91 static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, 92 - u8 *guid); 92 + guid_t *guid); 93 93 94 94 static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port); 95 95 static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port); ··· 801 801 int idx = 1; 802 802 int i; 803 803 804 - memcpy(repmsg->u.link_addr.guid, &raw->msg[idx], 16); 804 + import_guid(&repmsg->u.link_addr.guid, &raw->msg[idx]); 805 805 idx += 16; 806 806 repmsg->u.link_addr.nports = raw->msg[idx] & 0xf; 807 807 idx++; ··· 829 829 idx++; 830 830 if (idx > raw->curlen) 831 831 goto fail_len; 832 - memcpy(repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx], 16); 832 + import_guid(&repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx]); 833 833 idx += 16; 834 834 if (idx > raw->curlen) 835 835 goto fail_len; ··· 1029 1029 msg->req_type = (raw->msg[0] & 0x7f); 1030 1030 1031 1031 if (msg->reply_type == DP_SIDEBAND_REPLY_NAK) { 1032 - memcpy(msg->u.nak.guid, &raw->msg[1], 16); 1032 + import_guid(&msg->u.nak.guid, &raw->msg[1]); 1033 1033 msg->u.nak.reason = raw->msg[17]; 1034 1034 msg->u.nak.nak_data = raw->msg[18]; 1035 1035 return false; ··· 1078 1078 if (idx > raw->curlen) 1079 1079 goto fail_len; 1080 1080 1081 - memcpy(msg->u.conn_stat.guid, &raw->msg[idx], 16); 1081 + import_guid(&msg->u.conn_stat.guid, &raw->msg[idx]); 1082 1082 idx += 16; 1083 1083 if (idx > raw->curlen) 1084 1084 goto fail_len; ··· 1107 1107 if (idx > raw->curlen) 1108 1108 goto fail_len; 1109 1109 1110 - memcpy(msg->u.resource_stat.guid, &raw->msg[idx], 16); 1110 + import_guid(&msg->u.resource_stat.guid, &raw->msg[idx]); 1111 1111 idx += 16; 1112 1112 if (idx > raw->curlen) 1113 1113 goto fail_len; ··· 2174 2174 offset, size, buffer); 2175 2175 } 2176 2176 2177 - static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) 2177 + static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, guid_t *guid) 2178 2178 { 2179 2179 int ret = 0; 2180 2180 2181 - memcpy(mstb->guid, guid, 16); 2181 + guid_copy(&mstb->guid, guid); 2182 2182 2183 - if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) { 2183 + if (!drm_dp_validate_guid(mstb->mgr, &mstb->guid)) { 2184 + u8 buf[UUID_SIZE]; 2185 + 2186 + export_guid(buf, &mstb->guid); 2187 + 2184 2188 if (mstb->port_parent) { 2185 2189 ret = drm_dp_send_dpcd_write(mstb->mgr, 2186 2190 mstb->port_parent, 2187 - DP_GUID, 16, mstb->guid); 2191 + DP_GUID, sizeof(buf), buf); 2188 2192 } else { 2189 2193 ret = drm_dp_dpcd_write(mstb->mgr->aux, 2190 - DP_GUID, mstb->guid, 16); 2194 + DP_GUID, buf, sizeof(buf)); 2191 2195 } 2192 2196 } 2193 2197 ··· 2571 2567 return mstb; 2572 2568 } 2573 2569 2574 - static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper( 2575 - struct drm_dp_mst_branch *mstb, 2576 - const uint8_t *guid) 2570 + static struct drm_dp_mst_branch * 2571 + get_mst_branch_device_by_guid_helper(struct drm_dp_mst_branch *mstb, 2572 + const guid_t *guid) 2577 2573 { 2578 2574 struct drm_dp_mst_branch *found_mstb; 2579 2575 struct drm_dp_mst_port *port; ··· 2581 2577 if (!mstb) 2582 2578 return NULL; 2583 2579 2584 - if (memcmp(mstb->guid, guid, 16) == 0) 2580 + if (guid_equal(&mstb->guid, guid)) 2585 2581 return mstb; 2586 - 2587 2582 2588 2583 list_for_each_entry(port, &mstb->ports, next) { 2589 2584 found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid); ··· 2596 2593 2597 2594 static struct drm_dp_mst_branch * 2598 2595 drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr, 2599 - const uint8_t *guid) 2596 + const guid_t *guid) 2600 2597 { 2601 2598 struct drm_dp_mst_branch *mstb; 2602 2599 int ret; ··· 2698 2695 } 2699 2696 2700 2697 static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, 2701 - u8 *guid) 2698 + guid_t *guid) 2702 2699 { 2703 - u64 salt; 2704 - 2705 - if (memchr_inv(guid, 0, 16)) 2700 + if (!guid_is_null(guid)) 2706 2701 return true; 2707 2702 2708 - salt = get_jiffies_64(); 2709 - 2710 - memcpy(&guid[0], &salt, sizeof(u64)); 2711 - memcpy(&guid[8], &salt, sizeof(u64)); 2703 + guid_gen(guid); 2712 2704 2713 2705 return false; 2714 2706 } ··· 2943 2945 drm_dbg_kms(mgr->dev, "link address reply: %d\n", reply->nports); 2944 2946 drm_dp_dump_link_address(mgr, reply); 2945 2947 2946 - ret = drm_dp_check_mstb_guid(mstb, reply->guid); 2948 + ret = drm_dp_check_mstb_guid(mstb, &reply->guid); 2947 2949 if (ret) { 2948 2950 char buf[64]; 2949 2951 ··· 3797 3799 int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, 3798 3800 bool sync) 3799 3801 { 3802 + u8 buf[UUID_SIZE]; 3803 + guid_t guid; 3800 3804 int ret; 3801 - u8 guid[16]; 3802 3805 3803 3806 mutex_lock(&mgr->lock); 3804 3807 if (!mgr->mst_primary) ··· 3820 3821 } 3821 3822 3822 3823 /* Some hubs forget their guids after they resume */ 3823 - ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); 3824 - if (ret != 16) { 3824 + ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf)); 3825 + if (ret != sizeof(buf)) { 3825 3826 drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); 3826 3827 goto out_fail; 3827 3828 } 3828 3829 3829 - ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid); 3830 + import_guid(&guid, buf); 3831 + 3832 + ret = drm_dp_check_mstb_guid(mgr->mst_primary, &guid); 3830 3833 if (ret) { 3831 3834 drm_dbg_kms(mgr->dev, "check mstb failed - undocked during suspend?\n"); 3832 3835 goto out_fail; ··· 4006 4005 bool hotplug = false, dowork = false; 4007 4006 4008 4007 if (hdr->broadcast) { 4009 - const u8 *guid = NULL; 4008 + const guid_t *guid = NULL; 4010 4009 4011 4010 if (msg->req_type == DP_CONNECTION_STATUS_NOTIFY) 4012 - guid = msg->u.conn_stat.guid; 4011 + guid = &msg->u.conn_stat.guid; 4013 4012 else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY) 4014 - guid = msg->u.resource_stat.guid; 4013 + guid = &msg->u.resource_stat.guid; 4015 4014 4016 4015 if (guid) 4017 4016 mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid); ··· 5599 5598 * drm_dp_atomic_release_time_slots() 5600 5599 * 5601 5600 * Returns: 5602 - * 5603 5601 * 0 if the new state is valid, negative error code otherwise. 5604 5602 */ 5605 5603 int drm_dp_mst_atomic_check(struct drm_atomic_state *state) ··· 5635 5635 * topology object. 5636 5636 * 5637 5637 * RETURNS: 5638 - * 5639 5638 * The MST topology state or error pointer. 5640 5639 */ 5641 5640 struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, ··· 5654 5655 * topology object. 5655 5656 * 5656 5657 * Returns: 5657 - * 5658 5658 * The old MST topology state, or NULL if there's no topology state for this MST mgr 5659 5659 * in the global atomic state 5660 5660 */ ··· 5678 5680 * topology object. 5679 5681 * 5680 5682 * Returns: 5681 - * 5682 5683 * The new MST topology state, or NULL if there's no topology state for this MST mgr 5683 5684 * in the global atomic state 5684 5685 */
-6
drivers/gpu/drm/drm_atomic.c
··· 63 63 * hardware and flipped to. 64 64 * 65 65 * Returns: 66 - * 67 66 * 0 on success, a negative error code otherwise. 68 67 */ 69 68 int drm_crtc_commit_wait(struct drm_crtc_commit *commit) ··· 336 337 * not created by userspace through an IOCTL call. 337 338 * 338 339 * Returns: 339 - * 340 340 * Either the allocated state or the error code encoded into the pointer. When 341 341 * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 342 342 * entire atomic sequence must be restarted. All other errors are fatal. ··· 516 518 * is consistent. 517 519 * 518 520 * Returns: 519 - * 520 521 * Either the allocated state or the error code encoded into the pointer. When 521 522 * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 522 523 * entire atomic sequence must be restarted. All other errors are fatal. ··· 825 828 * object lock to make sure that the state is consistent. 826 829 * 827 830 * RETURNS: 828 - * 829 831 * Either the allocated state or the error code encoded into a pointer. 830 832 */ 831 833 struct drm_private_state * ··· 1057 1061 * make sure that the state is consistent. 1058 1062 * 1059 1063 * Returns: 1060 - * 1061 1064 * Either the allocated state or the error code encoded into the pointer. When 1062 1065 * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 1063 1066 * entire atomic sequence must be restarted. All other errors are fatal. ··· 1164 1169 * state is consistent. 1165 1170 * 1166 1171 * Returns: 1167 - * 1168 1172 * Either the allocated state or the error code encoded into the pointer. When 1169 1173 * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 1170 1174 * entire atomic sequence must be restarted.
-2
drivers/gpu/drm/drm_atomic_helper.c
··· 2266 2266 * automatically. 2267 2267 * 2268 2268 * Returns: 2269 - * 2270 2269 * 0 on success. -EBUSY when userspace schedules nonblocking commits too fast, 2271 2270 * -ENOMEM on allocation failures and -EINTR when a signal is pending. 2272 2271 */ ··· 3008 3009 * don't pass the right state structures to the callbacks. 3009 3010 * 3010 3011 * Returns: 3011 - * 3012 3012 * Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the 3013 3013 * waiting for the previous commits has been interrupted. 3014 3014 */
+4
drivers/gpu/drm/drm_crtc_internal.h
··· 320 320 bool drm_panic_is_enabled(struct drm_device *dev); 321 321 void drm_panic_register(struct drm_device *dev); 322 322 void drm_panic_unregister(struct drm_device *dev); 323 + void drm_panic_init(void); 324 + void drm_panic_exit(void); 323 325 #else 324 326 static inline bool drm_panic_is_enabled(struct drm_device *dev) { return false; } 325 327 static inline void drm_panic_register(struct drm_device *dev) {} 326 328 static inline void drm_panic_unregister(struct drm_device *dev) {} 329 + static inline void drm_panic_init(void) {} 330 + static inline void drm_panic_exit(void) {} 327 331 #endif 328 332 329 333 #endif /* __DRM_CRTC_INTERNAL_H__ */
+50 -50
drivers/gpu/drm/drm_drv.c
··· 34 34 #include <linux/pseudo_fs.h> 35 35 #include <linux/slab.h> 36 36 #include <linux/srcu.h> 37 + #include <linux/xarray.h> 37 38 38 39 #include <drm/drm_accel.h> 39 40 #include <drm/drm_cache.h> ··· 55 54 MODULE_DESCRIPTION("DRM shared core routines"); 56 55 MODULE_LICENSE("GPL and additional rights"); 57 56 58 - static DEFINE_SPINLOCK(drm_minor_lock); 59 - static struct idr drm_minors_idr; 57 + DEFINE_XARRAY_ALLOC(drm_minors_xa); 60 58 61 59 /* 62 60 * If the drm core fails to init for whatever reason, ··· 83 83 * registered and unregistered dynamically according to device-state. 84 84 */ 85 85 86 + static struct xarray *drm_minor_get_xa(enum drm_minor_type type) 87 + { 88 + if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER) 89 + return &drm_minors_xa; 90 + #if IS_ENABLED(CONFIG_DRM_ACCEL) 91 + else if (type == DRM_MINOR_ACCEL) 92 + return &accel_minors_xa; 93 + #endif 94 + else 95 + return ERR_PTR(-EOPNOTSUPP); 96 + } 97 + 86 98 static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, 87 99 enum drm_minor_type type) 88 100 { ··· 113 101 static void drm_minor_alloc_release(struct drm_device *dev, void *data) 114 102 { 115 103 struct drm_minor *minor = data; 116 - unsigned long flags; 117 104 118 105 WARN_ON(dev != minor->dev); 119 106 120 107 put_device(minor->kdev); 121 108 122 - if (minor->type == DRM_MINOR_ACCEL) { 123 - accel_minor_remove(minor->index); 124 - } else { 125 - spin_lock_irqsave(&drm_minor_lock, flags); 126 - idr_remove(&drm_minors_idr, minor->index); 127 - spin_unlock_irqrestore(&drm_minor_lock, flags); 128 - } 109 + xa_erase(drm_minor_get_xa(minor->type), minor->index); 129 110 } 111 + 112 + /* 113 + * DRM used to support 64 devices, for backwards compatibility we need to maintain the 114 + * minor allocation scheme where minors 0-63 are primary nodes, 64-127 are control nodes, 115 + * and 128-191 are render nodes. 116 + * After reaching the limit, we're allocating minors dynamically - first-come, first-serve. 117 + * Accel nodes are using a distinct major, so the minors are allocated in continuous 0-MAX 118 + * range. 119 + */ 120 + #define DRM_MINOR_LIMIT(t) ({ \ 121 + typeof(t) _t = (t); \ 122 + _t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \ 123 + }) 124 + #define DRM_EXTENDED_MINOR_LIMIT XA_LIMIT(192, (1 << MINORBITS) - 1) 130 125 131 126 static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type) 132 127 { 133 128 struct drm_minor *minor; 134 - unsigned long flags; 135 129 int r; 136 130 137 131 minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL); ··· 147 129 minor->type = type; 148 130 minor->dev = dev; 149 131 150 - idr_preload(GFP_KERNEL); 151 - if (type == DRM_MINOR_ACCEL) { 152 - r = accel_minor_alloc(); 153 - } else { 154 - spin_lock_irqsave(&drm_minor_lock, flags); 155 - r = idr_alloc(&drm_minors_idr, 156 - NULL, 157 - 64 * type, 158 - 64 * (type + 1), 159 - GFP_NOWAIT); 160 - spin_unlock_irqrestore(&drm_minor_lock, flags); 161 - } 162 - idr_preload_end(); 163 - 132 + r = xa_alloc(drm_minor_get_xa(type), &minor->index, 133 + NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL); 134 + if (r == -EBUSY && (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)) 135 + r = xa_alloc(&drm_minors_xa, &minor->index, 136 + NULL, DRM_EXTENDED_MINOR_LIMIT, GFP_KERNEL); 164 137 if (r < 0) 165 138 return r; 166 - 167 - minor->index = r; 168 139 169 140 r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor); 170 141 if (r) ··· 170 163 static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) 171 164 { 172 165 struct drm_minor *minor; 173 - unsigned long flags; 166 + void *entry; 174 167 int ret; 175 168 176 169 DRM_DEBUG("\n"); ··· 193 186 goto err_debugfs; 194 187 195 188 /* replace NULL with @minor so lookups will succeed from now on */ 196 - if (minor->type == DRM_MINOR_ACCEL) { 197 - accel_minor_replace(minor, minor->index); 198 - } else { 199 - spin_lock_irqsave(&drm_minor_lock, flags); 200 - idr_replace(&drm_minors_idr, minor, minor->index); 201 - spin_unlock_irqrestore(&drm_minor_lock, flags); 189 + entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL); 190 + if (xa_is_err(entry)) { 191 + ret = xa_err(entry); 192 + goto err_debugfs; 202 193 } 194 + WARN_ON(entry); 203 195 204 196 DRM_DEBUG("new minor registered %d\n", minor->index); 205 197 return 0; ··· 211 205 static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type type) 212 206 { 213 207 struct drm_minor *minor; 214 - unsigned long flags; 215 208 216 209 minor = *drm_minor_get_slot(dev, type); 217 210 if (!minor || !device_is_registered(minor->kdev)) 218 211 return; 219 212 220 213 /* replace @minor with NULL so lookups will fail from now on */ 221 - if (minor->type == DRM_MINOR_ACCEL) { 222 - accel_minor_replace(NULL, minor->index); 223 - } else { 224 - spin_lock_irqsave(&drm_minor_lock, flags); 225 - idr_replace(&drm_minors_idr, NULL, minor->index); 226 - spin_unlock_irqrestore(&drm_minor_lock, flags); 227 - } 214 + xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL); 228 215 229 216 device_del(minor->kdev); 230 217 dev_set_drvdata(minor->kdev, NULL); /* safety belt */ ··· 233 234 * minor->dev pointer will stay valid! However, the device may get unplugged and 234 235 * unregistered while you hold the minor. 235 236 */ 236 - struct drm_minor *drm_minor_acquire(unsigned int minor_id) 237 + struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id) 237 238 { 238 239 struct drm_minor *minor; 239 - unsigned long flags; 240 240 241 - spin_lock_irqsave(&drm_minor_lock, flags); 242 - minor = idr_find(&drm_minors_idr, minor_id); 241 + xa_lock(minor_xa); 242 + minor = xa_load(minor_xa, minor_id); 243 243 if (minor) 244 244 drm_dev_get(minor->dev); 245 - spin_unlock_irqrestore(&drm_minor_lock, flags); 245 + xa_unlock(minor_xa); 246 246 247 247 if (!minor) { 248 248 return ERR_PTR(-ENODEV); ··· 1034 1036 1035 1037 DRM_DEBUG("\n"); 1036 1038 1037 - minor = drm_minor_acquire(iminor(inode)); 1039 + minor = drm_minor_acquire(&drm_minors_xa, iminor(inode)); 1038 1040 if (IS_ERR(minor)) 1039 1041 return PTR_ERR(minor); 1040 1042 ··· 1065 1067 static void drm_core_exit(void) 1066 1068 { 1067 1069 drm_privacy_screen_lookup_exit(); 1070 + drm_panic_exit(); 1068 1071 accel_core_exit(); 1069 1072 unregister_chrdev(DRM_MAJOR, "drm"); 1070 1073 debugfs_remove(drm_debugfs_root); 1071 1074 drm_sysfs_destroy(); 1072 - idr_destroy(&drm_minors_idr); 1075 + WARN_ON(!xa_empty(&drm_minors_xa)); 1073 1076 drm_connector_ida_destroy(); 1074 1077 } 1075 1078 ··· 1079 1080 int ret; 1080 1081 1081 1082 drm_connector_ida_init(); 1082 - idr_init(&drm_minors_idr); 1083 1083 drm_memcpy_init_early(); 1084 1084 1085 1085 ret = drm_sysfs_init(); ··· 1096 1098 ret = accel_core_init(); 1097 1099 if (ret < 0) 1098 1100 goto error; 1101 + 1102 + drm_panic_init(); 1099 1103 1100 1104 drm_privacy_screen_lookup_init(); 1101 1105
+1 -8
drivers/gpu/drm/drm_file.c
··· 347 347 * resources for it. It also calls the &drm_driver.open driver callback. 348 348 * 349 349 * RETURNS: 350 - * 351 350 * 0 on success or negative errno value on failure. 352 351 */ 353 352 int drm_open(struct inode *inode, struct file *filp) ··· 355 356 struct drm_minor *minor; 356 357 int retcode; 357 358 358 - minor = drm_minor_acquire(iminor(inode)); 359 + minor = drm_minor_acquire(&drm_minors_xa, iminor(inode)); 359 360 if (IS_ERR(minor)) 360 361 return PTR_ERR(minor); 361 362 ··· 405 406 * in-kernel DRM client. 406 407 * 407 408 * RETURNS: 408 - * 409 409 * Always succeeds and returns 0. 410 410 */ 411 411 int drm_release(struct inode *inode, struct file *filp) ··· 475 477 * then restores the active in-kernel DRM client. 476 478 * 477 479 * RETURNS: 478 - * 479 480 * Always succeeds and returns 0. 480 481 */ 481 482 int drm_release_noglobal(struct inode *inode, struct file *filp) ··· 517 520 * safety. 518 521 * 519 522 * RETURNS: 520 - * 521 523 * Number of bytes read (always aligned to full events, and can be 0) or a 522 524 * negative error code on failure. 523 525 */ ··· 602 606 * See also drm_read(). 603 607 * 604 608 * RETURNS: 605 - * 606 609 * Mask of POLL flags indicating the current status of the file. 607 610 */ 608 611 __poll_t drm_poll(struct file *filp, struct poll_table_struct *wait) ··· 639 644 * already hold &drm_device.event_lock. 640 645 * 641 646 * RETURNS: 642 - * 643 647 * 0 on success or a negative error code on failure. 644 648 */ 645 649 int drm_event_reserve_init_locked(struct drm_device *dev, ··· 680 686 * drm_event_reserve_init_locked() instead. 681 687 * 682 688 * RETURNS: 683 - * 684 689 * 0 on success or a negative error code on failure. 685 690 */ 686 691 int drm_event_reserve_init(struct drm_device *dev,
+2 -5
drivers/gpu/drm/drm_gem.c
··· 689 689 * For a single handle lookup, use drm_gem_object_lookup(). 690 690 * 691 691 * Returns: 692 - * 693 692 * @objs filled in with GEM object pointers. Returned GEM objects need to be 694 693 * released with drm_gem_object_put(). -ENOENT is returned on a lookup 695 694 * failure. 0 is returned on success. ··· 736 737 * @filp: DRM file private date 737 738 * @handle: userspace handle 738 739 * 739 - * Returns: 740 + * If looking up an array of handles, use drm_gem_objects_lookup(). 740 741 * 742 + * Returns: 741 743 * A reference to the object named by the handle if such exists on @filp, NULL 742 744 * otherwise. 743 - * 744 - * If looking up an array of handles, use drm_gem_objects_lookup(). 745 745 */ 746 746 struct drm_gem_object * 747 747 drm_gem_object_lookup(struct drm_file *filp, u32 handle) ··· 761 763 * @timeout: timeout value in jiffies or zero to return immediately 762 764 * 763 765 * Returns: 764 - * 765 766 * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or 766 767 * greater than 0 on success. 767 768 */
-4
drivers/gpu/drm/drm_internal.h
··· 80 80 void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, 81 81 uint32_t handle); 82 82 83 - /* drm_drv.c */ 84 - struct drm_minor *drm_minor_acquire(unsigned int minor_id); 85 - void drm_minor_release(struct drm_minor *minor); 86 - 87 83 /* drm_managed.c */ 88 84 void drm_managed_release(struct drm_device *dev); 89 85 void drmm_add_final_kfree(struct drm_device *dev, void *container);
-1
drivers/gpu/drm/drm_modes.c
··· 539 539 * to reach those resolutions. 540 540 * 541 541 * Returns: 542 - * 543 542 * A pointer to the mode, allocated with drm_mode_create(). Returns NULL 544 543 * on error. 545 544 */
+300 -40
drivers/gpu/drm/drm_panic.c
··· 18 18 #include <linux/overflow.h> 19 19 #include <linux/printk.h> 20 20 #include <linux/types.h> 21 + #include <linux/utsname.h> 22 + #include <linux/zlib.h> 21 23 22 24 #include <drm/drm_drv.h> 23 25 #include <drm/drm_fourcc.h> ··· 28 26 #include <drm/drm_panic.h> 29 27 #include <drm/drm_plane.h> 30 28 #include <drm/drm_print.h> 29 + #include <drm/drm_rect.h> 31 30 32 31 #include "drm_crtc_internal.h" 33 32 ··· 88 85 PANIC_LINE(""), /* will be replaced by the panic description */ 89 86 }; 90 87 91 - #define PANIC_MSG_LINES ARRAY_SIZE(panic_msg) 88 + static const size_t panic_msg_lines = ARRAY_SIZE(panic_msg); 92 89 93 90 static const struct drm_panic_line logo_ascii[] = { 94 91 PANIC_LINE(" .--. _"), ··· 100 97 PANIC_LINE(" \\___)=(___/"), 101 98 }; 102 99 103 - #define PANIC_LOGO_LINES ARRAY_SIZE(logo_ascii) 100 + static const size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii); 104 101 105 102 #if defined(CONFIG_LOGO) && !defined(MODULE) 106 103 static const struct linux_logo *logo_mono; ··· 260 257 static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch, 261 258 const u8 *sbuf8, unsigned int spitch, 262 259 unsigned int height, unsigned int width, 263 - u16 fg16) 260 + unsigned int scale, u16 fg16) 264 261 { 265 262 unsigned int y, x; 266 263 267 264 for (y = 0; y < height; y++) 268 265 for (x = 0; x < width; x++) 269 - if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) 266 + if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) 270 267 iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, fg16); 271 268 } 272 269 273 270 static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch, 274 271 const u8 *sbuf8, unsigned int spitch, 275 272 unsigned int height, unsigned int width, 276 - u32 fg32) 273 + unsigned int scale, u32 fg32) 277 274 { 278 275 unsigned int y, x; 279 276 ··· 281 278 for (x = 0; x < width; x++) { 282 279 u32 off = y * dpitch + x * 3; 283 280 284 - if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) { 281 + if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) { 285 282 /* write blue-green-red to output in little endianness */ 286 283 iosys_map_wr(dmap, off, u8, (fg32 & 0x000000FF) >> 0); 287 284 iosys_map_wr(dmap, off + 1, u8, (fg32 & 0x0000FF00) >> 8); ··· 294 291 static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch, 295 292 const u8 *sbuf8, unsigned int spitch, 296 293 unsigned int height, unsigned int width, 297 - u32 fg32) 294 + unsigned int scale, u32 fg32) 298 295 { 299 296 unsigned int y, x; 300 297 301 298 for (y = 0; y < height; y++) 302 299 for (x = 0; x < width; x++) 303 - if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) 300 + if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) 304 301 iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, fg32); 305 302 } 306 303 307 304 static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect *clip, 308 - const u8 *sbuf8, unsigned int spitch, u32 fg_color) 305 + const u8 *sbuf8, unsigned int spitch, unsigned int scale, 306 + u32 fg_color) 309 307 { 310 308 unsigned int y, x; 311 309 312 310 for (y = 0; y < drm_rect_height(clip); y++) 313 311 for (x = 0; x < drm_rect_width(clip); x++) 314 - if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) 312 + if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) 315 313 sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color); 316 314 } 317 315 ··· 322 318 * @clip: destination rectangle 323 319 * @sbuf8: source buffer, in monochrome format, 8 pixels per byte. 324 320 * @spitch: source pitch in bytes 321 + * @scale: integer scale, source buffer is scale time smaller than destination 322 + * rectangle 325 323 * @fg_color: foreground color, in destination format 326 324 * 327 325 * This can be used to draw a font character, which is a monochrome image, to a 328 326 * framebuffer in other supported format. 329 327 */ 330 328 static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip, 331 - const u8 *sbuf8, unsigned int spitch, u32 fg_color) 329 + const u8 *sbuf8, unsigned int spitch, 330 + unsigned int scale, u32 fg_color) 331 + 332 332 { 333 333 struct iosys_map map; 334 334 335 335 if (sb->set_pixel) 336 - return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, fg_color); 336 + return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color); 337 337 338 338 map = sb->map[0]; 339 339 iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]); ··· 345 337 switch (sb->format->cpp[0]) { 346 338 case 2: 347 339 drm_panic_blit16(&map, sb->pitch[0], sbuf8, spitch, 348 - drm_rect_height(clip), drm_rect_width(clip), fg_color); 340 + drm_rect_height(clip), drm_rect_width(clip), scale, fg_color); 349 341 break; 350 342 case 3: 351 343 drm_panic_blit24(&map, sb->pitch[0], sbuf8, spitch, 352 - drm_rect_height(clip), drm_rect_width(clip), fg_color); 344 + drm_rect_height(clip), drm_rect_width(clip), scale, fg_color); 353 345 break; 354 346 case 4: 355 347 drm_panic_blit32(&map, sb->pitch[0], sbuf8, spitch, 356 - drm_rect_height(clip), drm_rect_width(clip), fg_color); 348 + drm_rect_height(clip), drm_rect_width(clip), scale, fg_color); 357 349 break; 358 350 default: 359 351 WARN_ONCE(1, "Can't blit with pixel width %d\n", sb->format->cpp[0]); ··· 493 485 for (j = 0; j < line_len; j++) { 494 486 src = get_char_bitmap(font, msg[i].txt[j], font_pitch); 495 487 rec.x2 = rec.x1 + font->width; 496 - drm_panic_blit(sb, &rec, src, font_pitch, color); 488 + drm_panic_blit(sb, &rec, src, font_pitch, 1, color); 497 489 rec.x1 += font->width; 498 490 } 499 491 } 492 + } 493 + 494 + static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *font) 495 + { 496 + if (logo_mono) { 497 + drm_rect_init(rect, 0, 0, logo_mono->width, logo_mono->height); 498 + } else { 499 + int logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width; 500 + 501 + drm_rect_init(rect, 0, 0, logo_width, logo_ascii_lines * font->height); 502 + } 503 + } 504 + 505 + static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect, 506 + const struct font_desc *font, u32 fg_color) 507 + { 508 + if (logo_mono) 509 + drm_panic_blit(sb, rect, logo_mono->data, 510 + DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color); 511 + else 512 + draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, rect, 513 + fg_color); 500 514 } 501 515 502 516 static void draw_panic_static_user(struct drm_scanout_buffer *sb) ··· 527 497 u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format); 528 498 const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL); 529 499 struct drm_rect r_screen, r_logo, r_msg; 530 - unsigned int logo_width, logo_height; 531 500 unsigned int msg_width, msg_height; 532 501 533 502 if (!font) 534 503 return; 535 504 536 505 r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height); 506 + drm_panic_logo_rect(&r_logo, font); 537 507 538 - if (logo_mono) { 539 - logo_width = logo_mono->width; 540 - logo_height = logo_mono->height; 541 - } else { 542 - logo_width = get_max_line_len(logo_ascii, PANIC_LOGO_LINES) * font->width; 543 - logo_height = PANIC_LOGO_LINES * font->height; 544 - } 545 - r_logo = DRM_RECT_INIT(0, 0, logo_width, logo_height); 546 - 547 - msg_width = min(get_max_line_len(panic_msg, PANIC_MSG_LINES) * font->width, sb->width); 548 - msg_height = min(PANIC_MSG_LINES * font->height, sb->height); 508 + msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width); 509 + msg_height = min(panic_msg_lines * font->height, sb->height); 549 510 r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height); 550 511 551 512 /* Center the panic message */ ··· 545 524 /* Fill with the background color, and draw text on top */ 546 525 drm_panic_fill(sb, &r_screen, bg_color); 547 526 548 - if ((r_msg.x1 >= logo_width || r_msg.y1 >= logo_height) && 549 - logo_width <= sb->width && logo_height <= sb->height) { 550 - if (logo_mono) 551 - drm_panic_blit(sb, &r_logo, logo_mono->data, DIV_ROUND_UP(logo_width, 8), 552 - fg_color); 553 - else 554 - draw_txt_rectangle(sb, font, logo_ascii, PANIC_LOGO_LINES, false, &r_logo, 555 - fg_color); 556 - } 557 - draw_txt_rectangle(sb, font, panic_msg, PANIC_MSG_LINES, true, &r_msg, fg_color); 527 + if (!drm_rect_overlap(&r_logo, &r_msg)) 528 + drm_panic_logo_draw(sb, &r_logo, font, fg_color); 529 + 530 + draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color); 558 531 } 559 532 560 533 /* ··· 630 615 } 631 616 } 632 617 618 + #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE) 619 + /* 620 + * It is unwise to allocate memory in the panic callback, so the buffers are 621 + * pre-allocated. Only 2 buffers and the zlib workspace are needed. 622 + * Two buffers are enough, using the following buffer usage: 623 + * 1) kmsg messages are dumped in buffer1 624 + * 2) kmsg is zlib-compressed into buffer2 625 + * 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1 626 + * 4) QR-code image is generated in buffer2 627 + * The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for 628 + * data segments. 629 + * 630 + * Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in 631 + * a V40 QR-code (177x177). 632 + * 633 + * If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put 634 + * directly in the QR code. 635 + * 1) kmsg messages are dumped in buffer1 636 + * 2) kmsg message is encoded as byte stream in buffer2 637 + * 3) QR-code image is generated in buffer1 638 + */ 639 + 640 + static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION; 641 + module_param(panic_qr_version, uint, 0644); 642 + MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code"); 643 + 644 + #define MAX_QR_DATA 2956 645 + #define MAX_ZLIB_RATIO 3 646 + #define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */ 647 + #define QR_BUFFER2_SIZE 4096 648 + #define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */ 649 + 650 + /* Compression parameters */ 651 + #define COMPR_LEVEL 6 652 + #define WINDOW_BITS 12 653 + #define MEM_LEVEL 4 654 + 655 + static char *qrbuf1; 656 + static char *qrbuf2; 657 + static struct z_stream_s stream; 658 + 659 + static void __init drm_panic_qr_init(void) 660 + { 661 + qrbuf1 = kmalloc(QR_BUFFER1_SIZE, GFP_KERNEL); 662 + qrbuf2 = kmalloc(QR_BUFFER2_SIZE, GFP_KERNEL); 663 + stream.workspace = kmalloc(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), 664 + GFP_KERNEL); 665 + } 666 + 667 + static void drm_panic_qr_exit(void) 668 + { 669 + kfree(qrbuf1); 670 + qrbuf1 = NULL; 671 + kfree(qrbuf2); 672 + qrbuf2 = NULL; 673 + kfree(stream.workspace); 674 + stream.workspace = NULL; 675 + } 676 + 677 + extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len); 678 + 679 + extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size, 680 + u8 *tmp, size_t tmp_size); 681 + 682 + static int drm_panic_get_qr_code_url(u8 **qr_image) 683 + { 684 + struct kmsg_dump_iter iter; 685 + char url[256]; 686 + size_t kmsg_len, max_kmsg_size; 687 + char *kmsg; 688 + int max_qr_data_size, url_len; 689 + 690 + url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&zl=", 691 + utsname()->machine, utsname()->release); 692 + 693 + max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len); 694 + max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE); 695 + 696 + /* get kmsg to buffer 1 */ 697 + kmsg_dump_rewind(&iter); 698 + kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len); 699 + 700 + if (!kmsg_len) 701 + return -ENODATA; 702 + kmsg = qrbuf1; 703 + 704 + try_again: 705 + if (zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, 706 + MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) 707 + return -EINVAL; 708 + 709 + stream.next_in = kmsg; 710 + stream.avail_in = kmsg_len; 711 + stream.total_in = 0; 712 + stream.next_out = qrbuf2; 713 + stream.avail_out = QR_BUFFER2_SIZE; 714 + stream.total_out = 0; 715 + 716 + if (zlib_deflate(&stream, Z_FINISH) != Z_STREAM_END) 717 + return -EINVAL; 718 + 719 + if (zlib_deflateEnd(&stream) != Z_OK) 720 + return -EINVAL; 721 + 722 + if (stream.total_out > max_qr_data_size) { 723 + /* too much data for the QR code, so skip the first line and try again */ 724 + kmsg = strchr(kmsg, '\n'); 725 + if (!kmsg) 726 + return -EINVAL; 727 + /* skip the first \n */ 728 + kmsg += 1; 729 + kmsg_len = strlen(kmsg); 730 + goto try_again; 731 + } 732 + *qr_image = qrbuf2; 733 + 734 + /* generate qr code image in buffer2 */ 735 + return drm_panic_qr_generate(url, qrbuf2, stream.total_out, QR_BUFFER2_SIZE, 736 + qrbuf1, QR_BUFFER1_SIZE); 737 + } 738 + 739 + static int drm_panic_get_qr_code_raw(u8 **qr_image) 740 + { 741 + struct kmsg_dump_iter iter; 742 + size_t kmsg_len; 743 + size_t max_kmsg_size = min(drm_panic_qr_max_data_size(panic_qr_version, 0), 744 + QR_BUFFER1_SIZE); 745 + 746 + kmsg_dump_rewind(&iter); 747 + kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len); 748 + if (!kmsg_len) 749 + return -ENODATA; 750 + 751 + *qr_image = qrbuf1; 752 + return drm_panic_qr_generate(NULL, qrbuf1, kmsg_len, QR_BUFFER1_SIZE, 753 + qrbuf2, QR_BUFFER2_SIZE); 754 + } 755 + 756 + static int drm_panic_get_qr_code(u8 **qr_image) 757 + { 758 + if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0) 759 + return drm_panic_get_qr_code_url(qr_image); 760 + else 761 + return drm_panic_get_qr_code_raw(qr_image); 762 + } 763 + 764 + /* 765 + * Draw the panic message at the center of the screen, with a QR Code 766 + */ 767 + static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb) 768 + { 769 + u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format); 770 + u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format); 771 + const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL); 772 + struct drm_rect r_screen, r_logo, r_msg, r_qr, r_qr_canvas; 773 + unsigned int max_qr_size, scale; 774 + unsigned int msg_width, msg_height; 775 + int qr_width, qr_canvas_width, qr_pitch, v_margin; 776 + u8 *qr_image; 777 + 778 + if (!font || !qrbuf1 || !qrbuf2 || !stream.workspace) 779 + return -ENOMEM; 780 + 781 + r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height); 782 + 783 + drm_panic_logo_rect(&r_logo, font); 784 + 785 + msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width); 786 + msg_height = min(panic_msg_lines * font->height, sb->height); 787 + r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height); 788 + 789 + max_qr_size = min(3 * sb->width / 4, 3 * sb->height / 4); 790 + 791 + qr_width = drm_panic_get_qr_code(&qr_image); 792 + if (qr_width <= 0) 793 + return -ENOSPC; 794 + 795 + qr_canvas_width = qr_width + QR_MARGIN * 2; 796 + scale = max_qr_size / qr_canvas_width; 797 + /* QR code is not readable if not scaled at least by 2 */ 798 + if (scale < 2) 799 + return -ENOSPC; 800 + 801 + pr_debug("QR width %d and scale %d\n", qr_width, scale); 802 + r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale); 803 + 804 + v_margin = (sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg)) / 5; 805 + 806 + drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin); 807 + r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale, 808 + qr_width * scale, qr_width * scale); 809 + 810 + /* Center the panic message */ 811 + drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2, 812 + 3 * v_margin + drm_rect_height(&r_qr_canvas)); 813 + 814 + /* Fill with the background color, and draw text on top */ 815 + drm_panic_fill(sb, &r_screen, bg_color); 816 + 817 + if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr)) 818 + drm_panic_logo_draw(sb, &r_logo, font, fg_color); 819 + 820 + draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color); 821 + 822 + /* Draw the qr code */ 823 + qr_pitch = DIV_ROUND_UP(qr_width, 8); 824 + drm_panic_fill(sb, &r_qr_canvas, fg_color); 825 + drm_panic_fill(sb, &r_qr, bg_color); 826 + drm_panic_blit(sb, &r_qr, qr_image, qr_pitch, scale, fg_color); 827 + return 0; 828 + } 829 + 830 + static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb) 831 + { 832 + if (_draw_panic_static_qr_code(sb)) 833 + draw_panic_static_user(sb); 834 + } 835 + #else 836 + static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb) 837 + { 838 + draw_panic_static_user(sb); 839 + } 840 + 841 + static void drm_panic_qr_init(void) {}; 842 + static void drm_panic_qr_exit(void) {}; 843 + #endif 844 + 633 845 /* 634 846 * drm_panic_is_format_supported() 635 847 * @format: a fourcc color code ··· 875 633 { 876 634 if (!strcmp(drm_panic_screen, "kmsg")) { 877 635 draw_panic_static_kmsg(sb); 636 + } else if (!strcmp(drm_panic_screen, "qr_code")) { 637 + draw_panic_static_qr_code(sb); 878 638 } else { 879 639 draw_panic_static_user(sb); 880 640 } ··· 887 643 u32 len; 888 644 889 645 if (description) { 890 - struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1]; 646 + struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1]; 891 647 892 648 desc_line->txt = description; 893 649 len = strlen(description); ··· 900 656 901 657 static void drm_panic_clear_description(void) 902 658 { 903 - struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1]; 659 + struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1]; 904 660 905 661 desc_line->len = 0; 906 662 desc_line->txt = NULL; ··· 1045 801 continue; 1046 802 kmsg_dump_unregister(&plane->kmsg_panic); 1047 803 } 804 + } 805 + 806 + /** 807 + * drm_panic_init() - initialize DRM panic. 808 + */ 809 + void __init drm_panic_init(void) 810 + { 811 + drm_panic_qr_init(); 812 + } 813 + 814 + /** 815 + * drm_panic_exit() - Free the resources taken by drm_panic_exit() 816 + */ 817 + void drm_panic_exit(void) 818 + { 819 + drm_panic_qr_exit(); 1048 820 }
+1003
drivers/gpu/drm/drm_panic_qr.rs
··· 1 + // SPDX-License-Identifier: MIT 2 + 3 + //! This is a simple QR encoder for DRM panic. 4 + //! 5 + //! It is called from a panic handler, so it should't allocate memory and 6 + //! does all the work on the stack or on the provided buffers. For 7 + //! simplification, it only supports low error correction, and applies the 8 + //! first mask (checkerboard). It will draw the smallest QRcode that can 9 + //! contain the string passed as parameter. To get the most compact 10 + //! QR code, the start of the URL is encoded as binary, and the 11 + //! compressed kmsg is encoded as numeric. 12 + //! 13 + //! The binary data must be a valid URL parameter, so the easiest way is 14 + //! to use base64 encoding. But this wastes 25% of data space, so the 15 + //! whole stack trace won't fit in the QR code. So instead it encodes 16 + //! every 13bits of input into 4 decimal digits, and then uses the 17 + //! efficient numeric encoding, that encode 3 decimal digits into 18 + //! 10bits. This makes 39bits of compressed data into 12 decimal digits, 19 + //! into 40bits in the QR code, so wasting only 2.5%. And the numbers are 20 + //! valid URL parameter, so the website can do the reverse, to get the 21 + //! binary data. 22 + //! 23 + //! Inspired by these 3 projects, all under MIT license: 24 + //! 25 + //! * <https://github.com/kennytm/qrcode-rust> 26 + //! * <https://github.com/erwanvivien/fast_qr> 27 + //! * <https://github.com/bjguillot/qr> 28 + 29 + use core::cmp; 30 + use kernel::str::CStr; 31 + 32 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] 33 + struct Version(usize); 34 + 35 + // Generator polynomials for ECC, only those that are needed for low quality. 36 + const P7: [u8; 7] = [87, 229, 146, 149, 238, 102, 21]; 37 + const P10: [u8; 10] = [251, 67, 46, 61, 118, 70, 64, 94, 32, 45]; 38 + const P15: [u8; 15] = [ 39 + 8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105, 40 + ]; 41 + const P18: [u8; 18] = [ 42 + 215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153, 43 + ]; 44 + const P20: [u8; 20] = [ 45 + 17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190, 46 + ]; 47 + const P22: [u8; 22] = [ 48 + 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105, 49 + 165, 231, 50 + ]; 51 + const P24: [u8; 24] = [ 52 + 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117, 53 + 232, 87, 96, 227, 21, 54 + ]; 55 + const P26: [u8; 26] = [ 56 + 173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102, 57 + 48, 227, 153, 145, 218, 70, 58 + ]; 59 + const P28: [u8; 28] = [ 60 + 168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87, 61 + 42, 195, 212, 119, 242, 37, 9, 123, 62 + ]; 63 + const P30: [u8; 30] = [ 64 + 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193, 65 + 224, 130, 156, 37, 251, 216, 238, 40, 192, 180, 66 + ]; 67 + 68 + /// QR Code parameters for Low quality ECC: 69 + /// - Error Correction polynomial. 70 + /// - Number of blocks in group 1. 71 + /// - Number of blocks in group 2. 72 + /// - Block size in group 1. 73 + /// 74 + /// (Block size in group 2 is one more than group 1). 75 + struct VersionParameter(&'static [u8], u8, u8, u8); 76 + const VPARAM: [VersionParameter; 40] = [ 77 + VersionParameter(&P7, 1, 0, 19), // V1 78 + VersionParameter(&P10, 1, 0, 34), // V2 79 + VersionParameter(&P15, 1, 0, 55), // V3 80 + VersionParameter(&P20, 1, 0, 80), // V4 81 + VersionParameter(&P26, 1, 0, 108), // V5 82 + VersionParameter(&P18, 2, 0, 68), // V6 83 + VersionParameter(&P20, 2, 0, 78), // V7 84 + VersionParameter(&P24, 2, 0, 97), // V8 85 + VersionParameter(&P30, 2, 0, 116), // V9 86 + VersionParameter(&P18, 2, 2, 68), // V10 87 + VersionParameter(&P20, 4, 0, 81), // V11 88 + VersionParameter(&P24, 2, 2, 92), // V12 89 + VersionParameter(&P26, 4, 0, 107), // V13 90 + VersionParameter(&P30, 3, 1, 115), // V14 91 + VersionParameter(&P22, 5, 1, 87), // V15 92 + VersionParameter(&P24, 5, 1, 98), // V16 93 + VersionParameter(&P28, 1, 5, 107), // V17 94 + VersionParameter(&P30, 5, 1, 120), // V18 95 + VersionParameter(&P28, 3, 4, 113), // V19 96 + VersionParameter(&P28, 3, 5, 107), // V20 97 + VersionParameter(&P28, 4, 4, 116), // V21 98 + VersionParameter(&P28, 2, 7, 111), // V22 99 + VersionParameter(&P30, 4, 5, 121), // V23 100 + VersionParameter(&P30, 6, 4, 117), // V24 101 + VersionParameter(&P26, 8, 4, 106), // V25 102 + VersionParameter(&P28, 10, 2, 114), // V26 103 + VersionParameter(&P30, 8, 4, 122), // V27 104 + VersionParameter(&P30, 3, 10, 117), // V28 105 + VersionParameter(&P30, 7, 7, 116), // V29 106 + VersionParameter(&P30, 5, 10, 115), // V30 107 + VersionParameter(&P30, 13, 3, 115), // V31 108 + VersionParameter(&P30, 17, 0, 115), // V32 109 + VersionParameter(&P30, 17, 1, 115), // V33 110 + VersionParameter(&P30, 13, 6, 115), // V34 111 + VersionParameter(&P30, 12, 7, 121), // V35 112 + VersionParameter(&P30, 6, 14, 121), // V36 113 + VersionParameter(&P30, 17, 4, 122), // V37 114 + VersionParameter(&P30, 4, 18, 122), // V38 115 + VersionParameter(&P30, 20, 4, 117), // V39 116 + VersionParameter(&P30, 19, 6, 118), // V40 117 + ]; 118 + 119 + const MAX_EC_SIZE: usize = 30; 120 + const MAX_BLK_SIZE: usize = 123; 121 + 122 + /// Position of the alignment pattern grid. 123 + const ALIGNMENT_PATTERNS: [&[u8]; 40] = [ 124 + &[], 125 + &[6, 18], 126 + &[6, 22], 127 + &[6, 26], 128 + &[6, 30], 129 + &[6, 34], 130 + &[6, 22, 38], 131 + &[6, 24, 42], 132 + &[6, 26, 46], 133 + &[6, 28, 50], 134 + &[6, 30, 54], 135 + &[6, 32, 58], 136 + &[6, 34, 62], 137 + &[6, 26, 46, 66], 138 + &[6, 26, 48, 70], 139 + &[6, 26, 50, 74], 140 + &[6, 30, 54, 78], 141 + &[6, 30, 56, 82], 142 + &[6, 30, 58, 86], 143 + &[6, 34, 62, 90], 144 + &[6, 28, 50, 72, 94], 145 + &[6, 26, 50, 74, 98], 146 + &[6, 30, 54, 78, 102], 147 + &[6, 28, 54, 80, 106], 148 + &[6, 32, 58, 84, 110], 149 + &[6, 30, 58, 86, 114], 150 + &[6, 34, 62, 90, 118], 151 + &[6, 26, 50, 74, 98, 122], 152 + &[6, 30, 54, 78, 102, 126], 153 + &[6, 26, 52, 78, 104, 130], 154 + &[6, 30, 56, 82, 108, 134], 155 + &[6, 34, 60, 86, 112, 138], 156 + &[6, 30, 58, 86, 114, 142], 157 + &[6, 34, 62, 90, 118, 146], 158 + &[6, 30, 54, 78, 102, 126, 150], 159 + &[6, 24, 50, 76, 102, 128, 154], 160 + &[6, 28, 54, 80, 106, 132, 158], 161 + &[6, 32, 58, 84, 110, 136, 162], 162 + &[6, 26, 54, 82, 110, 138, 166], 163 + &[6, 30, 58, 86, 114, 142, 170], 164 + ]; 165 + 166 + /// Version information for format V7-V40. 167 + const VERSION_INFORMATION: [u32; 34] = [ 168 + 0b00_0111_1100_1001_0100, 169 + 0b00_1000_0101_1011_1100, 170 + 0b00_1001_1010_1001_1001, 171 + 0b00_1010_0100_1101_0011, 172 + 0b00_1011_1011_1111_0110, 173 + 0b00_1100_0111_0110_0010, 174 + 0b00_1101_1000_0100_0111, 175 + 0b00_1110_0110_0000_1101, 176 + 0b00_1111_1001_0010_1000, 177 + 0b01_0000_1011_0111_1000, 178 + 0b01_0001_0100_0101_1101, 179 + 0b01_0010_1010_0001_0111, 180 + 0b01_0011_0101_0011_0010, 181 + 0b01_0100_1001_1010_0110, 182 + 0b01_0101_0110_1000_0011, 183 + 0b01_0110_1000_1100_1001, 184 + 0b01_0111_0111_1110_1100, 185 + 0b01_1000_1110_1100_0100, 186 + 0b01_1001_0001_1110_0001, 187 + 0b01_1010_1111_1010_1011, 188 + 0b01_1011_0000_1000_1110, 189 + 0b01_1100_1100_0001_1010, 190 + 0b01_1101_0011_0011_1111, 191 + 0b01_1110_1101_0111_0101, 192 + 0b01_1111_0010_0101_0000, 193 + 0b10_0000_1001_1101_0101, 194 + 0b10_0001_0110_1111_0000, 195 + 0b10_0010_1000_1011_1010, 196 + 0b10_0011_0111_1001_1111, 197 + 0b10_0100_1011_0000_1011, 198 + 0b10_0101_0100_0010_1110, 199 + 0b10_0110_1010_0110_0100, 200 + 0b10_0111_0101_0100_0001, 201 + 0b10_1000_1100_0110_1001, 202 + ]; 203 + 204 + /// Format info for low quality ECC. 205 + const FORMAT_INFOS_QR_L: [u16; 8] = [ 206 + 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, 207 + ]; 208 + 209 + impl Version { 210 + /// Returns the smallest QR version than can hold these segments. 211 + fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> { 212 + for v in (1..=40).map(|k| Version(k)) { 213 + if v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum() { 214 + return Some(v); 215 + } 216 + } 217 + None 218 + } 219 + 220 + fn width(&self) -> u8 { 221 + (self.0 as u8) * 4 + 17 222 + } 223 + 224 + fn max_data(&self) -> usize { 225 + self.g1_blk_size() * self.g1_blocks() + (self.g1_blk_size() + 1) * self.g2_blocks() 226 + } 227 + 228 + fn ec_size(&self) -> usize { 229 + VPARAM[self.0 - 1].0.len() 230 + } 231 + 232 + fn g1_blocks(&self) -> usize { 233 + VPARAM[self.0 - 1].1 as usize 234 + } 235 + 236 + fn g2_blocks(&self) -> usize { 237 + VPARAM[self.0 - 1].2 as usize 238 + } 239 + 240 + fn g1_blk_size(&self) -> usize { 241 + VPARAM[self.0 - 1].3 as usize 242 + } 243 + 244 + fn alignment_pattern(&self) -> &'static [u8] { 245 + &ALIGNMENT_PATTERNS[self.0 - 1] 246 + } 247 + 248 + fn poly(&self) -> &'static [u8] { 249 + VPARAM[self.0 - 1].0 250 + } 251 + 252 + fn version_info(&self) -> u32 { 253 + if *self >= Version(7) { 254 + VERSION_INFORMATION[self.0 - 7] 255 + } else { 256 + 0 257 + } 258 + } 259 + } 260 + 261 + /// Exponential table for Galois Field GF(256). 262 + const EXP_TABLE: [u8; 256] = [ 263 + 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 264 + 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 265 + 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 266 + 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 267 + 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 268 + 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 269 + 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 270 + 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 271 + 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 272 + 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 273 + 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 274 + 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 275 + 131, 27, 54, 108, 216, 173, 71, 142, 1, 276 + ]; 277 + 278 + /// Reverse exponential table for Galois Field GF(256). 279 + const LOG_TABLE: [u8; 256] = [ 280 + 175, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 281 + 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 282 + 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 283 + 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 284 + 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 285 + 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 286 + 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 287 + 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 288 + 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 289 + 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 290 + 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 291 + 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 292 + 232, 116, 214, 244, 234, 168, 80, 88, 175, 293 + ]; 294 + 295 + // 4 bits segment header. 296 + const MODE_STOP: u16 = 0; 297 + const MODE_NUMERIC: u16 = 1; 298 + const MODE_BINARY: u16 = 4; 299 + /// Padding bytes. 300 + const PADDING: [u8; 2] = [236, 17]; 301 + 302 + /// Get the next 13 bits of data, starting at specified offset (in bits). 303 + fn get_next_13b(data: &[u8], offset: usize) -> Option<(u16, usize)> { 304 + if offset < data.len() * 8 { 305 + let size = cmp::min(13, data.len() * 8 - offset); 306 + let byte_off = offset / 8; 307 + let bit_off = offset % 8; 308 + // `b` is 20 at max (`bit_off` <= 7 and `size` <= 13). 309 + let b = (bit_off + size) as u16; 310 + 311 + let first_byte = (data[byte_off] << bit_off >> bit_off) as u16; 312 + 313 + let number = match b { 314 + 0..=8 => first_byte >> (8 - b), 315 + 9..=16 => (first_byte << (b - 8)) + (data[byte_off + 1] >> (16 - b)) as u16, 316 + _ => { 317 + (first_byte << (b - 8)) 318 + + ((data[byte_off + 1] as u16) << (b - 16)) 319 + + (data[byte_off + 2] >> (24 - b)) as u16 320 + } 321 + }; 322 + Some((number, size)) 323 + } else { 324 + None 325 + } 326 + } 327 + 328 + /// Number of bits to encode characters in numeric mode. 329 + const NUM_CHARS_BITS: [usize; 4] = [0, 4, 7, 10]; 330 + const POW10: [u16; 4] = [1, 10, 100, 1000]; 331 + 332 + enum Segment<'a> { 333 + Numeric(&'a [u8]), 334 + Binary(&'a [u8]), 335 + } 336 + 337 + impl Segment<'_> { 338 + fn get_header(&self) -> (u16, usize) { 339 + match self { 340 + Segment::Binary(_) => (MODE_BINARY, 4), 341 + Segment::Numeric(_) => (MODE_NUMERIC, 4), 342 + } 343 + } 344 + 345 + // Returns the size of the length field in bits, depending on QR Version. 346 + fn length_bits_count(&self, version: Version) -> usize { 347 + let Version(v) = version; 348 + match self { 349 + Segment::Binary(_) => match v { 350 + 1..=9 => 8, 351 + _ => 16, 352 + }, 353 + Segment::Numeric(_) => match v { 354 + 1..=9 => 10, 355 + 10..=26 => 12, 356 + _ => 14, 357 + }, 358 + } 359 + } 360 + 361 + // Number of characters in the segment. 362 + fn character_count(&self) -> usize { 363 + match self { 364 + Segment::Binary(data) => data.len(), 365 + Segment::Numeric(data) => { 366 + let data_bits = data.len() * 8; 367 + let last_chars = match data_bits % 13 { 368 + 1 => 1, 369 + k => (k + 1) / 3, 370 + }; 371 + // 4 decimal numbers per 13bits + remainder. 372 + 4 * (data_bits / 13) + last_chars 373 + } 374 + } 375 + } 376 + 377 + fn get_length_field(&self, version: Version) -> (u16, usize) { 378 + ( 379 + self.character_count() as u16, 380 + self.length_bits_count(version), 381 + ) 382 + } 383 + 384 + fn total_size_bits(&self, version: Version) -> usize { 385 + let data_size = match self { 386 + Segment::Binary(data) => data.len() * 8, 387 + Segment::Numeric(_) => { 388 + let digits = self.character_count(); 389 + 10 * (digits / 3) + NUM_CHARS_BITS[digits % 3] 390 + } 391 + }; 392 + // header + length + data. 393 + 4 + self.length_bits_count(version) + data_size 394 + } 395 + 396 + fn iter(&self) -> SegmentIterator<'_> { 397 + SegmentIterator { 398 + segment: self, 399 + offset: 0, 400 + carry: 0, 401 + carry_len: 0, 402 + } 403 + } 404 + } 405 + 406 + struct SegmentIterator<'a> { 407 + segment: &'a Segment<'a>, 408 + offset: usize, 409 + carry: u16, 410 + carry_len: usize, 411 + } 412 + 413 + impl Iterator for SegmentIterator<'_> { 414 + type Item = (u16, usize); 415 + 416 + fn next(&mut self) -> Option<Self::Item> { 417 + match self.segment { 418 + Segment::Binary(data) => { 419 + if self.offset < data.len() { 420 + let byte = data[self.offset] as u16; 421 + self.offset += 1; 422 + Some((byte, 8)) 423 + } else { 424 + None 425 + } 426 + } 427 + Segment::Numeric(data) => { 428 + if self.carry_len == 3 { 429 + let out = (self.carry, NUM_CHARS_BITS[self.carry_len]); 430 + self.carry_len = 0; 431 + self.carry = 0; 432 + Some(out) 433 + } else if let Some((bits, size)) = get_next_13b(data, self.offset) { 434 + self.offset += size; 435 + let new_chars = match size { 436 + 1 => 1, 437 + k => (k + 1) / 3, 438 + }; 439 + if self.carry_len + new_chars > 3 { 440 + self.carry_len = new_chars + self.carry_len - 3; 441 + let out = ( 442 + self.carry * POW10[new_chars - self.carry_len] 443 + + bits / POW10[self.carry_len], 444 + NUM_CHARS_BITS[3], 445 + ); 446 + self.carry = bits % POW10[self.carry_len]; 447 + Some(out) 448 + } else { 449 + let out = ( 450 + self.carry * POW10[new_chars] + bits, 451 + NUM_CHARS_BITS[self.carry_len + new_chars], 452 + ); 453 + self.carry_len = 0; 454 + Some(out) 455 + } 456 + } else if self.carry_len > 0 { 457 + let out = (self.carry, NUM_CHARS_BITS[self.carry_len]); 458 + self.carry_len = 0; 459 + Some(out) 460 + } else { 461 + None 462 + } 463 + } 464 + } 465 + } 466 + } 467 + 468 + struct EncodedMsg<'a> { 469 + data: &'a mut [u8], 470 + ec_size: usize, 471 + g1_blocks: usize, 472 + g2_blocks: usize, 473 + g1_blk_size: usize, 474 + g2_blk_size: usize, 475 + poly: &'static [u8], 476 + version: Version, 477 + } 478 + 479 + /// Data to be put in the QR code, with correct segment encoding, padding, and 480 + /// Error Code Correction. 481 + impl EncodedMsg<'_> { 482 + fn new<'a, 'b>(segments: &[&Segment<'b>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { 483 + let version = Version::from_segments(segments)?; 484 + let ec_size = version.ec_size(); 485 + let g1_blocks = version.g1_blocks(); 486 + let g2_blocks = version.g2_blocks(); 487 + let g1_blk_size = version.g1_blk_size(); 488 + let g2_blk_size = g1_blk_size + 1; 489 + let poly = version.poly(); 490 + 491 + // clear the output. 492 + data.fill(0); 493 + 494 + let mut em = EncodedMsg { 495 + data: data, 496 + ec_size, 497 + g1_blocks, 498 + g2_blocks, 499 + g1_blk_size, 500 + g2_blk_size, 501 + poly, 502 + version, 503 + }; 504 + em.encode(segments); 505 + Some(em) 506 + } 507 + 508 + /// Push bits of data at an offset (in bits). 509 + fn push(&mut self, offset: &mut usize, bits: (u16, usize)) { 510 + let (number, len_bits) = bits; 511 + let byte_off = *offset / 8; 512 + let bit_off = *offset % 8; 513 + let b = bit_off + len_bits; 514 + 515 + match (bit_off, b) { 516 + (0, 0..=8) => { 517 + self.data[byte_off] = (number << (8 - b)) as u8; 518 + } 519 + (0, _) => { 520 + self.data[byte_off] = (number >> (b - 8)) as u8; 521 + self.data[byte_off + 1] = (number << (16 - b)) as u8; 522 + } 523 + (_, 0..=8) => { 524 + self.data[byte_off] |= (number << (8 - b)) as u8; 525 + } 526 + (_, 9..=16) => { 527 + self.data[byte_off] |= (number >> (b - 8)) as u8; 528 + self.data[byte_off + 1] = (number << (16 - b)) as u8; 529 + } 530 + _ => { 531 + self.data[byte_off] |= (number >> (b - 8)) as u8; 532 + self.data[byte_off + 1] = (number >> (b - 16)) as u8; 533 + self.data[byte_off + 2] = (number << (24 - b)) as u8; 534 + } 535 + } 536 + *offset += len_bits; 537 + } 538 + 539 + fn add_segments(&mut self, segments: &[&Segment<'_>]) { 540 + let mut offset: usize = 0; 541 + 542 + for s in segments.iter() { 543 + self.push(&mut offset, s.get_header()); 544 + self.push(&mut offset, s.get_length_field(self.version)); 545 + for bits in s.iter() { 546 + self.push(&mut offset, bits); 547 + } 548 + } 549 + self.push(&mut offset, (MODE_STOP, 4)); 550 + 551 + let pad_offset = (offset + 7) / 8; 552 + for i in pad_offset..self.version.max_data() { 553 + self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)]; 554 + } 555 + } 556 + 557 + fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) { 558 + let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE]; 559 + 560 + tmp[0..size].copy_from_slice(&self.data[offset..offset + size]); 561 + for i in 0..size { 562 + let lead_coeff = tmp[i] as usize; 563 + if lead_coeff == 0 { 564 + continue; 565 + } 566 + let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]); 567 + for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) { 568 + *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255]; 569 + } 570 + } 571 + self.data[ec_offset..ec_offset + self.ec_size] 572 + .copy_from_slice(&tmp[size..size + self.ec_size]); 573 + } 574 + 575 + fn compute_error_code(&mut self) { 576 + let mut offset = 0; 577 + let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size; 578 + 579 + for _ in 0..self.g1_blocks { 580 + self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset); 581 + offset += self.g1_blk_size; 582 + ec_offset += self.ec_size; 583 + } 584 + for _ in 0..self.g2_blocks { 585 + self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset); 586 + offset += self.g2_blk_size; 587 + ec_offset += self.ec_size; 588 + } 589 + } 590 + 591 + fn encode(&mut self, segments: &[&Segment<'_>]) { 592 + self.add_segments(segments); 593 + self.compute_error_code(); 594 + } 595 + 596 + fn iter(&self) -> EncodedMsgIterator<'_> { 597 + EncodedMsgIterator { 598 + em: self, 599 + offset: 0, 600 + } 601 + } 602 + } 603 + 604 + /// Iterator, to retrieve the data in the interleaved order needed by QR code. 605 + struct EncodedMsgIterator<'a> { 606 + em: &'a EncodedMsg<'a>, 607 + offset: usize, 608 + } 609 + 610 + impl Iterator for EncodedMsgIterator<'_> { 611 + type Item = u8; 612 + 613 + // Send the bytes in interleaved mode, first byte of first block of group1, 614 + // then first byte of second block of group1, ... 615 + fn next(&mut self) -> Option<Self::Item> { 616 + let em = self.em; 617 + let blocks = em.g1_blocks + em.g2_blocks; 618 + let g1_end = em.g1_blocks * em.g1_blk_size; 619 + let g2_end = g1_end + em.g2_blocks * em.g2_blk_size; 620 + let ec_end = g2_end + em.ec_size * blocks; 621 + 622 + if self.offset >= ec_end { 623 + return None; 624 + } 625 + 626 + let offset = if self.offset < em.g1_blk_size * blocks { 627 + // group1 and group2 interleaved 628 + let blk = self.offset % blocks; 629 + let blk_off = self.offset / blocks; 630 + if blk < em.g1_blocks { 631 + blk * em.g1_blk_size + blk_off 632 + } else { 633 + g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off 634 + } 635 + } else if self.offset < g2_end { 636 + // last byte of group2 blocks 637 + let blk2 = self.offset - blocks * em.g1_blk_size; 638 + em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1 639 + } else { 640 + // EC blocks 641 + let ec_offset = self.offset - g2_end; 642 + let blk = ec_offset % blocks; 643 + let blk_off = ec_offset / blocks; 644 + 645 + g2_end + blk * em.ec_size + blk_off 646 + }; 647 + self.offset += 1; 648 + Some(em.data[offset]) 649 + } 650 + } 651 + 652 + /// A QR code image, encoded as a linear binary framebuffer. 653 + /// 1 bit per module (pixel), each new line start at next byte boundary. 654 + /// Max width is 177 for V40 QR code, so `u8` is enough for coordinate. 655 + struct QrImage<'a> { 656 + data: &'a mut [u8], 657 + width: u8, 658 + stride: u8, 659 + version: Version, 660 + } 661 + 662 + impl QrImage<'_> { 663 + fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> { 664 + let width = em.version.width(); 665 + let stride = (width + 7) / 8; 666 + let data = qrdata; 667 + 668 + let mut qr_image = QrImage { 669 + data, 670 + width, 671 + stride, 672 + version: em.version, 673 + }; 674 + qr_image.draw_all(em.iter()); 675 + qr_image 676 + } 677 + 678 + fn clear(&mut self) { 679 + self.data.fill(0); 680 + } 681 + 682 + // Set pixel to light color. 683 + fn set(&mut self, x: u8, y: u8) { 684 + let off = y as usize * self.stride as usize + x as usize / 8; 685 + let mut v = self.data[off]; 686 + v |= 0x80 >> (x % 8); 687 + self.data[off] = v; 688 + } 689 + 690 + // Invert a module color. 691 + fn xor(&mut self, x: u8, y: u8) { 692 + let off = y as usize * self.stride as usize + x as usize / 8; 693 + self.data[off] ^= 0x80 >> (x % 8); 694 + } 695 + 696 + // Draw a light square at (x, y) top left corner. 697 + fn draw_square(&mut self, x: u8, y: u8, size: u8) { 698 + for k in 0..size { 699 + self.set(x + k, y); 700 + self.set(x, y + k + 1); 701 + self.set(x + size, y + k); 702 + self.set(x + k + 1, y + size); 703 + } 704 + } 705 + 706 + // Finder pattern: 3 8x8 square at the corners. 707 + fn draw_finders(&mut self) { 708 + self.draw_square(1, 1, 4); 709 + self.draw_square(self.width - 6, 1, 4); 710 + self.draw_square(1, self.width - 6, 4); 711 + for k in 0..8 { 712 + self.set(k, 7); 713 + self.set(self.width - k - 1, 7); 714 + self.set(k, self.width - 8); 715 + } 716 + for k in 0..7 { 717 + self.set(7, k); 718 + self.set(self.width - 8, k); 719 + self.set(7, self.width - 1 - k); 720 + } 721 + } 722 + 723 + fn is_finder(&self, x: u8, y: u8) -> bool { 724 + let end = self.width - 8; 725 + (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8) 726 + } 727 + 728 + // Alignment pattern: 5x5 squares in a grid. 729 + fn draw_alignments(&mut self) { 730 + let positions = self.version.alignment_pattern(); 731 + for &x in positions.iter() { 732 + for &y in positions.iter() { 733 + if !self.is_finder(x, y) { 734 + self.draw_square(x - 1, y - 1, 2); 735 + } 736 + } 737 + } 738 + } 739 + 740 + fn is_alignment(&self, x: u8, y: u8) -> bool { 741 + let positions = self.version.alignment_pattern(); 742 + for &ax in positions.iter() { 743 + for &ay in positions.iter() { 744 + if self.is_finder(ax, ay) { 745 + continue; 746 + } 747 + if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 { 748 + return true; 749 + } 750 + } 751 + } 752 + false 753 + } 754 + 755 + // Timing pattern: 2 dotted line between the finder patterns. 756 + fn draw_timing_patterns(&mut self) { 757 + let end = self.width - 8; 758 + 759 + for x in (9..end).step_by(2) { 760 + self.set(x, 6); 761 + self.set(6, x); 762 + } 763 + } 764 + 765 + fn is_timing(&self, x: u8, y: u8) -> bool { 766 + x == 6 || y == 6 767 + } 768 + 769 + // Mask info: 15 bits around the finders, written twice for redundancy. 770 + fn draw_maskinfo(&mut self) { 771 + let info: u16 = FORMAT_INFOS_QR_L[0]; 772 + let mut skip = 0; 773 + 774 + for k in 0..7 { 775 + if k == 6 { 776 + skip = 1; 777 + } 778 + if info & (1 << (14 - k)) == 0 { 779 + self.set(k + skip, 8); 780 + self.set(8, self.width - 1 - k); 781 + } 782 + } 783 + skip = 0; 784 + for k in 0..8 { 785 + if k == 2 { 786 + skip = 1; 787 + } 788 + if info & (1 << (7 - k)) == 0 { 789 + self.set(8, 8 - skip - k); 790 + self.set(self.width - 8 + k, 8); 791 + } 792 + } 793 + } 794 + 795 + fn is_maskinfo(&self, x: u8, y: u8) -> bool { 796 + let end = self.width - 8; 797 + // Count the dark module as mask info. 798 + (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8) 799 + } 800 + 801 + // Version info: 18bits written twice, close to the finders. 802 + fn draw_version_info(&mut self) { 803 + let vinfo = self.version.version_info(); 804 + let pos = self.width - 11; 805 + 806 + if vinfo != 0 { 807 + for x in 0..3 { 808 + for y in 0..6 { 809 + if vinfo & (1 << (x + y * 3)) == 0 { 810 + self.set(x + pos, y); 811 + self.set(y, x + pos); 812 + } 813 + } 814 + } 815 + } 816 + } 817 + 818 + fn is_version_info(&self, x: u8, y: u8) -> bool { 819 + let vinfo = self.version.version_info(); 820 + let pos = self.width - 11; 821 + 822 + vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6)) 823 + } 824 + 825 + // Returns true if the module is reserved (Not usable for data and EC). 826 + fn is_reserved(&self, x: u8, y: u8) -> bool { 827 + self.is_alignment(x, y) 828 + || self.is_finder(x, y) 829 + || self.is_timing(x, y) 830 + || self.is_maskinfo(x, y) 831 + || self.is_version_info(x, y) 832 + } 833 + 834 + // Last module to draw, at bottom left corner. 835 + fn is_last(&self, x: u8, y: u8) -> bool { 836 + x == 0 && y == self.width - 1 837 + } 838 + 839 + // Move to the next module according to QR code order. 840 + // From bottom right corner, to bottom left corner. 841 + fn next(&self, x: u8, y: u8) -> (u8, u8) { 842 + let x_adj = if x <= 6 { x + 1 } else { x }; 843 + let column_type = (self.width - x_adj) % 4; 844 + 845 + match column_type { 846 + 2 if y > 0 => (x + 1, y - 1), 847 + 0 if y < self.width - 1 => (x + 1, y + 1), 848 + 0 | 2 if x == 7 => (x - 2, y), 849 + _ => (x - 1, y), 850 + } 851 + } 852 + 853 + // Find next module that can hold data. 854 + fn next_available(&self, x: u8, y: u8) -> (u8, u8) { 855 + let (mut x, mut y) = self.next(x, y); 856 + while self.is_reserved(x, y) && !self.is_last(x, y) { 857 + (x, y) = self.next(x, y); 858 + } 859 + (x, y) 860 + } 861 + 862 + fn draw_data(&mut self, data: impl Iterator<Item = u8>) { 863 + let (mut x, mut y) = (self.width - 1, self.width - 1); 864 + for byte in data { 865 + for s in 0..8 { 866 + if byte & (0x80 >> s) == 0 { 867 + self.set(x, y); 868 + } 869 + (x, y) = self.next_available(x, y); 870 + } 871 + } 872 + // Set the remaining modules (0, 3 or 7 depending on version). 873 + // because 0 correspond to a light module. 874 + while !self.is_last(x, y) { 875 + if !self.is_reserved(x, y) { 876 + self.set(x, y); 877 + } 878 + (x, y) = self.next(x, y); 879 + } 880 + } 881 + 882 + // Apply checkerboard mask to all non-reserved modules. 883 + fn apply_mask(&mut self) { 884 + for x in 0..self.width { 885 + for y in 0..self.width { 886 + if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) { 887 + self.xor(x, y); 888 + } 889 + } 890 + } 891 + } 892 + 893 + // Draw the QR code with the provided data iterator. 894 + fn draw_all(&mut self, data: impl Iterator<Item = u8>) { 895 + // First clear the table, as it may have already some data. 896 + self.clear(); 897 + self.draw_finders(); 898 + self.draw_alignments(); 899 + self.draw_timing_patterns(); 900 + self.draw_version_info(); 901 + self.draw_data(data); 902 + self.draw_maskinfo(); 903 + self.apply_mask(); 904 + } 905 + } 906 + 907 + /// C entry point for the rust QR Code generator. 908 + /// 909 + /// Write the QR code image in the data buffer, and return the QR code width, 910 + /// or 0, if the data doesn't fit in a QR code. 911 + /// 912 + /// * `url`: The base URL of the QR code. It will be encoded as Binary segment. 913 + /// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it 914 + /// will be encoded as binary segment, otherwise it will be encoded 915 + /// efficiently as a numeric segment, and appended to the URL. 916 + /// * `data_len`: Length of the data, that needs to be encoded, must be less 917 + /// than data_size. 918 + /// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold 919 + /// a V40 QR code. It will then be overwritten with the QR code image. 920 + /// * `tmp`: A temporary buffer that the QR code encoder will use, to write the 921 + /// segments and ECC. 922 + /// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes 923 + /// long for V40. 924 + /// 925 + /// # Safety 926 + /// 927 + /// * `url` must be null or point at a nul-terminated string. 928 + /// * `data` must be valid for reading and writing for `data_size` bytes. 929 + /// * `tmp` must be valid for reading and writing for `tmp_size` bytes. 930 + /// 931 + /// They must remain valid for the duration of the function call. 932 + 933 + #[no_mangle] 934 + pub unsafe extern "C" fn drm_panic_qr_generate( 935 + url: *const i8, 936 + data: *mut u8, 937 + data_len: usize, 938 + data_size: usize, 939 + tmp: *mut u8, 940 + tmp_size: usize, 941 + ) -> u8 { 942 + if data_size < 4071 || tmp_size < 3706 || data_len > data_size { 943 + return 0; 944 + } 945 + // SAFETY: The caller ensures that `data` is a valid pointer for reading and 946 + // writing `data_size` bytes. 947 + let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) }; 948 + // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and 949 + // writing `tmp_size` bytes. 950 + let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) }; 951 + if url.is_null() { 952 + match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) { 953 + None => 0, 954 + Some(em) => { 955 + let qr_image = QrImage::new(&em, data_slice); 956 + qr_image.width 957 + } 958 + } 959 + } else { 960 + // SAFETY: The caller ensures that `url` is a valid pointer to a 961 + // nul-terminated string. 962 + let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) }; 963 + let segments = &[ 964 + &Segment::Binary(url_cstr.as_bytes()), 965 + &Segment::Numeric(&data_slice[0..data_len]), 966 + ]; 967 + match EncodedMsg::new(segments, tmp_slice) { 968 + None => 0, 969 + Some(em) => { 970 + let qr_image = QrImage::new(&em, data_slice); 971 + qr_image.width 972 + } 973 + } 974 + } 975 + } 976 + 977 + /// Returns the maximum data size that can fit in a QR code of this version. 978 + /// * `version`: QR code version, between 1-40. 979 + /// * `url_len`: Length of the URL. 980 + /// 981 + /// * If `url_len` > 0, remove the 2 segments header/length and also count the 982 + /// conversion to numeric segments. 983 + /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment. 984 + #[no_mangle] 985 + pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize { 986 + if version < 1 || version > 40 { 987 + return 0; 988 + } 989 + let max_data = Version(version as usize).max_data(); 990 + 991 + if url_len > 0 { 992 + // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes. 993 + if url_len + 5 >= max_data { 994 + 0 995 + } else { 996 + let max = max_data - url_len - 5; 997 + (max * 39) / 40 998 + } 999 + } else { 1000 + // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits). 1001 + max_data - 3 1002 + } 1003 + }
-1
drivers/gpu/drm/drm_rect.c
··· 85 85 * factors from @src to @dst. 86 86 * 87 87 * RETURNS: 88 - * 89 88 * %true if rectangle @dst is still visible after being clipped, 90 89 * %false otherwise. 91 90 */
-2
drivers/gpu/drm/drm_vblank.c
··· 686 686 * drm_atomic_helper_calc_timestamping_constants(). 687 687 * 688 688 * Returns: 689 - * 690 689 * Returns true on success, and false on failure, i.e. when no accurate 691 690 * timestamp could be acquired. 692 691 */ ··· 830 831 * drm_atomic_helper_calc_timestamping_constants(). 831 832 * 832 833 * Returns: 833 - * 834 834 * Returns true on success, and false on failure, i.e. when no accurate 835 835 * timestamp could be acquired. 836 836 */
-1
drivers/gpu/drm/i915/gem/i915_gem_object.h
··· 89 89 * @handle: userspace handle 90 90 * 91 91 * Returns: 92 - * 93 92 * A pointer to the object named by the handle if such exists on @filp, NULL 94 93 * otherwise. This object is only valid whilst under the RCU read lock, and 95 94 * note carefully the object may be in the process of being destroyed.
-1
drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
··· 418 418 * For an untiled surface, this removes any existing fence. 419 419 * 420 420 * Returns: 421 - * 422 421 * 0 on success, negative error code on failure. 423 422 */ 424 423 int i915_vma_pin_fence(struct i915_vma *vma)
-1
drivers/gpu/drm/i915/i915_vma.h
··· 389 389 * i915_vma_unpin_fence(). 390 390 * 391 391 * Returns: 392 - * 393 392 * True if the vma has a fence, false otherwise. 394 393 */ 395 394 int __must_check i915_vma_pin_fence(struct i915_vma *vma);
+9 -5
drivers/gpu/drm/imx/ipuv3/parallel-display.c
··· 34 34 35 35 struct imx_parallel_display { 36 36 struct device *dev; 37 - void *edid; 37 + const struct drm_edid *drm_edid; 38 38 u32 bus_format; 39 39 u32 bus_flags; 40 40 struct drm_display_mode mode; ··· 62 62 if (num_modes > 0) 63 63 return num_modes; 64 64 65 - if (imxpd->edid) { 66 - drm_connector_update_edid_property(connector, imxpd->edid); 67 - num_modes = drm_add_edid_modes(connector, imxpd->edid); 65 + if (imxpd->drm_edid) { 66 + drm_edid_connector_update(connector, imxpd->drm_edid); 67 + num_modes = drm_edid_connector_add_modes(connector); 68 68 } 69 69 70 70 if (np) { ··· 331 331 332 332 edidp = of_get_property(np, "edid", &edid_len); 333 333 if (edidp) 334 - imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL); 334 + imxpd->drm_edid = drm_edid_alloc(edidp, edid_len); 335 335 336 336 ret = of_property_read_string(np, "interface-pix-fmt", &fmt); 337 337 if (!ret) { ··· 355 355 356 356 static void imx_pd_remove(struct platform_device *pdev) 357 357 { 358 + struct imx_parallel_display *imxpd = platform_get_drvdata(pdev); 359 + 358 360 component_del(&pdev->dev, &imx_pd_ops); 361 + 362 + drm_edid_free(imxpd->drm_edid); 359 363 } 360 364 361 365 static const struct of_device_id imx_pd_dt_ids[] = {
+5
drivers/gpu/drm/omapdrm/omap_drv.c
··· 695 695 soc = soc_device_match(omapdrm_soc_devices); 696 696 priv->omaprev = soc ? (uintptr_t)soc->data : 0; 697 697 priv->wq = alloc_ordered_workqueue("omapdrm", 0); 698 + if (!priv->wq) { 699 + ret = -ENOMEM; 700 + goto err_alloc_workqueue; 701 + } 698 702 699 703 mutex_init(&priv->list_lock); 700 704 INIT_LIST_HEAD(&priv->obj_list); ··· 757 753 drm_mode_config_cleanup(ddev); 758 754 omap_gem_deinit(ddev); 759 755 destroy_workqueue(priv->wq); 756 + err_alloc_workqueue: 760 757 omap_disconnect_pipelines(ddev); 761 758 drm_dev_put(ddev); 762 759 return ret;
+9
drivers/gpu/drm/panel/Kconfig
··· 87 87 Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 88 88 45NA WUXGA PANEL DSI Video Mode panel 89 89 90 + config DRM_PANEL_BOE_TV101WUM_LL2 91 + tristate "BOE TV101WUM LL2 1200x1920 panel" 92 + depends on OF 93 + depends on DRM_MIPI_DSI 94 + depends on BACKLIGHT_CLASS_DEVICE 95 + help 96 + Say Y here if you want to support for BOE TV101WUM-LL2 97 + WUXGA PANEL DSI Video Mode panel 98 + 90 99 config DRM_PANEL_EBBG_FT8719 91 100 tristate "EBBG FT8719 panel driver" 92 101 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 6 6 obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o 7 7 obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o 8 8 obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o 9 + obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o 9 10 obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o 10 11 obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o 11 12 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
+241
drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: 3 + // Copyright (c) 2013, The Linux Foundation. All rights reserved. 4 + // Copyright (c) 2024, Neil Armstrong <neil.armstrong@linaro.org> 5 + 6 + #include <linux/delay.h> 7 + #include <linux/gpio/consumer.h> 8 + #include <linux/module.h> 9 + #include <linux/of.h> 10 + #include <linux/regulator/consumer.h> 11 + 12 + #include <drm/drm_mipi_dsi.h> 13 + #include <drm/drm_modes.h> 14 + #include <drm/drm_panel.h> 15 + #include <drm/drm_probe_helper.h> 16 + 17 + struct boe_tv101wum_ll2 { 18 + struct drm_panel panel; 19 + struct mipi_dsi_device *dsi; 20 + struct gpio_desc *reset_gpio; 21 + struct regulator_bulk_data *supplies; 22 + }; 23 + 24 + static const struct regulator_bulk_data boe_tv101wum_ll2_supplies[] = { 25 + { .supply = "vsp" }, 26 + { .supply = "vsn" }, 27 + }; 28 + 29 + static inline struct boe_tv101wum_ll2 *to_boe_tv101wum_ll2(struct drm_panel *panel) 30 + { 31 + return container_of(panel, struct boe_tv101wum_ll2, panel); 32 + } 33 + 34 + static void boe_tv101wum_ll2_reset(struct boe_tv101wum_ll2 *ctx) 35 + { 36 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 37 + usleep_range(5000, 6000); 38 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 39 + usleep_range(5000, 6000); 40 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 41 + 42 + msleep(120); 43 + } 44 + 45 + static int boe_tv101wum_ll2_on(struct boe_tv101wum_ll2 *ctx) 46 + { 47 + struct mipi_dsi_device *dsi = ctx->dsi; 48 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 49 + 50 + dsi->mode_flags |= MIPI_DSI_MODE_LPM; 51 + 52 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 53 + 54 + mipi_dsi_msleep(&dsi_ctx, 120); 55 + 56 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0e); 57 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xff, 0x81, 0x68, 0x6c, 0x22, 58 + 0x6d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00); 59 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x23); 60 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x00, 0x00); 61 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x2c, 0x00); 62 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x19); 63 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x38); 64 + 65 + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0c); 66 + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xfd); 67 + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x00); 68 + 69 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 70 + 71 + mipi_dsi_msleep(&dsi_ctx, 20); 72 + 73 + return dsi_ctx.accum_err; 74 + } 75 + 76 + static void boe_tv101wum_ll2_off(struct boe_tv101wum_ll2 *ctx) 77 + { 78 + struct mipi_dsi_device *dsi = ctx->dsi; 79 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 80 + 81 + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 82 + 83 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 84 + 85 + mipi_dsi_msleep(&dsi_ctx, 70); 86 + 87 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 88 + 89 + mipi_dsi_msleep(&dsi_ctx, 20); 90 + 91 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5a); 92 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5a); 93 + 94 + mipi_dsi_msleep(&dsi_ctx, 150); 95 + } 96 + 97 + static int boe_tv101wum_ll2_prepare(struct drm_panel *panel) 98 + { 99 + struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 100 + int ret; 101 + 102 + ret = regulator_bulk_enable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 103 + ctx->supplies); 104 + if (ret < 0) 105 + return ret; 106 + 107 + boe_tv101wum_ll2_reset(ctx); 108 + 109 + ret = boe_tv101wum_ll2_on(ctx); 110 + if (ret < 0) { 111 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 112 + regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 113 + ctx->supplies); 114 + return ret; 115 + } 116 + 117 + return 0; 118 + } 119 + 120 + static int boe_tv101wum_ll2_unprepare(struct drm_panel *panel) 121 + { 122 + struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 123 + 124 + /* Ignore errors on failure, in any case set gpio and disable regulators */ 125 + boe_tv101wum_ll2_off(ctx); 126 + 127 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 128 + 129 + regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 130 + ctx->supplies); 131 + 132 + return 0; 133 + } 134 + 135 + static const struct drm_display_mode boe_tv101wum_ll2_mode = { 136 + .clock = (1200 + 27 + 8 + 12) * (1920 + 155 + 8 + 32) * 60 / 1000, 137 + .hdisplay = 1200, 138 + .hsync_start = 1200 + 27, 139 + .hsync_end = 1200 + 27 + 8, 140 + .htotal = 1200 + 27 + 8 + 12, 141 + .vdisplay = 1920, 142 + .vsync_start = 1920 + 155, 143 + .vsync_end = 1920 + 155 + 8, 144 + .vtotal = 1920 + 155 + 8 + 32, 145 + .width_mm = 136, 146 + .height_mm = 217, 147 + .type = DRM_MODE_TYPE_DRIVER, 148 + }; 149 + 150 + static int boe_tv101wum_ll2_get_modes(struct drm_panel *panel, 151 + struct drm_connector *connector) 152 + { 153 + /* We do not set display_info.bpc since unset value is bpc=8 by default */ 154 + return drm_connector_helper_get_modes_fixed(connector, &boe_tv101wum_ll2_mode); 155 + } 156 + 157 + static const struct drm_panel_funcs boe_tv101wum_ll2_panel_funcs = { 158 + .prepare = boe_tv101wum_ll2_prepare, 159 + .unprepare = boe_tv101wum_ll2_unprepare, 160 + .get_modes = boe_tv101wum_ll2_get_modes, 161 + }; 162 + 163 + static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi) 164 + { 165 + struct device *dev = &dsi->dev; 166 + struct boe_tv101wum_ll2 *ctx; 167 + int ret; 168 + 169 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 170 + if (!ctx) 171 + return -ENOMEM; 172 + 173 + ret = devm_regulator_bulk_get_const(&dsi->dev, 174 + ARRAY_SIZE(boe_tv101wum_ll2_supplies), 175 + boe_tv101wum_ll2_supplies, 176 + &ctx->supplies); 177 + if (ret < 0) 178 + return ret; 179 + 180 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 181 + if (IS_ERR(ctx->reset_gpio)) 182 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 183 + "Failed to get reset-gpios\n"); 184 + 185 + ctx->dsi = dsi; 186 + mipi_dsi_set_drvdata(dsi, ctx); 187 + 188 + dsi->lanes = 4; 189 + dsi->format = MIPI_DSI_FMT_RGB888; 190 + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 191 + MIPI_DSI_MODE_VIDEO_HSE; 192 + 193 + drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs, 194 + DRM_MODE_CONNECTOR_DSI); 195 + ctx->panel.prepare_prev_first = true; 196 + 197 + ret = drm_panel_of_backlight(&ctx->panel); 198 + if (ret) 199 + return dev_err_probe(dev, ret, "Failed to get backlight\n"); 200 + 201 + drm_panel_add(&ctx->panel); 202 + 203 + ret = mipi_dsi_attach(dsi); 204 + if (ret < 0) { 205 + drm_panel_remove(&ctx->panel); 206 + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 207 + } 208 + 209 + return 0; 210 + } 211 + 212 + static void boe_tv101wum_ll2_remove(struct mipi_dsi_device *dsi) 213 + { 214 + struct boe_tv101wum_ll2 *ctx = mipi_dsi_get_drvdata(dsi); 215 + int ret; 216 + 217 + ret = mipi_dsi_detach(dsi); 218 + if (ret < 0) 219 + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 220 + 221 + drm_panel_remove(&ctx->panel); 222 + } 223 + 224 + static const struct of_device_id boe_tv101wum_ll2_of_match[] = { 225 + { .compatible = "boe,tv101wum-ll2" }, 226 + { /* sentinel */ } 227 + }; 228 + MODULE_DEVICE_TABLE(of, boe_tv101wum_ll2_of_match); 229 + 230 + static struct mipi_dsi_driver boe_tv101wum_ll2_driver = { 231 + .probe = boe_tv101wum_ll2_probe, 232 + .remove = boe_tv101wum_ll2_remove, 233 + .driver = { 234 + .name = "panel-boe-tv101wum_ll2", 235 + .of_match_table = boe_tv101wum_ll2_of_match, 236 + }, 237 + }; 238 + module_mipi_dsi_driver(boe_tv101wum_ll2_driver); 239 + 240 + MODULE_DESCRIPTION("DRM driver for BOE TV101WUM-LL2 Panel"); 241 + MODULE_LICENSE("GPL");
+1 -2
drivers/gpu/drm/panel/panel-edp.c
··· 1911 1911 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), 1912 1912 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), 1913 1913 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), 1914 + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"), 1914 1915 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), 1915 1916 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), 1916 1917 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), ··· 1977 1976 EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"), 1978 1977 EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), 1979 1978 EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), 1980 - 1981 - EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), 1982 1979 1983 1980 EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), 1984 1981 EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
+184 -183
drivers/gpu/drm/panel/panel-newvision-nv3051d.c
··· 47 47 static int panel_nv3051d_init_sequence(struct panel_nv3051d *ctx) 48 48 { 49 49 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 50 + struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi}; 50 51 51 52 /* 52 53 * Init sequence was supplied by device vendor with no 53 54 * documentation. 54 55 */ 55 56 56 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); 57 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); 58 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x01); 59 - mipi_dsi_dcs_write_seq(dsi, 0xE3, 0x00); 60 - mipi_dsi_dcs_write_seq(dsi, 0x03, 0x40); 61 - mipi_dsi_dcs_write_seq(dsi, 0x04, 0x00); 62 - mipi_dsi_dcs_write_seq(dsi, 0x05, 0x03); 63 - mipi_dsi_dcs_write_seq(dsi, 0x24, 0x12); 64 - mipi_dsi_dcs_write_seq(dsi, 0x25, 0x1E); 65 - mipi_dsi_dcs_write_seq(dsi, 0x26, 0x28); 66 - mipi_dsi_dcs_write_seq(dsi, 0x27, 0x52); 67 - mipi_dsi_dcs_write_seq(dsi, 0x28, 0x57); 68 - mipi_dsi_dcs_write_seq(dsi, 0x29, 0x01); 69 - mipi_dsi_dcs_write_seq(dsi, 0x2A, 0xDF); 70 - mipi_dsi_dcs_write_seq(dsi, 0x38, 0x9C); 71 - mipi_dsi_dcs_write_seq(dsi, 0x39, 0xA7); 72 - mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x53); 73 - mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00); 74 - mipi_dsi_dcs_write_seq(dsi, 0x49, 0x3C); 75 - mipi_dsi_dcs_write_seq(dsi, 0x59, 0xFE); 76 - mipi_dsi_dcs_write_seq(dsi, 0x5C, 0x00); 77 - mipi_dsi_dcs_write_seq(dsi, 0x91, 0x77); 78 - mipi_dsi_dcs_write_seq(dsi, 0x92, 0x77); 79 - mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x55); 80 - mipi_dsi_dcs_write_seq(dsi, 0xA1, 0x50); 81 - mipi_dsi_dcs_write_seq(dsi, 0xA4, 0x9C); 82 - mipi_dsi_dcs_write_seq(dsi, 0xA7, 0x02); 83 - mipi_dsi_dcs_write_seq(dsi, 0xA8, 0x01); 84 - mipi_dsi_dcs_write_seq(dsi, 0xA9, 0x01); 85 - mipi_dsi_dcs_write_seq(dsi, 0xAA, 0xFC); 86 - mipi_dsi_dcs_write_seq(dsi, 0xAB, 0x28); 87 - mipi_dsi_dcs_write_seq(dsi, 0xAC, 0x06); 88 - mipi_dsi_dcs_write_seq(dsi, 0xAD, 0x06); 89 - mipi_dsi_dcs_write_seq(dsi, 0xAE, 0x06); 90 - mipi_dsi_dcs_write_seq(dsi, 0xAF, 0x03); 91 - mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x08); 92 - mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x26); 93 - mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x28); 94 - mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28); 95 - mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33); 96 - mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x08); 97 - mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x26); 98 - mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x08); 99 - mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x26); 100 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); 101 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); 102 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02); 103 - mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x0E); 104 - mipi_dsi_dcs_write_seq(dsi, 0xD1, 0x0E); 105 - mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x29); 106 - mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x2B); 107 - mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C); 108 - mipi_dsi_dcs_write_seq(dsi, 0xD2, 0x0A); 109 - mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28); 110 - mipi_dsi_dcs_write_seq(dsi, 0xD3, 0x28); 111 - mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x11); 112 - mipi_dsi_dcs_write_seq(dsi, 0xD6, 0x0D); 113 - mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x32); 114 - mipi_dsi_dcs_write_seq(dsi, 0xD7, 0x30); 115 - mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x04); 116 - mipi_dsi_dcs_write_seq(dsi, 0xE1, 0x06); 117 - mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x0A); 118 - mipi_dsi_dcs_write_seq(dsi, 0xD8, 0x0A); 119 - mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x01); 120 - mipi_dsi_dcs_write_seq(dsi, 0xD9, 0x01); 121 - mipi_dsi_dcs_write_seq(dsi, 0xBD, 0x13); 122 - mipi_dsi_dcs_write_seq(dsi, 0xDD, 0x13); 123 - mipi_dsi_dcs_write_seq(dsi, 0xBC, 0x11); 124 - mipi_dsi_dcs_write_seq(dsi, 0xDC, 0x11); 125 - mipi_dsi_dcs_write_seq(dsi, 0xBB, 0x0F); 126 - mipi_dsi_dcs_write_seq(dsi, 0xDB, 0x0F); 127 - mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F); 128 - mipi_dsi_dcs_write_seq(dsi, 0xDA, 0x0F); 129 - mipi_dsi_dcs_write_seq(dsi, 0xBE, 0x18); 130 - mipi_dsi_dcs_write_seq(dsi, 0xDE, 0x18); 131 - mipi_dsi_dcs_write_seq(dsi, 0xBF, 0x0F); 132 - mipi_dsi_dcs_write_seq(dsi, 0xDF, 0x0F); 133 - mipi_dsi_dcs_write_seq(dsi, 0xC0, 0x17); 134 - mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x17); 135 - mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x3B); 136 - mipi_dsi_dcs_write_seq(dsi, 0xD5, 0x3C); 137 - mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x0B); 138 - mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0C); 139 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); 140 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); 141 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x03); 142 - mipi_dsi_dcs_write_seq(dsi, 0x00, 0x2A); 143 - mipi_dsi_dcs_write_seq(dsi, 0x01, 0x2A); 144 - mipi_dsi_dcs_write_seq(dsi, 0x02, 0x2A); 145 - mipi_dsi_dcs_write_seq(dsi, 0x03, 0x2A); 146 - mipi_dsi_dcs_write_seq(dsi, 0x04, 0x61); 147 - mipi_dsi_dcs_write_seq(dsi, 0x05, 0x80); 148 - mipi_dsi_dcs_write_seq(dsi, 0x06, 0xC7); 149 - mipi_dsi_dcs_write_seq(dsi, 0x07, 0x01); 150 - mipi_dsi_dcs_write_seq(dsi, 0x08, 0x82); 151 - mipi_dsi_dcs_write_seq(dsi, 0x09, 0x83); 152 - mipi_dsi_dcs_write_seq(dsi, 0x30, 0x2A); 153 - mipi_dsi_dcs_write_seq(dsi, 0x31, 0x2A); 154 - mipi_dsi_dcs_write_seq(dsi, 0x32, 0x2A); 155 - mipi_dsi_dcs_write_seq(dsi, 0x33, 0x2A); 156 - mipi_dsi_dcs_write_seq(dsi, 0x34, 0x61); 157 - mipi_dsi_dcs_write_seq(dsi, 0x35, 0xC5); 158 - mipi_dsi_dcs_write_seq(dsi, 0x36, 0x80); 159 - mipi_dsi_dcs_write_seq(dsi, 0x37, 0x23); 160 - mipi_dsi_dcs_write_seq(dsi, 0x40, 0x82); 161 - mipi_dsi_dcs_write_seq(dsi, 0x41, 0x83); 162 - mipi_dsi_dcs_write_seq(dsi, 0x42, 0x80); 163 - mipi_dsi_dcs_write_seq(dsi, 0x43, 0x81); 164 - mipi_dsi_dcs_write_seq(dsi, 0x44, 0x11); 165 - mipi_dsi_dcs_write_seq(dsi, 0x45, 0xF2); 166 - mipi_dsi_dcs_write_seq(dsi, 0x46, 0xF1); 167 - mipi_dsi_dcs_write_seq(dsi, 0x47, 0x11); 168 - mipi_dsi_dcs_write_seq(dsi, 0x48, 0xF4); 169 - mipi_dsi_dcs_write_seq(dsi, 0x49, 0xF3); 170 - mipi_dsi_dcs_write_seq(dsi, 0x50, 0x02); 171 - mipi_dsi_dcs_write_seq(dsi, 0x51, 0x01); 172 - mipi_dsi_dcs_write_seq(dsi, 0x52, 0x04); 173 - mipi_dsi_dcs_write_seq(dsi, 0x53, 0x03); 174 - mipi_dsi_dcs_write_seq(dsi, 0x54, 0x11); 175 - mipi_dsi_dcs_write_seq(dsi, 0x55, 0xF6); 176 - mipi_dsi_dcs_write_seq(dsi, 0x56, 0xF5); 177 - mipi_dsi_dcs_write_seq(dsi, 0x57, 0x11); 178 - mipi_dsi_dcs_write_seq(dsi, 0x58, 0xF8); 179 - mipi_dsi_dcs_write_seq(dsi, 0x59, 0xF7); 180 - mipi_dsi_dcs_write_seq(dsi, 0x7E, 0x02); 181 - mipi_dsi_dcs_write_seq(dsi, 0x7F, 0x80); 182 - mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x5A); 183 - mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x00); 184 - mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x0E); 185 - mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x0F); 186 - mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x04); 187 - mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x07); 188 - mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x06); 189 - mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x05); 190 - mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F); 191 - mipi_dsi_dcs_write_seq(dsi, 0xC7, 0x00); 192 - mipi_dsi_dcs_write_seq(dsi, 0xCA, 0x0E); 193 - mipi_dsi_dcs_write_seq(dsi, 0xCB, 0x0F); 194 - mipi_dsi_dcs_write_seq(dsi, 0xCC, 0x04); 195 - mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x07); 196 - mipi_dsi_dcs_write_seq(dsi, 0xCE, 0x06); 197 - mipi_dsi_dcs_write_seq(dsi, 0xCF, 0x05); 198 - mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0F); 199 - mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0F); 200 - mipi_dsi_dcs_write_seq(dsi, 0x84, 0x0E); 201 - mipi_dsi_dcs_write_seq(dsi, 0x85, 0x0F); 202 - mipi_dsi_dcs_write_seq(dsi, 0x86, 0x07); 203 - mipi_dsi_dcs_write_seq(dsi, 0x87, 0x04); 204 - mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05); 205 - mipi_dsi_dcs_write_seq(dsi, 0x89, 0x06); 206 - mipi_dsi_dcs_write_seq(dsi, 0x8A, 0x00); 207 - mipi_dsi_dcs_write_seq(dsi, 0x97, 0x0F); 208 - mipi_dsi_dcs_write_seq(dsi, 0x9A, 0x0E); 209 - mipi_dsi_dcs_write_seq(dsi, 0x9B, 0x0F); 210 - mipi_dsi_dcs_write_seq(dsi, 0x9C, 0x07); 211 - mipi_dsi_dcs_write_seq(dsi, 0x9D, 0x04); 212 - mipi_dsi_dcs_write_seq(dsi, 0x9E, 0x05); 213 - mipi_dsi_dcs_write_seq(dsi, 0x9F, 0x06); 214 - mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x00); 215 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); 216 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); 217 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02); 218 - mipi_dsi_dcs_write_seq(dsi, 0x01, 0x01); 219 - mipi_dsi_dcs_write_seq(dsi, 0x02, 0xDA); 220 - mipi_dsi_dcs_write_seq(dsi, 0x03, 0xBA); 221 - mipi_dsi_dcs_write_seq(dsi, 0x04, 0xA8); 222 - mipi_dsi_dcs_write_seq(dsi, 0x05, 0x9A); 223 - mipi_dsi_dcs_write_seq(dsi, 0x06, 0x70); 224 - mipi_dsi_dcs_write_seq(dsi, 0x07, 0xFF); 225 - mipi_dsi_dcs_write_seq(dsi, 0x08, 0x91); 226 - mipi_dsi_dcs_write_seq(dsi, 0x09, 0x90); 227 - mipi_dsi_dcs_write_seq(dsi, 0x0A, 0xFF); 228 - mipi_dsi_dcs_write_seq(dsi, 0x0B, 0x8F); 229 - mipi_dsi_dcs_write_seq(dsi, 0x0C, 0x60); 230 - mipi_dsi_dcs_write_seq(dsi, 0x0D, 0x58); 231 - mipi_dsi_dcs_write_seq(dsi, 0x0E, 0x48); 232 - mipi_dsi_dcs_write_seq(dsi, 0x0F, 0x38); 233 - mipi_dsi_dcs_write_seq(dsi, 0x10, 0x2B); 234 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30); 235 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52); 236 - mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x00); 237 - mipi_dsi_dcs_write_seq(dsi, 0x36, 0x02); 238 - mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x70); 57 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30); 58 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52); 59 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x01); 60 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE3, 0x00); 61 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x40); 62 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x00); 63 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x03); 64 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x12); 65 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x1E); 66 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x28); 67 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x52); 68 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x57); 69 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x01); 70 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2A, 0xDF); 71 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x9C); 72 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xA7); 73 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x53); 74 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x00); 75 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x3C); 76 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xFE); 77 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5C, 0x00); 78 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x77); 79 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x77); 80 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x55); 81 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA1, 0x50); 82 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA4, 0x9C); 83 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA7, 0x02); 84 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA8, 0x01); 85 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA9, 0x01); 86 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAA, 0xFC); 87 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAB, 0x28); 88 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAC, 0x06); 89 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAD, 0x06); 90 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAE, 0x06); 91 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAF, 0x03); 92 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x08); 93 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x26); 94 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x28); 95 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28); 96 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x33); 97 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x08); 98 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x26); 99 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x08); 100 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x26); 101 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30); 102 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52); 103 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02); 104 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x0E); 105 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD1, 0x0E); 106 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x29); 107 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD4, 0x2B); 108 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x0C); 109 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD2, 0x0A); 110 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28); 111 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD3, 0x28); 112 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x11); 113 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD6, 0x0D); 114 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x32); 115 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD7, 0x30); 116 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC1, 0x04); 117 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE1, 0x06); 118 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x0A); 119 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD8, 0x0A); 120 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x01); 121 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD9, 0x01); 122 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBD, 0x13); 123 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDD, 0x13); 124 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBC, 0x11); 125 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDC, 0x11); 126 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBB, 0x0F); 127 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDB, 0x0F); 128 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F); 129 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDA, 0x0F); 130 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBE, 0x18); 131 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDE, 0x18); 132 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBF, 0x0F); 133 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDF, 0x0F); 134 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC0, 0x17); 135 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x17); 136 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x3B); 137 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD5, 0x3C); 138 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x0B); 139 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0C); 140 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30); 141 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52); 142 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x03); 143 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x2A); 144 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x2A); 145 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x2A); 146 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x2A); 147 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x61); 148 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x80); 149 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0xC7); 150 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x01); 151 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x82); 152 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x83); 153 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x2A); 154 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x2A); 155 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x2A); 156 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x2A); 157 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x61); 158 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0xC5); 159 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x80); 160 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x23); 161 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x82); 162 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x83); 163 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x80); 164 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x81); 165 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x11); 166 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0xF2); 167 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0xF1); 168 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x11); 169 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0xF4); 170 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0xF3); 171 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x02); 172 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x01); 173 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x04); 174 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x03); 175 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x11); 176 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0xF6); 177 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0xF5); 178 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x11); 179 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xF8); 180 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xF7); 181 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7E, 0x02); 182 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7F, 0x80); 183 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x5A); 184 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x00); 185 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x0E); 186 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x0F); 187 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x04); 188 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x07); 189 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x06); 190 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x05); 191 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F); 192 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC7, 0x00); 193 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCA, 0x0E); 194 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCB, 0x0F); 195 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCC, 0x04); 196 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCD, 0x07); 197 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCE, 0x06); 198 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCF, 0x05); 199 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0F); 200 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x0F); 201 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x84, 0x0E); 202 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x0F); 203 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x86, 0x07); 204 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x04); 205 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0x05); 206 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x89, 0x06); 207 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8A, 0x00); 208 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0x0F); 209 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9A, 0x0E); 210 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9B, 0x0F); 211 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9C, 0x07); 212 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9D, 0x04); 213 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9E, 0x05); 214 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9F, 0x06); 215 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x00); 216 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30); 217 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52); 218 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02); 219 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x01); 220 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xDA); 221 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0xBA); 222 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0xA8); 223 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x9A); 224 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x70); 225 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0xFF); 226 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x91); 227 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x90); 228 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0A, 0xFF); 229 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0B, 0x8F); 230 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x60); 231 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0D, 0x58); 232 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0E, 0x48); 233 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0F, 0x38); 234 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x2B); 235 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30); 236 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52); 237 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x00); 238 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x02); 239 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x70); 239 240 240 241 dev_dbg(ctx->dev, "Panel init sequence done\n"); 241 242
+66 -145
drivers/gpu/drm/panel/panel-novatek-nt35950.c
··· 100 100 101 101 /* 102 102 * nt35950_set_cmd2_page - Select manufacturer control (CMD2) page 103 + * @dsi_ctx: context for mipi_dsi functions 103 104 * @nt: Main driver structure 104 105 * @page: Page number (0-7) 105 - * 106 - * Return: Number of transferred bytes or negative number on error 107 106 */ 108 - static int nt35950_set_cmd2_page(struct nt35950 *nt, u8 page) 107 + static void nt35950_set_cmd2_page(struct mipi_dsi_multi_context *dsi_ctx, 108 + struct nt35950 *nt, u8 page) 109 109 { 110 110 const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52, 111 111 0x08, page }; 112 - int ret; 113 112 114 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], mauc_cmd2_page, 113 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, mauc_cmd2_page, 115 114 ARRAY_SIZE(mauc_cmd2_page)); 116 - if (ret < 0) 117 - return ret; 118 - 119 - nt->last_page = page; 120 - return 0; 115 + if (!dsi_ctx->accum_err) 116 + nt->last_page = page; 121 117 } 122 118 123 119 /* 124 120 * nt35950_set_data_compression - Set data compression mode 121 + * @dsi_ctx: context for mipi_dsi functions 125 122 * @nt: Main driver structure 126 123 * @comp_mode: Compression mode 127 - * 128 - * Return: Number of transferred bytes or negative number on error 129 124 */ 130 - static int nt35950_set_data_compression(struct nt35950 *nt, u8 comp_mode) 125 + static void nt35950_set_data_compression(struct mipi_dsi_multi_context *dsi_ctx, 126 + struct nt35950 *nt, u8 comp_mode) 131 127 { 132 128 u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode }; 133 129 u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode }; 134 130 u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 }; 135 131 u8 last_page = nt->last_page; 136 - int ret; 137 132 138 133 /* Set CMD2 Page 0 if we're not there yet */ 139 - if (last_page != 0) { 140 - ret = nt35950_set_cmd2_page(nt, 0); 141 - if (ret < 0) 142 - return ret; 143 - } 134 + if (last_page != 0) 135 + nt35950_set_cmd2_page(dsi_ctx, nt, 0); 144 136 145 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_data_compression, 137 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_data_compression, 146 138 ARRAY_SIZE(cmd_data_compression)); 147 - if (ret < 0) 148 - return ret; 149 - 150 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_on, 139 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_on, 151 140 ARRAY_SIZE(cmd_vesa_dsc_on)); 152 - if (ret < 0) 153 - return ret; 154 141 155 142 /* Set the vesa dsc setting on Page 4 */ 156 - ret = nt35950_set_cmd2_page(nt, 4); 157 - if (ret < 0) 158 - return ret; 143 + nt35950_set_cmd2_page(dsi_ctx, nt, 4); 159 144 160 145 /* Display Stream Compression setting, always 0x03 */ 161 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_setting, 146 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_setting, 162 147 ARRAY_SIZE(cmd_vesa_dsc_setting)); 163 - if (ret < 0) 164 - return ret; 165 148 166 149 /* Get back to the previously set page */ 167 - return nt35950_set_cmd2_page(nt, last_page); 150 + nt35950_set_cmd2_page(dsi_ctx, nt, last_page); 168 151 } 169 152 170 153 /* 171 154 * nt35950_set_scaler - Enable/disable resolution upscaling 172 - * @nt: Main driver structure 155 + * @dsi_ctx: context for mipi_dsi functions 173 156 * @scale_up: Scale up function control 174 - * 175 - * Return: Number of transferred bytes or negative number on error 176 157 */ 177 - static int nt35950_set_scaler(struct nt35950 *nt, u8 scale_up) 158 + static void nt35950_set_scaler(struct mipi_dsi_multi_context *dsi_ctx, 159 + u8 scale_up) 178 160 { 179 161 u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up }; 180 162 181 - return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler, 182 - ARRAY_SIZE(cmd_scaler)); 163 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler, 164 + ARRAY_SIZE(cmd_scaler)); 183 165 } 184 166 185 167 /* 186 168 * nt35950_set_scale_mode - Resolution upscaling mode 187 - * @nt: Main driver structure 169 + * @dsi_ctx: context for mipi_dsi functions 188 170 * @mode: Scaler mode (MCS_DATA_COMPRESSION_*) 189 - * 190 - * Return: Number of transferred bytes or negative number on error 191 171 */ 192 - static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode) 172 + static void nt35950_set_scale_mode(struct mipi_dsi_multi_context *dsi_ctx, 173 + u8 mode) 193 174 { 194 175 u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode }; 195 176 196 - return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler, 197 - ARRAY_SIZE(cmd_scaler)); 177 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler, 178 + ARRAY_SIZE(cmd_scaler)); 198 179 } 199 180 200 181 /* 201 182 * nt35950_inject_black_image - Display a completely black image 202 - * @nt: Main driver structure 183 + * @dsi_ctx: context for mipi_dsi functions 203 184 * 204 185 * After IC setup, the attached panel may show random data 205 186 * due to driveric behavior changes (resolution, compression, ··· 189 208 * the display. 190 209 * It makes sense to push a black image before sending the sleep-out 191 210 * and display-on commands. 192 - * 193 - * Return: Number of transferred bytes or negative number on error 194 211 */ 195 - static int nt35950_inject_black_image(struct nt35950 *nt) 212 + static void nt35950_inject_black_image(struct mipi_dsi_multi_context *dsi_ctx) 196 213 { 197 214 const u8 cmd0_black_img[] = { 0x6f, 0x01 }; 198 215 const u8 cmd1_black_img[] = { 0xf3, 0x10 }; 199 216 u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 }; 200 - int ret; 201 217 202 218 /* Enable test command */ 203 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test)); 204 - if (ret < 0) 205 - return ret; 219 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test)); 206 220 207 221 /* Send a black image */ 208 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd0_black_img, 222 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd0_black_img, 209 223 ARRAY_SIZE(cmd0_black_img)); 210 - if (ret < 0) 211 - return ret; 212 - ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd1_black_img, 224 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd1_black_img, 213 225 ARRAY_SIZE(cmd1_black_img)); 214 - if (ret < 0) 215 - return ret; 216 226 217 227 /* Disable test command */ 218 228 cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00; 219 - return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test)); 229 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test)); 220 230 } 221 231 222 232 /* 223 233 * nt35950_set_dispout - Set Display Output register parameters 224 234 * @nt: Main driver structure 225 - * 226 - * Return: Number of transferred bytes or negative number on error 235 + * @dsi_ctx: context for mipi_dsi functions 227 236 */ 228 - static int nt35950_set_dispout(struct nt35950 *nt) 237 + static void nt35950_set_dispout(struct mipi_dsi_multi_context *dsi_ctx, 238 + struct nt35950 *nt) 229 239 { 230 240 u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 }; 231 241 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; ··· 226 254 if (mode_data[nt->cur_mode].enable_sram) 227 255 cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN; 228 256 229 - return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_dispout, 230 - ARRAY_SIZE(cmd_dispout)); 257 + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_dispout, 258 + ARRAY_SIZE(cmd_dispout)); 231 259 } 232 260 233 261 static int nt35950_get_current_mode(struct nt35950 *nt) ··· 256 284 { 257 285 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; 258 286 struct mipi_dsi_device *dsi = nt->dsi[0]; 259 - struct device *dev = &dsi->dev; 260 - int ret; 287 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 261 288 262 289 nt->cur_mode = nt35950_get_current_mode(nt); 263 290 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 264 291 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 265 292 266 - ret = nt35950_set_cmd2_page(nt, 0); 267 - if (ret < 0) 268 - return ret; 293 + nt35950_set_cmd2_page(&dsi_ctx, nt, 0); 294 + nt35950_set_data_compression(&dsi_ctx, nt, mode_data[nt->cur_mode].compression); 295 + nt35950_set_scale_mode(&dsi_ctx, mode_data[nt->cur_mode].scaler_mode); 296 + nt35950_set_scaler(&dsi_ctx, mode_data[nt->cur_mode].scaler_on); 297 + nt35950_set_dispout(&dsi_ctx, nt); 269 298 270 - ret = nt35950_set_data_compression(nt, mode_data[nt->cur_mode].compression); 271 - if (ret < 0) 272 - return ret; 273 - 274 - ret = nt35950_set_scale_mode(nt, mode_data[nt->cur_mode].scaler_mode); 275 - if (ret < 0) 276 - return ret; 277 - 278 - ret = nt35950_set_scaler(nt, mode_data[nt->cur_mode].scaler_on); 279 - if (ret < 0) 280 - return ret; 281 - 282 - ret = nt35950_set_dispout(nt); 283 - if (ret < 0) 284 - return ret; 285 - 286 - ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 287 - if (ret < 0) { 288 - dev_err(dev, "Failed to set tear on: %d\n", ret); 289 - return ret; 290 - } 291 - 292 - ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0); 293 - if (ret < 0) { 294 - dev_err(dev, "Failed to set tear scanline: %d\n", ret); 295 - return ret; 296 - } 299 + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 300 + mipi_dsi_dcs_set_tear_scanline_multi(&dsi_ctx, 0); 297 301 298 302 /* CMD2 Page 1 */ 299 - ret = nt35950_set_cmd2_page(nt, 1); 300 - if (ret < 0) 301 - return ret; 303 + nt35950_set_cmd2_page(&dsi_ctx, nt, 1); 302 304 303 305 /* Unknown command */ 304 - mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88); 306 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x88, 0x88); 305 307 306 308 /* CMD2 Page 7 */ 307 - ret = nt35950_set_cmd2_page(nt, 7); 308 - if (ret < 0) 309 - return ret; 309 + nt35950_set_cmd2_page(&dsi_ctx, nt, 7); 310 310 311 311 /* Enable SubPixel Rendering */ 312 - mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01); 312 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_EN, 0x01); 313 313 314 314 /* SPR Mode: YYG Rainbow-RGB */ 315 - mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB); 315 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_MODE, 316 + MCS_SPR_MODE_YYG_RAINBOW_RGB); 316 317 317 318 /* CMD3 */ 318 - ret = nt35950_inject_black_image(nt); 319 - if (ret < 0) 320 - return ret; 319 + nt35950_inject_black_image(&dsi_ctx); 320 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 321 + mipi_dsi_msleep(&dsi_ctx, 120); 321 322 322 - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 323 - if (ret < 0) 324 - return ret; 325 - msleep(120); 323 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 324 + mipi_dsi_msleep(&dsi_ctx, 120); 326 325 327 - ret = mipi_dsi_dcs_set_display_on(dsi); 328 - if (ret < 0) 329 - return ret; 330 - msleep(120); 326 + if (dsi_ctx.accum_err) 327 + return dsi_ctx.accum_err; 331 328 332 329 nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM; 333 330 nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM; ··· 304 363 return 0; 305 364 } 306 365 307 - static int nt35950_off(struct nt35950 *nt) 366 + static void nt35950_off(struct nt35950 *nt) 308 367 { 309 - struct device *dev = &nt->dsi[0]->dev; 310 - int ret; 368 + struct mipi_dsi_device *dsi = nt->dsi[0]; 369 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 311 370 312 - ret = mipi_dsi_dcs_set_display_off(nt->dsi[0]); 313 - if (ret < 0) { 314 - dev_err(dev, "Failed to set display off: %d\n", ret); 315 - goto set_lpm; 316 - } 317 - usleep_range(10000, 11000); 371 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 372 + mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000); 318 373 319 - ret = mipi_dsi_dcs_enter_sleep_mode(nt->dsi[0]); 320 - if (ret < 0) { 321 - dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 322 - goto set_lpm; 323 - } 324 - msleep(150); 374 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 375 + mipi_dsi_msleep(&dsi_ctx, 150); 325 376 326 - set_lpm: 327 377 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 328 378 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 329 - 330 - return 0; 331 379 } 332 380 333 381 static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev) ··· 357 427 static int nt35950_prepare(struct drm_panel *panel) 358 428 { 359 429 struct nt35950 *nt = to_nt35950(panel); 360 - struct device *dev = &nt->dsi[0]->dev; 361 430 int ret; 362 431 363 432 ret = regulator_enable(nt->vregs[0].consumer); ··· 381 452 nt35950_reset(nt); 382 453 383 454 ret = nt35950_on(nt); 384 - if (ret < 0) { 385 - dev_err(dev, "Failed to initialize panel: %d\n", ret); 386 - goto end; 387 - } 388 455 389 456 end: 390 457 if (ret < 0) { ··· 394 469 static int nt35950_unprepare(struct drm_panel *panel) 395 470 { 396 471 struct nt35950 *nt = to_nt35950(panel); 397 - struct device *dev = &nt->dsi[0]->dev; 398 - int ret; 399 472 400 - ret = nt35950_off(nt); 401 - if (ret < 0) 402 - dev_err(dev, "Failed to deinitialize panel: %d\n", ret); 473 + nt35950_off(nt); 403 474 404 475 gpiod_set_value_cansleep(nt->reset_gpio, 0); 405 476 regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);
+94 -110
drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
··· 19 19 struct drm_panel panel; 20 20 struct mipi_dsi_device *dsi; 21 21 struct gpio_desc *reset_gpio; 22 - struct regulator_bulk_data supplies[3]; 22 + struct regulator_bulk_data *supplies; 23 + }; 24 + 25 + static const struct regulator_bulk_data visionox_vtdr6130_supplies[] = { 26 + { .supply = "vddio" }, 27 + { .supply = "vci" }, 28 + { .supply = "vdd" }, 23 29 }; 24 30 25 31 static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel) ··· 46 40 static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx) 47 41 { 48 42 struct mipi_dsi_device *dsi = ctx->dsi; 49 - struct device *dev = &dsi->dev; 50 - int ret; 43 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 51 44 52 45 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 53 46 54 - ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 55 - if (ret) 56 - return ret; 47 + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 57 48 58 - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); 59 - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 0x00); 60 - mipi_dsi_dcs_write_seq(dsi, 0x59, 0x09); 61 - mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x01); 62 - mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x00); 63 - mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x01); 64 - mipi_dsi_dcs_write_seq(dsi, 0x70, 65 - 0x12, 0x00, 0x00, 0xab, 0x30, 0x80, 0x09, 0x60, 0x04, 66 - 0x38, 0x00, 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00, 67 - 0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 0x07, 0x00, 68 - 0x0c, 0x02, 0x77, 0x02, 0x8b, 0x18, 0x00, 0x10, 0xf0, 69 - 0x07, 0x10, 0x20, 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e, 70 - 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 71 - 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 0x22, 0x00, 0x2a, 72 - 0x40, 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8, 73 - 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b, 74 - 0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 0x00, 0x00, 75 - 0x00, 0x00, 0x00, 0x00); 76 - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x10); 77 - mipi_dsi_dcs_write_seq(dsi, 0xb1, 78 - 0x01, 0x38, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x01, 0x66, 79 - 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14, 80 - 0x05, 0xcc, 0x00); 81 - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x13); 82 - mipi_dsi_dcs_write_seq(dsi, 0xce, 83 - 0x09, 0x11, 0x09, 0x11, 0x08, 0xc1, 0x07, 0xfa, 0x05, 84 - 0xa4, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c, 85 - 0x00, 0x0c, 0x04, 0x00, 0x35); 86 - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x14); 87 - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x03, 0x33); 88 - mipi_dsi_dcs_write_seq(dsi, 0xb4, 89 - 0x00, 0x33, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 90 - 0x3e, 0x00, 0x00); 91 - mipi_dsi_dcs_write_seq(dsi, 0xb5, 92 - 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x01); 93 - mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0x00, 0x08, 0x09, 0x09, 0x09); 94 - mipi_dsi_dcs_write_seq(dsi, 0xbc, 95 - 0x10, 0x00, 0x00, 0x06, 0x11, 0x09, 0x3b, 0x09, 0x47, 96 - 0x09, 0x47, 0x00); 97 - mipi_dsi_dcs_write_seq(dsi, 0xbe, 98 - 0x10, 0x10, 0x00, 0x08, 0x22, 0x09, 0x19, 0x09, 0x25, 99 - 0x09, 0x25, 0x00); 100 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x80); 101 - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x14); 102 - mipi_dsi_dcs_write_seq(dsi, 0xfa, 0x08, 0x08, 0x08); 103 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x81); 104 - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x05); 105 - mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x0f); 106 - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x00); 107 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x82); 108 - mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x00); 109 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x51, 0x83); 110 - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x04); 111 - mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x00); 112 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00); 113 - mipi_dsi_dcs_write_seq(dsi, 0x65, 0x01); 114 - mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x9a); 115 - mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00); 49 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 50 + MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); 51 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 52 + MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 53 + 0x00); 54 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x09); 55 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x01); 56 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00); 57 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01); 58 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x12, 0x00, 0x00, 0xab, 59 + 0x30, 0x80, 0x09, 0x60, 0x04, 0x38, 0x00, 60 + 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00, 61 + 0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 62 + 0x07, 0x00, 0x0c, 0x02, 0x77, 0x02, 0x8b, 63 + 0x18, 0x00, 0x10, 0xf0, 0x07, 0x10, 0x20, 64 + 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 65 + 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 66 + 0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 67 + 0x22, 0x00, 0x2a, 0x40, 0x2a, 0xbe, 0x3a, 68 + 0xfc, 0x3a, 0xfa, 0x3a, 0xf8, 0x3b, 0x38, 69 + 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b, 70 + 0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 72 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x10); 73 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x01, 0x38, 0x00, 0x14, 74 + 0x00, 0x1c, 0x00, 0x01, 0x66, 0x00, 0x14, 75 + 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14, 76 + 0x05, 0xcc, 0x00); 77 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x13); 78 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x09, 0x11, 0x09, 0x11, 79 + 0x08, 0xc1, 0x07, 0xfa, 0x05, 0xa4, 0x00, 80 + 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c, 81 + 0x00, 0x0c, 0x04, 0x00, 0x35); 82 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x14); 83 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x03, 0x33); 84 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x00, 0x33, 0x00, 0x00, 85 + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 86 + 0x00); 87 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0x09, 0x09, 0x09, 88 + 0x09, 0x09, 0x09, 0x06, 0x01); 89 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x00, 0x08, 0x09, 90 + 0x09, 0x09); 91 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x10, 0x00, 0x00, 0x06, 92 + 0x11, 0x09, 0x3b, 0x09, 0x47, 0x09, 0x47, 93 + 0x00); 94 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x10, 0x10, 0x00, 0x08, 95 + 0x22, 0x09, 0x19, 0x09, 0x25, 0x09, 0x25, 96 + 0x00); 97 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x80); 98 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x14); 99 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x08, 0x08, 0x08); 100 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x81); 101 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x05); 102 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x0f); 103 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x00); 104 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x82); 105 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x00); 106 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x51, 0x83); 107 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x04); 108 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x00); 109 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00); 110 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x01); 111 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x9a); 112 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00); 116 113 117 - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 118 - if (ret < 0) { 119 - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 120 - return ret; 121 - } 122 - msleep(120); 114 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 115 + mipi_dsi_msleep(&dsi_ctx, 120); 123 116 124 - ret = mipi_dsi_dcs_set_display_on(dsi); 125 - if (ret < 0) { 126 - dev_err(dev, "Failed to set display on: %d\n", ret); 127 - return ret; 128 - } 129 - msleep(20); 117 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 118 + mipi_dsi_msleep(&dsi_ctx, 20); 130 119 131 - return 0; 120 + return dsi_ctx.accum_err; 132 121 } 133 122 134 - static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx) 123 + static void visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx) 135 124 { 136 125 struct mipi_dsi_device *dsi = ctx->dsi; 137 - struct device *dev = &dsi->dev; 138 - int ret; 126 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 139 127 140 128 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 141 129 142 - ret = mipi_dsi_dcs_set_display_off(dsi); 143 - if (ret < 0) { 144 - dev_err(dev, "Failed to set display off: %d\n", ret); 145 - return ret; 146 - } 147 - msleep(20); 130 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 131 + mipi_dsi_msleep(&dsi_ctx, 20); 148 132 149 - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 150 - if (ret < 0) { 151 - dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 152 - return ret; 153 - } 154 - msleep(120); 155 - 156 - return 0; 133 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 134 + mipi_dsi_msleep(&dsi_ctx, 120); 157 135 } 158 136 159 137 static int visionox_vtdr6130_prepare(struct drm_panel *panel) 160 138 { 161 139 struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel); 162 - struct device *dev = &ctx->dsi->dev; 163 140 int ret; 164 141 165 - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), 142 + ret = regulator_bulk_enable(ARRAY_SIZE(visionox_vtdr6130_supplies), 166 143 ctx->supplies); 167 144 if (ret < 0) 168 145 return ret; ··· 154 165 155 166 ret = visionox_vtdr6130_on(ctx); 156 167 if (ret < 0) { 157 - dev_err(dev, "Failed to initialize panel: %d\n", ret); 158 168 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 159 - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 169 + regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies), 170 + ctx->supplies); 160 171 return ret; 161 172 } 162 173 ··· 166 177 static int visionox_vtdr6130_unprepare(struct drm_panel *panel) 167 178 { 168 179 struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel); 169 - struct device *dev = &ctx->dsi->dev; 170 - int ret; 171 180 172 - ret = visionox_vtdr6130_off(ctx); 173 - if (ret < 0) 174 - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 181 + visionox_vtdr6130_off(ctx); 175 182 176 183 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 177 184 178 - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 185 + regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies), 186 + ctx->supplies); 179 187 180 188 return 0; 181 189 } ··· 252 266 if (!ctx) 253 267 return -ENOMEM; 254 268 255 - ctx->supplies[0].supply = "vddio"; 256 - ctx->supplies[1].supply = "vci"; 257 - ctx->supplies[2].supply = "vdd"; 258 - 259 - ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies), 260 - ctx->supplies); 269 + ret = devm_regulator_bulk_get_const(&dsi->dev, 270 + ARRAY_SIZE(visionox_vtdr6130_supplies), 271 + visionox_vtdr6130_supplies, 272 + &ctx->supplies); 261 273 if (ret < 0) 262 274 return ret; 263 275
-8
drivers/gpu/drm/renesas/rcar-du/Kconfig
··· 60 60 select DRM_MIPI_DSI 61 61 select RESET_CONTROLLER 62 62 63 - config DRM_RZG2L_MIPI_DSI 64 - tristate "RZ/G2L MIPI DSI Encoder Support" 65 - depends on DRM && DRM_BRIDGE && OF 66 - depends on ARCH_RENESAS || COMPILE_TEST 67 - select DRM_MIPI_DSI 68 - help 69 - Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders. 70 - 71 63 config DRM_RCAR_VSP 72 64 bool "R-Car DU VSP Compositor Support" if ARM 73 65 default y if ARM64
-2
drivers/gpu/drm/renesas/rcar-du/Makefile
··· 14 14 obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o 15 15 obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o 16 16 obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o 17 - 18 - obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi.c drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi_regs.h drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
+8
drivers/gpu/drm/renesas/rz-du/Kconfig
··· 10 10 help 11 11 Choose this option if you have an RZ/G2L alike chipset. 12 12 If M is selected the module will be called rzg2l-du-drm. 13 + 14 + config DRM_RZG2L_MIPI_DSI 15 + tristate "RZ/G2L MIPI DSI Encoder Support" 16 + depends on DRM && DRM_BRIDGE && OF 17 + depends on ARCH_RENESAS || COMPILE_TEST 18 + select DRM_MIPI_DSI 19 + help 20 + Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
+2
drivers/gpu/drm/renesas/rz-du/Makefile
··· 6 6 7 7 rzg2l-du-drm-$(CONFIG_VIDEO_RENESAS_VSP1) += rzg2l_du_vsp.o 8 8 obj-$(CONFIG_DRM_RZG2L_DU) += rzg2l-du-drm.o 9 + 10 + obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
+7 -1
drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
··· 28 28 #include "rzg2l_du_vsp.h" 29 29 30 30 #define DU_MCR0 0x00 31 + #define DU_MCR0_DPI_OE BIT(0) 31 32 #define DU_MCR0_DI_EN BIT(8) 32 33 33 34 #define DU_DITR0 0x10 ··· 217 216 218 217 static void rzg2l_du_start_stop(struct rzg2l_du_crtc *rcrtc, bool start) 219 218 { 219 + struct rzg2l_du_crtc_state *rstate = to_rzg2l_crtc_state(rcrtc->crtc.state); 220 220 struct rzg2l_du_device *rcdu = rcrtc->dev; 221 + u32 val = DU_MCR0_DI_EN; 221 222 222 - writel(start ? DU_MCR0_DI_EN : 0, rcdu->mmio + DU_MCR0); 223 + if (rstate->outputs & BIT(RZG2L_DU_OUTPUT_DPAD0)) 224 + val |= DU_MCR0_DPI_OE; 225 + 226 + writel(start ? val : 0, rcdu->mmio + DU_MCR0); 223 227 } 224 228 225 229 static void rzg2l_du_crtc_start(struct rzg2l_du_crtc *rcrtc)
+11
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
··· 25 25 * Device Information 26 26 */ 27 27 28 + static const struct rzg2l_du_device_info rzg2l_du_r9a07g043u_info = { 29 + .channels_mask = BIT(0), 30 + .routes = { 31 + [RZG2L_DU_OUTPUT_DPAD0] = { 32 + .possible_outputs = BIT(0), 33 + .port = 0, 34 + }, 35 + }, 36 + }; 37 + 28 38 static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = { 29 39 .channels_mask = BIT(0), 30 40 .routes = { ··· 50 40 }; 51 41 52 42 static const struct of_device_id rzg2l_du_of_table[] = { 43 + { .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info }, 53 44 { .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info }, 54 45 { /* sentinel */ } 55 46 };
+2 -1
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
··· 183 183 184 184 /* Find the output route corresponding to the port number. */ 185 185 for (i = 0; i < RZG2L_DU_OUTPUT_MAX; ++i) { 186 - if (rcdu->info->routes[i].port == ep.port) { 186 + if (rcdu->info->routes[i].possible_outputs && 187 + rcdu->info->routes[i].port == ep.port) { 187 188 output = i; 188 189 break; 189 190 }
+14 -10
drivers/gpu/drm/sti/sti_hdmi.c
··· 974 974 975 975 static int sti_hdmi_connector_get_modes(struct drm_connector *connector) 976 976 { 977 + const struct drm_display_info *info = &connector->display_info; 977 978 struct sti_hdmi_connector *hdmi_connector 978 979 = to_sti_hdmi_connector(connector); 979 980 struct sti_hdmi *hdmi = hdmi_connector->hdmi; 980 - struct edid *edid; 981 + const struct drm_edid *drm_edid; 981 982 int count; 982 983 983 984 DRM_DEBUG_DRIVER("\n"); 984 985 985 - edid = drm_get_edid(connector, hdmi->ddc_adapt); 986 - if (!edid) 986 + drm_edid = drm_edid_read(connector); 987 + 988 + drm_edid_connector_update(connector, drm_edid); 989 + 990 + cec_notifier_set_phys_addr(hdmi->notifier, 991 + connector->display_info.source_physical_address); 992 + 993 + if (!drm_edid) 987 994 goto fail; 988 995 989 - cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid); 990 - 991 - count = drm_add_edid_modes(connector, edid); 992 - drm_connector_update_edid_property(connector, edid); 996 + count = drm_edid_connector_add_modes(connector); 993 997 994 998 DRM_DEBUG_KMS("%s : %dx%d cm\n", 995 - (connector->display_info.is_hdmi ? "hdmi monitor" : "dvi monitor"), 996 - edid->width_cm, edid->height_cm); 999 + info->is_hdmi ? "hdmi monitor" : "dvi monitor", 1000 + info->width_mm / 10, info->height_mm / 10); 997 1001 998 - kfree(edid); 1002 + drm_edid_free(drm_edid); 999 1003 return count; 1000 1004 1001 1005 fail:
+1 -1
drivers/gpu/drm/tegra/drm.h
··· 133 133 struct drm_bridge *bridge; 134 134 struct drm_panel *panel; 135 135 struct i2c_adapter *ddc; 136 - const struct edid *edid; 136 + const struct drm_edid *drm_edid; 137 137 struct cec_notifier *cec; 138 138 unsigned int hpd_irq; 139 139 struct gpio_desc *hpd_gpio;
+13 -33
drivers/gpu/drm/tegra/gr3d.c
··· 46 46 unsigned int nclocks; 47 47 struct reset_control_bulk_data resets[RST_GR3D_MAX]; 48 48 unsigned int nresets; 49 + struct dev_pm_domain_list *pd_list; 49 50 50 51 DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 51 52 }; ··· 370 369 return 0; 371 370 } 372 371 373 - static void gr3d_del_link(void *link) 374 - { 375 - device_link_del(link); 376 - } 377 - 378 372 static int gr3d_init_power(struct device *dev, struct gr3d *gr3d) 379 373 { 380 - static const char * const opp_genpd_names[] = { "3d0", "3d1", NULL }; 381 - const u32 link_flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME; 382 - struct device **opp_virt_devs, *pd_dev; 383 - struct device_link *link; 384 - unsigned int i; 374 + struct dev_pm_domain_attach_data pd_data = { 375 + .pd_names = (const char *[]) { "3d0", "3d1" }, 376 + .num_pd_names = 2, 377 + }; 385 378 int err; 386 379 387 380 err = of_count_phandle_with_args(dev->of_node, "power-domains", ··· 409 414 if (dev->pm_domain) 410 415 return 0; 411 416 412 - err = devm_pm_opp_attach_genpd(dev, opp_genpd_names, &opp_virt_devs); 413 - if (err) 417 + err = dev_pm_domain_attach_list(dev, &pd_data, &gr3d->pd_list); 418 + if (err < 0) 414 419 return err; 415 - 416 - for (i = 0; opp_genpd_names[i]; i++) { 417 - pd_dev = opp_virt_devs[i]; 418 - if (!pd_dev) { 419 - dev_err(dev, "failed to get %s power domain\n", 420 - opp_genpd_names[i]); 421 - return -EINVAL; 422 - } 423 - 424 - link = device_link_add(dev, pd_dev, link_flags); 425 - if (!link) { 426 - dev_err(dev, "failed to link to %s\n", dev_name(pd_dev)); 427 - return -EINVAL; 428 - } 429 - 430 - err = devm_add_action_or_reset(dev, gr3d_del_link, link); 431 - if (err) 432 - return err; 433 - } 434 420 435 421 return 0; 436 422 } ··· 503 527 504 528 err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); 505 529 if (err) 506 - return err; 530 + goto err; 507 531 508 532 err = host1x_client_register(&gr3d->client.base); 509 533 if (err < 0) { 510 534 dev_err(&pdev->dev, "failed to register host1x client: %d\n", 511 535 err); 512 - return err; 536 + goto err; 513 537 } 514 538 515 539 /* initialize address register map */ ··· 517 541 set_bit(gr3d_addr_regs[i], gr3d->addr_regs); 518 542 519 543 return 0; 544 + err: 545 + dev_pm_domain_detach_list(gr3d->pd_list); 546 + return err; 520 547 } 521 548 522 549 static void gr3d_remove(struct platform_device *pdev) ··· 528 549 529 550 pm_runtime_disable(&pdev->dev); 530 551 host1x_client_unregister(&gr3d->client.base); 552 + dev_pm_domain_detach_list(gr3d->pd_list); 531 553 } 532 554 533 555 static int __maybe_unused gr3d_runtime_suspend(struct device *dev)
+3 -4
drivers/gpu/drm/tegra/hub.c
··· 521 521 522 522 static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out) 523 523 { 524 - u64 tmp, tmp1, tmp2; 524 + u64 tmp, tmp1; 525 525 526 526 tmp = (u64)dfixed_trunc(in); 527 - tmp2 = (u64)out; 528 - tmp1 = (tmp << NFB) + (tmp2 >> 1); 529 - do_div(tmp1, tmp2); 527 + tmp1 = (tmp << NFB) + ((u64)out >> 1); 528 + do_div(tmp1, out); 530 529 531 530 return lower_32_bits(tmp1); 532 531 }
+17 -12
drivers/gpu/drm/tegra/output.c
··· 21 21 int tegra_output_connector_get_modes(struct drm_connector *connector) 22 22 { 23 23 struct tegra_output *output = connector_to_output(connector); 24 - struct edid *edid = NULL; 24 + const struct drm_edid *drm_edid; 25 25 int err = 0; 26 26 27 27 /* ··· 34 34 return err; 35 35 } 36 36 37 - if (output->edid) 38 - edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); 37 + if (output->drm_edid) 38 + drm_edid = drm_edid_dup(output->drm_edid); 39 39 else if (output->ddc) 40 - edid = drm_get_edid(connector, output->ddc); 40 + drm_edid = drm_edid_read_ddc(connector, output->ddc); 41 41 42 - cec_notifier_set_phys_addr_from_edid(output->cec, edid); 43 - drm_connector_update_edid_property(connector, edid); 42 + drm_edid_connector_update(connector, drm_edid); 43 + cec_notifier_set_phys_addr(output->cec, 44 + connector->display_info.source_physical_address); 44 45 45 - if (edid) { 46 - err = drm_add_edid_modes(connector, edid); 47 - kfree(edid); 48 - } 46 + err = drm_edid_connector_add_modes(connector); 47 + drm_edid_free(drm_edid); 49 48 50 49 return err; 51 50 } ··· 97 98 int tegra_output_probe(struct tegra_output *output) 98 99 { 99 100 struct device_node *ddc, *panel; 101 + const void *edid; 100 102 unsigned long flags; 101 103 int err, size; 102 104 ··· 124 124 return PTR_ERR(output->panel); 125 125 } 126 126 127 - output->edid = of_get_property(output->of_node, "nvidia,edid", &size); 128 - 129 127 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); 130 128 if (ddc) { 131 129 output->ddc = of_get_i2c_adapter_by_node(ddc); ··· 134 136 return err; 135 137 } 136 138 } 139 + 140 + edid = of_get_property(output->of_node, "nvidia,edid", &size); 141 + output->drm_edid = drm_edid_alloc(edid, size); 137 142 138 143 output->hpd_gpio = devm_fwnode_gpiod_get(output->dev, 139 144 of_fwnode_handle(output->of_node), ··· 188 187 if (output->ddc) 189 188 i2c_put_adapter(output->ddc); 190 189 190 + drm_edid_free(output->drm_edid); 191 + 191 192 return err; 192 193 } 193 194 ··· 200 197 201 198 if (output->ddc) 202 199 i2c_put_adapter(output->ddc); 200 + 201 + drm_edid_free(output->drm_edid); 203 202 } 204 203 205 204 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
+10 -3
drivers/gpu/drm/tiny/gm12u320.c
··· 464 464 * Note this assumes this driver is only ever used with the Acer C120, if we 465 465 * add support for other devices the vendor and model should be parameterized. 466 466 */ 467 - static struct edid gm12u320_edid = { 467 + static const struct edid gm12u320_edid = { 468 468 .header = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }, 469 469 .mfg_id = { 0x04, 0x72 }, /* "ACR" */ 470 470 .prod_code = { 0x20, 0xc1 }, /* C120h */ ··· 523 523 524 524 static int gm12u320_conn_get_modes(struct drm_connector *connector) 525 525 { 526 - drm_connector_update_edid_property(connector, &gm12u320_edid); 527 - return drm_add_edid_modes(connector, &gm12u320_edid); 526 + const struct drm_edid *drm_edid; 527 + int count; 528 + 529 + drm_edid = drm_edid_alloc(&gm12u320_edid, sizeof(gm12u320_edid)); 530 + drm_edid_connector_update(connector, drm_edid); 531 + count = drm_edid_connector_add_modes(connector); 532 + drm_edid_free(drm_edid); 533 + 534 + return count; 528 535 } 529 536 530 537 static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {
+4 -3
drivers/gpu/host1x/dev.c
··· 404 404 if (err < 0) 405 405 goto put_group; 406 406 407 - host->domain = iommu_domain_alloc(&platform_bus_type); 408 - if (!host->domain) { 409 - err = -ENOMEM; 407 + host->domain = iommu_paging_domain_alloc(host->dev); 408 + if (IS_ERR(host->domain)) { 409 + err = PTR_ERR(host->domain); 410 + host->domain = NULL; 410 411 goto put_cache; 411 412 } 412 413
+2
drivers/gpu/host1x/dev.h
··· 9 9 #include <linux/device.h> 10 10 #include <linux/iommu.h> 11 11 #include <linux/iova.h> 12 + #include <linux/irqreturn.h> 12 13 #include <linux/platform_device.h> 13 14 #include <linux/reset.h> 14 15 ··· 82 81 void (*disable_syncpt_intr)(struct host1x *host, unsigned int id); 83 82 void (*disable_all_syncpt_intrs)(struct host1x *host); 84 83 int (*free_syncpt_irq)(struct host1x *host); 84 + irqreturn_t (*isr)(int irq, void *dev_id); 85 85 }; 86 86 87 87 struct host1x_sid_entry {
+3 -34
drivers/gpu/host1x/hw/intr_hw.c
··· 6 6 * Copyright (c) 2010-2013, NVIDIA Corporation. 7 7 */ 8 8 9 - #include <linux/interrupt.h> 10 - #include <linux/irq.h> 11 9 #include <linux/io.h> 12 10 13 11 #include "../intr.h" 14 12 #include "../dev.h" 15 - 16 - struct host1x_intr_irq_data { 17 - struct host1x *host; 18 - u32 offset; 19 - }; 20 13 21 14 static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) 22 15 { ··· 47 54 } 48 55 } 49 56 50 - static void intr_hw_init(struct host1x *host, u32 cpm) 57 + static int 58 + host1x_intr_init_host_sync(struct host1x *host, u32 cpm) 51 59 { 52 60 #if HOST1X_HW < 6 53 61 /* disable the ip_busy_timeout. this prevents write drops */ ··· 79 85 host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); 80 86 } 81 87 #endif 82 - } 83 - 84 - static int 85 - host1x_intr_init_host_sync(struct host1x *host, u32 cpm) 86 - { 87 - int err, i; 88 - struct host1x_intr_irq_data *irq_data; 89 - 90 - irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); 91 - if (!irq_data) 92 - return -ENOMEM; 93 - 94 - host1x_hw_intr_disable_all_syncpt_intrs(host); 95 - 96 - for (i = 0; i < host->num_syncpt_irqs; i++) { 97 - irq_data[i].host = host; 98 - irq_data[i].offset = i; 99 - 100 - err = devm_request_irq(host->dev, host->syncpt_irqs[i], 101 - syncpt_thresh_isr, IRQF_SHARED, 102 - "host1x_syncpt", &irq_data[i]); 103 - if (err < 0) 104 - return err; 105 - } 106 - 107 - intr_hw_init(host, cpm); 108 88 109 89 return 0; 110 90 } ··· 112 144 .enable_syncpt_intr = host1x_intr_enable_syncpt_intr, 113 145 .disable_syncpt_intr = host1x_intr_disable_syncpt_intr, 114 146 .disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs, 147 + .isr = syncpt_thresh_isr, 115 148 };
+20 -1
drivers/gpu/host1x/intr.c
··· 6 6 */ 7 7 8 8 #include <linux/clk.h> 9 - 9 + #include <linux/interrupt.h> 10 10 #include "dev.h" 11 11 #include "fence.h" 12 12 #include "intr.h" ··· 100 100 101 101 int host1x_intr_init(struct host1x *host) 102 102 { 103 + struct host1x_intr_irq_data *irq_data; 103 104 unsigned int id; 105 + int i, err; 104 106 105 107 mutex_init(&host->intr_mutex); 106 108 ··· 111 109 112 110 spin_lock_init(&syncpt->fences.lock); 113 111 INIT_LIST_HEAD(&syncpt->fences.list); 112 + } 113 + 114 + irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); 115 + if (!irq_data) 116 + return -ENOMEM; 117 + 118 + host1x_hw_intr_disable_all_syncpt_intrs(host); 119 + 120 + for (i = 0; i < host->num_syncpt_irqs; i++) { 121 + irq_data[i].host = host; 122 + irq_data[i].offset = i; 123 + 124 + err = devm_request_irq(host->dev, host->syncpt_irqs[i], 125 + host->intr_op->isr, IRQF_SHARED, 126 + "host1x_syncpt", &irq_data[i]); 127 + if (err < 0) 128 + return err; 114 129 } 115 130 116 131 return 0;
+5
drivers/gpu/host1x/intr.h
··· 11 11 struct host1x; 12 12 struct host1x_syncpt_fence; 13 13 14 + struct host1x_intr_irq_data { 15 + struct host1x *host; 16 + u32 offset; 17 + }; 18 + 14 19 /* Initialize host1x sync point interrupt */ 15 20 int host1x_intr_init(struct host1x *host); 16 21
+6 -6
include/drm/display/drm_dp_mst_helper.h
··· 244 244 bool link_address_sent; 245 245 246 246 /* global unique identifier to identify branch devices */ 247 - u8 guid[16]; 247 + guid_t guid; 248 248 }; 249 249 250 250 251 251 struct drm_dp_nak_reply { 252 - u8 guid[16]; 252 + guid_t guid; 253 253 u8 reason; 254 254 u8 nak_data; 255 255 }; 256 256 257 257 struct drm_dp_link_address_ack_reply { 258 - u8 guid[16]; 258 + guid_t guid; 259 259 u8 nports; 260 260 struct drm_dp_link_addr_reply_port { 261 261 bool input_port; ··· 265 265 bool ddps; 266 266 bool legacy_device_plug_status; 267 267 u8 dpcd_revision; 268 - u8 peer_guid[16]; 268 + guid_t peer_guid; 269 269 u8 num_sdp_streams; 270 270 u8 num_sdp_stream_sinks; 271 271 } ports[16]; ··· 348 348 }; 349 349 350 350 struct drm_dp_connection_status_notify { 351 - u8 guid[16]; 351 + guid_t guid; 352 352 u8 port_number; 353 353 bool legacy_device_plug_status; 354 354 bool displayport_device_plug_status; ··· 425 425 426 426 struct drm_dp_resource_status_notify { 427 427 u8 port_number; 428 - u8 guid[16]; 428 + guid_t guid; 429 429 u16 available_pbn; 430 430 }; 431 431
+2 -16
include/drm/drm_accel.h
··· 51 51 52 52 #if IS_ENABLED(CONFIG_DRM_ACCEL) 53 53 54 + extern struct xarray accel_minors_xa; 55 + 54 56 void accel_core_exit(void); 55 57 int accel_core_init(void); 56 - void accel_minor_remove(int index); 57 - int accel_minor_alloc(void); 58 - void accel_minor_replace(struct drm_minor *minor, int index); 59 58 void accel_set_device_instance_params(struct device *kdev, int index); 60 59 int accel_open(struct inode *inode, struct file *filp); 61 60 void accel_debugfs_init(struct drm_device *dev); ··· 70 71 { 71 72 /* Return 0 to allow drm_core_init to complete successfully */ 72 73 return 0; 73 - } 74 - 75 - static inline void accel_minor_remove(int index) 76 - { 77 - } 78 - 79 - static inline int accel_minor_alloc(void) 80 - { 81 - return -EOPNOTSUPP; 82 - } 83 - 84 - static inline void accel_minor_replace(struct drm_minor *minor, int index) 85 - { 86 74 } 87 75 88 76 static inline void accel_set_device_instance_params(struct device *kdev, int index)
+1 -1
include/drm/drm_atomic.h
··· 460 460 * 461 461 * Used for signaling unbound planes/connectors. 462 462 * When a connector or plane is not bound to any CRTC, it's still important 463 - * to preserve linearity to prevent the atomic states from being freed to early. 463 + * to preserve linearity to prevent the atomic states from being freed too early. 464 464 * 465 465 * This commit (if set) is not bound to any CRTC, but will be completed when 466 466 * drm_atomic_helper_commit_hw_done() is called.
+5
include/drm/drm_file.h
··· 45 45 struct device; 46 46 struct file; 47 47 48 + extern struct xarray drm_minors_xa; 49 + 48 50 /* 49 51 * FIXME: Not sure we want to have drm_minor here in the end, but to avoid 50 52 * header include loops we need it here for now. ··· 435 433 } 436 434 437 435 void drm_file_update_pid(struct drm_file *); 436 + 437 + struct drm_minor *drm_minor_acquire(struct xarray *minors_xa, unsigned int minor_id); 438 + void drm_minor_release(struct drm_minor *minor); 438 439 439 440 int drm_open(struct inode *inode, struct file *filp); 440 441 int drm_open_helper(struct file *filp, struct drm_minor *minor);
+15
include/drm/drm_rect.h
··· 238 238 drm_rect_height(src) >> 16); 239 239 } 240 240 241 + /** 242 + * drm_rect_overlap - Check if two rectangles overlap 243 + * @a: first rectangle 244 + * @b: second rectangle 245 + * 246 + * RETURNS: 247 + * %true if the rectangles overlap, %false otherwise. 248 + */ 249 + static inline bool drm_rect_overlap(const struct drm_rect *a, 250 + const struct drm_rect *b) 251 + { 252 + return (a->x2 > b->x1 && b->x2 > a->x1 && 253 + a->y2 > b->y1 && b->y2 > a->y1); 254 + } 255 + 241 256 bool drm_rect_intersect(struct drm_rect *r, const struct drm_rect *clip); 242 257 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 243 258 const struct drm_rect *clip);
+1 -1
include/drm/ttm/ttm_bo.h
··· 222 222 struct ttm_operation_ctx *ctx; 223 223 /** @ticket: The struct ww_acquire_ctx if any. */ 224 224 struct ww_acquire_ctx *ticket; 225 - /** @tryock_only: Only use trylock for locking. */ 225 + /** @trylock_only: Only use trylock for locking. */ 226 226 bool trylock_only; 227 227 }; 228 228