diff options
author | Dave Airlie <airlied@redhat.com> | 2023-09-22 16:28:29 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2023-09-22 16:28:36 +1000 |
commit | f107ff76a8c242b298413ef52db9978dc3fe0153 (patch) | |
tree | a72a1f708c1d18338d7f875f07ec2c152881750b | |
parent | ce9ecca0238b140b88f43859b211c9fdfd8e5b70 (diff) | |
parent | 15d30b46573d75f5cb58cfacded8ebab9c76a2b0 (diff) |
Merge tag 'drm-misc-next-2023-09-11-1' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v6.7-rc1:
UAPI Changes:
- Nouveau changed to not set NO_PREFETCH flag explicitly.
Cross-subsystem Changes:
- Update documentation of dma-buf intro and uapi.
- fbdev/sbus fixes.
- Use initializer macros in a lot of fbdev drivers.
- Add Boris Brezillon as Panfrost driver maintainer.
- Add Jessica Zhang as drm/panel reviewer.
- Make more fbdev drivers use fb_ops helpers for deferred io.
- Small hid trailing whitespace fix.
- Use fb_ops in hid/picolcd
Core Changes:
- Assorted small fixes to ttm tests, drm/mst.
- Documentation updates to bridge.
- Add kunit tests for some drm_fb functions.
- Rework drm_debugfs implementation.
- Update xe documentation to mark todos as completed.
Driver Changes:
- Add support to rockchip for rv1126 mipi-dsi and vop.
- Assorted small fixes to nouveau, bridge/samsung-dsim,
bridge/lvds-codec, loongson, rockchip, panfrost, gma500, repaper,
komeda, virtio, ssd130x.
- Add support for simple panels Mitsubishi AA084XE01,
JDI LPM102A188A,
- Documentation updates to accel/ivpu.
- Some nouveau scheduling/fence fixes.
- Power management related fixes and other fixes to ivpu.
- Assorted bridge/it66121 fixes.
- Make platform drivers return void in remove() callback.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/3da6554b-3b47-fe7d-c4ea-21f4f819dbb6@linux.intel.com
125 files changed, 3030 insertions, 1281 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/jdi,lpm102a188a.yaml b/Documentation/devicetree/bindings/display/panel/jdi,lpm102a188a.yaml new file mode 100644 index 000000000000..2f4d27a309a7 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/jdi,lpm102a188a.yaml @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/jdi,lpm102a188a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: JDI LPM102A188A 2560x1800 10.2" DSI Panel + +maintainers: + - Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt> + +description: | + This panel requires a dual-channel DSI host to operate. It supports two modes: + - left-right: each channel drives the left or right half of the screen + - even-odd: each channel drives the even or odd lines of the screen + + Each of the DSI channels controls a separate DSI peripheral. The peripheral + driven by the first link (DSI-LINK1) is considered the primary peripheral + and controls the device. The 'link2' property contains a phandle to the + peripheral driven by the second link (DSI-LINK2). + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: jdi,lpm102a188a + + reg: true + enable-gpios: true + reset-gpios: true + power-supply: true + backlight: true + + ddi-supply: + description: The regulator that provides IOVCC (1.8V). + + link2: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + phandle to the DSI peripheral on the secondary link. Note that the + presence of this property marks the containing node as DSI-LINK1. + +required: + - compatible + - reg + +if: + required: + - link2 +then: + required: + - power-supply + - ddi-supply + - enable-gpios + - reset-gpios + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/gpio/tegra-gpio.h> + + dsia: dsi@54300000 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x54300000 0x0 0x00040000>; + + link2: panel@0 { + compatible = "jdi,lpm102a188a"; + reg = <0>; + }; + }; + + dsib: dsi@54400000{ + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x54400000 0x0 0x00040000>; + nvidia,ganged-mode = <&dsia>; + + link1: panel@0 { + compatible = "jdi,lpm102a188a"; + reg = <0>; + power-supply = <&pplcd_vdd>; + ddi-supply = <&pp1800_lcdio>; + enable-gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; + link2 = <&link2>; + backlight = <&backlight>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 25b4589d4a58..50143fe67471 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -238,6 +238,8 @@ properties: - logictechno,lttd800480070-l6wh-rt # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel - mitsubishi,aa070mc01-ca1 + # Mitsubishi AA084XE01 8.4" XGA TFT LCD panel + - mitsubishi,aa084xe01 # Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module - multi-inno,mi0700s4t-6 # Multi-Inno Technology Co.,Ltd MI0800FT-9 8" 800x600 TFT Resistive Touch Module diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml index 8e8a40879140..ccf79e738fa1 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml @@ -18,6 +18,7 @@ properties: - rockchip,rk3288-mipi-dsi - rockchip,rk3399-mipi-dsi - rockchip,rk3568-mipi-dsi + - rockchip,rv1126-mipi-dsi - const: snps,dw-mipi-dsi interrupts: @@ -77,6 +78,7 @@ allOf: enum: - rockchip,px30-mipi-dsi - rockchip,rk3568-mipi-dsi + - rockchip,rv1126-mipi-dsi then: properties: diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml index df61cb5f5c54..b339b7e708c6 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml @@ -31,6 +31,7 @@ properties: - rockchip,rk3368-vop - rockchip,rk3399-vop-big - rockchip,rk3399-vop-lit + - rockchip,rv1126-vop reg: minItems: 1 diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index f92a32d095d9..0c153d79ccc4 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -5,14 +5,30 @@ The dma-buf subsystem provides the framework for sharing buffers for hardware (DMA) access across multiple device drivers and subsystems, and for synchronizing asynchronous hardware access. -This is used, for example, by drm "prime" multi-GPU support, but is of -course not limited to GPU use cases. - -The three main components of this are: (1) dma-buf, representing a -sg_table and exposed to userspace as a file descriptor to allow passing -between devices, (2) fence, which provides a mechanism to signal when -one device has finished access, and (3) reservation, which manages the -shared or exclusive fence(s) associated with the buffer. +As an example, it is used extensively by the DRM subsystem to exchange +buffers between processes, contexts, library APIs within the same +process, and also to exchange buffers with other subsystems such as +V4L2. + +This document describes the way in which kernel subsystems can use and +interact with the three main primitives offered by dma-buf: + + - dma-buf, representing a sg_table and exposed to userspace as a file + descriptor to allow passing between processes, subsystems, devices, + etc; + - dma-fence, providing a mechanism to signal when an asynchronous + hardware operation has completed; and + - dma-resv, which manages a set of dma-fences for a particular dma-buf + allowing implicit (kernel-ordered) synchronization of work to + preserve the illusion of coherent access + + +Userspace API principles and use +-------------------------------- + +For more details on how to design your subsystem's API for dma-buf use, please +see Documentation/userspace-api/dma-buf-alloc-exchange.rst. + Shared DMA Buffers ------------------ diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 65fb3036a580..eef5fd19bc92 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -486,3 +486,10 @@ and the CRTC index is its position in this array. .. kernel-doc:: include/uapi/drm/drm_mode.h :internal: + + +dma-buf interoperability +======================== + +Please see Documentation/userspace-api/dma-buf-alloc-exchange.rst for +information on how dma-buf is integrated and exposed within DRM. diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index 2516fe141db6..b67f8e6a1825 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -67,14 +67,8 @@ platforms. When the time comes for Xe, the protection will be lifted on Xe and kept in i915. -Xe driver will be protected with both STAGING Kconfig and force_probe. Changes in -the uAPI are expected while the driver is behind these protections. STAGING will -be removed when the driver uAPI gets to a mature state where we can guarantee the -‘no regression’ rule. Then force_probe will be lifted only for future platforms -that will be productized with Xe driver, but not with i915. - -Xe – Pre-Merge Goals -==================== +Xe – Pre-Merge Goals - Work-in-Progress +======================================= Drm_scheduler ------------- @@ -94,41 +88,6 @@ depend on any other patch touching drm_scheduler itself that was not yet merged through drm-misc. This, by itself, already includes the reach of an agreement for uniform 1 to 1 relationship implementation / usage across drivers. -GPU VA ------- -Two main goals of Xe are meeting together here: - -1) Have an uAPI that aligns with modern UMD needs. - -2) Early upstream engagement. - -RedHat engineers working on Nouveau proposed a new DRM feature to handle keeping -track of GPU virtual address mappings. This is still not merged upstream, but -this aligns very well with our goals and with our VM_BIND. The engagement with -upstream and the port of Xe towards GPUVA is already ongoing. - -As a key measurable result, Xe needs to be aligned with the GPU VA and working in -our tree. Missing Nouveau patches should *not* block Xe and any needed GPUVA -related patch should be independent and present on dri-devel or acked by -maintainers to go along with the first Xe pull request towards drm-next. - -DRM_VM_BIND ------------ -Nouveau, and Xe are all implementing ‘VM_BIND’ and new ‘Exec’ uAPIs in order to -fulfill the needs of the modern uAPI. Xe merge should *not* be blocked on the -development of a common new drm_infrastructure. However, the Xe team needs to -engage with the community to explore the options of a common API. - -As a key measurable result, the DRM_VM_BIND needs to be documented in this file -below, or this entire block deleted if the consensus is for independent drivers -vm_bind ioctls. - -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to enforce the overall locking scheme for all major -structs and list (so vm and vma). So, a consensus is needed, and possibly some -common helpers. If helpers are needed, they should be also documented in this -document. - ASYNC VM_BIND ------------- Although having a common DRM level IOCTL for VM_BIND is not a requirement to get @@ -212,6 +171,14 @@ This item ties into the GPUVA, VM_BIND, and even long-running compute support. As a key measurable result, we need to have a community consensus documented in this document and the Xe driver prepared for the changes, if necessary. +Xe – uAPI high level overview +============================= + +...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. + +Xe – Pre-Merge Goals - Completed +================================ + Dev_coredump ------------ @@ -229,7 +196,37 @@ infrastructure with overall possible improvements, like multiple file support for better organization of the dumps, snapshot support, dmesg extra print, and whatever may make sense and help the overall infrastructure. -Xe – uAPI high level overview -============================= +DRM_VM_BIND +----------- +Nouveau, and Xe are all implementing ‘VM_BIND’ and new ‘Exec’ uAPIs in order to +fulfill the needs of the modern uAPI. Xe merge should *not* be blocked on the +development of a common new drm_infrastructure. However, the Xe team needs to +engage with the community to explore the options of a common API. -...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. +As a key measurable result, the DRM_VM_BIND needs to be documented in this file +below, or this entire block deleted if the consensus is for independent drivers +vm_bind ioctls. + +Although having a common DRM level IOCTL for VM_BIND is not a requirement to get +Xe merged, it is mandatory to enforce the overall locking scheme for all major +structs and list (so vm and vma). So, a consensus is needed, and possibly some +common helpers. If helpers are needed, they should be also documented in this +document. + +GPU VA +------ +Two main goals of Xe are meeting together here: + +1) Have an uAPI that aligns with modern UMD needs. + +2) Early upstream engagement. + +RedHat engineers working on Nouveau proposed a new DRM feature to handle keeping +track of GPU virtual address mappings. This is still not merged upstream, but +this aligns very well with our goals and with our VM_BIND. The engagement with +upstream and the port of Xe towards GPUVA is already ongoing. + +As a key measurable result, Xe needs to be aligned with the GPU VA and working in +our tree. Missing Nouveau patches should *not* block Xe and any needed GPUVA +related patch should be independent and present on dri-devel or acked by +maintainers to go along with the first Xe pull request towards drm-next. diff --git a/Documentation/userspace-api/dma-buf-alloc-exchange.rst b/Documentation/userspace-api/dma-buf-alloc-exchange.rst new file mode 100644 index 000000000000..fdff19fce13e --- /dev/null +++ b/Documentation/userspace-api/dma-buf-alloc-exchange.rst @@ -0,0 +1,389 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright 2021-2023 Collabora Ltd. + +======================== +Exchanging pixel buffers +======================== + +As originally designed, the Linux graphics subsystem had extremely limited +support for sharing pixel-buffer allocations between processes, devices, and +subsystems. Modern systems require extensive integration between all three +classes; this document details how applications and kernel subsystems should +approach this sharing for two-dimensional image data. + +It is written with reference to the DRM subsystem for GPU and display devices, +V4L2 for media devices, and also to Vulkan, EGL and Wayland, for userspace +support, however any other subsystems should also follow this design and advice. + + +Glossary of terms +================= + +.. glossary:: + + image: + Conceptually a two-dimensional array of pixels. The pixels may be stored + in one or more memory buffers. Has width and height in pixels, pixel + format and modifier (implicit or explicit). + + row: + A span along a single y-axis value, e.g. from co-ordinates (0,100) to + (200,100). + + scanline: + Synonym for row. + + column: + A span along a single x-axis value, e.g. from co-ordinates (100,0) to + (100,100). + + memory buffer: + A piece of memory for storing (parts of) pixel data. Has stride and size + in bytes and at least one handle in some API. May contain one or more + planes. + + plane: + A two-dimensional array of some or all of an image's color and alpha + channel values. + + pixel: + A picture element. Has a single color value which is defined by one or + more color channels values, e.g. R, G and B, or Y, Cb and Cr. May also + have an alpha value as an additional channel. + + pixel data: + Bytes or bits that represent some or all of the color/alpha channel values + of a pixel or an image. The data for one pixel may be spread over several + planes or memory buffers depending on format and modifier. + + color value: + A tuple of numbers, representing a color. Each element in the tuple is a + color channel value. + + color channel: + One of the dimensions in a color model. For example, RGB model has + channels R, G, and B. Alpha channel is sometimes counted as a color + channel as well. + + pixel format: + A description of how pixel data represents the pixel's color and alpha + values. + + modifier: + A description of how pixel data is laid out in memory buffers. + + alpha: + A value that denotes the color coverage in a pixel. Sometimes used for + translucency instead. + + stride: + A value that denotes the relationship between pixel-location co-ordinates + and byte-offset values. Typically used as the byte offset between two + pixels at the start of vertically-consecutive tiling blocks. For linear + layouts, the byte offset between two vertically-adjacent pixels. For + non-linear formats the stride must be computed in a consistent way, which + usually is done as-if the layout was linear. + + pitch: + Synonym for stride. + + +Formats and modifiers +===================== + +Each buffer must have an underlying format. This format describes the color +values provided for each pixel. Although each subsystem has its own format +descriptions (e.g. V4L2 and fbdev), the ``DRM_FORMAT_*`` tokens should be reused +wherever possible, as they are the standard descriptions used for interchange. +These tokens are described in the ``drm_fourcc.h`` file, which is a part of +DRM's uAPI. + +Each ``DRM_FORMAT_*`` token describes the translation between a pixel +co-ordinate in an image, and the color values for that pixel contained within +its memory buffers. The number and type of color channels are described: +whether they are RGB or YUV, integer or floating-point, the size of each channel +and their locations within the pixel memory, and the relationship between color +planes. + +For example, ``DRM_FORMAT_ARGB8888`` describes a format in which each pixel has +a single 32-bit value in memory. Alpha, red, green, and blue, color channels are +available at 8-bit precision per channel, ordered respectively from most to +least significant bits in little-endian storage. ``DRM_FORMAT_*`` is not +affected by either CPU or device endianness; the byte pattern in memory is +always as described in the format definition, which is usually little-endian. + +As a more complex example, ``DRM_FORMAT_NV12`` describes a format in which luma +and chroma YUV samples are stored in separate planes, where the chroma plane is +stored at half the resolution in both dimensions (i.e. one U/V chroma +sample is stored for each 2x2 pixel grouping). + +Format modifiers describe a translation mechanism between these per-pixel memory +samples, and the actual memory storage for the buffer. The most straightforward +modifier is ``DRM_FORMAT_MOD_LINEAR``, describing a scheme in which each plane +is laid out row-sequentially, from the top-left to the bottom-right corner. +This is considered the baseline interchange format, and most convenient for CPU +access. + +Modern hardware employs much more sophisticated access mechanisms, typically +making use of tiled access and possibly also compression. For example, the +``DRM_FORMAT_MOD_VIVANTE_TILED`` modifier describes memory storage where pixels +are stored in 4x4 blocks arranged in row-major ordering, i.e. the first tile in +a plane stores pixels (0,0) to (3,3) inclusive, and the second tile in a plane +stores pixels (4,0) to (7,3) inclusive. + +Some modifiers may modify the number of planes required for an image; for +example, the ``I915_FORMAT_MOD_Y_TILED_CCS`` modifier adds a second plane to RGB +formats in which it stores data about the status of every tile, notably +including whether the tile is fully populated with pixel data, or can be +expanded from a single solid color. + +These extended layouts are highly vendor-specific, and even specific to +particular generations or configurations of devices per-vendor. For this reason, +support of modifiers must be explicitly enumerated and negotiated by all users +in order to ensure a compatible and optimal pipeline, as discussed below. + + +Dimensions and size +=================== + +Each pixel buffer must be accompanied by logical pixel dimensions. This refers +to the number of unique samples which can be extracted from, or stored to, the +underlying memory storage. For example, even though a 1920x1080 +``DRM_FORMAT_NV12`` buffer has a luma plane containing 1920x1080 samples for the Y +component, and 960x540 samples for the U and V components, the overall buffer is +still described as having dimensions of 1920x1080. + +The in-memory storage of a buffer is not guaranteed to begin immediately at the +base address of the underlying memory, nor is it guaranteed that the memory +storage is tightly clipped to either dimension. + +Each plane must therefore be described with an ``offset`` in bytes, which will be +added to the base address of the memory storage before performing any per-pixel +calculations. This may be used to combine multiple planes into a single memory +buffer; for example, ``DRM_FORMAT_NV12`` may be stored in a single memory buffer +where the luma plane's storage begins immediately at the start of the buffer +with an offset of 0, and the chroma plane's storage follows within the same buffer +beginning from the byte offset for that plane. + +Each plane must also have a ``stride`` in bytes, expressing the offset in memory +between two contiguous row. For example, a ``DRM_FORMAT_MOD_LINEAR`` buffer +with dimensions of 1000x1000 may have been allocated as if it were 1024x1000, in +order to allow for aligned access patterns. In this case, the buffer will still +be described with a width of 1000, however the stride will be ``1024 * bpp``, +indicating that there are 24 pixels at the positive extreme of the x axis whose +values are not significant. + +Buffers may also be padded further in the y dimension, simply by allocating a +larger area than would ordinarily be required. For example, many media decoders +are not able to natively output buffers of height 1080, but instead require an +effective height of 1088 pixels. In this case, the buffer continues to be +described as having a height of 1080, with the memory allocation for each buffer +being increased to account for the extra padding. + + +Enumeration +=========== + +Every user of pixel buffers must be able to enumerate a set of supported formats +and modifiers, described together. Within KMS, this is achieved with the +``IN_FORMATS`` property on each DRM plane, listing the supported DRM formats, and +the modifiers supported for each format. In userspace, this is supported through +the `EGL_EXT_image_dma_buf_import_modifiers`_ extension entrypoints for EGL, the +`VK_EXT_image_drm_format_modifier`_ extension for Vulkan, and the +`zwp_linux_dmabuf_v1`_ extension for Wayland. + +Each of these interfaces allows users to query a set of supported +format+modifier combinations. + + +Negotiation +=========== + +It is the responsibility of userspace to negotiate an acceptable format+modifier +combination for its usage. This is performed through a simple intersection of +lists. For example, if a user wants to use Vulkan to render an image to be +displayed on a KMS plane, it must: + + - query KMS for the ``IN_FORMATS`` property for the given plane + - query Vulkan for the supported formats for its physical device, making sure + to pass the ``VkImageUsageFlagBits`` and ``VkImageCreateFlagBits`` + corresponding to the intended rendering use + - intersect these formats to determine the most appropriate one + - for this format, intersect the lists of supported modifiers for both KMS and + Vulkan, to obtain a final list of acceptable modifiers for that format + +This intersection must be performed for all usages. For example, if the user +also wishes to encode the image to a video stream, it must query the media API +it intends to use for encoding for the set of modifiers it supports, and +additionally intersect against this list. + +If the intersection of all lists is an empty list, it is not possible to share +buffers in this way, and an alternate strategy must be considered (e.g. using +CPU access routines to copy data between the different uses, with the +corresponding performance cost). + +The resulting modifier list is unsorted; the order is not significant. + + +Allocation +========== + +Once userspace has determined an appropriate format, and corresponding list of +acceptable modifiers, it must allocate the buffer. As there is no universal +buffer-allocation interface available at either kernel or userspace level, the +client makes an arbitrary choice of allocation interface such as Vulkan, GBM, or +a media API. + +Each allocation request must take, at a minimum: the pixel format, a list of +acceptable modifiers, and the buffer's width and height. Each API may extend +this set of properties in different ways, such as allowing allocation in more +than two dimensions, intended usage patterns, etc. + +The component which allocates the buffer will make an arbitrary choice of what +it considers the 'best' modifier within the acceptable list for the requested +allocation, any padding required, and further properties of the underlying +memory buffers such as whether they are stored in system or device-specific +memory, whether or not they are physically contiguous, and their cache mode. +These properties of the memory buffer are not visible to userspace, however the +``dma-heaps`` API is an effort to address this. + +After allocation, the client must query the allocator to determine the actual +modifier selected for the buffer, as well as the per-plane offset and stride. +Allocators are not permitted to vary the format in use, to select a modifier not +provided within the acceptable list, nor to vary the pixel dimensions other than +the padding expressed through offset, stride, and size. + +Communicating additional constraints, such as alignment of stride or offset, +placement within a particular memory area, etc, is out of scope of dma-buf, +and is not solved by format and modifier tokens. + + +Import +====== + +To use a buffer within a different context, device, or subsystem, the user +passes these parameters (format, modifier, width, height, and per-plane offset +and stride) to an importing API. + +Each memory buffer is referred to by a buffer handle, which may be unique or +duplicated within an image. For example, a ``DRM_FORMAT_NV12`` buffer may have +the luma and chroma buffers combined into a single memory buffer by use of the +per-plane offset parameters, or they may be completely separate allocations in +memory. For this reason, each import and allocation API must provide a separate +handle for each plane. + +Each kernel subsystem has its own types and interfaces for buffer management. +DRM uses GEM buffer objects (BOs), V4L2 has its own references, etc. These types +are not portable between contexts, processes, devices, or subsystems. + +To address this, ``dma-buf`` handles are used as the universal interchange for +buffers. Subsystem-specific operations are used to export native buffer handles +to a ``dma-buf`` file descriptor, and to import those file descriptors into a +native buffer handle. dma-buf file descriptors can be transferred between +contexts, processes, devices, and subsystems. + +For example, a Wayland media player may use V4L2 to decode a video frame into a +``DRM_FORMAT_NV12`` buffer. This will result in two memory planes (luma and +chroma) being dequeued by the user from V4L2. These planes are then exported to +one dma-buf file descriptor per plane, these descriptors are then sent along +with the metadata (format, modifier, width, height, per-plane offset and stride) +to the Wayland server. The Wayland server will then import these file +descriptors as an EGLImage for use through EGL/OpenGL (ES), a VkImage for use +through Vulkan, or a KMS framebuffer object; each of these import operations +will take the same metadata and convert the dma-buf file descriptors into their +native buffer handles. + +Having a non-empty intersection of supported modifiers does not guarantee that +import will succeed into all consumers; they may have constraints beyond those +implied by modifiers which must be satisfied. + + +Implicit modifiers +================== + +The concept of modifiers post-dates all of the subsystems mentioned above. As +such, it has been retrofitted into all of these APIs, and in order to ensure +backwards compatibility, support is needed for drivers and userspace which do +not (yet) support modifiers. + +As an example, GBM is used to allocate buffers to be shared between EGL for +rendering and KMS for display. It has two entrypoints for allocating buffers: +``gbm_bo_create`` which only takes the format, width, height, and a usage token, +and ``gbm_bo_create_with_modifiers`` which extends this with a list of modifiers. + +In the latter case, the allocation is as discussed above, being provided with a +list of acceptable modifiers that the implementation can choose from (or fail if +it is not possible to allocate within those constraints). In the former case +where modifiers are not provided, the GBM implementation must make its own +choice as to what is likely to be the 'best' layout. Such a choice is entirely +implementation-specific: some will internally use tiled layouts which are not +CPU-accessible if the implementation decides that is a good idea through +whatever heuristic. It is the implementation's responsibility to ensure that +this choice is appropriate. + +To support this case where the layout is not known because there is no awareness +of modifiers, a special ``DRM_FORMAT_MOD_INVALID`` token has been defined. This +pseudo-modifier declares that the layout is not known, and that the driver +should use its own logic to determine what the underlying layout may be. + +.. note:: + + ``DRM_FORMAT_MOD_INVALID`` is a non-zero value. The modifier value zero is + ``DRM_FORMAT_MOD_LINEAR``, which is an explicit guarantee that the image + has the linear layout. Care and attention should be taken to ensure that + zero as a default value is not mixed up with either no modifier or the linear + modifier. Also note that in some APIs the invalid modifier value is specified + with an out-of-band flag, like in ``DRM_IOCTL_MODE_ADDFB2``. + +There are four cases where this token may be used: + - during enumeration, an interface may return ``DRM_FORMAT_MOD_INVALID``, either + as the sole member of a modifier list to declare that explicit modifiers are + not supported, or as part of a larger list to declare that implicit modifiers + may be used + - during allocation, a user may supply ``DRM_FORMAT_MOD_INVALID``, either as the + sole member of a modifier list (equivalent to not supplying a modifier list + at all) to declare that explicit modifiers are not supported and must not be + used, or as part of a larger list to declare that an allocation using implicit + modifiers is acceptable + - in a post-allocation query, an implementation may return + ``DRM_FORMAT_MOD_INVALID`` as the modifier of the allocated buffer to declare + that the underlying layout is implementation-defined and that an explicit + modifier description is not available; per the above rules, this may only be + returned when the user has included ``DRM_FORMAT_MOD_INVALID`` as part of the + list of acceptable modifiers, or not provided a list + - when importing a buffer, the user may supply ``DRM_FORMAT_MOD_INVALID`` as the + buffer modifier (or not supply a modifier) to indicate that the modifier is + unknown for whatever reason; this is only acceptable when the buffer has + not been allocated with an explicit modifier + +It follows from this that for any single buffer, the complete chain of operations +formed by the producer and all the consumers must be either fully implicit or fully +explicit. For example, if a user wishes to allocate a buffer for use between +GPU, display, and media, but the media API does not support modifiers, then the +user **must not** allocate the buffer with explicit modifiers and attempt to +import the buffer into the media API with no modifier, but either perform the +allocation using implicit modifiers, or allocate the buffer for media use +separately and copy between the two buffers. + +As one exception to the above, allocations may be 'upgraded' from implicit +to explicit modifiers. For example, if the buffer is allocated with +``gbm_bo_create`` (taking no modifiers), the user may then query the modifier with +``gbm_bo_get_modifier`` and then use this modifier as an explicit modifier token +if a valid modifier is returned. + +When allocating buffers for exchange between different users and modifiers are +not available, implementations are strongly encouraged to use +``DRM_FORMAT_MOD_LINEAR`` for their allocation, as this is the universal baseline +for exchange. However, it is not guaranteed that this will result in the correct +interpretation of buffer content, as implicit modifier operation may still be +subject to driver-specific heuristics. + +Any new users - userspace programs and protocols, kernel subsystems, etc - +wishing to exchange buffers must offer interoperability through dma-buf file +descriptors for memory planes, DRM format tokens to describe the format, DRM +format modifiers to describe the layout in memory, at least width and height for +dimensions, and at least offset and stride for each memory plane. + +.. _zwp_linux_dmabuf_v1: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml +.. _VK_EXT_image_drm_format_modifier: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_drm_format_modifier.html +.. _EGL_EXT_image_dma_buf_import_modifiers: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst index 72a65db0c498..031df47a7c19 100644 --- a/Documentation/userspace-api/index.rst +++ b/Documentation/userspace-api/index.rst @@ -22,6 +22,7 @@ place where this information is gathered. unshare spec_ctrl accelerators/ocxl + dma-buf-alloc-exchange ebpf/index ELF ioctl/index diff --git a/MAINTAINERS b/MAINTAINERS index bf0f54c24f81..5ea898ffd8de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1626,10 +1626,9 @@ F: drivers/gpu/drm/arm/display/include/ F: drivers/gpu/drm/arm/display/komeda/ ARM MALI PANFROST DRM DRIVER +M: Boris Brezillon <boris.brezillon@collabora.com> M: Rob Herring <robh@kernel.org> -M: Tomeu Vizoso <tomeu.vizoso@collabora.com> R: Steven Price <steven.price@arm.com> -R: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> L: dri-devel@lists.freedesktop.org S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc @@ -6132,6 +6131,7 @@ L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/driver-api/dma-buf.rst +F: Documentation/userspace-api/dma-buf-alloc-exchange.rst F: drivers/dma-buf/ F: include/linux/*fence.h F: include/linux/dma-buf.h @@ -7138,6 +7138,7 @@ F: include/drm/gpu_scheduler.h DRM PANEL DRIVERS M: Neil Armstrong <neil.armstrong@linaro.org> +R: Jessica Zhang <quic_jesszhan@quicinc.com> R: Sam Ravnborg <sam@ravnborg.org> L: dri-devel@lists.freedesktop.org S: Maintained diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index 4a9baf02439e..94b4ac12cf24 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -79,29 +79,30 @@ static const struct drm_info_list accel_debugfs_list[] = { #define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list) /** - * accel_debugfs_init() - Initialize debugfs for accel minor - * @minor: Pointer to the drm_minor instance. - * @minor_id: The minor's id + * accel_debugfs_init() - Initialize debugfs for device + * @dev: Pointer to the device instance. * - * This function initializes the drm minor's debugfs members and creates - * a root directory for the minor in debugfs. It also creates common files - * for accelerators and calls the driver's debugfs init callback. + * This function creates a root directory for the device in debugfs. */ -void accel_debugfs_init(struct drm_minor *minor, int minor_id) +void accel_debugfs_init(struct drm_device *dev) { - struct drm_device *dev = minor->dev; - char name[64]; + drm_debugfs_dev_init(dev, accel_debugfs_root); +} + +/** + * accel_debugfs_register() - Register debugfs for device + * @dev: Pointer to the device instance. + * + * Creates common files for accelerators. + */ +void accel_debugfs_register(struct drm_device *dev) +{ + struct drm_minor *minor = dev->accel; - INIT_LIST_HEAD(&minor->debugfs_list); - mutex_init(&minor->debugfs_lock); - sprintf(name, "%d", minor_id); - minor->debugfs_root = debugfs_create_dir(name, accel_debugfs_root); + minor->debugfs_root = dev->debugfs_root; drm_debugfs_create_files(accel_debugfs_list, ACCEL_DEBUGFS_ENTRIES, - minor->debugfs_root, minor); - - if (dev->driver->debugfs_init) - dev->driver->debugfs_init(minor); + dev->debugfs_root, minor); } /** diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index ba79f397c9e8..fa0680ba9340 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -518,78 +518,52 @@ static int ivpu_dev_init(struct ivpu_device *vdev) lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); ret = ivpu_pci_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize PCI device: %d\n", ret); + if (ret) goto err_xa_destroy; - } ret = ivpu_irq_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize IRQs: %d\n", ret); + if (ret) goto err_xa_destroy; - } /* Init basic HW info based on buttress registers which are accessible before power up */ ret = ivpu_hw_info_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize HW info: %d\n", ret); + if (ret) goto err_xa_destroy; - } /* Power up early so the rest of init code can access VPU registers */ ret = ivpu_hw_power_up(vdev); - if (ret) { - ivpu_err(vdev, "Failed to power up HW: %d\n", ret); + if (ret) goto err_xa_destroy; - } ret = ivpu_mmu_global_context_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret); + if (ret) goto err_power_down; - } ret = ivpu_mmu_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret); + if (ret) goto err_mmu_gctx_fini; - } - ret = ivpu_fw_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize firmware: %d\n", ret); + ret = ivpu_mmu_reserved_context_init(vdev); + if (ret) goto err_mmu_gctx_fini; - } + + ret = ivpu_fw_init(vdev); + if (ret) + goto err_mmu_rctx_fini; ret = ivpu_ipc_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize IPC: %d\n", ret); + if (ret) goto err_fw_fini; - } - ret = ivpu_pm_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize PM: %d\n", ret); - goto err_ipc_fini; - } + ivpu_pm_init(vdev); ret = ivpu_job_done_thread_init(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize job done thread: %d\n", ret); + if (ret) goto err_ipc_fini; - } - - ret = ivpu_fw_load(vdev); - if (ret) { - ivpu_err(vdev, "Failed to load firmware: %d\n", ret); - goto err_job_done_thread_fini; - } ret = ivpu_boot(vdev); - if (ret) { - ivpu_err(vdev, "Failed to boot: %d\n", ret); + if (ret) goto err_job_done_thread_fini; - } ivpu_pm_enable(vdev); @@ -601,6 +575,8 @@ err_ipc_fini: ivpu_ipc_fini(vdev); err_fw_fini: ivpu_fw_fini(vdev); +err_mmu_rctx_fini: + ivpu_mmu_reserved_context_fini(vdev); err_mmu_gctx_fini: ivpu_mmu_global_context_fini(vdev); err_power_down: @@ -624,6 +600,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) ivpu_ipc_fini(vdev); ivpu_fw_fini(vdev); + ivpu_mmu_reserved_context_fini(vdev); ivpu_mmu_global_context_fini(vdev); drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); @@ -651,10 +628,8 @@ static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, vdev); ret = ivpu_dev_init(vdev); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize VPU device: %d\n", ret); + if (ret) return ret; - } ret = drm_dev_register(&vdev->drm, 0); if (ret) { diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 9e8c075fe9ef..12a63f8a73e8 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -28,12 +28,13 @@ #define IVPU_HW_37XX 37 #define IVPU_HW_40XX 40 -#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0 -/* SSID 1 is used by the VPU to represent invalid context */ -#define IVPU_USER_CONTEXT_MIN_SSID 2 -#define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 63) +#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0 +/* SSID 1 is used by the VPU to represent reserved context */ +#define IVPU_RESERVED_CONTEXT_MMU_SSID 1 +#define IVPU_USER_CONTEXT_MIN_SSID 2 +#define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 63) -#define IVPU_NUM_ENGINES 2 +#define IVPU_NUM_ENGINES 2 #define IVPU_PLATFORM_SILICON 0 #define IVPU_PLATFORM_SIMICS 2 @@ -75,6 +76,11 @@ #define IVPU_WA(wa_name) (vdev->wa.wa_name) +#define IVPU_PRINT_WA(wa_name) do { \ + if (IVPU_WA(wa_name)) \ + ivpu_dbg(vdev, MISC, "Using WA: " #wa_name "\n"); \ +} while (0) + struct ivpu_wa_table { bool punit_disabled; bool clear_runtime_mem; @@ -104,6 +110,7 @@ struct ivpu_device { struct ivpu_pm_info *pm; struct ivpu_mmu_context gctx; + struct ivpu_mmu_context rctx; struct xarray context_xa; struct xa_limit context_xa_limit; @@ -117,6 +124,7 @@ struct ivpu_device { int jsm; int tdr; int reschedule_suspend; + int autosuspend; } timeout; }; diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 9827ea4d7b83..d57e103aae1c 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -301,6 +301,8 @@ int ivpu_fw_init(struct ivpu_device *vdev) if (ret) goto err_fw_release; + ivpu_fw_load(vdev); + return 0; err_fw_release: @@ -314,7 +316,7 @@ void ivpu_fw_fini(struct ivpu_device *vdev) ivpu_fw_release(vdev); } -int ivpu_fw_load(struct ivpu_device *vdev) +void ivpu_fw_load(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; u64 image_end_offset = fw->image_load_offset + fw->image_size; @@ -331,8 +333,6 @@ int ivpu_fw_load(struct ivpu_device *vdev) } wmb(); /* Flush WC buffers after writing fw->mem */ - - return 0; } static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 8567fdf925fe..10ae2847f0ef 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -31,7 +31,7 @@ struct ivpu_fw_info { int ivpu_fw_init(struct ivpu_device *vdev); void ivpu_fw_fini(struct ivpu_device *vdev); -int ivpu_fw_load(struct ivpu_device *vdev); +void ivpu_fw_load(struct ivpu_device *vdev); void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *bp); static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 9eae1c241bc0..edd4d860f135 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -104,6 +104,11 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) if (ivpu_device_id(vdev) == PCI_DEVICE_ID_MTL && ivpu_revision(vdev) < 4) vdev->wa.interrupt_clear_with_0 = true; + + IVPU_PRINT_WA(punit_disabled); + IVPU_PRINT_WA(clear_runtime_mem); + IVPU_PRINT_WA(d3hot_after_power_off); + IVPU_PRINT_WA(interrupt_clear_with_0); } static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) @@ -113,11 +118,13 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.jsm = 50000; vdev->timeout.tdr = 2000000; vdev->timeout.reschedule_suspend = 1000; + vdev->timeout.autosuspend = -1; } else { vdev->timeout.boot = 1000; vdev->timeout.jsm = 500; vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; + vdev->timeout.autosuspend = 10; } } @@ -345,10 +352,10 @@ static int ivpu_boot_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val) static int ivpu_boot_top_noc_qrenqn_check(struct ivpu_device *vdev, u32 exp_val) { - u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QREQN); + u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN); - if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) || - !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, exp_val, val)) + if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) || + !REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, exp_val, val)) return -EIO; return 0; @@ -356,10 +363,10 @@ static int ivpu_boot_top_noc_qrenqn_check(struct ivpu_device *vdev, u32 exp_val) static int ivpu_boot_top_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val) { - u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QACCEPTN); + u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QACCEPTN); - if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) || - !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, exp_val, val)) + if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) || + !REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, exp_val, val)) return -EIO; return 0; @@ -367,10 +374,10 @@ static int ivpu_boot_top_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_va static int ivpu_boot_top_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val) { - u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QDENY); + u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QDENY); - if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) || - !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, val)) + if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) || + !REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, val)) return -EIO; return 0; @@ -423,15 +430,15 @@ static int ivpu_boot_host_ss_top_noc_drive(struct ivpu_device *vdev, bool enable int ret; u32 val; - val = REGV_RD32(MTL_VPU_TOP_NOC_QREQN); + val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN); if (enable) { - val = REG_SET_FLD(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, val); - val = REG_SET_FLD(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, val); + val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val); + val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val); } else { - val = REG_CLR_FLD(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, val); - val = REG_CLR_FLD(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, val); + val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val); + val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val); } - REGV_WR32(MTL_VPU_TOP_NOC_QREQN, val); + REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val); ret = ivpu_boot_top_noc_qacceptn_check(vdev, enable ? 0x1 : 0x0); if (ret) { @@ -563,17 +570,17 @@ static void ivpu_boot_soc_cpu_boot(struct ivpu_device *vdev) { u32 val; - val = REGV_RD32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC); - val = REG_SET_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTRUN0, val); + val = REGV_RD32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC); + val = REG_SET_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTRUN0, val); - val = REG_CLR_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTVEC, val); - REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); + val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTVEC, val); + REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); - val = REG_SET_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); - REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); + val = REG_SET_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); + REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); - val = REG_CLR_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); - REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); + val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); + REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); val = vdev->fw->entry_point >> 9; REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val); @@ -777,17 +784,17 @@ static void ivpu_hw_37xx_wdt_disable(struct ivpu_device *vdev) u32 val; /* Enable writing and set non-zero WDT value */ - REGV_WR32(MTL_VPU_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE); - REGV_WR32(MTL_VPU_CPU_SS_TIM_WATCHDOG, TIM_WATCHDOG_RESET_VALUE); + REGV_WR32(VPU_37XX_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE); + REGV_WR32(VPU_37XX_CPU_SS_TIM_WATCHDOG, TIM_WATCHDOG_RESET_VALUE); /* Enable writing and disable watchdog timer */ - REGV_WR32(MTL_VPU_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE); - REGV_WR32(MTL_VPU_CPU_SS_TIM_WDOG_EN, 0); + REGV_WR32(VPU_37XX_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE); + REGV_WR32(VPU_37XX_CPU_SS_TIM_WDOG_EN, 0); /* Now clear the timeout interrupt */ - val = REGV_RD32(MTL_VPU_CPU_SS_TIM_GEN_CONFIG); - val = REG_CLR_FLD(MTL_VPU_CPU_SS_TIM_GEN_CONFIG, WDOG_TO_INT_CLR, val); - REGV_WR32(MTL_VPU_CPU_SS_TIM_GEN_CONFIG, val); + val = REGV_RD32(VPU_37XX_CPU_SS_TIM_GEN_CONFIG); + val = REG_CLR_FLD(VPU_37XX_CPU_SS_TIM_GEN_CONFIG, WDOG_TO_INT_CLR, val); + REGV_WR32(VPU_37XX_CPU_SS_TIM_GEN_CONFIG, val); } static u32 ivpu_hw_37xx_pll_to_freq(u32 ratio, u32 config) @@ -834,10 +841,10 @@ static u32 ivpu_hw_37xx_reg_telemetry_enable_get(struct ivpu_device *vdev) static void ivpu_hw_37xx_reg_db_set(struct ivpu_device *vdev, u32 db_id) { - u32 reg_stride = MTL_VPU_CPU_SS_DOORBELL_1 - MTL_VPU_CPU_SS_DOORBELL_0; - u32 val = REG_FLD(MTL_VPU_CPU_SS_DOORBELL_0, SET); + u32 reg_stride = VPU_37XX_CPU_SS_DOORBELL_1 - VPU_37XX_CPU_SS_DOORBELL_0; + u32 val = REG_FLD(VPU_37XX_CPU_SS_DOORBELL_0, SET); - REGV_WR32I(MTL_VPU_CPU_SS_DOORBELL_0, reg_stride, db_id, val); + REGV_WR32I(VPU_37XX_CPU_SS_DOORBELL_0, reg_stride, db_id, val); } static u32 ivpu_hw_37xx_reg_ipc_rx_addr_get(struct ivpu_device *vdev) @@ -854,7 +861,7 @@ static u32 ivpu_hw_37xx_reg_ipc_rx_count_get(struct ivpu_device *vdev) static void ivpu_hw_37xx_reg_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr) { - REGV_WR32(MTL_VPU_CPU_SS_TIM_IPC_FIFO, vpu_addr); + REGV_WR32(VPU_37XX_CPU_SS_TIM_IPC_FIFO, vpu_addr); } static void ivpu_hw_37xx_irq_clear(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h index 6e4e915948f9..4083beb5e9db 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h @@ -3,70 +3,70 @@ * Copyright (C) 2020-2023 Intel Corporation */ -#ifndef __IVPU_HW_MTL_REG_H__ -#define __IVPU_HW_MTL_REG_H__ +#ifndef __IVPU_HW_37XX_REG_H__ +#define __IVPU_HW_37XX_REG_H__ #include <linux/bits.h> -#define VPU_37XX_BUTTRESS_INTERRUPT_TYPE 0x00000000u +#define VPU_37XX_BUTTRESS_INTERRUPT_TYPE 0x00000000u -#define VPU_37XX_BUTTRESS_INTERRUPT_STAT 0x00000004u -#define VPU_37XX_BUTTRESS_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0) +#define VPU_37XX_BUTTRESS_INTERRUPT_STAT 0x00000004u +#define VPU_37XX_BUTTRESS_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0) #define VPU_37XX_BUTTRESS_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1) #define VPU_37XX_BUTTRESS_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2) -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0 0x00000008u -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0) -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16) +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0 0x00000008u +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0) +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16) -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1 0x0000000cu -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0) -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16) +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1 0x0000000cu +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0) +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16) -#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD2 0x00000010u +#define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD2 0x00000010u #define VPU_37XX_BUTTRESS_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0) -#define VPU_37XX_BUTTRESS_WP_REQ_CMD 0x00000014u +#define VPU_37XX_BUTTRESS_WP_REQ_CMD 0x00000014u #define VPU_37XX_BUTTRESS_WP_REQ_CMD_SEND_MASK BIT_MASK(0) #define VPU_37XX_BUTTRESS_WP_DOWNLOAD 0x00000018u #define VPU_37XX_BUTTRESS_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0) #define VPU_37XX_BUTTRESS_CURRENT_PLL 0x0000001cu -#define VPU_37XX_BUTTRESS_CURRENT_PLL_RATIO_MASK GENMASK(15, 0) +#define VPU_37XX_BUTTRESS_CURRENT_PLL_RATIO_MASK GENMASK(15, 0) -#define VPU_37XX_BUTTRESS_PLL_ENABLE 0x00000020u +#define VPU_37XX_BUTTRESS_PLL_ENABLE 0x00000020u -#define VPU_37XX_BUTTRESS_FMIN_FUSE 0x00000024u -#define VPU_37XX_BUTTRESS_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0) -#define VPU_37XX_BUTTRESS_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8) +#define VPU_37XX_BUTTRESS_FMIN_FUSE 0x00000024u +#define VPU_37XX_BUTTRESS_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0) +#define VPU_37XX_BUTTRESS_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8) -#define VPU_37XX_BUTTRESS_FMAX_FUSE 0x00000028u -#define VPU_37XX_BUTTRESS_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0) +#define VPU_37XX_BUTTRESS_FMAX_FUSE 0x00000028u +#define VPU_37XX_BUTTRESS_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0) -#define VPU_37XX_BUTTRESS_TILE_FUSE 0x0000002cu +#define VPU_37XX_BUTTRESS_TILE_FUSE 0x0000002cu #define VPU_37XX_BUTTRESS_TILE_FUSE_VALID_MASK BIT_MASK(0) -#define VPU_37XX_BUTTRESS_TILE_FUSE_SKU_MASK GENMASK(3, 2) +#define VPU_37XX_BUTTRESS_TILE_FUSE_SKU_MASK GENMASK(3, 2) -#define VPU_37XX_BUTTRESS_LOCAL_INT_MASK 0x00000030u -#define VPU_37XX_BUTTRESS_GLOBAL_INT_MASK 0x00000034u +#define VPU_37XX_BUTTRESS_LOCAL_INT_MASK 0x00000030u +#define VPU_37XX_BUTTRESS_GLOBAL_INT_MASK 0x00000034u -#define VPU_37XX_BUTTRESS_PLL_STATUS 0x00000040u +#define VPU_37XX_BUTTRESS_PLL_STATUS 0x00000040u #define VPU_37XX_BUTTRESS_PLL_STATUS_LOCK_MASK BIT_MASK(1) -#define VPU_37XX_BUTTRESS_VPU_STATUS 0x00000044u +#define VPU_37XX_BUTTRESS_VPU_STATUS 0x00000044u #define VPU_37XX_BUTTRESS_VPU_STATUS_READY_MASK BIT_MASK(0) #define VPU_37XX_BUTTRESS_VPU_STATUS_IDLE_MASK BIT_MASK(1) -#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL 0x00000060u -#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0) -#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2) +#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL 0x00000060u +#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0) +#define VPU_37XX_BUTTRESS_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2) #define VPU_37XX_BUTTRESS_VPU_IP_RESET 0x00000050u -#define VPU_37XX_BUTTRESS_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0) +#define VPU_37XX_BUTTRESS_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0) #define VPU_37XX_BUTTRESS_VPU_TELEMETRY_OFFSET 0x00000080u -#define VPU_37XX_BUTTRESS_VPU_TELEMETRY_SIZE 0x00000084u +#define VPU_37XX_BUTTRESS_VPU_TELEMETRY_SIZE 0x00000084u #define VPU_37XX_BUTTRESS_VPU_TELEMETRY_ENABLE 0x00000088u #define VPU_37XX_BUTTRESS_ATS_ERR_LOG_0 0x000000a0u @@ -74,9 +74,9 @@ #define VPU_37XX_BUTTRESS_ATS_ERR_CLEAR 0x000000a8u #define VPU_37XX_BUTTRESS_UFI_ERR_LOG 0x000000b0u -#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0) -#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12) -#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20) +#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0) +#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12) +#define VPU_37XX_BUTTRESS_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20) #define VPU_37XX_BUTTRESS_UFI_ERR_CLEAR 0x000000b4u @@ -113,17 +113,17 @@ #define VPU_37XX_HOST_SS_NOC_QDENY 0x0000015cu #define VPU_37XX_HOST_SS_NOC_QDENY_TOP_SOCMMIO_MASK BIT_MASK(0) -#define MTL_VPU_TOP_NOC_QREQN 0x00000160u -#define MTL_VPU_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0) -#define MTL_VPU_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(1) +#define VPU_37XX_TOP_NOC_QREQN 0x00000160u +#define VPU_37XX_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0) +#define VPU_37XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(1) -#define MTL_VPU_TOP_NOC_QACCEPTN 0x00000164u -#define MTL_VPU_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0) -#define MTL_VPU_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(1) +#define VPU_37XX_TOP_NOC_QACCEPTN 0x00000164u +#define VPU_37XX_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0) +#define VPU_37XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(1) -#define MTL_VPU_TOP_NOC_QDENY 0x00000168u -#define MTL_VPU_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0) -#define MTL_VPU_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(1) +#define VPU_37XX_TOP_NOC_QDENY 0x00000168u +#define VPU_37XX_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0) +#define VPU_37XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(1) #define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN 0x00000170u #define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0) @@ -140,9 +140,9 @@ #define VPU_37XX_HOST_SS_ICB_STATUS_0_TIMER_2_INT_MASK BIT_MASK(2) #define VPU_37XX_HOST_SS_ICB_STATUS_0_TIMER_3_INT_MASK BIT_MASK(3) #define VPU_37XX_HOST_SS_ICB_STATUS_0_HOST_IPC_FIFO_INT_MASK BIT_MASK(4) -#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_0_INT_MASK BIT_MASK(5) -#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_1_INT_MASK BIT_MASK(6) -#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_2_INT_MASK BIT_MASK(7) +#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_0_INT_MASK BIT_MASK(5) +#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_1_INT_MASK BIT_MASK(6) +#define VPU_37XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_2_INT_MASK BIT_MASK(7) #define VPU_37XX_HOST_SS_ICB_STATUS_0_NOC_FIREWALL_INT_MASK BIT_MASK(8) #define VPU_37XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_0_INT_MASK BIT_MASK(30) #define VPU_37XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_1_INT_MASK BIT_MASK(31) @@ -164,14 +164,14 @@ #define VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT_FILL_LEVEL_MASK GENMASK(23, 16) #define VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT_RSVD0_MASK GENMASK(31, 24) -#define VPU_37XX_HOST_SS_AON_PWR_ISO_EN0 0x00030020u +#define VPU_37XX_HOST_SS_AON_PWR_ISO_EN0 0x00030020u #define VPU_37XX_HOST_SS_AON_PWR_ISO_EN0_MSS_CPU_MASK BIT_MASK(3) #define VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0 0x00030024u -#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0_MSS_CPU_MASK BIT_MASK(3) +#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0_MSS_CPU_MASK BIT_MASK(3) #define VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0 0x00030028u -#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0_MSS_CPU_MASK BIT_MASK(3) +#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0_MSS_CPU_MASK BIT_MASK(3) #define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu #define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0_MSS_CPU_MASK BIT_MASK(3) @@ -187,47 +187,14 @@ #define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1) #define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3) -#define VPU_37XX_HOST_SS_WORKPOINT_CONFIG_MIRROR 0x00082020u +#define VPU_37XX_HOST_SS_WORKPOINT_CONFIG_MIRROR 0x00082020u #define VPU_37XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_FINAL_PLL_FREQ_MASK GENMASK(15, 0) #define VPU_37XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_CONFIG_ID_MASK GENMASK(31, 16) -#define VPU_37XX_HOST_MMU_IDR0 0x00200000u -#define VPU_37XX_HOST_MMU_IDR1 0x00200004u -#define VPU_37XX_HOST_MMU_IDR3 0x0020000cu -#define VPU_37XX_HOST_MMU_IDR5 0x00200014u -#define VPU_37XX_HOST_MMU_CR0 0x00200020u -#define VPU_37XX_HOST_MMU_CR0ACK 0x00200024u -#define VPU_37XX_HOST_MMU_CR1 0x00200028u -#define VPU_37XX_HOST_MMU_CR2 0x0020002cu -#define VPU_37XX_HOST_MMU_IRQ_CTRL 0x00200050u -#define VPU_37XX_HOST_MMU_IRQ_CTRLACK 0x00200054u - -#define VPU_37XX_HOST_MMU_GERROR 0x00200060u -#define VPU_37XX_HOST_MMU_GERROR_CMDQ_MASK BIT_MASK(0) -#define VPU_37XX_HOST_MMU_GERROR_EVTQ_ABT_MASK BIT_MASK(2) -#define VPU_37XX_HOST_MMU_GERROR_PRIQ_ABT_MASK BIT_MASK(3) -#define VPU_37XX_HOST_MMU_GERROR_MSI_CMDQ_ABT_MASK BIT_MASK(4) -#define VPU_37XX_HOST_MMU_GERROR_MSI_EVTQ_ABT_MASK BIT_MASK(5) -#define VPU_37XX_HOST_MMU_GERROR_MSI_PRIQ_ABT_MASK BIT_MASK(6) -#define VPU_37XX_HOST_MMU_GERROR_MSI_ABT_MASK BIT_MASK(7) - -#define VPU_37XX_HOST_MMU_GERRORN 0x00200064u - -#define VPU_37XX_HOST_MMU_STRTAB_BASE 0x00200080u -#define VPU_37XX_HOST_MMU_STRTAB_BASE_CFG 0x00200088u -#define VPU_37XX_HOST_MMU_CMDQ_BASE 0x00200090u -#define VPU_37XX_HOST_MMU_CMDQ_PROD 0x00200098u -#define VPU_37XX_HOST_MMU_CMDQ_CONS 0x0020009cu -#define VPU_37XX_HOST_MMU_EVTQ_BASE 0x002000a0u -#define VPU_37XX_HOST_MMU_EVTQ_PROD 0x002000a8u -#define VPU_37XX_HOST_MMU_EVTQ_CONS 0x002000acu -#define VPU_37XX_HOST_MMU_EVTQ_PROD_SEC (0x002000a8u + SZ_64K) -#define VPU_37XX_HOST_MMU_EVTQ_CONS_SEC (0x002000acu + SZ_64K) - #define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES 0x00360000u #define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_CACHE_OVERRIDE_EN_MASK BIT_MASK(0) -#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AWCACHE_OVERRIDE_MASK BIT_MASK(1) -#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_ARCACHE_OVERRIDE_MASK BIT_MASK(2) +#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AWCACHE_OVERRIDE_MASK BIT_MASK(1) +#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_ARCACHE_OVERRIDE_MASK BIT_MASK(2) #define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_NOSNOOP_OVERRIDE_EN_MASK BIT_MASK(3) #define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AW_NOSNOOP_OVERRIDE_MASK BIT_MASK(4) #define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AR_NOSNOOP_OVERRIDE_MASK BIT_MASK(5) @@ -246,36 +213,36 @@ #define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8) #define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9) -#define MTL_VPU_CPU_SS_DSU_LEON_RT_BASE 0x04000000u -#define MTL_VPU_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u -#define MTL_VPU_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u -#define MTL_VPU_CPU_SS_DSU_LEON_RT_NPC_REG 0x04400014u -#define MTL_VPU_CPU_SS_DSU_LEON_RT_DSU_TRAP_REG 0x04400020u +#define VPU_37XX_CPU_SS_DSU_LEON_RT_BASE 0x04000000u +#define VPU_37XX_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u +#define VPU_37XX_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u +#define VPU_37XX_CPU_SS_DSU_LEON_RT_NPC_REG 0x04400014u +#define VPU_37XX_CPU_SS_DSU_LEON_RT_DSU_TRAP_REG 0x04400020u -#define MTL_VPU_CPU_SS_MSSCPU_CPR_CLK_SET 0x06010004u -#define MTL_VPU_CPU_SS_MSSCPU_CPR_CLK_SET_CPU_DSU_MASK BIT_MASK(1) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_CLK_SET 0x06010004u +#define VPU_37XX_CPU_SS_MSSCPU_CPR_CLK_SET_CPU_DSU_MASK BIT_MASK(1) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_RST_CLR 0x06010018u -#define MTL_VPU_CPU_SS_MSSCPU_CPR_RST_CLR_CPU_DSU_MASK BIT_MASK(1) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_RST_CLR 0x06010018u +#define VPU_37XX_CPU_SS_MSSCPU_CPR_RST_CLR_CPU_DSU_MASK BIT_MASK(1) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC 0x06010040u -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN0_MASK BIT_MASK(0) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME0_MASK BIT_MASK(1) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN1_MASK BIT_MASK(2) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME1_MASK BIT_MASK(3) -#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTVEC_MASK GENMASK(31, 4) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC 0x06010040u +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN0_MASK BIT_MASK(0) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME0_MASK BIT_MASK(1) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN1_MASK BIT_MASK(2) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME1_MASK BIT_MASK(3) +#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTVEC_MASK GENMASK(31, 4) -#define MTL_VPU_CPU_SS_TIM_WATCHDOG 0x0602009cu -#define MTL_VPU_CPU_SS_TIM_WDOG_EN 0x060200a4u -#define MTL_VPU_CPU_SS_TIM_SAFE 0x060200a8u -#define MTL_VPU_CPU_SS_TIM_IPC_FIFO 0x060200f0u +#define VPU_37XX_CPU_SS_TIM_WATCHDOG 0x0602009cu +#define VPU_37XX_CPU_SS_TIM_WDOG_EN 0x060200a4u +#define VPU_37XX_CPU_SS_TIM_SAFE 0x060200a8u +#define VPU_37XX_CPU_SS_TIM_IPC_FIFO 0x060200f0u -#define MTL_VPU_CPU_SS_TIM_GEN_CONFIG 0x06021008u -#define MTL_VPU_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) +#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u +#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) -#define MTL_VPU_CPU_SS_DOORBELL_0 0x06300000u -#define MTL_VPU_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) +#define VPU_37XX_CPU_SS_DOORBELL_0 0x06300000u +#define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) -#define MTL_VPU_CPU_SS_DOORBELL_1 0x06301000u +#define VPU_37XX_CPU_SS_DOORBELL_1 0x06301000u -#endif /* __IVPU_HW_MTL_REG_H__ */ +#endif /* __IVPU_HW_37XX_REG_H__ */ diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 34626d66fa10..1c2528549635 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -126,6 +126,10 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) if (ivpu_hw_gen(vdev) == IVPU_HW_40XX) vdev->wa.disable_clock_relinquish = true; + + IVPU_PRINT_WA(punit_disabled); + IVPU_PRINT_WA(clear_runtime_mem); + IVPU_PRINT_WA(disable_clock_relinquish); } static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) @@ -135,16 +139,19 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.jsm = 50000; vdev->timeout.tdr = 2000000; vdev->timeout.reschedule_suspend = 1000; + vdev->timeout.autosuspend = -1; } else if (ivpu_is_simics(vdev)) { vdev->timeout.boot = 50; vdev->timeout.jsm = 500; vdev->timeout.tdr = 10000; vdev->timeout.reschedule_suspend = 10; + vdev->timeout.autosuspend = -1; } else { vdev->timeout.boot = 1000; vdev->timeout.jsm = 500; vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; + vdev->timeout.autosuspend = 10; } } diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index fa0af59e39ab..6b2e9dbb284a 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -426,15 +426,20 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) int ivpu_ipc_init(struct ivpu_device *vdev) { struct ivpu_ipc_info *ipc = vdev->ipc; - int ret = -ENOMEM; + int ret; ipc->mem_tx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC); - if (!ipc->mem_tx) - return ret; + if (!ipc->mem_tx) { + ivpu_err(vdev, "Failed to allocate mem_tx\n"); + return -ENOMEM; + } ipc->mem_rx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC); - if (!ipc->mem_rx) + if (!ipc->mem_rx) { + ivpu_err(vdev, "Failed to allocate mem_rx\n"); + ret = -ENOMEM; goto err_free_tx; + } ipc->mm_tx = devm_gen_pool_create(vdev->drm.dev, __ffs(IVPU_IPC_ALIGNMENT), -1, "TX_IPC_JSM"); diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index baefaf7bb3cb..473e1fc686a7 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -7,12 +7,45 @@ #include <linux/highmem.h> #include "ivpu_drv.h" -#include "ivpu_hw_37xx_reg.h" #include "ivpu_hw_reg_io.h" #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" #include "ivpu_pm.h" +#define IVPU_MMU_REG_IDR0 0x00200000u +#define IVPU_MMU_REG_IDR1 0x00200004u +#define IVPU_MMU_REG_IDR3 0x0020000cu +#define IVPU_MMU_REG_IDR5 0x00200014u +#define IVPU_MMU_REG_CR0 0x00200020u +#define IVPU_MMU_REG_CR0ACK 0x00200024u +#define IVPU_MMU_REG_CR1 0x00200028u +#define IVPU_MMU_REG_CR2 0x0020002cu +#define IVPU_MMU_REG_IRQ_CTRL 0x00200050u +#define IVPU_MMU_REG_IRQ_CTRLACK 0x00200054u + +#define IVPU_MMU_REG_GERROR 0x00200060u +#define IVPU_MMU_REG_GERROR_CMDQ_MASK BIT_MASK(0) +#define IVPU_MMU_REG_GERROR_EVTQ_ABT_MASK BIT_MASK(2) +#define IVPU_MMU_REG_GERROR_PRIQ_ABT_MASK BIT_MASK(3) +#define IVPU_MMU_REG_GERROR_MSI_CMDQ_ABT_MASK BIT_MASK(4) +#define IVPU_MMU_REG_GERROR_MSI_EVTQ_ABT_MASK BIT_MASK(5) +#define IVPU_MMU_REG_GERROR_MSI_PRIQ_ABT_MASK BIT_MASK(6) +#define IVPU_MMU_REG_GERROR_MSI_ABT_MASK BIT_MASK(7) + +#define IVPU_MMU_REG_GERRORN 0x00200064u + +#define IVPU_MMU_REG_STRTAB_BASE 0x00200080u +#define IVPU_MMU_REG_STRTAB_BASE_CFG 0x00200088u +#define IVPU_MMU_REG_CMDQ_BASE 0x00200090u +#define IVPU_MMU_REG_CMDQ_PROD 0x00200098u +#define IVPU_MMU_REG_CMDQ_CONS 0x0020009cu +#define IVPU_MMU_REG_EVTQ_BASE 0x002000a0u +#define IVPU_MMU_REG_EVTQ_PROD 0x002000a8u +#define IVPU_MMU_REG_EVTQ_CONS 0x002000acu +#define IVPU_MMU_REG_EVTQ_PROD_SEC (0x002000a8u + SZ_64K) +#define IVPU_MMU_REG_EVTQ_CONS_SEC (0x002000acu + SZ_64K) +#define IVPU_MMU_REG_CMDQ_CONS_ERR_MASK GENMASK(30, 24) + #define IVPU_MMU_IDR0_REF 0x080f3e0f #define IVPU_MMU_IDR0_REF_SIMICS 0x080f3e1f #define IVPU_MMU_IDR1_REF 0x0e739d18 @@ -186,13 +219,13 @@ #define IVPU_MMU_REG_TIMEOUT_US (10 * USEC_PER_MSEC) #define IVPU_MMU_QUEUE_TIMEOUT_US (100 * USEC_PER_MSEC) -#define IVPU_MMU_GERROR_ERR_MASK ((REG_FLD(VPU_37XX_HOST_MMU_GERROR, CMDQ)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, EVTQ_ABT)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, PRIQ_ABT)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_CMDQ_ABT)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_EVTQ_ABT)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_PRIQ_ABT)) | \ - (REG_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_ABT))) +#define IVPU_MMU_GERROR_ERR_MASK ((REG_FLD(IVPU_MMU_REG_GERROR, CMDQ)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, EVTQ_ABT)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, PRIQ_ABT)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, MSI_CMDQ_ABT)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, MSI_EVTQ_ABT)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, MSI_PRIQ_ABT)) | \ + (REG_FLD(IVPU_MMU_REG_GERROR, MSI_ABT))) static char *ivpu_mmu_event_to_str(u32 cmd) { @@ -250,15 +283,15 @@ static void ivpu_mmu_config_check(struct ivpu_device *vdev) else val_ref = IVPU_MMU_IDR0_REF; - val = REGV_RD32(VPU_37XX_HOST_MMU_IDR0); + val = REGV_RD32(IVPU_MMU_REG_IDR0); if (val != val_ref) ivpu_dbg(vdev, MMU, "IDR0 0x%x != IDR0_REF 0x%x\n", val, val_ref); - val = REGV_RD32(VPU_37XX_HOST_MMU_IDR1); + val = REGV_RD32(IVPU_MMU_REG_IDR1); if (val != IVPU_MMU_IDR1_REF) ivpu_dbg(vdev, MMU, "IDR1 0x%x != IDR1_REF 0x%x\n", val, IVPU_MMU_IDR1_REF); - val = REGV_RD32(VPU_37XX_HOST_MMU_IDR3); + val = REGV_RD32(IVPU_MMU_REG_IDR3); if (val != IVPU_MMU_IDR3_REF) ivpu_dbg(vdev, MMU, "IDR3 0x%x != IDR3_REF 0x%x\n", val, IVPU_MMU_IDR3_REF); @@ -269,7 +302,7 @@ static void ivpu_mmu_config_check(struct ivpu_device *vdev) else val_ref = IVPU_MMU_IDR5_REF; - val = REGV_RD32(VPU_37XX_HOST_MMU_IDR5); + val = REGV_RD32(IVPU_MMU_REG_IDR5); if (val != val_ref) ivpu_dbg(vdev, MMU, "IDR5 0x%x != IDR5_REF 0x%x\n", val, val_ref); } @@ -396,18 +429,18 @@ static int ivpu_mmu_irqs_setup(struct ivpu_device *vdev) u32 irq_ctrl = IVPU_MMU_IRQ_EVTQ_EN | IVPU_MMU_IRQ_GERROR_EN; int ret; - ret = ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_IRQ_CTRL, 0); + ret = ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_IRQ_CTRL, 0); if (ret) return ret; - return ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_IRQ_CTRL, irq_ctrl); + return ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_IRQ_CTRL, irq_ctrl); } static int ivpu_mmu_cmdq_wait_for_cons(struct ivpu_device *vdev) { struct ivpu_mmu_queue *cmdq = &vdev->mmu->cmdq; - return REGV_POLL(VPU_37XX_HOST_MMU_CMDQ_CONS, cmdq->cons, (cmdq->prod == cmdq->cons), + return REGV_POLL(IVPU_MMU_REG_CMDQ_CONS, cmdq->cons, (cmdq->prod == cmdq->cons), IVPU_MMU_QUEUE_TIMEOUT_US); } @@ -447,7 +480,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) return ret; clflush_cache_range(q->base, IVPU_MMU_CMDQ_SIZE); - REGV_WR32(VPU_37XX_HOST_MMU_CMDQ_PROD, q->prod); + REGV_WR32(IVPU_MMU_REG_CMDQ_PROD, q->prod); ret = ivpu_mmu_cmdq_wait_for_cons(vdev); if (ret) @@ -495,7 +528,7 @@ static int ivpu_mmu_reset(struct ivpu_device *vdev) mmu->evtq.prod = 0; mmu->evtq.cons = 0; - ret = ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_CR0, 0); + ret = ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_CR0, 0); if (ret) return ret; @@ -505,17 +538,17 @@ static int ivpu_mmu_reset(struct ivpu_device *vdev) FIELD_PREP(IVPU_MMU_CR1_QUEUE_SH, IVPU_MMU_SH_ISH) | FIELD_PREP(IVPU_MMU_CR1_QUEUE_OC, IVPU_MMU_CACHE_WB) | FIELD_PREP(IVPU_MMU_CR1_QUEUE_IC, IVPU_MMU_CACHE_WB); - REGV_WR32(VPU_37XX_HOST_MMU_CR1, val); + REGV_WR32(IVPU_MMU_REG_CR1, val); - REGV_WR64(VPU_37XX_HOST_MMU_STRTAB_BASE, mmu->strtab.dma_q); - REGV_WR32(VPU_37XX_HOST_MMU_STRTAB_BASE_CFG, mmu->strtab.base_cfg); + REGV_WR64(IVPU_MMU_REG_STRTAB_BASE, mmu->strtab.dma_q); + REGV_WR32(IVPU_MMU_REG_STRTAB_BASE_CFG, mmu->strtab.base_cfg); - REGV_WR64(VPU_37XX_HOST_MMU_CMDQ_BASE, mmu->cmdq.dma_q); - REGV_WR32(VPU_37XX_HOST_MMU_CMDQ_PROD, 0); - REGV_WR32(VPU_37XX_HOST_MMU_CMDQ_CONS, 0); + REGV_WR64(IVPU_MMU_REG_CMDQ_BASE, mmu->cmdq.dma_q); + REGV_WR32(IVPU_MMU_REG_CMDQ_PROD, 0); + REGV_WR32(IVPU_MMU_REG_CMDQ_CONS, 0); val = IVPU_MMU_CR0_CMDQEN; - ret = ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_CR0, val); + ret = ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_CR0, val); if (ret) return ret; @@ -531,17 +564,17 @@ static int ivpu_mmu_reset(struct ivpu_device *vdev) if (ret) return ret; - REGV_WR64(VPU_37XX_HOST_MMU_EVTQ_BASE, mmu->evtq.dma_q); - REGV_WR32(VPU_37XX_HOST_MMU_EVTQ_PROD_SEC, 0); - REGV_WR32(VPU_37XX_HOST_MMU_EVTQ_CONS_SEC, 0); + REGV_WR64(IVPU_MMU_REG_EVTQ_BASE, mmu->evtq.dma_q); + REGV_WR32(IVPU_MMU_REG_EVTQ_PROD_SEC, 0); + REGV_WR32(IVPU_MMU_REG_EVTQ_CONS_SEC, 0); val |= IVPU_MMU_CR0_EVTQEN; - ret = ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_CR0, val); + ret = ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_CR0, val); if (ret) return ret; val |= IVPU_MMU_CR0_ATSCHK; - ret = ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_CR0, val); + ret = ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_CR0, val); if (ret) return ret; @@ -550,7 +583,7 @@ static int ivpu_mmu_reset(struct ivpu_device *vdev) return ret; val |= IVPU_MMU_CR0_SMMUEN; - return ivpu_mmu_reg_write(vdev, VPU_37XX_HOST_MMU_CR0, val); + return ivpu_mmu_reg_write(vdev, IVPU_MMU_REG_CR0, val); } static void ivpu_mmu_strtab_link_cd(struct ivpu_device *vdev, u32 sid) @@ -801,14 +834,14 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev) u32 idx = IVPU_MMU_Q_IDX(evtq->cons); u32 *evt = evtq->base + (idx * IVPU_MMU_EVTQ_CMD_SIZE); - evtq->prod = REGV_RD32(VPU_37XX_HOST_MMU_EVTQ_PROD_SEC); + evtq->prod = REGV_RD32(IVPU_MMU_REG_EVTQ_PROD_SEC); if (!CIRC_CNT(IVPU_MMU_Q_IDX(evtq->prod), IVPU_MMU_Q_IDX(evtq->cons), IVPU_MMU_Q_COUNT)) return NULL; clflush_cache_range(evt, IVPU_MMU_EVTQ_CMD_SIZE); evtq->cons = (evtq->cons + 1) & IVPU_MMU_Q_WRAP_MASK; - REGV_WR32(VPU_37XX_HOST_MMU_EVTQ_CONS_SEC, evtq->cons); + REGV_WR32(IVPU_MMU_REG_EVTQ_CONS_SEC, evtq->cons); return evt; } @@ -841,35 +874,35 @@ void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev) ivpu_dbg(vdev, IRQ, "MMU error\n"); - gerror_val = REGV_RD32(VPU_37XX_HOST_MMU_GERROR); - gerrorn_val = REGV_RD32(VPU_37XX_HOST_MMU_GERRORN); + gerror_val = REGV_RD32(IVPU_MMU_REG_GERROR); + gerrorn_val = REGV_RD32(IVPU_MMU_REG_GERRORN); active = gerror_val ^ gerrorn_val; if (!(active & IVPU_MMU_GERROR_ERR_MASK)) return; - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, MSI_ABT, active)) ivpu_warn_ratelimited(vdev, "MMU MSI ABT write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_PRIQ_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, MSI_PRIQ_ABT, active)) ivpu_warn_ratelimited(vdev, "MMU PRIQ MSI ABT write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_EVTQ_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, MSI_EVTQ_ABT, active)) ivpu_warn_ratelimited(vdev, "MMU EVTQ MSI ABT write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, MSI_CMDQ_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, MSI_CMDQ_ABT, active)) ivpu_warn_ratelimited(vdev, "MMU CMDQ MSI ABT write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, PRIQ_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, PRIQ_ABT, active)) ivpu_err_ratelimited(vdev, "MMU PRIQ write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, EVTQ_ABT, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, EVTQ_ABT, active)) ivpu_err_ratelimited(vdev, "MMU EVTQ write aborted\n"); - if (REG_TEST_FLD(VPU_37XX_HOST_MMU_GERROR, CMDQ, active)) + if (REG_TEST_FLD(IVPU_MMU_REG_GERROR, CMDQ, active)) ivpu_err_ratelimited(vdev, "MMU CMDQ write aborted\n"); - REGV_WR32(VPU_37XX_HOST_MMU_GERRORN, gerror_val); + REGV_WR32(IVPU_MMU_REG_GERRORN, gerror_val); } int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable) diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 1d2e554e2c4a..0c8c65351919 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -427,8 +427,10 @@ ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u3 INIT_LIST_HEAD(&ctx->bo_list); ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable); - if (ret) + if (ret) { + ivpu_err(vdev, "Failed to initialize pgtable for ctx %u: %d\n", context_id, ret); return ret; + } if (!context_id) { start = vdev->hw->ranges.global.start; @@ -467,6 +469,16 @@ void ivpu_mmu_global_context_fini(struct ivpu_device *vdev) return ivpu_mmu_context_fini(vdev, &vdev->gctx); } +int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev) +{ + return ivpu_mmu_user_context_init(vdev, &vdev->rctx, IVPU_RESERVED_CONTEXT_MMU_SSID); +} + +void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev) +{ + return ivpu_mmu_user_context_fini(vdev, &vdev->rctx); +} + void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid) { struct ivpu_file_priv *file_priv; @@ -488,13 +500,13 @@ int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context ret = ivpu_mmu_context_init(vdev, ctx, ctx_id); if (ret) { - ivpu_err(vdev, "Failed to initialize context: %d\n", ret); + ivpu_err(vdev, "Failed to initialize context %u: %d\n", ctx_id, ret); return ret; } ret = ivpu_mmu_set_pgtable(vdev, ctx_id, &ctx->pgtable); if (ret) { - ivpu_err(vdev, "Failed to set page table: %d\n", ret); + ivpu_err(vdev, "Failed to set page table for context %u: %d\n", ctx_id, ret); goto err_context_fini; } diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h index 961a0d6a6c7f..f15d8c630d8a 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.h +++ b/drivers/accel/ivpu/ivpu_mmu_context.h @@ -32,6 +32,8 @@ struct ivpu_mmu_context { int ivpu_mmu_global_context_init(struct ivpu_device *vdev); void ivpu_mmu_global_context_fini(struct ivpu_device *vdev); +int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev); +void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev); int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id); void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index e6f27daf5560..28a0d1111e12 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -282,10 +282,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev) pm_runtime_put_autosuspend(vdev->drm.dev); } -int ivpu_pm_init(struct ivpu_device *vdev) +void ivpu_pm_init(struct ivpu_device *vdev) { struct device *dev = vdev->drm.dev; struct ivpu_pm_info *pm = vdev->pm; + int delay; pm->vdev = vdev; pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT; @@ -293,16 +294,15 @@ int ivpu_pm_init(struct ivpu_device *vdev) atomic_set(&pm->in_reset, 0); INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work); - pm_runtime_use_autosuspend(dev); - if (ivpu_disable_recovery) - pm_runtime_set_autosuspend_delay(dev, -1); - else if (ivpu_is_silicon(vdev)) - pm_runtime_set_autosuspend_delay(dev, 100); + delay = -1; else - pm_runtime_set_autosuspend_delay(dev, 60000); + delay = vdev->timeout.autosuspend; - return 0; + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, delay); + + ivpu_dbg(vdev, PM, "Autosuspend delay = %d\n", delay); } void ivpu_pm_cancel_recovery(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index fd4eada1290f..f41c30a14a40 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -19,7 +19,7 @@ struct ivpu_pm_info { u32 suspend_reschedule_counter; }; -int ivpu_pm_init(struct ivpu_device *vdev); +void ivpu_pm_init(struct ivpu_device *vdev); void ivpu_pm_enable(struct ivpu_device *vdev); void ivpu_pm_disable(struct ivpu_device *vdev); void ivpu_pm_cancel_recovery(struct ivpu_device *vdev); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 4b230933b28e..cbef4ff28cd8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -219,7 +219,7 @@ static void dm_helpers_construct_old_payload( /* Set correct time_slots/PBN of old payload. * other fields (delete & dsc_enabled) in * struct drm_dp_mst_atomic_payload are don't care fields - * while calling drm_dp_remove_payload() + * while calling drm_dp_remove_payload_part2() */ for (i = 0; i < current_link_table.stream_count; i++) { dc_alloc = @@ -263,13 +263,12 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - - /* It's OK for this to fail */ new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); if (enable) { target_payload = new_payload; + /* It's OK for this to fail */ drm_dp_add_payload_part1(mst_mgr, mst_state, new_payload); } else { /* construct old payload by VCPI*/ @@ -277,7 +276,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( new_payload, &old_payload); target_payload = &old_payload; - drm_dp_remove_payload(mst_mgr, mst_state, &old_payload, new_payload); + drm_dp_remove_payload_part1(mst_mgr, mst_state, new_payload); } /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or @@ -344,7 +343,7 @@ bool dm_helpers_dp_mst_send_payload_allocation( struct amdgpu_dm_connector *aconnector; struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_mgr *mst_mgr; - struct drm_dp_mst_atomic_payload *payload; + struct drm_dp_mst_atomic_payload *new_payload, *old_payload; enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD; enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD; int ret = 0; @@ -357,15 +356,20 @@ bool dm_helpers_dp_mst_send_payload_allocation( mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); + new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); if (!enable) { set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; clr_flag = MST_ALLOCATE_NEW_PAYLOAD; } - if (enable) - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload); + if (enable) { + ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); + } else { + dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div, + new_payload, old_payload); + drm_dp_remove_payload_part2(mst_mgr, mst_state, old_payload, new_payload); + } if (ret) { amdgpu_dm_set_mst_status(&aconnector->mst_status, diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index 4618687a8f4d..f3e744172673 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -1223,7 +1223,7 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc, return 0; } -static void +static int komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, struct komeda_pipeline_state *new) { @@ -1243,8 +1243,12 @@ komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, c = komeda_pipeline_get_component(pipe, id); c_st = komeda_component_get_state_and_set_user(c, drm_st, NULL, new->crtc); + if (PTR_ERR(c_st) == -EDEADLK) + return -EDEADLK; WARN_ON(IS_ERR(c_st)); } + + return 0; } /* release unclaimed pipeline resource */ @@ -1266,9 +1270,8 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, if (WARN_ON(IS_ERR_OR_NULL(st))) return -EINVAL; - komeda_pipeline_unbound_components(pipe, st); + return komeda_pipeline_unbound_components(pipe, st); - return 0; } /* Since standalone disabled components must be disabled separately and in the diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 44a660a4bdbf..ba82a1142adf 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -181,6 +181,7 @@ config DRM_NWL_MIPI_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY select MFD_SYSCON select MULTIPLEXER @@ -227,6 +228,7 @@ config DRM_SAMSUNG_DSIM select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY help The Samsung MIPI DSIM bridge controller driver. diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 800555aef97f..ad8241758896 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1231,9 +1231,7 @@ static int anx78xx_i2c_probe(struct i2c_client *client) mutex_init(&anx78xx->lock); -#if IS_ENABLED(CONFIG_OF) anx78xx->bridge.of_node = client->dev.of_node; -#endif anx78xx->client = client; i2c_set_clientdata(client, anx78xx); @@ -1367,12 +1365,6 @@ static void anx78xx_i2c_remove(struct i2c_client *client) kfree(anx78xx->edid); } -static const struct i2c_device_id anx78xx_id[] = { - { "anx7814", 0 }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(i2c, anx78xx_id); - static const struct of_device_id anx78xx_match_table[] = { { .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses }, { .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses }, @@ -1389,7 +1381,6 @@ static struct i2c_driver anx78xx_driver = { }, .probe = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, - .id_table = anx78xx_id, }; module_i2c_driver(anx78xx_driver); diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig index ec35215a2003..cced81633ddc 100644 --- a/drivers/gpu/drm/bridge/cadence/Kconfig +++ b/drivers/gpu/drm/bridge/cadence/Kconfig @@ -4,6 +4,7 @@ config DRM_CDNS_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY depends on OF help diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index 466641c77fe9..3c9b42c9d2ee 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -1447,10 +1447,14 @@ static int it66121_audio_get_eld(struct device *dev, void *data, struct it66121_ctx *ctx = dev_get_drvdata(dev); mutex_lock(&ctx->lock); - - memcpy(buf, ctx->connector->eld, - min(sizeof(ctx->connector->eld), len)); - + if (!ctx->connector) { + /* Pass en empty ELD if connector not available */ + dev_dbg(dev, "No connector present, passing empty EDID data"); + memset(buf, 0, len); + } else { + memcpy(buf, ctx->connector->eld, + min(sizeof(ctx->connector->eld), len)); + } mutex_unlock(&ctx->lock); return 0; @@ -1501,7 +1505,6 @@ static const char * const it66121_supplies[] = { static int it66121_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 }; struct device_node *ep; int ret; @@ -1523,7 +1526,7 @@ static int it66121_probe(struct i2c_client *client) ctx->dev = dev; ctx->client = client; - ctx->info = (const struct it66121_chip_info *) id->driver_data; + ctx->info = i2c_get_match_data(client); of_property_read_u32(ep, "bus-width", &ctx->bus_width); of_node_put(ep); @@ -1609,13 +1612,6 @@ static void it66121_remove(struct i2c_client *client) mutex_destroy(&ctx->lock); } -static const struct of_device_id it66121_dt_match[] = { - { .compatible = "ite,it66121" }, - { .compatible = "ite,it6610" }, - { } -}; -MODULE_DEVICE_TABLE(of, it66121_dt_match); - static const struct it66121_chip_info it66121_chip_info = { .id = ID_IT66121, .vid = 0x4954, @@ -1628,6 +1624,13 @@ static const struct it66121_chip_info it6610_chip_info = { .pid = 0x0611, }; +static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", &it66121_chip_info }, + { .compatible = "ite,it6610", &it6610_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, it66121_dt_match); + static const struct i2c_device_id it66121_id[] = { { "it66121", (kernel_ulong_t) &it66121_chip_info }, { "it6610", (kernel_ulong_t) &it6610_chip_info }, diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 4eaea67fb71c..03532efb893b 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -45,7 +45,6 @@ struct lt8912 { u8 data_lanes; bool is_power_on; - bool is_attached; }; static int lt8912_write_init_config(struct lt8912 *lt) @@ -559,6 +558,13 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, struct lt8912 *lt = bridge_to_lt8912(bridge); int ret; + ret = drm_bridge_attach(bridge->encoder, lt->hdmi_port, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + dev_err(lt->dev, "Failed to attach next bridge (%d)\n", ret); + return ret; + } + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ret = lt8912_bridge_connector_init(bridge); if (ret) { @@ -575,8 +581,6 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, if (ret) goto error; - lt->is_attached = true; - return 0; error: @@ -588,15 +592,10 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge) { struct lt8912 *lt = bridge_to_lt8912(bridge); - if (lt->is_attached) { - lt8912_hard_power_off(lt); - - if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) - drm_bridge_hpd_disable(lt->hdmi_port); + lt8912_hard_power_off(lt); - drm_connector_unregister(<->connector); - drm_connector_cleanup(<->connector); - } + if (lt->connector.dev && lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) + drm_bridge_hpd_disable(lt->hdmi_port); } static enum drm_connector_status @@ -750,7 +749,6 @@ static void lt8912_remove(struct i2c_client *client) { struct lt8912 *lt = i2c_get_clientdata(client); - lt8912_bridge_detach(<->bridge); drm_bridge_remove(<->bridge); lt8912_free_i2c(lt); lt8912_put_dt(lt); diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c index 8c5668dca0c4..991732c4b629 100644 --- a/drivers/gpu/drm/bridge/lvds-codec.c +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -5,6 +5,7 @@ */ #include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> @@ -71,12 +72,6 @@ static void lvds_codec_disable(struct drm_bridge *bridge) "Failed to disable regulator \"vcc\": %d\n", ret); } -static const struct drm_bridge_funcs funcs = { - .attach = lvds_codec_attach, - .enable = lvds_codec_enable, - .disable = lvds_codec_disable, -}; - #define MAX_INPUT_SEL_FORMATS 1 static u32 * lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, @@ -102,7 +97,7 @@ lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } -static const struct drm_bridge_funcs funcs_decoder = { +static const struct drm_bridge_funcs funcs = { .attach = lvds_codec_attach, .enable = lvds_codec_enable, .disable = lvds_codec_disable, @@ -184,8 +179,9 @@ static int lvds_codec_probe(struct platform_device *pdev) return ret; } else { lvds_codec->bus_format = ret; - lvds_codec->bridge.funcs = &funcs_decoder; } + } else { + lvds_codec->bus_format = MEDIA_BUS_FMT_RGB888_1X24; } /* diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 9316384b4474..e00d2e94c751 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -4,6 +4,8 @@ * Copyright (C) 2017 Broadcom */ +#include <linux/device.h> + #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_connector.h> @@ -19,6 +21,7 @@ struct panel_bridge { struct drm_bridge bridge; struct drm_connector connector; struct drm_panel *panel; + struct device_link *link; u32 connector_type; }; @@ -60,6 +63,8 @@ static int panel_bridge_attach(struct drm_bridge *bridge, { struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); struct drm_connector *connector = &panel_bridge->connector; + struct drm_panel *panel = panel_bridge->panel; + struct drm_device *drm_dev = bridge->dev; int ret; if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) @@ -70,6 +75,14 @@ static int panel_bridge_attach(struct drm_bridge *bridge, return -ENODEV; } + panel_bridge->link = device_link_add(drm_dev->dev, panel->dev, + DL_FLAG_STATELESS); + if (!panel_bridge->link) { + DRM_ERROR("Failed to add device link between %s and %s\n", + dev_name(drm_dev->dev), dev_name(panel->dev)); + return -EINVAL; + } + drm_connector_helper_add(connector, &panel_bridge_connector_helper_funcs); @@ -78,6 +91,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge, panel_bridge->connector_type); if (ret) { DRM_ERROR("Failed to initialize connector\n"); + device_link_del(panel_bridge->link); return ret; } @@ -100,6 +114,8 @@ static void panel_bridge_detach(struct drm_bridge *bridge) struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); struct drm_connector *connector = &panel_bridge->connector; + device_link_del(panel_bridge->link); + /* * Cleanup the connector if we know it was initialized. * @@ -302,9 +318,7 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, panel_bridge->panel = panel; panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs; -#ifdef CONFIG_OF panel_bridge->bridge.of_node = panel->dev->of_node; -#endif panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; panel_bridge->bridge.type = connector_type; diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index cf777bdb25d2..19bdb32dbc9a 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -385,7 +385,7 @@ static const unsigned int imx8mm_dsim_reg_values[] = { [RESET_TYPE] = DSIM_SWRST, [PLL_TIMER] = 500, [STOP_STATE_CNT] = 0xf, - [PHYCTRL_ULPS_EXIT] = 0, + [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf), [PHYCTRL_VREG_LP] = 0, [PHYCTRL_SLEW_UP] = 0, [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06), @@ -413,6 +413,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .m_min = 41, .m_max = 125, .min_freq = 500, + .has_broken_fifoctrl_emptyhdr = 1, }; static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { @@ -429,6 +430,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .m_min = 41, .m_max = 125, .min_freq = 500, + .has_broken_fifoctrl_emptyhdr = 1, }; static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { @@ -1010,8 +1012,20 @@ static int samsung_dsim_wait_for_hdr_fifo(struct samsung_dsim *dsi) do { u32 reg = samsung_dsim_read(dsi, DSIM_FIFOCTRL_REG); - if (reg & DSIM_SFR_HEADER_EMPTY) - return 0; + if (!dsi->driver_data->has_broken_fifoctrl_emptyhdr) { + if (reg & DSIM_SFR_HEADER_EMPTY) + return 0; + } else { + if (!(reg & DSIM_SFR_HEADER_FULL)) { + /* + * Wait a little bit, so the pending data can + * actually leave the FIFO to avoid overflow. + */ + if (!cond_resched()) + usleep_range(950, 1050); + return 0; + } + } if (!cond_resched()) usleep_range(950, 1050); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 6c1d79474505..52d91a0df85e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3541,9 +3541,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, | DRM_BRIDGE_OP_HPD; hdmi->bridge.interlace_allowed = true; hdmi->bridge.ddc = hdmi->ddc; -#ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; -#endif memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 04d4a1a10698..a8dd2a2e7c7b 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1182,9 +1182,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, dsi->bridge.driver_private = dsi; dsi->bridge.funcs = &dw_mipi_dsi_bridge_funcs; -#ifdef CONFIG_OF dsi->bridge.of_node = pdev->dev.of_node; -#endif return dsi; } diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index ed96cfcfa304..e04f87ff755a 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3255,15 +3255,15 @@ out_get_port: } EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status); -static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_atomic_payload *payload) +static int drm_dp_create_payload_at_dfp(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_atomic_payload *payload) { return drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, payload->time_slots); } -static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_atomic_payload *payload) +static int drm_dp_create_payload_to_remote(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_atomic_payload *payload) { int ret; struct drm_dp_mst_port *port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); @@ -3276,17 +3276,20 @@ static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, return ret; } -static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_topology_state *mst_state, - struct drm_dp_mst_atomic_payload *payload) +static void drm_dp_destroy_payload_at_remote_and_dfp(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_atomic_payload *payload) { drm_dbg_kms(mgr->dev, "\n"); /* it's okay for these to fail */ - drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0); - drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0); + if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE) { + drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0); + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_DFP; + } - return 0; + if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) + drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0); } /** @@ -3296,81 +3299,105 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, * @payload: The payload to write * * Determines the starting time slot for the given payload, and programs the VCPI for this payload - * into hardware. After calling this, the driver should generate ACT and payload packets. + * into the DPCD of DPRX. After calling this, the driver should generate ACT and payload packets. * - * Returns: 0 on success, error code on failure. In the event that this fails, - * @payload.vc_start_slot will also be set to -1. + * Returns: 0 on success, error code on failure. */ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_state *mst_state, struct drm_dp_mst_atomic_payload *payload) { struct drm_dp_mst_port *port; - int ret; + int ret = 0; + bool allocate = true; + + /* Update mst mgr info */ + if (mgr->payload_count == 0) + mgr->next_start_slot = mst_state->start_slot; + + payload->vc_start_slot = mgr->next_start_slot; + + mgr->payload_count++; + mgr->next_start_slot += payload->time_slots; + /* Allocate payload to immediate downstream facing port */ port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); if (!port) { drm_dbg_kms(mgr->dev, - "VCPI %d for port %p not in topology, not creating a payload\n", + "VCPI %d for port %p not in topology, not creating a payload to remote\n", payload->vcpi, payload->port); - payload->vc_start_slot = -1; - return 0; + allocate = false; } - if (mgr->payload_count == 0) - mgr->next_start_slot = mst_state->start_slot; - - payload->vc_start_slot = mgr->next_start_slot; + if (allocate) { + ret = drm_dp_create_payload_at_dfp(mgr, payload); + if (ret < 0) + drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n", + payload->port, ret); - ret = drm_dp_create_payload_step1(mgr, payload); - drm_dp_mst_topology_put_port(port); - if (ret < 0) { - drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n", - payload->port, ret); - payload->vc_start_slot = -1; - return ret; } - mgr->payload_count++; - mgr->next_start_slot += payload->time_slots; + payload->payload_allocation_status = + (!allocate || ret < 0) ? DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL : + DRM_DP_MST_PAYLOAD_ALLOCATION_DFP; - return 0; + drm_dp_mst_topology_put_port(port); + + return ret; } EXPORT_SYMBOL(drm_dp_add_payload_part1); /** - * drm_dp_remove_payload() - Remove an MST payload + * drm_dp_remove_payload_part1() - Remove an MST payload along the virtual channel * @mgr: Manager to use. * @mst_state: The MST atomic state - * @old_payload: The payload with its old state - * @new_payload: The payload to write + * @payload: The payload to remove * - * Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates - * the starting time slots of all other payloads which would have been shifted towards the start of - * the VC table as a result. After calling this, the driver should generate ACT and payload packets. + * Removes a payload along the virtual channel if it was successfully allocated. + * After calling this, the driver should set HW to generate ACT and then switch to new + * payload allocation state. */ -void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_topology_state *mst_state, - const struct drm_dp_mst_atomic_payload *old_payload, - struct drm_dp_mst_atomic_payload *new_payload) +void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_atomic_payload *payload) { - struct drm_dp_mst_atomic_payload *pos; + /* Remove remote payload allocation */ bool send_remove = false; - /* We failed to make the payload, so nothing to do */ - if (new_payload->vc_start_slot == -1) - return; - mutex_lock(&mgr->lock); - send_remove = drm_dp_mst_port_downstream_of_branch(new_payload->port, mgr->mst_primary); + send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary); mutex_unlock(&mgr->lock); if (send_remove) - drm_dp_destroy_payload_step1(mgr, mst_state, new_payload); + drm_dp_destroy_payload_at_remote_and_dfp(mgr, mst_state, payload); else drm_dbg_kms(mgr->dev, "Payload for VCPI %d not in topology, not sending remove\n", - new_payload->vcpi); + payload->vcpi); + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL; +} +EXPORT_SYMBOL(drm_dp_remove_payload_part1); + +/** + * drm_dp_remove_payload_part2() - Remove an MST payload locally + * @mgr: Manager to use. + * @mst_state: The MST atomic state + * @old_payload: The payload with its old state + * @new_payload: The payload with its latest state + * + * Updates the starting time slots of all other payloads which would have been shifted towards + * the start of the payload ID table as a result of removing a payload. Driver should call this + * function whenever it removes a payload in its HW. It's independent to the result of payload + * allocation/deallocation at branch devices along the virtual channel. + */ +void drm_dp_remove_payload_part2(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + const struct drm_dp_mst_atomic_payload *old_payload, + struct drm_dp_mst_atomic_payload *new_payload) +{ + struct drm_dp_mst_atomic_payload *pos; + + /* Remove local payload allocation */ list_for_each_entry(pos, &mst_state->payloads, next) { if (pos != new_payload && pos->vc_start_slot > new_payload->vc_start_slot) pos->vc_start_slot -= old_payload->time_slots; @@ -3382,9 +3409,10 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, if (new_payload->delete) drm_dp_mst_put_port_malloc(new_payload->port); -} -EXPORT_SYMBOL(drm_dp_remove_payload); + new_payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE; +} +EXPORT_SYMBOL(drm_dp_remove_payload_part2); /** * drm_dp_add_payload_part2() - Execute payload update part 2 * @mgr: Manager to use. @@ -3403,21 +3431,19 @@ int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, int ret = 0; /* Skip failed payloads */ - if (payload->vc_start_slot == -1) { - drm_dbg_kms(mgr->dev, "Part 1 of payload creation for %s failed, skipping part 2\n", + if (payload->payload_allocation_status != DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) { + drm_dbg_kms(state->dev, "Part 1 of payload creation for %s failed, skipping part 2\n", payload->port->connector->name); return -EIO; } - ret = drm_dp_create_payload_step2(mgr, payload); - if (ret < 0) { - if (!payload->delete) - drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n", - payload->port, ret); - else - drm_dbg_kms(mgr->dev, "Step 2 of removing MST payload for %p failed: %d\n", - payload->port, ret); - } + /* Allocate payload to remote end */ + ret = drm_dp_create_payload_to_remote(mgr, payload); + if (ret < 0) + drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n", + payload->port, ret); + else + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE; return ret; } @@ -4328,6 +4354,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, drm_dp_mst_get_port_malloc(port); payload->port = port; payload->vc_start_slot = -1; + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE; list_add(&payload->next, &topology_state->payloads); } payload->time_slots = req_slots; @@ -4497,7 +4524,7 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state) } /* Now that previous state is committed, it's safe to copy over the start slot - * assignments + * and allocation status assignments */ list_for_each_entry(old_payload, &old_mst_state->payloads, next) { if (old_payload->delete) @@ -4506,6 +4533,8 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state) new_payload = drm_atomic_get_mst_payload_state(new_mst_state, old_payload->port); new_payload->vc_start_slot = old_payload->vc_start_slot; + new_payload->payload_allocation_status = + old_payload->payload_allocation_status; } } } @@ -4822,6 +4851,13 @@ void drm_dp_mst_dump_topology(struct seq_file *m, struct drm_dp_mst_atomic_payload *payload; int i, ret; + static const char *const status[] = { + "None", + "Local", + "DFP", + "Remote", + }; + mutex_lock(&mgr->lock); if (mgr->mst_primary) drm_dp_mst_dump_mstb(m, mgr->mst_primary); @@ -4838,7 +4874,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n", state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div); - seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | sink name |\n"); + seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | status | sink name |\n"); for (i = 0; i < mgr->max_payloads; i++) { list_for_each_entry(payload, &state->payloads, next) { char name[14]; @@ -4847,7 +4883,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, continue; fetch_monitor_name(mgr, payload->port, name, sizeof(name)); - seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %19s\n", + seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %8s %19s\n", i, payload->port->port_num, payload->vcpi, @@ -4855,6 +4891,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, payload->vc_start_slot + payload->time_slots - 1, payload->pbn, payload->dsc_enabled ? "Y" : "N", + status[payload->payload_allocation_status], (*name != 0) ? name : "Unknown"); } } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c277b198fa3f..f1a503aafe5a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1841,9 +1841,9 @@ static const struct drm_debugfs_info drm_atomic_debugfs_list[] = { {"state", drm_state_info, 0}, }; -void drm_atomic_debugfs_init(struct drm_minor *minor) +void drm_atomic_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_atomic_debugfs_list, + drm_debugfs_add_files(dev, drm_atomic_debugfs_list, ARRAY_SIZE(drm_atomic_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 39e68e45bb12..30d66bee0ec6 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1384,9 +1384,9 @@ static const struct drm_debugfs_info drm_bridge_debugfs_list[] = { { "bridge_chains", drm_bridge_chains_info, 0 }, }; -void drm_bridge_debugfs_init(struct drm_minor *minor) +void drm_bridge_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_bridge_debugfs_list, + drm_debugfs_add_files(dev, drm_bridge_debugfs_list, ARRAY_SIZE(drm_bridge_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 037e36f2049c..2762572f286e 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -535,9 +535,9 @@ static const struct drm_debugfs_info drm_client_debugfs_list[] = { { "internal_clients", drm_client_debugfs_internal_clients, 0 }, }; -void drm_client_debugfs_init(struct drm_minor *minor) +void drm_client_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_client_debugfs_list, + drm_debugfs_add_files(dev, drm_client_debugfs_list, ARRAY_SIZE(drm_client_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 501a10edd0e1..8556c3b3ff88 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -232,7 +232,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, /* drm_atomic.c */ #ifdef CONFIG_DEBUG_FS struct drm_minor; -void drm_atomic_debugfs_init(struct drm_minor *minor); +void drm_atomic_debugfs_init(struct drm_device *dev); #endif int __drm_atomic_helper_disable_plane(struct drm_plane *plane, diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 2de43ff3ce0a..34c7d1a580e3 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -150,6 +150,9 @@ static int drm_debugfs_open(struct inode *inode, struct file *file) { struct drm_info_node *node = inode->i_private; + if (!device_is_registered(node->minor->kdev)) + return -ENODEV; + return single_open(file, node->info_ent->show, node); } @@ -157,6 +160,10 @@ static int drm_debugfs_entry_open(struct inode *inode, struct file *file) { struct drm_debugfs_entry *entry = inode->i_private; struct drm_debugfs_info *node = &entry->file; + struct drm_minor *minor = entry->dev->primary ?: entry->dev->accel; + + if (!device_is_registered(minor->kdev)) + return -ENODEV; return single_open(file, node->show, entry); } @@ -227,7 +234,7 @@ EXPORT_SYMBOL(drm_debugfs_gpuva_info); * * Create a given set of debugfs files represented by an array of * &struct drm_info_list in the given root directory. These files will be removed - * automatically on drm_debugfs_cleanup(). + * automatically on drm_debugfs_dev_fini(). */ void drm_debugfs_create_files(const struct drm_info_list *files, int count, struct dentry *root, struct drm_minor *minor) @@ -242,7 +249,7 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count, if (features && !drm_core_check_all_features(dev, features)) continue; - tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); + tmp = drmm_kzalloc(dev, sizeof(*tmp), GFP_KERNEL); if (tmp == NULL) continue; @@ -251,111 +258,89 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count, 0444, root, tmp, &drm_debugfs_fops); tmp->info_ent = &files[i]; - - mutex_lock(&minor->debugfs_lock); - list_add(&tmp->list, &minor->debugfs_list); - mutex_unlock(&minor->debugfs_lock); } } EXPORT_SYMBOL(drm_debugfs_create_files); -int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root) +int drm_debugfs_remove_files(const struct drm_info_list *files, int count, + struct dentry *root, struct drm_minor *minor) { - struct drm_device *dev = minor->dev; - struct drm_debugfs_entry *entry, *tmp; - char name[64]; - - INIT_LIST_HEAD(&minor->debugfs_list); - mutex_init(&minor->debugfs_lock); - sprintf(name, "%d", minor_id); - minor->debugfs_root = debugfs_create_dir(name, root); - - drm_debugfs_add_files(minor->dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES); - - if (drm_drv_uses_atomic_modeset(dev)) { - drm_atomic_debugfs_init(minor); - drm_bridge_debugfs_init(minor); - } - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_framebuffer_debugfs_init(minor); + int i; - drm_client_debugfs_init(minor); - } + for (i = 0; i < count; i++) { + struct dentry *dent = debugfs_lookup(files[i].name, root); - if (dev->driver->debugfs_init) - dev->driver->debugfs_init(minor); + if (!dent) + continue; - list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { - debugfs_create_file(entry->file.name, 0444, - minor->debugfs_root, entry, &drm_debugfs_entry_fops); - list_del(&entry->list); + drmm_kfree(minor->dev, d_inode(dent)->i_private); + debugfs_remove(dent); } - return 0; } +EXPORT_SYMBOL(drm_debugfs_remove_files); -void drm_debugfs_late_register(struct drm_device *dev) +/** + * drm_debugfs_dev_init - create debugfs directory for the device + * @dev: the device which we want to create the directory for + * @root: the parent directory depending on the device type + * + * Creates the debugfs directory for the device under the given root directory. + */ +void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root) { - struct drm_minor *minor = dev->primary; - struct drm_debugfs_entry *entry, *tmp; - - if (!minor) - return; - - list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { - debugfs_create_file(entry->file.name, 0444, - minor->debugfs_root, entry, &drm_debugfs_entry_fops); - list_del(&entry->list); - } + dev->debugfs_root = debugfs_create_dir(dev->unique, root); } -int drm_debugfs_remove_files(const struct drm_info_list *files, int count, - struct drm_minor *minor) +/** + * drm_debugfs_dev_fini - cleanup debugfs directory + * @dev: the device to cleanup the debugfs stuff + * + * Remove the debugfs directory, might be called multiple times. + */ +void drm_debugfs_dev_fini(struct drm_device *dev) { - struct list_head *pos, *q; - struct drm_info_node *tmp; - int i; - - mutex_lock(&minor->debugfs_lock); - for (i = 0; i < count; i++) { - list_for_each_safe(pos, q, &minor->debugfs_list) { - tmp = list_entry(pos, struct drm_info_node, list); - if (tmp->info_ent == &files[i]) { - debugfs_remove(tmp->dent); - list_del(pos); - kfree(tmp); - } - } - } - mutex_unlock(&minor->debugfs_lock); - return 0; + debugfs_remove_recursive(dev->debugfs_root); + dev->debugfs_root = NULL; } -EXPORT_SYMBOL(drm_debugfs_remove_files); -static void drm_debugfs_remove_all_files(struct drm_minor *minor) +void drm_debugfs_dev_register(struct drm_device *dev) { - struct drm_info_node *node, *tmp; + drm_debugfs_add_files(dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES); - mutex_lock(&minor->debugfs_lock); - list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) { - debugfs_remove(node->dent); - list_del(&node->list); - kfree(node); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_framebuffer_debugfs_init(dev); + drm_client_debugfs_init(dev); + } + if (drm_drv_uses_atomic_modeset(dev)) { + drm_atomic_debugfs_init(dev); + drm_bridge_debugfs_init(dev); } - mutex_unlock(&minor->debugfs_lock); } -void drm_debugfs_cleanup(struct drm_minor *minor) +int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root) { - if (!minor->debugfs_root) - return; + struct drm_device *dev = minor->dev; + char name[64]; + + sprintf(name, "%d", minor_id); + minor->debugfs_symlink = debugfs_create_symlink(name, root, + dev->unique); - drm_debugfs_remove_all_files(minor); + /* TODO: Only for compatibility with drivers */ + minor->debugfs_root = dev->debugfs_root; - debugfs_remove_recursive(minor->debugfs_root); - minor->debugfs_root = NULL; + if (dev->driver->debugfs_init && dev->render != minor) + dev->driver->debugfs_init(minor); + + return 0; +} + +void drm_debugfs_unregister(struct drm_minor *minor) +{ + debugfs_remove(minor->debugfs_symlink); + minor->debugfs_symlink = NULL; } /** @@ -381,9 +366,8 @@ void drm_debugfs_add_file(struct drm_device *dev, const char *name, entry->file.data = data; entry->dev = dev; - mutex_lock(&dev->debugfs_mutex); - list_add(&entry->list, &dev->debugfs_list); - mutex_unlock(&dev->debugfs_mutex); + debugfs_create_file(name, 0444, dev->debugfs_root, entry, + &drm_debugfs_entry_fops); } EXPORT_SYMBOL(drm_debugfs_add_file); @@ -540,13 +524,13 @@ static const struct file_operations drm_connector_fops = { void drm_debugfs_connector_add(struct drm_connector *connector) { - struct drm_minor *minor = connector->dev->primary; + struct drm_device *dev = connector->dev; struct dentry *root; - if (!minor->debugfs_root) + if (!dev->debugfs_root) return; - root = debugfs_create_dir(connector->name, minor->debugfs_root); + root = debugfs_create_dir(connector->name, dev->debugfs_root); connector->debugfs_entry = root; /* force */ @@ -581,7 +565,7 @@ void drm_debugfs_connector_remove(struct drm_connector *connector) void drm_debugfs_crtc_add(struct drm_crtc *crtc) { - struct drm_minor *minor = crtc->dev->primary; + struct drm_device *dev = crtc->dev; struct dentry *root; char *name; @@ -589,7 +573,7 @@ void drm_debugfs_crtc_add(struct drm_crtc *crtc) if (!name) return; - root = debugfs_create_dir(name, minor->debugfs_root); + root = debugfs_create_dir(name, dev->debugfs_root); kfree(name); crtc->debugfs_entry = root; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3eda026ffac6..535f16e7882e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -172,10 +172,9 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) if (!minor) return 0; - if (minor->type == DRM_MINOR_ACCEL) { - accel_debugfs_init(minor, minor->index); - } else { - ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); + if (minor->type != DRM_MINOR_ACCEL) { + ret = drm_debugfs_register(minor, minor->index, + drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_debugfs; @@ -199,7 +198,7 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) return 0; err_debugfs: - drm_debugfs_cleanup(minor); + drm_debugfs_unregister(minor); return ret; } @@ -223,7 +222,7 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ device_del(minor->kdev); dev_set_drvdata(minor->kdev, NULL); /* safety belt */ - drm_debugfs_cleanup(minor); + drm_debugfs_unregister(minor); } /* @@ -598,7 +597,6 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); - mutex_destroy(&dev->debugfs_mutex); drm_legacy_destroy_members(dev); } @@ -639,14 +637,12 @@ static int drm_dev_init(struct drm_device *dev, INIT_LIST_HEAD(&dev->filelist_internal); INIT_LIST_HEAD(&dev->clientlist); INIT_LIST_HEAD(&dev->vblank_event_list); - INIT_LIST_HEAD(&dev->debugfs_list); spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->filelist_mutex); mutex_init(&dev->clientlist_mutex); mutex_init(&dev->master_mutex); - mutex_init(&dev->debugfs_mutex); ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL); if (ret) @@ -697,6 +693,11 @@ static int drm_dev_init(struct drm_device *dev, goto err; } + if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) + accel_debugfs_init(dev); + else + drm_debugfs_dev_init(dev, drm_debugfs_root); + return 0; err: @@ -786,6 +787,9 @@ static void drm_dev_release(struct kref *ref) { struct drm_device *dev = container_of(ref, struct drm_device, ref); + /* Just in case register/unregister was never called */ + drm_debugfs_dev_fini(dev); + if (dev->driver->release) dev->driver->release(dev); @@ -916,6 +920,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (drm_dev_needs_global_mutex(dev)) mutex_lock(&drm_global_mutex); + if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) + accel_debugfs_register(dev); + else + drm_debugfs_dev_register(dev); + ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_minors; @@ -1001,6 +1010,7 @@ void drm_dev_unregister(struct drm_device *dev) drm_minor_unregister(dev, DRM_MINOR_ACCEL); drm_minor_unregister(dev, DRM_MINOR_PRIMARY); drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_debugfs_dev_fini(dev); } EXPORT_SYMBOL(drm_dev_unregister); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index aff3746dedfb..ba51deb6d042 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -1222,9 +1222,9 @@ static const struct drm_debugfs_info drm_framebuffer_debugfs_list[] = { { "framebuffer", drm_framebuffer_info, 0 }, }; -void drm_framebuffer_debugfs_init(struct drm_minor *minor) +void drm_framebuffer_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_framebuffer_debugfs_list, + drm_debugfs_add_files(dev, drm_framebuffer_debugfs_list, ARRAY_SIZE(drm_framebuffer_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index ba12acd55139..ab9a472f4a47 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -180,27 +180,32 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map); /* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) -int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root); -void drm_debugfs_cleanup(struct drm_minor *minor); -void drm_debugfs_late_register(struct drm_device *dev); +void drm_debugfs_dev_fini(struct drm_device *dev); +void drm_debugfs_dev_register(struct drm_device *dev); +int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root); +void drm_debugfs_unregister(struct drm_minor *minor); void drm_debugfs_connector_add(struct drm_connector *connector); void drm_debugfs_connector_remove(struct drm_connector *connector); void drm_debugfs_crtc_add(struct drm_crtc *crtc); void drm_debugfs_crtc_remove(struct drm_crtc *crtc); void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc); #else -static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root) +static inline void drm_debugfs_dev_fini(struct drm_device *dev) { - return 0; } -static inline void drm_debugfs_cleanup(struct drm_minor *minor) +static inline void drm_debugfs_dev_register(struct drm_device *dev) { } -static inline void drm_debugfs_late_register(struct drm_device *dev) +static inline int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root) +{ + return 0; +} + +static inline void drm_debugfs_unregister(struct drm_minor *minor) { } @@ -259,4 +264,4 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, /* drm_framebuffer.c */ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); -void drm_framebuffer_debugfs_init(struct drm_minor *minor); +void drm_framebuffer_debugfs_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 87eb591fe9b5..8525ef851540 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -54,8 +54,6 @@ int drm_modeset_register_all(struct drm_device *dev) if (ret) goto err_connector; - drm_debugfs_late_register(dev); - return 0; err_connector: diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index c8b611a2f6c6..1188a8d61caf 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -81,7 +81,6 @@ extern void gma_encoder_destroy(struct drm_encoder *encoder); /* Common clock related functions */ extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); -extern void gma_clock(int refclk, struct gma_clock_t *clock); extern bool gma_pll_is_valid(struct drm_crtc *crtc, const struct gma_limit_t *limit, struct gma_clock_t *clock); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index f7f709df99b4..c5edfa4aa4cc 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -161,14 +161,6 @@ #define PSB_NUM_VBLANKS 2 - -#define PSB_2D_SIZE (256*1024*1024) -#define PSB_MAX_RELOC_PAGES 1024 - -#define PSB_LOW_REG_OFFS 0x0204 -#define PSB_HIGH_REG_OFFS 0x0600 - -#define PSB_NUM_VBLANKS 2 #define PSB_WATCHDOG_DELAY (HZ * 2) #define PSB_LID_DELAY (HZ / 10) @@ -424,6 +416,7 @@ struct drm_psb_private { uint32_t pipestat[PSB_NUM_PIPE]; spinlock_t irqmask_lock; + bool irq_enabled; /* Power */ bool pm_initialized; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 0bb85494e3da..c111e933e1ed 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -186,19 +186,13 @@ extern bool psb_intel_ddc_probe(struct i2c_adapter *adapter); extern void psb_intel_crtc_init(struct drm_device *dev, int pipe, struct psb_intel_mode_device *mode_dev); -extern void psb_intel_crt_init(struct drm_device *dev); extern bool psb_intel_sdvo_init(struct drm_device *dev, int output_device); -extern void psb_intel_dvo_init(struct drm_device *dev); -extern void psb_intel_tv_init(struct drm_device *dev); extern void psb_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level); extern void oaktrail_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); -extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev); -extern void mid_dsi_init(struct drm_device *dev, - struct psb_intel_mode_device *mode_dev, int dsi_num); extern struct drm_encoder *gma_best_encoder(struct drm_connector *connector); extern void gma_connector_attach_encoder(struct gma_connector *connector, @@ -214,11 +208,6 @@ extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); -extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, - int sdvoB); -extern int intelfb_probe(struct drm_device *dev); -extern int intelfb_remove(struct drm_device *dev, - struct drm_framebuffer *fb); extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -242,9 +231,6 @@ extern void cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern void psb_intel_attach_force_audio_property(struct drm_connector *connector); -extern void psb_intel_attach_broadcast_rgb_property(struct drm_connector *connector); - extern int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val); extern int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val); extern void cdv_sb_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 343c51250207..7bbb79b0497d 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -327,6 +327,8 @@ int gma_irq_install(struct drm_device *dev) gma_irq_postinstall(dev); + dev_priv->irq_enabled = true; + return 0; } @@ -337,6 +339,9 @@ void gma_irq_uninstall(struct drm_device *dev) unsigned long irqflags; unsigned int i; + if (!dev_priv->irq_enabled) + return; + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (dev_priv->ops->hotplug_enable) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index e3f176a093d2..5f73cdabe7a1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -557,12 +557,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_dp_mst_topology_state *old_mst_state = - drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); struct drm_dp_mst_topology_state *new_mst_state = drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); - const struct drm_dp_mst_atomic_payload *old_payload = - drm_atomic_get_mst_payload_state(old_mst_state, connector->port); struct drm_dp_mst_atomic_payload *new_payload = drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -572,8 +568,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); - drm_dp_remove_payload(&intel_dp->mst_mgr, new_mst_state, - old_payload, new_payload); + drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } @@ -588,6 +583,14 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); + struct drm_dp_mst_topology_state *new_mst_state = + drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); + const struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, connector->port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *dev_priv = to_i915(connector->base.dev); bool last_mst_stream; @@ -608,6 +611,9 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, wait_for_act_sent(encoder, old_crtc_state); + drm_dp_remove_payload_part2(&intel_dp->mst_mgr, new_mst_state, + old_payload, new_payload); + intel_ddi_disable_transcoder_func(old_crtc_state); if (DISPLAY_VER(dev_priv) >= 9) diff --git a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c index a2277a0d6d06..0006ea52b83c 100644 --- a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c @@ -255,19 +255,17 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) return ret; } -static int dw_hdmi_imx_remove(struct platform_device *pdev) +static void dw_hdmi_imx_remove(struct platform_device *pdev) { struct imx_hdmi *hdmi = platform_get_drvdata(pdev); component_del(&pdev->dev, &dw_hdmi_imx_ops); dw_hdmi_remove(hdmi->hdmi); - - return 0; } static struct platform_driver dw_hdmi_imx_platform_driver = { .probe = dw_hdmi_imx_probe, - .remove = dw_hdmi_imx_remove, + .remove_new = dw_hdmi_imx_remove, .driver = { .name = "dwhdmi-imx", .of_match_table = dw_hdmi_imx_dt_ids, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c index 4a866ac60fff..352fa31ab4ed 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c @@ -292,10 +292,9 @@ static int imx_drm_platform_probe(struct platform_device *pdev) return ret; } -static int imx_drm_platform_remove(struct platform_device *pdev) +static void imx_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &imx_drm_ops); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -324,7 +323,7 @@ MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); static struct platform_driver imx_drm_pdrv = { .probe = imx_drm_platform_probe, - .remove = imx_drm_platform_remove, + .remove_new = imx_drm_platform_remove, .driver = { .name = "imx-drm", .pm = &imx_drm_pm_ops, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index c45fc8f4744d..989eca32d325 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -737,7 +737,7 @@ free_child: return ret; } -static int imx_ldb_remove(struct platform_device *pdev) +static void imx_ldb_remove(struct platform_device *pdev) { struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); int i; @@ -750,12 +750,11 @@ static int imx_ldb_remove(struct platform_device *pdev) } component_del(&pdev->dev, &imx_ldb_ops); - return 0; } static struct platform_driver imx_ldb_driver = { .probe = imx_ldb_probe, - .remove = imx_ldb_remove, + .remove_new = imx_ldb_remove, .driver = { .of_match_table = imx_ldb_dt_ids, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c index d6832f506322..b49bddb85535 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-tve.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c @@ -645,10 +645,9 @@ static int imx_tve_probe(struct platform_device *pdev) return component_add(dev, &imx_tve_ops); } -static int imx_tve_remove(struct platform_device *pdev) +static void imx_tve_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_tve_ops); - return 0; } static const struct of_device_id imx_tve_dt_ids[] = { @@ -659,7 +658,7 @@ MODULE_DEVICE_TABLE(of, imx_tve_dt_ids); static struct platform_driver imx_tve_driver = { .probe = imx_tve_probe, - .remove = imx_tve_remove, + .remove_new = imx_tve_remove, .driver = { .of_match_table = imx_tve_dt_ids, .name = "imx-tve", diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index 89585b31b985..ef29c9a61a46 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -441,10 +441,9 @@ static int ipu_drm_probe(struct platform_device *pdev) return component_add(dev, &ipu_crtc_ops); } -static int ipu_drm_remove(struct platform_device *pdev) +static void ipu_drm_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ipu_crtc_ops); - return 0; } struct platform_driver ipu_drm_driver = { @@ -452,5 +451,5 @@ struct platform_driver ipu_drm_driver = { .name = "imx-ipuv3-crtc", }, .probe = ipu_drm_probe, - .remove = ipu_drm_remove, + .remove_new = ipu_drm_remove, }; diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 0fa0b590830b..70349739dd89 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -353,11 +353,9 @@ static int imx_pd_probe(struct platform_device *pdev) return component_add(dev, &imx_pd_ops); } -static int imx_pd_remove(struct platform_device *pdev) +static void imx_pd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_pd_ops); - - return 0; } static const struct of_device_id imx_pd_dt_ids[] = { @@ -368,7 +366,7 @@ MODULE_DEVICE_TABLE(of, imx_pd_dt_ids); static struct platform_driver imx_pd_driver = { .probe = imx_pd_probe, - .remove = imx_pd_remove, + .remove_new = imx_pd_remove, .driver = { .of_match_table = imx_pd_dt_ids, .name = "imx-parallel-display", diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 8dbd4847d3a6..c2547d48d6aa 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1449,7 +1449,7 @@ static int ingenic_drm_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &ingenic_master_ops, match); } -static int ingenic_drm_remove(struct platform_device *pdev) +static void ingenic_drm_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1457,8 +1457,6 @@ static int ingenic_drm_remove(struct platform_device *pdev) ingenic_drm_unbind(dev); else component_master_del(dev, &ingenic_master_ops); - - return 0; } static int ingenic_drm_suspend(struct device *dev) @@ -1611,7 +1609,7 @@ static struct platform_driver ingenic_drm_driver = { .of_match_table = of_match_ptr(ingenic_drm_of_match), }, .probe = ingenic_drm_probe, - .remove = ingenic_drm_remove, + .remove_new = ingenic_drm_remove, }; static int ingenic_drm_init(void) diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 6d236547f611..5bd9072352b5 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -922,10 +922,9 @@ static int ingenic_ipu_probe(struct platform_device *pdev) return component_add(&pdev->dev, &ingenic_ipu_ops); } -static int ingenic_ipu_remove(struct platform_device *pdev) +static void ingenic_ipu_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ingenic_ipu_ops); - return 0; } static const u32 jz4725b_ipu_formats[] = { @@ -992,7 +991,7 @@ static struct platform_driver ingenic_ipu_driver = { .of_match_table = ingenic_ipu_of_match, }, .probe = ingenic_ipu_probe, - .remove = ingenic_ipu_remove, + .remove_new = ingenic_ipu_remove, }; struct platform_driver *ingenic_ipu_driver_ptr = &ingenic_ipu_driver; diff --git a/drivers/gpu/drm/loongson/lsdc_pixpll.c b/drivers/gpu/drm/loongson/lsdc_pixpll.c index 04c15b4697e2..2609a2256da4 100644 --- a/drivers/gpu/drm/loongson/lsdc_pixpll.c +++ b/drivers/gpu/drm/loongson/lsdc_pixpll.c @@ -120,12 +120,14 @@ static int lsdc_pixel_pll_setup(struct lsdc_pixpll * const this) struct lsdc_pixpll_parms *pparms; this->mmio = ioremap(this->reg_base, this->reg_size); - if (IS_ERR_OR_NULL(this->mmio)) + if (!this->mmio) return -ENOMEM; pparms = kzalloc(sizeof(*pparms), GFP_KERNEL); - if (IS_ERR_OR_NULL(pparms)) + if (!pparms) { + iounmap(this->mmio); return -ENOMEM; + } pparms->ref_clock = LSDC_PLL_REF_CLK_KHZ; diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 575e7c56219f..fa527935ffd4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -751,10 +751,9 @@ static int adreno_probe(struct platform_device *pdev) return 0; } -static int adreno_remove(struct platform_device *pdev) +static void adreno_remove(struct platform_device *pdev) { component_del(&pdev->dev, &a3xx_ops); - return 0; } static void adreno_shutdown(struct platform_device *pdev) @@ -869,7 +868,7 @@ static const struct dev_pm_ops adreno_pm_ops = { static struct platform_driver adreno_driver = { .probe = adreno_probe, - .remove = adreno_remove, + .remove_new = adreno_remove, .shutdown = adreno_shutdown, .driver = { .name = "adreno", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index aa6ba2cf4b84..82381d12414d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1302,11 +1302,9 @@ static int dpu_dev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, dpu_kms_init); } -static int dpu_dev_remove(struct platform_device *pdev) +static void dpu_dev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } static int __maybe_unused dpu_runtime_suspend(struct device *dev) @@ -1382,7 +1380,7 @@ MODULE_DEVICE_TABLE(of, dpu_dt_match); static struct platform_driver dpu_driver = { .probe = dpu_dev_probe, - .remove = dpu_dev_remove, + .remove_new = dpu_dev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm_dpu", diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 700df4040e9a..e5012fa6771f 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -560,11 +560,9 @@ static int mdp4_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, mdp4_kms_init); } -static int mdp4_remove(struct platform_device *pdev) +static void mdp4_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } static const struct of_device_id mdp4_dt_match[] = { @@ -575,7 +573,7 @@ MODULE_DEVICE_TABLE(of, mdp4_dt_match); static struct platform_driver mdp4_platform_driver = { .probe = mdp4_probe, - .remove = mdp4_remove, + .remove_new = mdp4_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "mdp4", diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 92bf9d949d09..8a7b44376bc6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -942,11 +942,10 @@ static int mdp5_dev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, mdp5_kms_init); } -static int mdp5_dev_remove(struct platform_device *pdev) +static void mdp5_dev_remove(struct platform_device *pdev) { DBG(""); component_master_del(&pdev->dev, &msm_drm_ops); - return 0; } static __maybe_unused int mdp5_runtime_suspend(struct device *dev) @@ -987,7 +986,7 @@ MODULE_DEVICE_TABLE(of, mdp5_dt_match); static struct platform_driver mdp5_driver = { .probe = mdp5_dev_probe, - .remove = mdp5_dev_remove, + .remove_new = mdp5_dev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm_mdp", diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 76f13954015b..01784e9e7127 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1296,7 +1296,7 @@ static int dp_display_probe(struct platform_device *pdev) return rc; } -static int dp_display_remove(struct platform_device *pdev) +static void dp_display_remove(struct platform_device *pdev) { struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); @@ -1304,8 +1304,6 @@ static int dp_display_remove(struct platform_device *pdev) dp_display_deinit_sub_modules(dp); platform_set_drvdata(pdev, NULL); - - return 0; } static int dp_pm_resume(struct device *dev) @@ -1415,7 +1413,7 @@ static const struct dev_pm_ops dp_pm_ops = { static struct platform_driver dp_display_driver = { .probe = dp_display_probe, - .remove = dp_display_remove, + .remove_new = dp_display_remove, .driver = { .name = "msm-dp-display", .of_match_table = dp_dt_match, diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index baab79ab6e74..7a8208cd6649 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -161,14 +161,12 @@ static int dsi_dev_probe(struct platform_device *pdev) return 0; } -static int dsi_dev_remove(struct platform_device *pdev) +static void dsi_dev_remove(struct platform_device *pdev) { struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); DBG(""); dsi_destroy(msm_dsi); - - return 0; } static const struct of_device_id dt_match[] = { @@ -187,7 +185,7 @@ static const struct dev_pm_ops dsi_pm_ops = { static struct platform_driver dsi_driver = { .probe = dsi_dev_probe, - .remove = dsi_dev_remove, + .remove_new = dsi_dev_remove, .driver = { .name = "msm_dsi", .of_match_table = dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 60509fb39710..b6bcb9f675fe 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -551,15 +551,13 @@ err_put_phy: return ret; } -static int msm_hdmi_dev_remove(struct platform_device *pdev) +static void msm_hdmi_dev_remove(struct platform_device *pdev) { struct hdmi *hdmi = dev_get_drvdata(&pdev->dev); component_del(&pdev->dev, &msm_hdmi_ops); msm_hdmi_put_phy(hdmi); - - return 0; } static const struct of_device_id msm_hdmi_dt_match[] = { @@ -574,7 +572,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { static struct platform_driver msm_hdmi_driver = { .probe = msm_hdmi_dev_probe, - .remove = msm_hdmi_dev_remove, + .remove_new = msm_hdmi_dev_remove, .driver = { .name = "hdmi_msm", .of_match_table = msm_hdmi_dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 3e00fb8190b2..88a3423b7f24 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -177,11 +177,9 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev) return 0; } -static int msm_hdmi_phy_remove(struct platform_device *pdev) +static void msm_hdmi_phy_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id msm_hdmi_phy_dt_match[] = { @@ -200,7 +198,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { static struct platform_driver msm_hdmi_phy_platform_driver = { .probe = msm_hdmi_phy_probe, - .remove = msm_hdmi_phy_remove, + .remove_new = msm_hdmi_phy_remove, .driver = { .name = "msm_hdmi_phy", .of_match_table = msm_hdmi_phy_dt_match, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 4bd028fa7500..a428951ee539 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1278,11 +1278,9 @@ static int msm_pdev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, NULL); } -static int msm_pdev_remove(struct platform_device *pdev) +static void msm_pdev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } void msm_drv_shutdown(struct platform_device *pdev) @@ -1303,7 +1301,7 @@ void msm_drv_shutdown(struct platform_device *pdev) static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, - .remove = msm_pdev_remove, + .remove_new = msm_pdev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm", diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 2e87dd6cb17b..a429b704059e 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -497,15 +497,13 @@ static int mdss_probe(struct platform_device *pdev) return 0; } -static int mdss_remove(struct platform_device *pdev) +static void mdss_remove(struct platform_device *pdev) { struct msm_mdss *mdss = platform_get_drvdata(pdev); of_platform_depopulate(&pdev->dev); msm_mdss_destroy(mdss); - - return 0; } static const struct msm_mdss_data msm8998_data = { @@ -629,7 +627,7 @@ MODULE_DEVICE_TABLE(of, mdss_dt_match); static struct platform_driver mdss_platform_driver = { .probe = mdss_probe, - .remove = mdss_remove, + .remove_new = mdss_remove, .driver = { .name = "msm-mdss", .of_match_table = mdss_dt_match, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 4e7c9c353c51..bba01fa0780c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -882,21 +882,26 @@ struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) static void nv50_msto_cleanup(struct drm_atomic_state *state, - struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_topology_state *new_mst_state, struct drm_dp_mst_topology_mgr *mgr, struct nv50_msto *msto) { struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); - struct drm_dp_mst_atomic_payload *payload = - drm_atomic_get_mst_payload_state(mst_state, msto->mstc->port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, msto->mstc->port); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(state, mgr); + const struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, msto->mstc->port); NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); if (msto->disabled) { msto->mstc = NULL; msto->disabled = false; + drm_dp_remove_payload_part2(mgr, new_mst_state, old_payload, new_payload); } else if (msto->enabled) { - drm_dp_add_payload_part2(mgr, state, payload); + drm_dp_add_payload_part2(mgr, state, new_payload); msto->enabled = false; } } @@ -910,19 +915,15 @@ nv50_msto_prepare(struct drm_atomic_state *state, struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; - struct drm_dp_mst_topology_state *old_mst_state; - struct drm_dp_mst_atomic_payload *payload, *old_payload; + struct drm_dp_mst_atomic_payload *payload; NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); - old_mst_state = drm_atomic_get_old_mst_topology_state(state, mgr); - payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port); - old_payload = drm_atomic_get_mst_payload_state(old_mst_state, mstc->port); // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? if (msto->disabled) { - drm_dp_remove_payload(mgr, mst_state, old_payload, payload); + drm_dp_remove_payload_part1(mgr, mst_state, payload); nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } else { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1fe17ff95f5e..3666a7403e47 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -189,21 +189,12 @@ u_free(void *addr) static inline void * u_memcpya(uint64_t user, unsigned int nmemb, unsigned int size) { - void *mem; - void __user *userptr = (void __force __user *)(uintptr_t)user; + void __user *userptr = u64_to_user_ptr(user); + size_t bytes; - size *= nmemb; - - mem = kvmalloc(size, GFP_KERNEL); - if (!mem) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(mem, userptr, size)) { - u_free(mem); - return ERR_PTR(-EFAULT); - } - - return mem; + if (unlikely(check_mul_overflow(nmemb, size, &bytes))) + return NULL; + return vmemdup_user(userptr, bytes); } #include <nvif/object.h> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 869e535faefa..2d6d96ee3547 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -244,6 +244,17 @@ config DRM_PANEL_JDI_LT070ME05000 The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses 24 bit per pixel. +config DRM_PANEL_JDI_LPM102A188A + tristate "JDI LPM102A188A DSI panel" + depends on OF && GPIOLIB + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for JDI LPM102A188A DSI + command mode panel as found in Google Pixel C devices. + The panel has a 2560×1800 resolution. It provides a MIPI DSI interface + to the host. + config DRM_PANEL_JDI_R63452 tristate "JDI R63452 Full HD DSI panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 433e93d57949..157c77ff157f 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JADARD_JD9365DA_H3) += panel-jadard-jd9365da-h3.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o +obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c new file mode 100644 index 000000000000..5b5082efb282 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2014 Google, Inc. + * + * Copyright (C) 2022 Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt> + * + * Adapted from the downstream Pixel C driver written by Sean Paul + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#define MCS_CMD_ACS_PROT 0xB0 +#define MCS_CMD_ACS_PROT_OFF (0 << 0) + +#define MCS_PWR_CTRL_FUNC 0xD0 +#define MCS_PWR_CTRL_PARAM1_DEFAULT (2 << 0) +#define MCS_PWR_CTRL_PARAM1_VGH_210_DIV (1 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_240_DIV (2 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_280_DIV (3 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_330_DIV (4 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_410_DIV (5 << 4) +#define MCS_PWR_CTRL_PARAM2_DEFAULT (9 << 4) +#define MCS_PWR_CTRL_PARAM2_VGL_210_DIV (1 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_240_DIV (2 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_280_DIV (3 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_330_DIV (4 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_410_DIV (5 << 0) + +struct jdi_panel { + struct drm_panel base; + struct mipi_dsi_device *link1; + struct mipi_dsi_device *link2; + + struct regulator *supply; + struct regulator *ddi_supply; + struct backlight_device *backlight; + + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + + const struct drm_display_mode *mode; +}; + +static inline struct jdi_panel *to_panel_jdi(struct drm_panel *panel) +{ + return container_of(panel, struct jdi_panel, base); +} + +static void jdi_wait_frames(struct jdi_panel *jdi, unsigned int frames) +{ + unsigned int refresh = drm_mode_vrefresh(jdi->mode); + + if (WARN_ON(frames > refresh)) + return; + + msleep(1000 / (refresh / frames)); +} + +static int jdi_panel_disable(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + + backlight_disable(jdi->backlight); + + jdi_wait_frames(jdi, 2); + + return 0; +} + +static int jdi_panel_unprepare(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + int ret; + + ret = mipi_dsi_dcs_set_display_off(jdi->link1); + if (ret < 0) + dev_err(panel->dev, "failed to set display off: %d\n", ret); + + ret = mipi_dsi_dcs_set_display_off(jdi->link2); + if (ret < 0) + dev_err(panel->dev, "failed to set display off: %d\n", ret); + + /* Specified by JDI @ 50ms, subject to change */ + msleep(50); + + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link1); + if (ret < 0) + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link2); + if (ret < 0) + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); + + /* Specified by JDI @ 150ms, subject to change */ + msleep(150); + + gpiod_set_value(jdi->reset_gpio, 1); + + /* T4 = 1ms */ + usleep_range(1000, 3000); + + gpiod_set_value(jdi->enable_gpio, 0); + + /* T5 = 2ms */ + usleep_range(2000, 4000); + + regulator_disable(jdi->ddi_supply); + + /* T6 = 2ms plus some time to discharge capacitors */ + usleep_range(7000, 9000); + + regulator_disable(jdi->supply); + /* Specified by JDI @ 20ms, subject to change */ + msleep(20); + + return ret; +} + +static int jdi_setup_symmetrical_split(struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + const struct drm_display_mode *mode) +{ + int err; + + err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_column_address(right, 0, mode->hdisplay / 2 - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set page address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set page address: %d\n", err); + return err; + } + + return 0; +} + +static int jdi_write_dcdc_registers(struct jdi_panel *jdi) +{ + /* Clear the manufacturer command access protection */ + mipi_dsi_generic_write_seq(jdi->link1, MCS_CMD_ACS_PROT, + MCS_CMD_ACS_PROT_OFF); + mipi_dsi_generic_write_seq(jdi->link2, MCS_CMD_ACS_PROT, + MCS_CMD_ACS_PROT_OFF); + /* + * Change the VGH/VGL divide rations to move the noise generated by the + * TCONN. This should hopefully avoid interaction with the backlight + * controller. + */ + mipi_dsi_generic_write_seq(jdi->link1, MCS_PWR_CTRL_FUNC, + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | + MCS_PWR_CTRL_PARAM1_DEFAULT, + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | + MCS_PWR_CTRL_PARAM2_DEFAULT); + + mipi_dsi_generic_write_seq(jdi->link2, MCS_PWR_CTRL_FUNC, + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | + MCS_PWR_CTRL_PARAM1_DEFAULT, + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | + MCS_PWR_CTRL_PARAM2_DEFAULT); + + return 0; +} + +static int jdi_panel_prepare(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + int err; + + /* Disable backlight to avoid showing random pixels + * with a conservative delay for it to take effect. + */ + backlight_disable(jdi->backlight); + jdi_wait_frames(jdi, 3); + + jdi->link1->mode_flags |= MIPI_DSI_MODE_LPM; + jdi->link2->mode_flags |= MIPI_DSI_MODE_LPM; + + err = regulator_enable(jdi->supply); + if (err < 0) { + dev_err(panel->dev, "failed to enable supply: %d\n", err); + return err; + } + /* T1 = 2ms */ + usleep_range(2000, 4000); + + err = regulator_enable(jdi->ddi_supply); + if (err < 0) { + dev_err(panel->dev, "failed to enable ddi_supply: %d\n", err); + goto supply_off; + } + /* T2 = 1ms */ + usleep_range(1000, 3000); + + gpiod_set_value(jdi->enable_gpio, 1); + /* T3 = 10ms */ + usleep_range(10000, 15000); + + gpiod_set_value(jdi->reset_gpio, 0); + /* Specified by JDI @ 3ms, subject to change */ + usleep_range(3000, 5000); + + /* + * TODO: The device supports both left-right and even-odd split + * configurations, but this driver currently supports only the left- + * right split. To support a different mode a mechanism needs to be + * put in place to communicate the configuration back to the DSI host + * controller. + */ + err = jdi_setup_symmetrical_split(jdi->link1, jdi->link2, + jdi->mode); + if (err < 0) { + dev_err(panel->dev, "failed to set up symmetrical split: %d\n", + err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_scanline(jdi->link1, + jdi->mode->vdisplay - 16); + if (err < 0) { + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_scanline(jdi->link2, + jdi->mode->vdisplay - 16); + if (err < 0) { + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_on(jdi->link1, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (err < 0) { + dev_err(panel->dev, "failed to set tear on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_on(jdi->link2, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (err < 0) { + dev_err(panel->dev, "failed to set tear on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_pixel_format(jdi->link1, MIPI_DCS_PIXEL_FMT_24BIT); + if (err < 0) { + dev_err(panel->dev, "failed to set pixel format: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_pixel_format(jdi->link2, MIPI_DCS_PIXEL_FMT_24BIT); + if (err < 0) { + dev_err(panel->dev, "failed to set pixel format: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link1); + if (err < 0) { + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link2); + if (err < 0) { + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); + goto poweroff; + } + + err = jdi_write_dcdc_registers(jdi); + if (err < 0) { + dev_err(panel->dev, "failed to write dcdc registers: %d\n", err); + goto poweroff; + } + /* + * We need to wait 150ms between mipi_dsi_dcs_exit_sleep_mode() and + * mipi_dsi_dcs_set_display_on(). + */ + msleep(150); + + err = mipi_dsi_dcs_set_display_on(jdi->link1); + if (err < 0) { + dev_err(panel->dev, "failed to set display on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_display_on(jdi->link2); + if (err < 0) { + dev_err(panel->dev, "failed to set display on: %d\n", err); + goto poweroff; + } + + jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM; + jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM; + + return 0; + +poweroff: + regulator_disable(jdi->ddi_supply); + + /* T6 = 2ms plus some time to discharge capacitors */ + usleep_range(7000, 9000); +supply_off: + regulator_disable(jdi->supply); + /* Specified by JDI @ 20ms, subject to change */ + msleep(20); + + return err; +} + +static int jdi_panel_enable(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + + /* + * Ensure we send image data before turning the backlight + * on, to avoid the display showing random pixels. + */ + jdi_wait_frames(jdi, 3); + + backlight_enable(jdi->backlight); + + return 0; +} + +static const struct drm_display_mode default_mode = { + .clock = (2560 + 80 + 80 + 80) * (1800 + 4 + 4 + 4) * 60 / 1000, + .hdisplay = 2560, + .hsync_start = 2560 + 80, + .hsync_end = 2560 + 80 + 80, + .htotal = 2560 + 80 + 80 + 80, + .vdisplay = 1800, + .vsync_start = 1800 + 4, + .vsync_end = 1800 + 4 + 4, + .vtotal = 1800 + 4 + 4 + 4, + .flags = 0, +}; + +static int jdi_panel_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + struct jdi_panel *jdi = to_panel_jdi(panel); + struct device *dev = &jdi->link1->dev; + + mode = drm_mode_duplicate(connector->dev, &default_mode); + if (!mode) { + dev_err(dev, "failed to add mode %ux%ux@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = 211; + connector->display_info.height_mm = 148; + connector->display_info.bpc = 8; + + return 1; +} + +static const struct drm_panel_funcs jdi_panel_funcs = { + .prepare = jdi_panel_prepare, + .enable = jdi_panel_enable, + .disable = jdi_panel_disable, + .unprepare = jdi_panel_unprepare, + .get_modes = jdi_panel_get_modes, +}; + +static const struct of_device_id jdi_of_match[] = { + { .compatible = "jdi,lpm102a188a", }, + { } +}; +MODULE_DEVICE_TABLE(of, jdi_of_match); + +static int jdi_panel_add(struct jdi_panel *jdi) +{ + struct device *dev = &jdi->link1->dev; + + jdi->mode = &default_mode; + + jdi->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(jdi->supply)) + return dev_err_probe(dev, PTR_ERR(jdi->supply), + "failed to get power regulator\n"); + + jdi->ddi_supply = devm_regulator_get(dev, "ddi"); + if (IS_ERR(jdi->ddi_supply)) + return dev_err_probe(dev, PTR_ERR(jdi->ddi_supply), + "failed to get ddi regulator\n"); + + jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(jdi->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio), + "failed to get reset gpio\n"); + /* T4 = 1ms */ + usleep_range(1000, 3000); + + jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(jdi->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio), + "failed to get enable gpio\n"); + /* T5 = 2ms */ + usleep_range(2000, 4000); + + jdi->backlight = devm_of_find_backlight(dev); + if (IS_ERR(jdi->backlight)) + return dev_err_probe(dev, PTR_ERR(jdi->backlight), + "failed to create backlight\n"); + + drm_panel_init(&jdi->base, &jdi->link1->dev, &jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + drm_panel_add(&jdi->base); + + return 0; +} + +static void jdi_panel_del(struct jdi_panel *jdi) +{ + if (jdi->base.dev) + drm_panel_remove(&jdi->base); + + if (jdi->link2) + put_device(&jdi->link2->dev); +} + +static int jdi_panel_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_device *secondary = NULL; + struct jdi_panel *jdi; + struct device_node *np; + int err; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = 0; + + /* Find DSI-LINK1 */ + np = of_parse_phandle(dsi->dev.of_node, "link2", 0); + if (np) { + secondary = of_find_mipi_dsi_device_by_node(np); + of_node_put(np); + + if (!secondary) + return -EPROBE_DEFER; + } + + /* register a panel for only the DSI-LINK1 interface */ + if (secondary) { + jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); + if (!jdi) { + put_device(&secondary->dev); + return -ENOMEM; + } + + mipi_dsi_set_drvdata(dsi, jdi); + + jdi->link1 = dsi; + jdi->link2 = secondary; + + err = jdi_panel_add(jdi); + if (err < 0) { + put_device(&secondary->dev); + return err; + } + } + + err = mipi_dsi_attach(dsi); + if (err < 0) { + if (secondary) + jdi_panel_del(jdi); + + return err; + } + + return 0; +} + +static void jdi_panel_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); + int err; + + /* only detach from host for the DSI-LINK2 interface */ + if (!jdi) + mipi_dsi_detach(dsi); + + err = jdi_panel_disable(&jdi->base); + if (err < 0) + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); + + err = mipi_dsi_detach(dsi); + if (err < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); + + jdi_panel_del(jdi); +} + +static void jdi_panel_dsi_shutdown(struct mipi_dsi_device *dsi) +{ + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); + + if (!jdi) + return; + + jdi_panel_disable(&jdi->base); +} + +static struct mipi_dsi_driver jdi_panel_dsi_driver = { + .driver = { + .name = "panel-jdi-lpm102a188a", + .of_match_table = jdi_of_match, + }, + .probe = jdi_panel_dsi_probe, + .remove = jdi_panel_dsi_remove, + .shutdown = jdi_panel_dsi_shutdown, +}; +module_mipi_dsi_driver(jdi_panel_dsi_driver); + +MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>"); +MODULE_AUTHOR("Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>"); +MODULE_DESCRIPTION("DRM Driver for JDI LPM102A188A DSI panel, command mode"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 213008499caa..f9a69f347068 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -5,10 +5,6 @@ * * Copyright (C) 2016 Linaro Ltd * Author: Sumit Semwal <sumit.semwal@linaro.org> - * - * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a - * JDI model LT070ME05000, and its data sheet is at: - * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 95959dcc6e0e..857bc01591db 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2793,6 +2793,32 @@ static const struct panel_desc mitsubishi_aa070mc01 = { .bus_flags = DRM_BUS_FLAG_DE_HIGH, }; +static const struct drm_display_mode mitsubishi_aa084xe01_mode = { + .clock = 56234, + .hdisplay = 1024, + .hsync_start = 1024 + 24, + .hsync_end = 1024 + 24 + 63, + .htotal = 1024 + 24 + 63 + 1, + .vdisplay = 768, + .vsync_start = 768 + 3, + .vsync_end = 768 + 3 + 6, + .vtotal = 768 + 3 + 6 + 1, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc mitsubishi_aa084xe01 = { + .modes = &mitsubishi_aa084xe01_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 1024, + .height = 768, + }, + .bus_format = MEDIA_BUS_FMT_RGB565_1X16, + .connector_type = DRM_MODE_CONNECTOR_DPI, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, +}; + static const struct display_timing multi_inno_mi0700s4t_6_timing = { .pixelclock = { 29000000, 33000000, 38000000 }, .hactive = { 800, 800, 800 }, @@ -4322,6 +4348,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "mitsubishi,aa070mc01-ca1", .data = &mitsubishi_aa070mc01, }, { + .compatible = "mitsubishi,aa084xe01", + .data = &mitsubishi_aa084xe01, + }, { .compatible = "multi-inno,mi0700s4t-6", .data = &multi_inno_mi0700s4t_6, }, { diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index d28b99732dde..2faa344d89ee 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -390,8 +390,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) dma_set_max_seg_size(pfdev->dev, UINT_MAX); irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); - if (irq <= 0) - return -ENODEV; + if (irq < 0) + return irq; err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index a8b4827dc425..033f5e684707 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -810,8 +810,8 @@ int panfrost_job_init(struct panfrost_device *pfdev) spin_lock_init(&js->job_lock); js->irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job"); - if (js->irq <= 0) - return -ENODEV; + if (js->irq < 0) + return js->irq; ret = devm_request_threaded_irq(pfdev->dev, js->irq, panfrost_job_irq_handler, diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index c0123d09f699..d54d4e7b2195 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -755,8 +755,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev) int err, irq; irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); - if (irq <= 0) - return -ENODEV; + if (irq < 0) + return irq; err = devm_request_threaded_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 30493ce87419..e5db4e0095ba 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -172,7 +172,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops, * Platform driver */ -static int shmob_drm_remove(struct platform_device *pdev) +static void shmob_drm_remove(struct platform_device *pdev) { struct shmob_drm_device *sdev = platform_get_drvdata(pdev); struct drm_device *ddev = sdev->ddev; @@ -181,8 +181,6 @@ static int shmob_drm_remove(struct platform_device *pdev) drm_kms_helper_poll_fini(ddev); free_irq(sdev->irq, ddev); drm_dev_put(ddev); - - return 0; } static int shmob_drm_probe(struct platform_device *pdev) @@ -288,7 +286,7 @@ err_free_drm_dev: static struct platform_driver shmob_drm_platform_driver = { .probe = shmob_drm_probe, - .remove = shmob_drm_remove, + .remove_new = shmob_drm_remove, .driver = { .name = "shmob-drm", .pm = pm_sleep_ptr(&shmob_drm_pm_ops), diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 0100162a73b2..8bafb2a2747f 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -198,6 +198,11 @@ #define RK3568_DSI1_TURNDISABLE BIT(2) #define RK3568_DSI1_FORCERXMODE BIT(0) +#define RV1126_GRF_DSIPHY_CON 0x10220 +#define RV1126_DSI_FORCETXSTOPMODE (0xf << 4) +#define RV1126_DSI_TURNDISABLE BIT(2) +#define RV1126_DSI_FORCERXMODE BIT(0) + #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) enum { @@ -1651,6 +1656,18 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { { /* sentinel */ } }; +static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = { + { + .reg = 0xffb30000, + .lanecfg1_grf_reg = RV1126_GRF_DSIPHY_CON, + .lanecfg1 = HIWORD_UPDATE(0, RV1126_DSI_TURNDISABLE | + RV1126_DSI_FORCERXMODE | + RV1126_DSI_FORCETXSTOPMODE), + .max_data_lanes = 4, + }, + { /* sentinel */ } +}; + static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { { .compatible = "rockchip,px30-mipi-dsi", @@ -1664,6 +1681,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { }, { .compatible = "rockchip,rk3568-mipi-dsi", .data = &rk3568_chip_data, + }, { + .compatible = "rockchip,rv1126-mipi-dsi", + .data = &rv1126_chip_data, }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 14320bc73e5b..e1ea50c8fd39 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -765,11 +765,6 @@ out: } } -static void vop_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); -} - static inline bool rockchip_afbc(u64 modifier) { return modifier == ROCKCHIP_AFBC_MOD; @@ -1131,7 +1126,7 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = { static const struct drm_plane_funcs vop_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = vop_plane_destroy, + .destroy = drm_plane_cleanup, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -1602,11 +1597,6 @@ static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { .atomic_disable = vop_crtc_atomic_disable, }; -static void vop_crtc_destroy(struct drm_crtc *crtc) -{ - drm_crtc_cleanup(crtc); -} - static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) { struct rockchip_crtc_state *rockchip_state; @@ -1614,7 +1604,8 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) if (WARN_ON(!crtc->state)) return NULL; - rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); + rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), + sizeof(*rockchip_state), GFP_KERNEL); if (!rockchip_state) return NULL; @@ -1639,7 +1630,10 @@ static void vop_crtc_reset(struct drm_crtc *crtc) if (crtc->state) vop_crtc_destroy_state(crtc, crtc->state); - __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); + if (crtc_state) + __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } #ifdef CONFIG_DRM_ANALOGIX_DP @@ -1710,7 +1704,7 @@ vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, static const struct drm_crtc_funcs vop_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .destroy = vop_crtc_destroy, + .destroy = drm_crtc_cleanup, .reset = vop_crtc_reset, .atomic_duplicate_state = vop_crtc_duplicate_state, .atomic_destroy_state = vop_crtc_destroy_state, @@ -1961,7 +1955,7 @@ static void vop_destroy_crtc(struct vop *vop) */ list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, head) - vop_plane_destroy(plane); + drm_plane_cleanup(plane); /* * Destroy CRTC after vop_plane_destroy() since vop_disable_plane() diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 583df4d22f7e..c306806aa3de 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2079,30 +2079,15 @@ static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { .atomic_disable = vop2_crtc_atomic_disable, }; -static void vop2_crtc_reset(struct drm_crtc *crtc) -{ - struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); - - if (crtc->state) { - __drm_atomic_helper_crtc_destroy_state(crtc->state); - kfree(vcstate); - } - - vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL); - if (!vcstate) - return; - - crtc->state = &vcstate->base; - crtc->state->crtc = crtc; -} - static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) { - struct rockchip_crtc_state *vcstate, *old_vcstate; + struct rockchip_crtc_state *vcstate; - old_vcstate = to_rockchip_crtc_state(crtc->state); + if (WARN_ON(!crtc->state)) + return NULL; - vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL); + vcstate = kmemdup(to_rockchip_crtc_state(crtc->state), + sizeof(*vcstate), GFP_KERNEL); if (!vcstate) return NULL; @@ -2120,6 +2105,20 @@ static void vop2_crtc_destroy_state(struct drm_crtc *crtc, kfree(vcstate); } +static void vop2_crtc_reset(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *vcstate = + kzalloc(sizeof(*vcstate), GFP_KERNEL); + + if (crtc->state) + vop2_crtc_destroy_state(crtc, crtc->state); + + if (vcstate) + __drm_atomic_helper_crtc_reset(crtc, &vcstate->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); +} + static const struct drm_crtc_funcs vop2_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 7b2805006776..d053ef027552 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -1120,6 +1120,59 @@ static const struct vop_data rk3328_vop = { .max_output = { 4096, 2160 }, }; +static const struct vop_common rv1126_common = { + .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14), + .dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6), + .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0), + .dither_up = VOP_REG(PX30_DSP_CTRL2, 0x1, 2), + .dsp_lut_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 5), + .gate_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 0), +}; + +static const struct vop_modeset rv1126_modeset = { + .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rv1126_output = { + .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1), + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2), + .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26), + .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), +}; + +static const struct vop_misc rv1126_misc = { + .global_regdone_en = VOP_REG(PX30_SYS_CTRL2, 0x1, 13), +}; + +static const struct vop_win_data rv1126_vop_win_data[] = { + { .base = 0x00, .phy = &px30_win0_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &px30_win2_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data rv1126_vop = { + .version = VOP_VERSION(2, 0xb), + .intr = &px30_intr, + .common = &rv1126_common, + .modeset = &rv1126_modeset, + .output = &rv1126_output, + .misc = &rv1126_misc, + .win = rv1126_vop_win_data, + .win_size = ARRAY_SIZE(rv1126_vop_win_data), + .max_output = { 1920, 1080 }, + .lut_size = 1024, +}; + static const struct of_device_id vop_driver_dt_match[] = { { .compatible = "rockchip,rk3036-vop", .data = &rk3036_vop }, @@ -1147,6 +1200,8 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &rk3228_vop }, { .compatible = "rockchip,rk3328-vop", .data = &rk3328_vop }, + { .compatible = "rockchip,rv1126-vop", + .data = &rv1126_vop }, {}, }; MODULE_DEVICE_TABLE(of, vop_driver_dt_match); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 5a80b228d18c..3b4dde09538a 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -272,8 +272,8 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) /* Enable the PWM */ pwm_enable(ssd130x->pwm); - dev_dbg(dev, "Using PWM%d with a %lluns period.\n", - ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm)); + dev_dbg(dev, "Using PWM %s with a %lluns period.\n", + ssd130x->pwm->label, pwm_get_period(ssd130x->pwm)); return 0; } @@ -553,14 +553,45 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, struct ssd130x_plane_state *ssd130x_state) { - struct drm_rect fullscreen = { - .x1 = 0, - .x2 = ssd130x->width, - .y1 = 0, - .y2 = ssd130x->height, - }; - - ssd130x_update_rect(ssd130x, ssd130x_state, &fullscreen); + unsigned int page_height = ssd130x->device_info->page_height; + unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height); + u8 *data_array = ssd130x_state->data_array; + unsigned int width = ssd130x->width; + int ret, i; + + if (!ssd130x->page_address_mode) { + memset(data_array, 0, width * pages); + + /* Set address range for horizontal addressing mode */ + ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset, width); + if (ret < 0) + return; + + ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset, pages); + if (ret < 0) + return; + + /* Write out update in one go if we aren't using page addressing mode */ + ssd130x_write_data(ssd130x, data_array, width * pages); + } else { + /* + * In page addressing mode, the start address needs to be reset, + * and each page then needs to be written out separately. + */ + memset(data_array, 0, width); + + for (i = 0; i < pages; i++) { + ret = ssd130x_set_page_pos(ssd130x, + ssd130x->page_offset + i, + ssd130x->col_offset); + if (ret < 0) + return; + + ret = ssd130x_write_data(ssd130x, data_array, width); + if (ret < 0) + return; + } + } } static int ssd130x_fb_blit_rect(struct drm_plane_state *state, diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index 87968b3e7fb8..aa39b13615eb 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -40,8 +40,8 @@ struct ssd130x_deviceinfo { u32 default_width; u32 default_height; u32 page_height; - int need_pwm; - int need_chargepump; + bool need_pwm; + bool need_chargepump; bool page_mode_only; }; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 13b182ab905f..be61c9d1a4f0 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1746,8 +1746,15 @@ static void tegra_dc_early_unregister(struct drm_crtc *crtc) unsigned int count = ARRAY_SIZE(debugfs_files); struct drm_minor *minor = crtc->dev->primary; struct tegra_dc *dc = to_tegra_dc(crtc); + struct dentry *root; + +#ifdef CONFIG_DEBUG_FS + root = crtc->debugfs_entry; +#else + root = NULL; +#endif - drm_debugfs_remove_files(dc->debugfs_files, count, minor); + drm_debugfs_remove_files(dc->debugfs_files, count, root, minor); kfree(dc->debugfs_files); dc->debugfs_files = NULL; } diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index a9870c828374..fbfe92a816d4 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -256,6 +256,7 @@ static void tegra_dsi_early_unregister(struct drm_connector *connector) struct tegra_dsi *dsi = to_dsi(output); drm_debugfs_remove_files(dsi->debugfs_files, count, + connector->debugfs_entry, connector->dev->primary); kfree(dsi->debugfs_files); dsi->debugfs_files = NULL; diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 80c760986d9e..0ba3ca3ac509 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1116,7 +1116,8 @@ static void tegra_hdmi_early_unregister(struct drm_connector *connector) unsigned int count = ARRAY_SIZE(debugfs_files); struct tegra_hdmi *hdmi = to_hdmi(output); - drm_debugfs_remove_files(hdmi->debugfs_files, count, minor); + drm_debugfs_remove_files(hdmi->debugfs_files, count, + connector->debugfs_entry, minor); kfree(hdmi->debugfs_files); hdmi->debugfs_files = NULL; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 61b437a84806..d5a3d3f4fece 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1708,6 +1708,7 @@ static void tegra_sor_early_unregister(struct drm_connector *connector) struct tegra_sor *sor = to_sor(output); drm_debugfs_remove_files(sor->debugfs_files, count, + connector->debugfs_entry, connector->dev->primary); kfree(sor->debugfs_files); sor->debugfs_files = NULL; diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 474bb7a1c4ee..1a6bd291345d 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -3,11 +3,13 @@ #include <kunit/test.h> #include <drm/drm_device.h> +#include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_format_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_kunit_helpers.h> #include <drm/drm_mode.h> #include <drm/drm_print.h> #include <drm/drm_rect.h> @@ -16,6 +18,8 @@ #define TEST_BUF_SIZE 50 +#define TEST_USE_DEFAULT_PITCH 0 + struct convert_to_gray8_result { unsigned int dst_pitch; const u8 expected[TEST_BUF_SIZE]; @@ -72,6 +76,11 @@ struct convert_to_mono_result { const u8 expected[TEST_BUF_SIZE]; }; +struct fb_swab_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + struct convert_xrgb8888_case { const char *name; unsigned int pitch; @@ -88,6 +97,7 @@ struct convert_xrgb8888_case { struct convert_to_xrgb2101010_result xrgb2101010_result; struct convert_to_argb2101010_result argb2101010_result; struct convert_to_mono_result mono_result; + struct fb_swab_result swab_result; }; static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { @@ -97,50 +107,54 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .clip = DRM_RECT_INIT(0, 0, 1, 1), .xrgb8888 = { 0x01FF0000 }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x4C }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xE0 }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7C00 }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFC00 }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF801 }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x00, 0x00, 0xFF }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF0000 }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FF00000 }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFF00000 }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b0 }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x0000FF01 }, + }, }, { .name = "single_pixel_clip_rectangle", @@ -151,50 +165,54 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x10FF0000, }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x4C }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xE0 }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7C00 }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFC00 }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF801 }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x00, 0x00, 0xFF }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF0000 }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FF00000 }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFF00000 }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b0 }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x0000FF10 }, + }, }, { /* Well known colors: White, black, red, green, blue, magenta, @@ -212,7 +230,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0x00, 0x4C, 0x99, @@ -221,7 +239,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0x00, 0xE0, 0x1C, @@ -230,7 +248,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x0000, 0xF800, 0x07E0, @@ -245,7 +263,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7FFF, 0x0000, 0x7C00, 0x03E0, @@ -254,7 +272,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x8000, 0xFC00, 0x83E0, @@ -263,7 +281,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x0001, 0xF801, 0x07C1, @@ -272,7 +290,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, @@ -281,7 +299,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFFFFFF, 0xFF000000, 0xFFFF0000, 0xFF00FF00, @@ -290,7 +308,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FFFFFFF, 0x00000000, 0x3FF00000, 0x000FFC00, @@ -299,7 +317,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFFFFFF, 0xC0000000, 0xFFF00000, 0xC00FFC00, @@ -308,7 +326,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b01, 0b10, @@ -316,6 +334,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0b11, }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0xFFFFFF11, 0x00000022, + 0x0000FF33, 0x00FF0044, + 0xFF000055, 0xFF00FF66, + 0x00FFFF77, 0xFFFF0088, + }, + }, }, { /* Randomly picked colors. Full buffer within the clip area. */ @@ -423,6 +450,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0b010, 0b000, }, }, + .swab_result = { + .dst_pitch = 20, + .expected = { + 0x9C440EA1, 0x054D11B1, 0x03F3A8C1, 0x00000000, 0x00000000, + 0x73F06CD1, 0x9C440EA2, 0x054D11B2, 0x00000000, 0x00000000, + 0x0303A8C2, 0x73F06CD2, 0x9C440EA3, 0x00000000, 0x00000000, + }, + }, }, }; @@ -437,7 +472,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { * The size of the destination buffer or negative value on error. */ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, - const struct drm_rect *clip) + const struct drm_rect *clip, int plane) { const struct drm_format_info *dst_fi = drm_format_info(dst_format); @@ -445,7 +480,7 @@ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, return -EINVAL; if (!dst_pitch) - dst_pitch = drm_format_info_min_pitch(dst_fi, 0, drm_rect_width(clip)); + dst_pitch = drm_format_info_min_pitch(dst_fi, plane, drm_rect_width(clip)); return dst_pitch * drm_rect_height(clip); } @@ -519,7 +554,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -530,7 +565,11 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -549,7 +588,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -560,7 +599,10 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -579,7 +621,7 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -590,7 +632,10 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -615,7 +660,7 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_XRGB1555, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -626,7 +671,10 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_xrgb1555(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -646,7 +694,7 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB1555, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -657,7 +705,10 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb1555(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -677,7 +728,7 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGBA5551, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -688,7 +739,10 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgba5551(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -708,7 +762,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -723,7 +777,10 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) * RGB888 expected results are already in little-endian * order, so there's no need to convert the test output. */ - drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -742,7 +799,7 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB8888, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -753,7 +810,10 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb8888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -773,7 +833,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -784,7 +844,10 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -804,7 +867,7 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB2101010, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -815,7 +878,10 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -834,7 +900,7 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) .pitches = { params->pitch, 0, 0 }, }; - dst_size = conversion_buf_size(DRM_FORMAT_C1, result->dst_pitch, ¶ms->clip); + dst_size = conversion_buf_size(DRM_FORMAT_C1, result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); @@ -846,10 +912,639 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_mono(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } +static void drm_test_fb_swab(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct fb_swab_result *result = ¶ms->swab_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XRGB8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_swab(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + +struct clip_offset_case { + const char *name; + unsigned int pitch; + u32 format; + struct drm_rect clip; + unsigned int expected_offset; +}; + +static struct clip_offset_case clip_offset_cases[] = { + { + .name = "pass through", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .expected_offset = 0 + }, + { + .name = "horizontal offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 0, 3, 3), + .expected_offset = 4, + }, + { + .name = "vertical offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 1, 3, 3), + .expected_offset = 12, + }, + { + .name = "horizontal and vertical offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 1, 3, 3), + .expected_offset = 16, + }, + { + .name = "horizontal offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 0, 3, 3), + .expected_offset = 4, + }, + { + .name = "vertical offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 1, 3, 3), + .expected_offset = 20, + }, + { + .name = "horizontal and vertical offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 1, 3, 3), + .expected_offset = 24, + }, +}; + +static void clip_offset_case_desc(struct clip_offset_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(clip_offset, clip_offset_cases, clip_offset_case_desc); + +static void drm_test_fb_clip_offset(struct kunit *test) +{ + const struct clip_offset_case *params = test->param_value; + const struct drm_format_info *format_info = drm_format_info(params->format); + + unsigned int offset; + unsigned int pitch = params->pitch; + + if (pitch == TEST_USE_DEFAULT_PITCH) + pitch = drm_format_info_min_pitch(format_info, 0, + drm_rect_width(¶ms->clip)); + + /* + * Assure that the pitch is not zero, because this will inevitable cause the + * wrong expected result + */ + KUNIT_ASSERT_NE(test, pitch, 0); + + offset = drm_fb_clip_offset(pitch, format_info, ¶ms->clip); + + KUNIT_EXPECT_EQ(test, offset, params->expected_offset); +} + +struct fb_build_fourcc_list_case { + const char *name; + u32 native_fourccs[TEST_BUF_SIZE]; + size_t native_fourccs_size; + u32 expected[TEST_BUF_SIZE]; + size_t expected_fourccs_size; +}; + +static struct fb_build_fourcc_list_case fb_build_fourcc_list_cases[] = { + { + .name = "no native formats", + .native_fourccs = { }, + .native_fourccs_size = 0, + .expected = { DRM_FORMAT_XRGB8888 }, + .expected_fourccs_size = 1, + }, + { + .name = "XRGB8888 as native format", + .native_fourccs = { DRM_FORMAT_XRGB8888 }, + .native_fourccs_size = 1, + .expected = { DRM_FORMAT_XRGB8888 }, + .expected_fourccs_size = 1, + }, + { + .name = "remove duplicates", + .native_fourccs = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + }, + .native_fourccs_size = 11, + .expected = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + }, + .expected_fourccs_size = 3, + }, + { + .name = "convert alpha formats", + .native_fourccs = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_RGBA1010102, + DRM_FORMAT_BGRA1010102, + }, + .native_fourccs_size = 12, + .expected = { + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_BGRX5551, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_RGBX1010102, + DRM_FORMAT_BGRX1010102, + }, + .expected_fourccs_size = 12, + }, + { + .name = "random formats", + .native_fourccs = { + DRM_FORMAT_Y212, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_C8, + DRM_FORMAT_BGR888, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_R10, + DRM_FORMAT_XYUV8888, + }, + .native_fourccs_size = 10, + .expected = { + DRM_FORMAT_Y212, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_C8, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_R10, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XRGB8888, + }, + .expected_fourccs_size = 10, + }, +}; + +static void fb_build_fourcc_list_case_desc(struct fb_build_fourcc_list_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(fb_build_fourcc_list, fb_build_fourcc_list_cases, fb_build_fourcc_list_case_desc); + +static void drm_test_fb_build_fourcc_list(struct kunit *test) +{ + const struct fb_build_fourcc_list_case *params = test->param_value; + u32 fourccs_out[TEST_BUF_SIZE] = {0}; + size_t nfourccs_out; + struct drm_device *drm; + struct device *dev; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0, DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + nfourccs_out = drm_fb_build_fourcc_list(drm, params->native_fourccs, + params->native_fourccs_size, + fourccs_out, TEST_BUF_SIZE); + + KUNIT_EXPECT_EQ(test, nfourccs_out, params->expected_fourccs_size); + KUNIT_EXPECT_MEMEQ(test, fourccs_out, params->expected, TEST_BUF_SIZE); +} + +struct fb_memcpy_case { + const char *name; + u32 format; + struct drm_rect clip; + unsigned int src_pitches[DRM_FORMAT_MAX_PLANES]; + const u32 src[DRM_FORMAT_MAX_PLANES][TEST_BUF_SIZE]; + unsigned int dst_pitches[DRM_FORMAT_MAX_PLANES]; + const u32 expected[DRM_FORMAT_MAX_PLANES][TEST_BUF_SIZE]; +}; + +/* The `src` and `expected` buffers are u32 arrays. To deal with planes that + * have a cpp != 4 the values are stored together on the same u32 number in a + * way so the order in memory is correct in a little-endian machine. + * + * Because of that, on some occasions, parts of a u32 will not be part of the + * test, to make this explicit the 0xFF byte is used on those parts. + */ + +static struct fb_memcpy_case fb_memcpy_cases[] = { + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1 * 4 }, + .src = {{ 0x01020304 }}, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = {{ 0x01020304 }}, + }, + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1 * 4, 1 }, + .src = { + { 0x01020304 }, + { 0xFFFFFF01 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1, 1, 1 }, + .src = { + { 0xFFFFFF01 }, + { 0xFFFFFF01 }, + { 0xFFFFFF01 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x00000001 }, + { 0x00000001 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 4 }, + .src = { + { + 0x00000000, 0x00000000, + 0x00000000, 0x01020304, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 4, 2 * 1 }, + .src = { + { + 0x00000000, 0x00000000, + 0x00000000, 0x01020304, + }, + { 0x01000000 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 1, 2 * 1, 2 * 1 }, + .src = { + { 0x01000000 }, + { 0x01000000 }, + { 0x01000000 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x00000001 }, + { 0x00000001 }, + { 0x00000001 }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 4 }, + .src = { + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x11FFFFFF, 0x22000000, 0x00000000, + 0x00000000, 0x33FF0000, 0x4400FF00, 0x00000000, + 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000, + 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0x11FFFFFF, 0x22000000, + 0x33FF0000, 0x4400FF00, + 0x550000FF, 0x66FF00FF, + 0x77FFFF00, 0x8800FFFF, + }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 4, 4 * 1 }, + .src = { + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFF000000, 0x00000000, + 0x00000000, 0xFFFF0000, 0xFF00FF00, 0x00000000, + 0x00000000, 0xFF0000FF, 0xFFFF00FF, 0x00000000, + 0x00000000, 0xFFFFFF00, 0xFF00FFFF, 0x00000000, + }, + { + 0x00000000, + 0x00221100, + 0x00443300, + 0x00665500, + 0x00887700, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0xFFFFFFFF, 0xFF000000, + 0xFFFF0000, 0xFF00FF00, + 0xFF0000FF, 0xFFFF00FF, + 0xFFFFFF00, 0xFF00FFFF, + }, + { + 0x44332211, + 0x88776655, + }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 1, 4 * 1, 4 * 1 }, + .src = { + { + 0x00000000, + 0x0000FF00, + 0x00954C00, + 0x00691D00, + 0x00B2E100, + }, + { + 0x00000000, + 0x00000000, + 0x00BEDE00, + 0x00436500, + 0x00229B00, + }, + { + 0x00000000, + 0x00000000, + 0x007E9C00, + 0x0083E700, + 0x00641A00, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0x954C00FF, + 0xB2E1691D, + }, + { + 0xBEDE0000, + 0x229B4365, + }, + { + 0x7E9C0000, + 0x641A83E7, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 4 }, + .src = { + { + 0xA10E449C, 0xB1114D05, 0xC1A8F303, + 0xD16CF073, 0xA20E449C, 0xB2114D05, + 0xC2A80303, 0xD26CF073, 0xA30E449C, + }, + }, + .dst_pitches = { 5 * 4 }, + .expected = { + { + 0xA10E449C, 0xB1114D05, 0xC1A8F303, 0x00000000, 0x00000000, + 0xD16CF073, 0xA20E449C, 0xB2114D05, 0x00000000, 0x00000000, + 0xC2A80303, 0xD26CF073, 0xA30E449C, 0x00000000, 0x00000000, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 4, 3 * 1 }, + .src = { + { + 0xFF0E449C, 0xFF114D05, 0xFFA8F303, + 0xFF6CF073, 0xFF0E449C, 0xFF114D05, + 0xFFA80303, 0xFF6CF073, 0xFF0E449C, + }, + { + 0xB2C1B1A1, + 0xD2A3D1A2, + 0xFFFFFFC2, + }, + }, + .dst_pitches = { 5 * 4, 5 * 1 }, + .expected = { + { + 0xFF0E449C, 0xFF114D05, 0xFFA8F303, 0x00000000, 0x00000000, + 0xFF6CF073, 0xFF0E449C, 0xFF114D05, 0x00000000, 0x00000000, + 0xFFA80303, 0xFF6CF073, 0xFF0E449C, 0x00000000, 0x00000000, + }, + { + 0x00C1B1A1, + 0xD1A2B200, + 0xD2A30000, + 0xFF0000C2, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 1, 3 * 1, 3 * 1 }, + .src = { + { + 0xBAC1323D, + 0xBA34323D, + 0xFFFFFF3D, + }, + { + 0xE1ABEC2A, + 0xE1EAEC2A, + 0xFFFFFF2A, + }, + { + 0xBCEBE4D7, + 0xBC65E4D7, + 0xFFFFFFD7, + }, + }, + .dst_pitches = { 5 * 1, 5 * 1, 5 * 1 }, + .expected = { + { + 0x00C1323D, + 0x323DBA00, + 0xBA340000, + 0xFF00003D, + }, + { + 0x00ABEC2A, + 0xEC2AE100, + 0xE1EA0000, + 0xFF00002A, + }, + { + 0x00EBE4D7, + 0xE4D7BC00, + 0xBC650000, + 0xFF0000D7, + }, + }, + }, +}; + +static void fb_memcpy_case_desc(struct fb_memcpy_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s: %p4cc", t->name, &t->format); +} + +KUNIT_ARRAY_PARAM(fb_memcpy, fb_memcpy_cases, fb_memcpy_case_desc); + +static void drm_test_fb_memcpy(struct kunit *test) +{ + const struct fb_memcpy_case *params = test->param_value; + size_t dst_size[DRM_FORMAT_MAX_PLANES] = { 0 }; + u32 *buf[DRM_FORMAT_MAX_PLANES] = { 0 }; + __le32 *src_cp[DRM_FORMAT_MAX_PLANES] = { 0 }; + __le32 *expected[DRM_FORMAT_MAX_PLANES] = { 0 }; + struct iosys_map dst[DRM_FORMAT_MAX_PLANES]; + struct iosys_map src[DRM_FORMAT_MAX_PLANES]; + + struct drm_framebuffer fb = { + .format = drm_format_info(params->format), + }; + + memcpy(fb.pitches, params->src_pitches, DRM_FORMAT_MAX_PLANES * sizeof(int)); + + for (size_t i = 0; i < fb.format->num_planes; i++) { + dst_size[i] = conversion_buf_size(params->format, params->dst_pitches[i], + ¶ms->clip, i); + KUNIT_ASSERT_GT(test, dst_size[i], 0); + + buf[i] = kunit_kzalloc(test, dst_size[i], GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf[i]); + iosys_map_set_vaddr(&dst[i], buf[i]); + + src_cp[i] = cpubuf_to_le32(test, params->src[i], TEST_BUF_SIZE); + iosys_map_set_vaddr(&src[i], src_cp[i]); + } + + const unsigned int *dst_pitches = params->dst_pitches[0] == TEST_USE_DEFAULT_PITCH ? NULL : + params->dst_pitches; + + drm_fb_memcpy(dst, dst_pitches, src, &fb, ¶ms->clip); + + for (size_t i = 0; i < fb.format->num_planes; i++) { + expected[i] = cpubuf_to_le32(test, params->expected[i], TEST_BUF_SIZE); + KUNIT_EXPECT_MEMEQ_MSG(test, buf[i], expected[i], dst_size[i], + "Failed expectation on plane %zu", i); + } +} + static struct kunit_case drm_format_helper_test_cases[] = { KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params), @@ -862,6 +1557,10 @@ static struct kunit_case drm_format_helper_test_cases[] = { KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_mono, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_swab, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_clip_offset, clip_offset_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_build_fourcc_list, fb_build_fourcc_list_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_memcpy, fb_memcpy_gen_params), {} }; diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 13ae148f59b9..73dd4f4289c2 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -949,7 +949,7 @@ static int repaper_probe(struct spi_device *spi) match = device_get_match_data(dev); if (match) { - model = (enum repaper_model)match; + model = (enum repaper_model)(uintptr_t)match; } else { spi_id = spi_get_device_id(spi); model = (enum repaper_model)spi_id->driver_data; diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 4126c384286b..8513b671f871 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -344,8 +344,6 @@ void virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj, struct virtio_gpu_mem_entry *ents, unsigned int nents); -int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev); -int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev); void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, struct virtio_gpu_output *output); int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev); @@ -394,11 +392,8 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_fence *fence); void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); -void virtio_gpu_fence_ack(struct virtqueue *vq); void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work); -void virtio_gpu_dequeue_fence_func(struct work_struct *work); - void virtio_gpu_notify(struct virtio_gpu_device *vgdev); int @@ -465,8 +460,6 @@ struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, int flags); struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, struct dma_buf *buf); -int virtgpu_gem_prime_get_uuid(struct drm_gem_object *obj, - uuid_t *uuid); struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 0cea301cc9a9..fbcc4b45cff5 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -878,11 +878,7 @@ config HID_PICOLCD_FB default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=FB || FB=y - select FB_DEFERRED_IO - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS_DEFERRED help Provide access to PicoLCD's 256x64 monochrome display via a framebuffer device. @@ -1044,7 +1040,7 @@ config HID_SONY * Guitar Hero PS3 and PC guitar dongles config SONY_FF - bool "Sony PS2/3/4 accessories force feedback support" + bool "Sony PS2/3/4 accessories force feedback support" depends on HID_SONY select INPUT_FF_MEMLESS help diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index d726aaafb146..a4dccdcda26f 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -283,54 +283,6 @@ out: mutex_unlock(&info->lock); } -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - if (!info->par) - return; - sys_fillrect(info, rect); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - if (!info->par) - return; - sys_copyarea(info, area); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* Stub to call the system default and update the image on the picoLCD */ -static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - if (!info->par) - return; - sys_imageblit(info, image); - - schedule_delayed_work(&info->deferred_work, 0); -} - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it's inefficient to do anything less than a full screen draw - */ -static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - if (!info->par) - return -ENODEV; - ret = fb_sys_write(info, buf, count, ppos); - if (ret >= 0) - schedule_delayed_work(&info->deferred_work, 0); - return ret; -} - static int picolcd_fb_blank(int blank, struct fb_info *info) { /* We let fb notification do this for us via lcd/backlight device */ @@ -417,18 +369,31 @@ static int picolcd_set_par(struct fb_info *info) return 0; } +static void picolcdfb_ops_damage_range(struct fb_info *info, off_t off, size_t len) +{ + if (!info->par) + return; + schedule_delayed_work(&info->deferred_work, 0); +} + +static void picolcdfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + if (!info->par) + return; + schedule_delayed_work(&info->deferred_work, 0); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(picolcdfb_ops, + picolcdfb_ops_damage_range, + picolcdfb_ops_damage_area) + static const struct fb_ops picolcdfb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(picolcdfb_ops), .fb_destroy = picolcd_fb_destroy, - .fb_read = fb_sys_read, - .fb_write = picolcd_fb_write, .fb_blank = picolcd_fb_blank, - .fb_fillrect = picolcd_fb_fillrect, - .fb_copyarea = picolcd_fb_copyarea, - .fb_imageblit = picolcd_fb_imageblit, .fb_check_var = picolcd_fb_check_var, .fb_set_par = picolcd_set_par, - .fb_mmap = fb_deferred_io_mmap, }; diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index 5dda3c65a38e..77ab44362f16 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -4,12 +4,8 @@ menuconfig FB_TFT depends on FB && SPI depends on FB_DEVICE depends on GPIOLIB || COMPILE_TEST - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO select FB_BACKLIGHT + select FB_SYSMEM_HELPERS_DEFERRED config FB_TFT_AGM1264K_FL tristate "FB driver for the AGM1264K-FL LCD display" diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index eac1d570f437..3626f429b002 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -357,61 +357,6 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagereflis dirty_lines_start, dirty_lines_end); } -static void fbtft_fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct fbtft_par *par = info->par; - - dev_dbg(info->dev, - "%s: dx=%d, dy=%d, width=%d, height=%d\n", - __func__, rect->dx, rect->dy, rect->width, rect->height); - sys_fillrect(info, rect); - - par->fbtftops.mkdirty(info, rect->dy, rect->height); -} - -static void fbtft_fb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct fbtft_par *par = info->par; - - dev_dbg(info->dev, - "%s: dx=%d, dy=%d, width=%d, height=%d\n", - __func__, area->dx, area->dy, area->width, area->height); - sys_copyarea(info, area); - - par->fbtftops.mkdirty(info, area->dy, area->height); -} - -static void fbtft_fb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct fbtft_par *par = info->par; - - dev_dbg(info->dev, - "%s: dx=%d, dy=%d, width=%d, height=%d\n", - __func__, image->dx, image->dy, image->width, image->height); - sys_imageblit(info, image); - - par->fbtftops.mkdirty(info, image->dy, image->height); -} - -static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct fbtft_par *par = info->par; - ssize_t res; - - dev_dbg(info->dev, - "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos); - res = fb_sys_write(info, buf, count, ppos); - - /* TODO: only mark changed area update all for now */ - par->fbtftops.mkdirty(info, -1, 0); - - return res; -} - /* from pxafb.c */ static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) { @@ -473,6 +418,32 @@ static int fbtft_fb_blank(int blank, struct fb_info *info) return ret; } +static void fbtft_ops_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct fbtft_par *par = info->par; + + /* TODO: only mark changed area update all for now */ + par->fbtftops.mkdirty(info, -1, 0); +} + +static void fbtft_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + struct fbtft_par *par = info->par; + + par->fbtftops.mkdirty(info, y, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(fbtft_ops, + fbtft_ops_damage_range, + fbtft_ops_damage_area) + +static const struct fb_ops fbtft_ops = { + .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(fbtft_ops), + .fb_setcolreg = fbtft_fb_setcolreg, + .fb_blank = fbtft_fb_blank, +}; + static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) { if (src->write) @@ -521,7 +492,6 @@ static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) * Creates a new frame buffer info structure. * * Also creates and populates the following structures: - * info->fbops * info->fbdefio * info->pseudo_palette * par->fbtftops @@ -536,7 +506,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, { struct fb_info *info; struct fbtft_par *par; - struct fb_ops *fbops = NULL; struct fb_deferred_io *fbdefio = NULL; u8 *vmem = NULL; void *txbuf = NULL; @@ -611,10 +580,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, if (!vmem) goto alloc_fail; - fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL); - if (!fbops) - goto alloc_fail; - fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL); if (!fbdefio) goto alloc_fail; @@ -638,19 +603,9 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, goto alloc_fail; info->screen_buffer = vmem; - info->fbops = fbops; + info->fbops = &fbtft_ops; info->fbdefio = fbdefio; - fbops->owner = dev->driver->owner; - fbops->fb_read = fb_sys_read; - fbops->fb_write = fbtft_fb_write; - fbops->fb_fillrect = fbtft_fb_fillrect; - fbops->fb_copyarea = fbtft_fb_copyarea; - fbops->fb_imageblit = fbtft_fb_imageblit; - fbops->fb_setcolreg = fbtft_fb_setcolreg; - fbops->fb_blank = fbtft_fb_blank; - fbops->fb_mmap = fb_deferred_io_mmap; - fbdefio->delay = HZ / fps; fbdefio->sort_pagereflist = true; fbdefio->deferred_io = fbtft_deferred_io; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index eac0ba39581e..e2a8d9bc0679 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -518,21 +518,23 @@ config FB_SBUS help Say Y if you want support for SBUS or UPA based frame buffer device. +config FB_SBUS_HELPERS + bool + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + config FB_BW2 bool "BWtwo support" depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the BWtwo frame buffer. config FB_CG3 bool "CGthree support" depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the CGthree frame buffer. @@ -557,9 +559,7 @@ config FB_FFB config FB_TCX bool "TCX (SS4/SS5 only) support" depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the TCX 24/8bit frame buffer. @@ -567,9 +567,7 @@ config FB_TCX config FB_CG14 bool "CGfourteen (SX) support" depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the CGfourteen frame buffer on Desktop SPARCsystems with the SX graphics option. @@ -577,9 +575,7 @@ config FB_CG14 config FB_P9100 bool "P9100 (Sparcbook 3 only) support" depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the P9100 card supported on Sparcbook 3 machines. @@ -587,9 +583,7 @@ config FB_P9100 config FB_LEO bool "Leo (ZX) support" depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SBUS_HELPERS help This is the frame buffer device driver for the SBUS-based Sun ZX (leo) frame buffer cards. @@ -1900,11 +1894,8 @@ config FB_BROADSHEET config FB_HYPERV tristate "Microsoft Hyper-V Synthetic Video support" depends on FB && HYPERV - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DEFERRED_IO select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA + select FB_IOMEM_HELPERS_DEFERRED select VIDEO_NOMODESET help This framebuffer driver supports Microsoft Hyper-V Synthetic Video. diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 70569f7027ed..8e15220152bd 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -8,6 +8,7 @@ obj-y += core/ obj-$(CONFIG_FB_MACMODES) += macmodes.o +obj-$(CONFIG_FB_SBUS) += sbuslib.o obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o # Hardware specific drivers go first @@ -45,14 +46,14 @@ obj-$(CONFIG_FB_LE80578) += vermilion/ obj-$(CONFIG_FB_S3) += s3fb.o obj-$(CONFIG_FB_ARK) += arkfb.o obj-$(CONFIG_FB_STI) += stifb.o -obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o -obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o -obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o -obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o -obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o -obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o -obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o -obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o +obj-$(CONFIG_FB_FFB) += ffb.o +obj-$(CONFIG_FB_CG6) += cg6.o +obj-$(CONFIG_FB_CG3) += cg3.o +obj-$(CONFIG_FB_BW2) += bw2.o +obj-$(CONFIG_FB_CG14) += cg14.o +obj-$(CONFIG_FB_P9100) += p9100.o +obj-$(CONFIG_FB_TCX) += tcx.o +obj-$(CONFIG_FB_LEO) += leo.o obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o diff --git a/drivers/video/fbdev/bw2.c b/drivers/video/fbdev/bw2.c index de34f1f333e2..eaab51be74f8 100644 --- a/drivers/video/fbdev/bw2.c +++ b/drivers/video/fbdev/bw2.c @@ -31,8 +31,8 @@ static int bw2_blank(int, struct fb_info *); -static int bw2_mmap(struct fb_info *, struct vm_area_struct *); -static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long); +static int bw2_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int bw2_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); /* * Frame buffer operations @@ -40,15 +40,8 @@ static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long); static const struct fb_ops bw2_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(bw2), .fb_blank = bw2_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = bw2_mmap, - .fb_ioctl = bw2_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; /* OBio addresses for the bwtwo registers */ @@ -161,7 +154,7 @@ static struct sbus_mmap_map bw2_mmap_map[] = { { .size = 0 } }; -static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int bw2_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct bw2_par *par = (struct bw2_par *)info->par; @@ -171,7 +164,7 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) vma); } -static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int bw2_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUN2BW, 1, info->fix.smem_len); diff --git a/drivers/video/fbdev/cg14.c b/drivers/video/fbdev/cg14.c index c0336c051c24..c161b2af8933 100644 --- a/drivers/video/fbdev/cg14.c +++ b/drivers/video/fbdev/cg14.c @@ -31,27 +31,20 @@ static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); - -static int cg14_mmap(struct fb_info *, struct vm_area_struct *); -static int cg14_ioctl(struct fb_info *, unsigned int, unsigned long); static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static int cg14_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int cg14_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* * Frame buffer operations */ static const struct fb_ops cg14_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(cg14), .fb_setcolreg = cg14_setcolreg, .fb_pan_display = cg14_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = cg14_mmap, - .fb_ioctl = cg14_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; #define CG14_MCR_INTENABLE_SHIFT 7 @@ -265,7 +258,7 @@ static int cg14_setcolreg(unsigned regno, return 0; } -static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int cg14_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct cg14_par *par = (struct cg14_par *) info->par; @@ -274,7 +267,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) par->iospace, vma); } -static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int cg14_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct cg14_par *par = (struct cg14_par *) info->par; struct cg14_regs __iomem *regs = par->regs; diff --git a/drivers/video/fbdev/cg3.c b/drivers/video/fbdev/cg3.c index 0a897d5be334..5e1f1b9a81b6 100644 --- a/drivers/video/fbdev/cg3.c +++ b/drivers/video/fbdev/cg3.c @@ -33,8 +33,8 @@ static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int cg3_blank(int, struct fb_info *); -static int cg3_mmap(struct fb_info *, struct vm_area_struct *); -static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long); +static int cg3_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int cg3_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); /* * Frame buffer operations @@ -42,16 +42,9 @@ static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long); static const struct fb_ops cg3_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(cg3), .fb_setcolreg = cg3_setcolreg, .fb_blank = cg3_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = cg3_mmap, - .fb_ioctl = cg3_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; @@ -225,7 +218,7 @@ static struct sbus_mmap_map cg3_mmap_map[] = { { .size = 0 } }; -static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int cg3_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct cg3_par *par = (struct cg3_par *)info->par; @@ -235,7 +228,7 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) vma); } -static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int cg3_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUN3COLOR, 8, info->fix.smem_len); diff --git a/drivers/video/fbdev/cg6.c b/drivers/video/fbdev/cg6.c index 8ef6ac9132f3..69d3ce50948d 100644 --- a/drivers/video/fbdev/cg6.c +++ b/drivers/video/fbdev/cg6.c @@ -37,16 +37,18 @@ static void cg6_imageblit(struct fb_info *, const struct fb_image *); static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); static int cg6_sync(struct fb_info *); -static int cg6_mmap(struct fb_info *, struct vm_area_struct *); -static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static int cg6_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int cg6_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* * Frame buffer operations */ static const struct fb_ops cg6_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_SBUS_OPS_RDWR(cg6), .fb_setcolreg = cg6_setcolreg, .fb_blank = cg6_blank, .fb_pan_display = cg6_pan_display, @@ -54,11 +56,8 @@ static const struct fb_ops cg6_ops = { .fb_copyarea = cg6_copyarea, .fb_imageblit = cg6_imageblit, .fb_sync = cg6_sync, - .fb_mmap = cg6_mmap, - .fb_ioctl = cg6_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif + __FB_DEFAULT_SBUS_OPS_IOCTL(cg6), + __FB_DEFAULT_SBUS_OPS_MMAP(cg6), }; /* Offset of interesting structures in the OBIO space */ @@ -590,7 +589,7 @@ static struct sbus_mmap_map cg6_mmap_map[] = { { .size = 0 } }; -static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int cg6_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct cg6_par *par = (struct cg6_par *)info->par; @@ -599,7 +598,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) par->which_io, vma); } -static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int cg6_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index baf7e852c75b..e80d6429f76a 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -151,6 +151,12 @@ config FB_IOMEM_HELPERS select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT +config FB_IOMEM_HELPERS_DEFERRED + bool + depends on FB_CORE + select FB_DEFERRED_IO + select FB_IOMEM_HELPERS + config FB_SYSMEM_HELPERS bool depends on FB_CORE diff --git a/drivers/video/fbdev/ffb.c b/drivers/video/fbdev/ffb.c index e3a9bb7e9dea..2a0f5337e091 100644 --- a/drivers/video/fbdev/ffb.c +++ b/drivers/video/fbdev/ffb.c @@ -37,16 +37,18 @@ static void ffb_imageblit(struct fb_info *, const struct fb_image *); static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *); static int ffb_sync(struct fb_info *); -static int ffb_mmap(struct fb_info *, struct vm_area_struct *); -static int ffb_ioctl(struct fb_info *, unsigned int, unsigned long); static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* * Frame buffer operations */ static const struct fb_ops ffb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_SBUS_OPS_RDWR(ffb), .fb_setcolreg = ffb_setcolreg, .fb_blank = ffb_blank, .fb_pan_display = ffb_pan_display, @@ -54,11 +56,8 @@ static const struct fb_ops ffb_ops = { .fb_copyarea = ffb_copyarea, .fb_imageblit = ffb_imageblit, .fb_sync = ffb_sync, - .fb_mmap = ffb_mmap, - .fb_ioctl = ffb_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif + __FB_DEFAULT_SBUS_OPS_IOCTL(ffb), + __FB_DEFAULT_SBUS_OPS_MMAP(ffb), }; /* Register layout and definitions */ @@ -850,7 +849,7 @@ static struct sbus_mmap_map ffb_mmap_map[] = { { .size = 0 } }; -static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct ffb_par *par = (struct ffb_par *)info->par; @@ -859,7 +858,7 @@ static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma) 0, vma); } -static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct ffb_par *par = (struct ffb_par *)info->par; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index b9965cbdd764..2e27c6bd8044 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -848,58 +848,38 @@ static int hvfb_blank(int blank, struct fb_info *info) return 1; /* get fb_blank to set the colormap to all black */ } -static void hvfb_cfb_fillrect(struct fb_info *p, - const struct fb_fillrect *rect) +static void hvfb_ops_damage_range(struct fb_info *info, off_t off, size_t len) { - struct hvfb_par *par = p->par; - - cfb_fillrect(p, rect); - if (par->synchronous_fb) - synthvid_update(p, 0, 0, INT_MAX, INT_MAX); - else - hvfb_ondemand_refresh_throttle(par, rect->dx, rect->dy, - rect->width, rect->height); + /* TODO: implement damage handling */ } -static void hvfb_cfb_copyarea(struct fb_info *p, - const struct fb_copyarea *area) +static void hvfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) { - struct hvfb_par *par = p->par; + struct hvfb_par *par = info->par; - cfb_copyarea(p, area); if (par->synchronous_fb) - synthvid_update(p, 0, 0, INT_MAX, INT_MAX); + synthvid_update(info, 0, 0, INT_MAX, INT_MAX); else - hvfb_ondemand_refresh_throttle(par, area->dx, area->dy, - area->width, area->height); + hvfb_ondemand_refresh_throttle(par, x, y, width, height); } -static void hvfb_cfb_imageblit(struct fb_info *p, - const struct fb_image *image) -{ - struct hvfb_par *par = p->par; - - cfb_imageblit(p, image); - if (par->synchronous_fb) - synthvid_update(p, 0, 0, INT_MAX, INT_MAX); - else - hvfb_ondemand_refresh_throttle(par, image->dx, image->dy, - image->width, image->height); -} +/* + * TODO: GEN1 codepaths allocate from system or DMA-able memory. Fix the + * driver to use the _SYSMEM_ or _DMAMEM_ helpers in these cases. + */ +FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(hvfb_ops, + hvfb_ops_damage_range, + hvfb_ops_damage_area) static const struct fb_ops hvfb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(hvfb_ops), .fb_check_var = hvfb_check_var, .fb_set_par = hvfb_set_par, .fb_setcolreg = hvfb_setcolreg, - .fb_fillrect = hvfb_cfb_fillrect, - .fb_copyarea = hvfb_cfb_copyarea, - .fb_imageblit = hvfb_cfb_imageblit, .fb_blank = hvfb_blank, - .fb_mmap = fb_deferred_io_mmap, }; - /* Get options from kernel paramenter "video=" */ static void hvfb_get_option(struct fb_info *info) { diff --git a/drivers/video/fbdev/leo.c b/drivers/video/fbdev/leo.c index 2f725cd7633a..7cf525c76079 100644 --- a/drivers/video/fbdev/leo.c +++ b/drivers/video/fbdev/leo.c @@ -31,28 +31,21 @@ static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int leo_blank(int, struct fb_info *); - -static int leo_mmap(struct fb_info *, struct vm_area_struct *); -static int leo_ioctl(struct fb_info *, unsigned int, unsigned long); static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static int leo_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int leo_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* * Frame buffer operations */ static const struct fb_ops leo_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(leo), .fb_setcolreg = leo_setcolreg, .fb_blank = leo_blank, .fb_pan_display = leo_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = leo_mmap, - .fb_ioctl = leo_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; #define LEO_OFF_LC_SS0_KRN 0x00200000UL @@ -414,7 +407,7 @@ static struct sbus_mmap_map leo_mmap_map[] = { { .size = 0 } }; -static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int leo_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct leo_par *par = (struct leo_par *)info->par; @@ -423,7 +416,7 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) par->which_io, vma); } -static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int leo_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUNLEO, 32, info->fix.smem_len); diff --git a/drivers/video/fbdev/p9100.c b/drivers/video/fbdev/p9100.c index ca06886d9578..e1356f8a866e 100644 --- a/drivers/video/fbdev/p9100.c +++ b/drivers/video/fbdev/p9100.c @@ -31,8 +31,8 @@ static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int p9100_blank(int, struct fb_info *); -static int p9100_mmap(struct fb_info *, struct vm_area_struct *); -static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long); +static int p9100_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int p9100_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); /* * Frame buffer operations @@ -40,16 +40,9 @@ static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long); static const struct fb_ops p9100_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(p9100), .fb_setcolreg = p9100_setcolreg, .fb_blank = p9100_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = p9100_mmap, - .fb_ioctl = p9100_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; /* P9100 control registers */ @@ -218,7 +211,7 @@ static struct sbus_mmap_map p9100_mmap_map[] = { { 0, 0, 0 } }; -static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int p9100_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct p9100_par *par = (struct p9100_par *)info->par; @@ -227,8 +220,7 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) par->which_io, vma); } -static int p9100_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) +static int p9100_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { /* Make it look like a cg3. */ return sbusfb_ioctl_helper(cmd, arg, info, diff --git a/drivers/video/fbdev/sbuslib.h b/drivers/video/fbdev/sbuslib.h index a6b9a2467646..6466b4cbcd7b 100644 --- a/drivers/video/fbdev/sbuslib.h +++ b/drivers/video/fbdev/sbuslib.h @@ -3,6 +3,11 @@ #ifndef _SBUSLIB_H #define _SBUSLIB_H +struct device_node; +struct fb_info; +struct fb_var_screeninfo; +struct vm_area_struct; + struct sbus_mmap_map { unsigned long voff; unsigned long poff; @@ -14,7 +19,6 @@ struct sbus_mmap_map { extern void sbusfb_fill_var(struct fb_var_screeninfo *var, struct device_node *dp, int bpp); -struct vm_area_struct; extern int sbusfb_mmap_helper(struct sbus_mmap_map *map, unsigned long physbase, unsigned long fbsize, unsigned long iospace, @@ -25,4 +29,35 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); +/* + * Initialize struct fb_ops for SBUS I/O. + */ + +#define __FB_DEFAULT_SBUS_OPS_RDWR(__prefix) \ + .fb_read = fb_io_read, \ + .fb_write = fb_io_write + +#define __FB_DEFAULT_SBUS_OPS_DRAW(__prefix) \ + .fb_fillrect = cfb_fillrect, \ + .fb_copyarea = cfb_copyarea, \ + .fb_imageblit = cfb_imageblit + +#ifdef CONFIG_COMPAT +#define __FB_DEFAULT_SBUS_OPS_IOCTL(__prefix) \ + .fb_ioctl = __prefix ## _sbusfb_ioctl, \ + .fb_compat_ioctl = sbusfb_compat_ioctl +#else +#define __FB_DEFAULT_SBUS_OPS_IOCTL(__prefix) \ + .fb_ioctl = __prefix ## _sbusfb_ioctl +#endif + +#define __FB_DEFAULT_SBUS_OPS_MMAP(__prefix) \ + .fb_mmap = __prefix ## _sbusfb_mmap + +#define FB_DEFAULT_SBUS_OPS(__prefix) \ + __FB_DEFAULT_SBUS_OPS_RDWR(__prefix), \ + __FB_DEFAULT_SBUS_OPS_DRAW(__prefix), \ + __FB_DEFAULT_SBUS_OPS_IOCTL(__prefix), \ + __FB_DEFAULT_SBUS_OPS_MMAP(__prefix) + #endif /* _SBUSLIB_H */ diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 387d18706fec..90a77d19b236 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -894,64 +894,6 @@ static int ufx_handle_damage(struct ufx_data *dev, int x, int y, return 0; } -/* Path triggered by usermode clients who write to filesystem - * e.g. cat filename > /dev/fb1 - * Not used by X Windows or text-mode console. But useful for testing. - * Slow because of extra copy and we must assume all pixels dirty. */ -static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t result; - struct ufx_data *dev = info->par; - u32 offset = (u32) *ppos; - - result = fb_sys_write(info, buf, count, ppos); - - if (result > 0) { - int start = max((int)(offset / info->fix.line_length), 0); - int lines = min((u32)((result / info->fix.line_length) + 1), - (u32)info->var.yres); - - ufx_handle_damage(dev, 0, start, info->var.xres, lines); - } - - return result; -} - -static void ufx_ops_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - - struct ufx_data *dev = info->par; - - sys_copyarea(info, area); - - ufx_handle_damage(dev, area->dx, area->dy, - area->width, area->height); -} - -static void ufx_ops_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct ufx_data *dev = info->par; - - sys_imageblit(info, image); - - ufx_handle_damage(dev, image->dx, image->dy, - image->width, image->height); -} - -static void ufx_ops_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct ufx_data *dev = info->par; - - sys_fillrect(info, rect); - - ufx_handle_damage(dev, rect->dx, rect->dy, rect->width, - rect->height); -} - /* NOTE: fb_defio.c is holding info->fbdefio.mutex * Touching ANY framebuffer memory that triggers a page fault * in fb_defio will cause a deadlock, when it also tries to @@ -1279,14 +1221,31 @@ static int ufx_ops_blank(int blank_mode, struct fb_info *info) return 0; } +static void ufx_ops_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct ufx_data *dev = info->par; + int start = max((int)(off / info->fix.line_length), 0); + int lines = min((u32)((len / info->fix.line_length) + 1), (u32)info->var.yres); + + ufx_handle_damage(dev, 0, start, info->var.xres, lines); +} + +static void ufx_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + struct ufx_data *dev = info->par; + + ufx_handle_damage(dev, x, y, width, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(ufx_ops, + ufx_ops_damage_range, + ufx_ops_damage_area) + static const struct fb_ops ufx_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = ufx_ops_write, + __FB_DEFAULT_DEFERRED_OPS_RDWR(ufx_ops), .fb_setcolreg = ufx_ops_setcolreg, - .fb_fillrect = ufx_ops_fillrect, - .fb_copyarea = ufx_ops_copyarea, - .fb_imageblit = ufx_ops_imageblit, + __FB_DEFAULT_DEFERRED_OPS_DRAW(ufx_ops), .fb_mmap = ufx_ops_mmap, .fb_ioctl = ufx_ops_ioctl, .fb_open = ufx_ops_open, diff --git a/drivers/video/fbdev/tcx.c b/drivers/video/fbdev/tcx.c index 7fb8179a8f41..fe7b7bc77eda 100644 --- a/drivers/video/fbdev/tcx.c +++ b/drivers/video/fbdev/tcx.c @@ -32,28 +32,21 @@ static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int tcx_blank(int, struct fb_info *); - -static int tcx_mmap(struct fb_info *, struct vm_area_struct *); -static int tcx_ioctl(struct fb_info *, unsigned int, unsigned long); static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *); +static int tcx_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static int tcx_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* * Frame buffer operations */ static const struct fb_ops tcx_ops = { .owner = THIS_MODULE, + FB_DEFAULT_SBUS_OPS(tcx), .fb_setcolreg = tcx_setcolreg, .fb_blank = tcx_blank, .fb_pan_display = tcx_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = tcx_mmap, - .fb_ioctl = tcx_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sbusfb_compat_ioctl, -#endif }; /* THC definitions */ @@ -299,7 +292,7 @@ static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = { { .size = 0 } }; -static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int tcx_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct tcx_par *par = (struct tcx_par *)info->par; @@ -308,8 +301,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) par->which_io, vma); } -static int tcx_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) +static int tcx_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct tcx_par *par = (struct tcx_par *) info->par; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index b70762ead13c..2460ff4ac86b 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -716,68 +716,6 @@ static void dlfb_offload_damage(struct dlfb_data *dlfb, int x, int y, int width, } /* - * Path triggered by usermode clients who write to filesystem - * e.g. cat filename > /dev/fb1 - * Not used by X Windows or text-mode console. But useful for testing. - * Slow because of extra copy and we must assume all pixels dirty. - */ -static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t result; - struct dlfb_data *dlfb = info->par; - u32 offset = (u32) *ppos; - - result = fb_sys_write(info, buf, count, ppos); - - if (result > 0) { - int start = max((int)(offset / info->fix.line_length), 0); - int lines = min((u32)((result / info->fix.line_length) + 1), - (u32)info->var.yres); - - dlfb_handle_damage(dlfb, 0, start, info->var.xres, - lines); - } - - return result; -} - -/* hardware has native COPY command (see libdlo), but not worth it for fbcon */ -static void dlfb_ops_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - - struct dlfb_data *dlfb = info->par; - - sys_copyarea(info, area); - - dlfb_offload_damage(dlfb, area->dx, area->dy, - area->width, area->height); -} - -static void dlfb_ops_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct dlfb_data *dlfb = info->par; - - sys_imageblit(info, image); - - dlfb_offload_damage(dlfb, image->dx, image->dy, - image->width, image->height); -} - -static void dlfb_ops_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct dlfb_data *dlfb = info->par; - - sys_fillrect(info, rect); - - dlfb_offload_damage(dlfb, rect->dx, rect->dy, rect->width, - rect->height); -} - -/* * NOTE: fb_defio.c is holding info->fbdefio.mutex * Touching ANY framebuffer memory that triggers a page fault * in fb_defio will cause a deadlock, when it also tries to @@ -1186,14 +1124,31 @@ static int dlfb_ops_blank(int blank_mode, struct fb_info *info) return 0; } +static void dlfb_ops_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct dlfb_data *dlfb = info->par; + int start = max((int)(off / info->fix.line_length), 0); + int lines = min((u32)((len / info->fix.line_length) + 1), (u32)info->var.yres); + + dlfb_handle_damage(dlfb, 0, start, info->var.xres, lines); +} + +static void dlfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + struct dlfb_data *dlfb = info->par; + + dlfb_offload_damage(dlfb, x, y, width, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(dlfb_ops, + dlfb_ops_damage_range, + dlfb_ops_damage_area) + static const struct fb_ops dlfb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = dlfb_ops_write, + __FB_DEFAULT_DEFERRED_OPS_RDWR(dlfb_ops), .fb_setcolreg = dlfb_ops_setcolreg, - .fb_fillrect = dlfb_ops_fillrect, - .fb_copyarea = dlfb_ops_copyarea, - .fb_imageblit = dlfb_ops_imageblit, + __FB_DEFAULT_DEFERRED_OPS_DRAW(dlfb_ops), .fb_mmap = dlfb_ops_mmap, .fb_ioctl = dlfb_ops_ioctl, .fb_open = dlfb_ops_open, diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 05100e91ecb9..6fc9bb2979e4 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -53,6 +53,7 @@ struct samsung_dsim_driver_data { unsigned int plltmr_reg; unsigned int has_freqband:1; unsigned int has_clklane_stop:1; + unsigned int has_broken_fifoctrl_emptyhdr:1; unsigned int num_clks; unsigned int min_freq; unsigned int max_freq; diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index ed5c9660563c..4429d3b1745b 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -46,6 +46,13 @@ struct drm_dp_mst_topology_ref_history { }; #endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */ +enum drm_dp_mst_payload_allocation { + DRM_DP_MST_PAYLOAD_ALLOCATION_NONE, + DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL, + DRM_DP_MST_PAYLOAD_ALLOCATION_DFP, + DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE, +}; + struct drm_dp_mst_branch; /** @@ -537,7 +544,7 @@ struct drm_dp_mst_atomic_payload { * drm_dp_mst_atomic_wait_for_dependencies() has been called, which will ensure the * previous MST states payload start slots have been copied over to the new state. Note * that a new start slot won't be assigned/removed from this payload until - * drm_dp_add_payload_part1()/drm_dp_remove_payload() have been called. + * drm_dp_add_payload_part1()/drm_dp_remove_payload_part2() have been called. * * Acquire the MST modesetting lock, and then wait for any pending MST-related commits to * get committed to hardware by calling drm_crtc_commit_wait() on each of the * &drm_crtc_commit structs in &drm_dp_mst_topology_state.commit_deps. @@ -564,6 +571,9 @@ struct drm_dp_mst_atomic_payload { /** @dsc_enabled: Whether or not this payload has DSC enabled */ bool dsc_enabled : 1; + /** @payload_allocation_status: The allocation status of this payload */ + enum drm_dp_mst_payload_allocation payload_allocation_status; + /** @next: The list node for this payload */ struct list_head next; }; @@ -842,10 +852,13 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, struct drm_atomic_state *state, struct drm_dp_mst_atomic_payload *payload); -void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_topology_state *mst_state, - const struct drm_dp_mst_atomic_payload *old_payload, - struct drm_dp_mst_atomic_payload *new_payload); +void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_atomic_payload *payload); +void drm_dp_remove_payload_part2(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + const struct drm_dp_mst_atomic_payload *old_payload, + struct drm_dp_mst_atomic_payload *new_payload); int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr); diff --git a/include/drm/drm_accel.h b/include/drm/drm_accel.h index d4955062c77e..f4d3784b1dce 100644 --- a/include/drm/drm_accel.h +++ b/include/drm/drm_accel.h @@ -58,7 +58,8 @@ int accel_minor_alloc(void); void accel_minor_replace(struct drm_minor *minor, int index); void accel_set_device_instance_params(struct device *kdev, int index); int accel_open(struct inode *inode, struct file *filp); -void accel_debugfs_init(struct drm_minor *minor, int minor_id); +void accel_debugfs_init(struct drm_device *dev); +void accel_debugfs_register(struct drm_device *dev); #else @@ -89,7 +90,11 @@ static inline void accel_set_device_instance_params(struct device *kdev, int ind { } -static inline void accel_debugfs_init(struct drm_minor *minor, int minor_id) +static inline void accel_debugfs_init(struct drm_device *dev) +{ +} + +static inline void accel_debugfs_register(struct drm_device *dev) { } diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 9a022caacf93..cf8e1220a4ac 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -1126,7 +1126,7 @@ struct drm_bridge_state { struct drm_bus_cfg input_bus_cfg; /** - * @output_bus_cfg: input bus configuration + * @output_bus_cfg: output bus configuration */ struct drm_bus_cfg output_bus_cfg; }; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index c339fc85fd07..cfb7dcdb66c4 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -32,6 +32,8 @@ #include <drm/drm_mode_object.h> #include <drm/drm_modes.h> +struct device_node; + struct drm_bridge; struct drm_bridge_timings; struct drm_connector; @@ -716,10 +718,8 @@ struct drm_bridge { struct drm_encoder *encoder; /** @chain_node: used to form a bridge chain */ struct list_head chain_node; -#ifdef CONFIG_OF /** @of_node: device node pointer to the bridge */ struct device_node *of_node; -#endif /** @list: to keep track of all added bridges */ struct list_head list; /** @@ -950,6 +950,6 @@ static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, } #endif -void drm_bridge_debugfs_init(struct drm_minor *minor); +void drm_bridge_debugfs_init(struct drm_device *dev); #endif diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index c0a14b40c039..d47458ecdac4 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -195,6 +195,6 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode); drm_for_each_connector_iter(connector, iter) \ if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) -void drm_client_debugfs_init(struct drm_minor *minor); +void drm_client_debugfs_init(struct drm_device *dev); #endif diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index d300fde6c1a4..18cf46e3478b 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -498,6 +498,8 @@ enum drm_privacy_screen_status { * ITU-R BT.601 colorimetry format * The DP spec does not say whether this is the 525 or the 625 * line version. + * @DRM_MODE_COLORIMETRY_COUNT: + * Not a valid value; merely used four counting */ enum drm_colorspace { /* For Default case, driver will set the colorspace */ @@ -522,7 +524,6 @@ enum drm_colorspace { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED = 13, DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT = 14, DRM_MODE_COLORIMETRY_BT601_YCC = 15, - /* not a valid value; merely used for counting */ DRM_MODE_COLORIMETRY_COUNT }; diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h index cb2c1956a214..7213ce15e4ff 100644 --- a/include/drm/drm_debugfs.h +++ b/include/drm/drm_debugfs.h @@ -142,8 +142,8 @@ struct drm_debugfs_entry { void drm_debugfs_create_files(const struct drm_info_list *files, int count, struct dentry *root, struct drm_minor *minor); -int drm_debugfs_remove_files(const struct drm_info_list *files, - int count, struct drm_minor *minor); +int drm_debugfs_remove_files(const struct drm_info_list *files, int count, + struct dentry *root, struct drm_minor *minor); void drm_debugfs_add_file(struct drm_device *dev, const char *name, int (*show)(struct seq_file*, void*), void *data); diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 7cf4afae2e79..c490977ee250 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -312,19 +312,11 @@ struct drm_device { struct drm_fb_helper *fb_helper; /** - * @debugfs_mutex: + * @debugfs_root: * - * Protects &debugfs_list access. + * Root directory for debugfs files. */ - struct mutex debugfs_mutex; - - /** - * @debugfs_list: - * - * List of debugfs files to be created by the DRM device. The files - * must be added during drm_dev_register(). - */ - struct list_head debugfs_list; + struct dentry *debugfs_root; /* Everything below here is for legacy driver, never use! */ /* private: */ diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 9813fa759b75..e2640dc64e08 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -581,4 +581,12 @@ static inline bool drm_firmware_drivers_only(void) return video_firmware_drivers_only(); } +#if defined(CONFIG_DEBUG_FS) +void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root); +#else +static inline void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root) +{ +} +#endif + #endif diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 010239392adf..489cc3758a82 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -79,10 +79,8 @@ struct drm_minor { struct device *kdev; /* Linux device */ struct drm_device *dev; + struct dentry *debugfs_symlink; struct dentry *debugfs_root; - - struct list_head debugfs_list; - struct mutex debugfs_lock; /* Protects debugfs_list. */ }; /** diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h index a58a14c9f222..262db0c3beee 100644 --- a/include/uapi/drm/ivpu_accel.h +++ b/include/uapi/drm/ivpu_accel.h @@ -69,8 +69,20 @@ extern "C" { #define DRM_IVPU_CONTEXT_PRIORITY_FOCUS 2 #define DRM_IVPU_CONTEXT_PRIORITY_REALTIME 3 -#define DRM_IVPU_CAP_METRIC_STREAMER 1 -#define DRM_IVPU_CAP_DMA_MEMORY_RANGE 2 +/** + * DRM_IVPU_CAP_METRIC_STREAMER + * + * Metric streamer support. Provides sampling of various hardware performance + * metrics like DMA bandwidth and cache miss/hits. Can be used for profiling. + */ +#define DRM_IVPU_CAP_METRIC_STREAMER 1 +/** + * DRM_IVPU_CAP_DMA_MEMORY_RANGE + * + * Driver has capability to allocate separate memory range + * accessible by hardware DMA. + */ +#define DRM_IVPU_CAP_DMA_MEMORY_RANGE 2 /** * struct drm_ivpu_param - Get/Set VPU parameters @@ -123,6 +135,8 @@ struct drm_ivpu_param { * %DRM_IVPU_PARAM_SKU: * VPU SKU ID (read-only) * + * %DRM_IVPU_PARAM_CAPABILITIES: + * Supported capabilities (read-only) */ __u32 param; |