mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-19 12:39:03 +02:00
drm-misc-next for v6.9:
UAPI Changes: virtio: - add Venus capset defines Cross-subsystem Changes: Core Changes: - fix drm_fixp2int_ceil() - documentation fixes - clean ups - allow DRM_MM_DEBUG with DRM=m - build fixes for debugfs support - EDID cleanups - sched: error-handling fixes - ttm: add tests Driver Changes: bridge: - ite-6505: fix DP link-training bug - samsung-dsim: fix error checking in probe - tc358767: fix regmap usage efifb: - use copy of global screen_info state hisilicon: - fix EDID includes mgag200: - improve ioremap usage - convert to struct drm_edid nouveau: - disp: use kmemdup() - fix EDID includes - documentation fixes panel: - ltk050h3146w: error-handling fixes - panel-edp: support delay between power-on and enable; use put_sync in unprepare; support Mediatek MT8173 Chromebooks, BOE NV116WHM-N49 V8.0, BOE NV122WUM-N41, CSO MNC207QS1-1 plus DT bindings - panel-lvds: support EDT ETML0700Z9NDHA plus DT bindings - panel-novatek: FRIDA FRD400B25025-A-CTK plus DT bindings qaic: - fixes to BO handling - make use of DRM managed release - fix order of remove operations rockchip: - analogix_dp: get encoder port from DT - inno_hdmi: support HDMI for RK3128 - lvds: error-handling fixes simplefb: - fix logging ssd130x: - support SSD133x plus DT bindings tegra: - fix error handling tilcdc: - make use of DRM managed release v3d: - show memory stats in debugfs vc4: - fix error handling in plane prepare_fb - fix framebuffer test in plane helpers vesafb: - use copy of global screen_info state virtio: - cleanups vkms: - fix OOB access when programming the LUT - Kconfig improvements vmwgfx: - unmap surface before changing plane state - fix memory leak in error handling - documentation fixes -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmWgDSsACgkQaA3BHVML eiPG5AgAjK42pY25OezV/wmUiffhfDluTbjw+Cjwg/IzZ+RyAMcf1q7R8Oid6G6o kG64WfUmBURwdOQ2nvtJGum8YoBx70uvmKyFzhu20v+e9HT/EFizRi7Qvg71Il/0 l8WQ5BJ1W6PvJKgEU4io+OWWhDyZ1B3GpCvkd30wF2Vfi0CPeeVAvwmeKC5Rj4lE lbYa93sAS/neNkTBvhEEUGoz/t9+5FqAMarygM6hYzDVgnhs8Mbm/pRKCUgPvYvp 871oibBPenQGP6jkWU1h1UWIa5CACvHgkebSGUGy6b5e9jPBRrSmlnRhiviJEY1/ 6x7kGnB69r6I40CdY/1cnTqyhJ25cA== =GX2h -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2024-01-11' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v6.9: UAPI Changes: virtio: - add Venus capset defines Cross-subsystem Changes: Core Changes: - fix drm_fixp2int_ceil() - documentation fixes - clean ups - allow DRM_MM_DEBUG with DRM=m - build fixes for debugfs support - EDID cleanups - sched: error-handling fixes - ttm: add tests Driver Changes: bridge: - ite-6505: fix DP link-training bug - samsung-dsim: fix error checking in probe - tc358767: fix regmap usage efifb: - use copy of global screen_info state hisilicon: - fix EDID includes mgag200: - improve ioremap usage - convert to struct drm_edid nouveau: - disp: use kmemdup() - fix EDID includes - documentation fixes panel: - ltk050h3146w: error-handling fixes - panel-edp: support delay between power-on and enable; use put_sync in unprepare; support Mediatek MT8173 Chromebooks, BOE NV116WHM-N49 V8.0, BOE NV122WUM-N41, CSO MNC207QS1-1 plus DT bindings - panel-lvds: support EDT ETML0700Z9NDHA plus DT bindings - panel-novatek: FRIDA FRD400B25025-A-CTK plus DT bindings qaic: - fixes to BO handling - make use of DRM managed release - fix order of remove operations rockchip: - analogix_dp: get encoder port from DT - inno_hdmi: support HDMI for RK3128 - lvds: error-handling fixes simplefb: - fix logging ssd130x: - support SSD133x plus DT bindings tegra: - fix error handling tilcdc: - make use of DRM managed release v3d: - show memory stats in debugfs vc4: - fix error handling in plane prepare_fb - fix framebuffer test in plane helpers vesafb: - use copy of global screen_info state virtio: - cleanups vkms: - fix OOB access when programming the LUT - Kconfig improvements vmwgfx: - unmap surface before changing plane state - fix memory leak in error handling - documentation fixes Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20240111154902.GA8448@linux-uq9g
This commit is contained in:
commit
f8e4806e0d
|
@ -15,7 +15,9 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: hydis,hva40wv1
|
||||
- enum:
|
||||
- frida,frd400b25025
|
||||
- hydis,hva40wv1
|
||||
- const: novatek,nt35510
|
||||
description: This indicates the panel manufacturer of the panel
|
||||
that is in turn using the NT35510 panel driver. The compatible
|
||||
|
|
|
@ -42,6 +42,8 @@ properties:
|
|||
- auo,b101ew05
|
||||
# Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel
|
||||
- chunghwa,claa070wp03xg
|
||||
# EDT ETML0700Z9NDHA 7.0" WSVGA (1024x600) color TFT LCD LVDS panel
|
||||
- edt,etml0700z9ndha
|
||||
# HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel
|
||||
- hannstar,hsd101pww2
|
||||
# Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel
|
||||
|
|
|
@ -131,9 +131,9 @@ allOf:
|
|||
const: sinowealth,sh1106
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 132
|
||||
height:
|
||||
solomon,height:
|
||||
default: 64
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
|
@ -149,9 +149,9 @@ allOf:
|
|||
- solomon,ssd1305
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 132
|
||||
height:
|
||||
solomon,height:
|
||||
default: 64
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
|
@ -167,9 +167,9 @@ allOf:
|
|||
- solomon,ssd1306
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 128
|
||||
height:
|
||||
solomon,height:
|
||||
default: 64
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
|
@ -185,9 +185,9 @@ allOf:
|
|||
- solomon,ssd1307
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 128
|
||||
height:
|
||||
solomon,height:
|
||||
default: 39
|
||||
solomon,dclk-div:
|
||||
default: 2
|
||||
|
@ -205,9 +205,9 @@ allOf:
|
|||
- solomon,ssd1309
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 128
|
||||
height:
|
||||
solomon,height:
|
||||
default: 64
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
|
|
|
@ -30,9 +30,9 @@ allOf:
|
|||
const: solomon,ssd1322
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 480
|
||||
height:
|
||||
solomon,height:
|
||||
default: 128
|
||||
|
||||
- if:
|
||||
|
@ -42,9 +42,9 @@ allOf:
|
|||
const: solomon,ssd1325
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 128
|
||||
height:
|
||||
solomon,height:
|
||||
default: 80
|
||||
|
||||
- if:
|
||||
|
@ -54,9 +54,9 @@ allOf:
|
|||
const: solomon,ssd1327
|
||||
then:
|
||||
properties:
|
||||
width:
|
||||
solomon,width:
|
||||
default: 128
|
||||
height:
|
||||
solomon,height:
|
||||
default: 128
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/solomon,ssd133x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Solomon SSD133x OLED Display Controllers
|
||||
|
||||
maintainers:
|
||||
- Javier Martinez Canillas <javierm@redhat.com>
|
||||
|
||||
allOf:
|
||||
- $ref: solomon,ssd-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- solomon,ssd1331
|
||||
|
||||
solomon,width:
|
||||
default: 96
|
||||
|
||||
solomon,height:
|
||||
default: 64
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
oled@0 {
|
||||
compatible = "solomon,ssd1331";
|
||||
reg = <0x0>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
dc-gpios = <&gpio2 8>;
|
||||
spi-max-frequency = <10000000>;
|
||||
};
|
||||
};
|
|
@ -1,234 +0,0 @@
|
|||
==========================
|
||||
Xe – Merge Acceptance Plan
|
||||
==========================
|
||||
Xe is a new driver for Intel GPUs that supports both integrated and
|
||||
discrete platforms starting with Tiger Lake (first Intel Xe Architecture).
|
||||
|
||||
This document aims to establish a merge plan for the Xe, by writing down clear
|
||||
pre-merge goals, in order to avoid unnecessary delays.
|
||||
|
||||
Xe – Overview
|
||||
=============
|
||||
The main motivation of Xe is to have a fresh base to work from that is
|
||||
unencumbered by older platforms, whilst also taking the opportunity to
|
||||
rearchitect our driver to increase sharing across the drm subsystem, both
|
||||
leveraging and allowing us to contribute more towards other shared components
|
||||
like TTM and drm/scheduler.
|
||||
|
||||
This is also an opportunity to start from the beginning with a clean uAPI that is
|
||||
extensible by design and already aligned with the modern userspace needs. For
|
||||
this reason, the memory model is solely based on GPU Virtual Address space
|
||||
bind/unbind (‘VM_BIND’) of GEM buffer objects (BOs) and execution only supporting
|
||||
explicit synchronization. With persistent mapping across the execution, the
|
||||
userspace does not need to provide a list of all required mappings during each
|
||||
submission.
|
||||
|
||||
The new driver leverages a lot from i915. As for display, the intent is to share
|
||||
the display code with the i915 driver so that there is maximum reuse there.
|
||||
|
||||
As for the power management area, the goal is to have a much-simplified support
|
||||
for the system suspend states (S-states), PCI device suspend states (D-states),
|
||||
GPU/Render suspend states (R-states) and frequency management. It should leverage
|
||||
as much as possible all the existent PCI-subsystem infrastructure (pm and
|
||||
runtime_pm) and underlying firmware components such PCODE and GuC for the power
|
||||
states and frequency decisions.
|
||||
|
||||
Repository:
|
||||
|
||||
https://gitlab.freedesktop.org/drm/xe/kernel (branch drm-xe-next)
|
||||
|
||||
Xe – Platforms
|
||||
==============
|
||||
Currently, Xe is already functional and has experimental support for multiple
|
||||
platforms starting from Tiger Lake, with initial support in userspace implemented
|
||||
in Mesa (for Iris and Anv, our OpenGL and Vulkan drivers), as well as in NEO
|
||||
(for OpenCL and Level0).
|
||||
|
||||
During a transition period, platforms will be supported by both Xe and i915.
|
||||
However, the force_probe mechanism existent in both drivers will allow only one
|
||||
official and by-default probe at a given time.
|
||||
|
||||
For instance, in order to probe a DG2 which PCI ID is 0x5690 by Xe instead of
|
||||
i915, the following set of parameters need to be used:
|
||||
|
||||
```
|
||||
i915.force_probe=!5690 xe.force_probe=5690
|
||||
```
|
||||
|
||||
In both drivers, the ‘.require_force_probe’ protection forces the user to use the
|
||||
force_probe parameter while the driver is under development. This protection is
|
||||
only removed when the support for the platform and the uAPI are stable. Stability
|
||||
which needs to be demonstrated by CI results.
|
||||
|
||||
In order to avoid user space regressions, i915 will continue to support all the
|
||||
current platforms that are already out of this protection. Xe support will be
|
||||
forever experimental and dependent on the usage of force_probe for these
|
||||
platforms.
|
||||
|
||||
When the time comes for Xe, the protection will be lifted on Xe and kept in i915.
|
||||
|
||||
Xe – Pre-Merge Goals - Work-in-Progress
|
||||
=======================================
|
||||
|
||||
Display integration with i915
|
||||
-----------------------------
|
||||
In order to share the display code with the i915 driver so that there is maximum
|
||||
reuse, the i915/display/ code is built twice, once for i915.ko and then for
|
||||
xe.ko. Currently, the i915/display code in Xe tree is polluted with many 'ifdefs'
|
||||
depending on the build target. The goal is to refactor both Xe and i915/display
|
||||
code simultaneously in order to get a clean result before they land upstream, so
|
||||
that display can already be part of the initial pull request towards drm-next.
|
||||
|
||||
However, display code should not gate the acceptance of Xe in upstream. Xe
|
||||
patches will be refactored in a way that display code can be removed, if needed,
|
||||
from the first pull request of Xe towards drm-next. The expectation is that when
|
||||
both drivers are part of the drm-tip, the introduction of cleaner patches will be
|
||||
easier and speed up.
|
||||
|
||||
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
|
||||
================================
|
||||
|
||||
Drm_exec
|
||||
--------
|
||||
Helper to make dma_resv locking for a big number of buffers is getting removed in
|
||||
the drm_exec series proposed in https://patchwork.freedesktop.org/patch/524376/
|
||||
If that happens, Xe needs to change and incorporate the changes in the driver.
|
||||
The goal is to engage with the Community to understand if the best approach is to
|
||||
move that to the drivers that are using it or if we should keep the helpers in
|
||||
place waiting for Xe to get merged.
|
||||
|
||||
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.
|
||||
|
||||
Userptr integration and vm_bind
|
||||
-------------------------------
|
||||
Different drivers implement different ways of dealing with execution of userptr.
|
||||
With multiple drivers currently introducing support to VM_BIND, the goal is to
|
||||
aim for a DRM consensus on what’s the best way to have that support. To some
|
||||
extent this is already getting addressed itself with the GPUVA where likely the
|
||||
userptr will be a GPUVA with a NULL GEM call VM bind directly on the userptr.
|
||||
However, there are more aspects around the rules for that and the usage of
|
||||
mmu_notifiers, locking and other aspects.
|
||||
|
||||
This task here has the goal of introducing a documentation of the basic rules.
|
||||
|
||||
The documentation *needs* to first live in this document (API session below) and
|
||||
then moved to another more specific document or at Xe level or at DRM level.
|
||||
|
||||
Documentation should include:
|
||||
|
||||
* The userptr part of the VM_BIND api.
|
||||
|
||||
* Locking, including the page-faulting case.
|
||||
|
||||
* O(1) complexity under VM_BIND.
|
||||
|
||||
The document is now included in the drm documentation :doc:`here </gpu/drm-vm-bind-async>`.
|
||||
|
||||
Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when
|
||||
the second driver supporting VM_BIND+userptr appears. Details to be defined when
|
||||
the time comes.
|
||||
|
||||
The DRM GPUVM helpers do not yet include the userptr parts, but discussions
|
||||
about implementing them are ongoing.
|
||||
|
||||
ASYNC VM_BIND
|
||||
-------------
|
||||
Although having a common DRM level IOCTL for VM_BIND is not a requirement to get
|
||||
Xe merged, it is mandatory to have a consensus with other drivers and Mesa.
|
||||
It needs to be clear how to handle async VM_BIND and interactions with userspace
|
||||
memory fences. Ideally with helper support so people don't get it wrong in all
|
||||
possible ways.
|
||||
|
||||
As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of
|
||||
various flavors, error handling and sample API suggestions are documented in
|
||||
:doc:`The ASYNC VM_BIND document </gpu/drm-vm-bind-async>`.
|
||||
|
||||
Drm_scheduler
|
||||
-------------
|
||||
Xe primarily uses Firmware based scheduling (GuC FW). However, it will use
|
||||
drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to
|
||||
resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is
|
||||
not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and
|
||||
drm_sched_entity.
|
||||
|
||||
Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but
|
||||
some consensus needs to be reached between Xe and other community drivers that
|
||||
could also benefit from this work, for coupling FW based/assisted submission such
|
||||
as the ARM’s new Mali GPU driver, and others.
|
||||
|
||||
As a key measurable result, the patch series introducing Xe itself shall not
|
||||
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.
|
||||
|
||||
Long running compute: minimal data structure/scaffolding
|
||||
--------------------------------------------------------
|
||||
The generic scheduler code needs to include the handling of endless compute
|
||||
contexts, with the minimal scaffolding for preempt-ctx fences (probably on the
|
||||
drm_sched_entity) and making sure drm_scheduler can cope with the lack of job
|
||||
completion fence.
|
||||
|
||||
The goal is to achieve a consensus ahead of Xe initial pull-request, ideally with
|
||||
this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any
|
||||
drm driver, including Xe, could re-use and add their own individual needs on top
|
||||
in a next stage. However, this should not block the initial merge.
|
||||
|
||||
Dev_coredump
|
||||
------------
|
||||
|
||||
Xe needs to align with other drivers on the way that the error states are
|
||||
dumped, avoiding a Xe only error_state solution. The goal is to use devcoredump
|
||||
infrastructure to report error states, since it produces a standardized way
|
||||
by exposing a virtual and temporary /sys/class/devcoredump device.
|
||||
|
||||
As the key measurable result, Xe driver needs to provide GPU snapshots captured
|
||||
at hang time through devcoredump, but without depending on any core modification
|
||||
of devcoredump infrastructure itself.
|
||||
|
||||
Later, when we are in-tree, the goal is to collaborate with devcoredump
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
|
@ -120,6 +120,29 @@ Contact: Daniel Vetter, respective driver maintainers
|
|||
|
||||
Level: Advanced
|
||||
|
||||
Rename drm_atomic_state
|
||||
-----------------------
|
||||
|
||||
The KMS framework uses two slightly different definitions for the ``state``
|
||||
concept. For a given object (plane, CRTC, encoder, etc., so
|
||||
``drm_$OBJECT_state``), the state is the entire state of that object. However,
|
||||
at the device level, ``drm_atomic_state`` refers to a state update for a
|
||||
limited number of objects.
|
||||
|
||||
The state isn't the entire device state, but only the full state of some
|
||||
objects in that device. This is confusing to newcomers, and
|
||||
``drm_atomic_state`` should be renamed to something clearer like
|
||||
``drm_atomic_commit``.
|
||||
|
||||
In addition to renaming the structure itself, it would also imply renaming some
|
||||
related functions (``drm_atomic_state_alloc``, ``drm_atomic_state_get``,
|
||||
``drm_atomic_state_put``, ``drm_atomic_state_init``,
|
||||
``__drm_atomic_state_free``, etc.).
|
||||
|
||||
Contact: Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
Level: Advanced
|
||||
|
||||
Fallout from atomic KMS
|
||||
-----------------------
|
||||
|
||||
|
|
|
@ -10467,7 +10467,6 @@ F: drivers/media/rc/img-ir/
|
|||
|
||||
IMGTEC POWERVR DRM DRIVER
|
||||
M: Frank Binns <frank.binns@imgtec.com>
|
||||
M: Donald Robson <donald.robson@imgtec.com>
|
||||
M: Matt Coster <matt.coster@imgtec.com>
|
||||
S: Supported
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
|
|
@ -358,8 +358,8 @@ static struct mhi_channel_config aic100_channels[] = {
|
|||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.num = 21,
|
||||
.name = "QAIC_TIMESYNC",
|
||||
.num = 21,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
|
@ -390,8 +390,8 @@ static struct mhi_channel_config aic100_channels[] = {
|
|||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.num = 23,
|
||||
.name = "QAIC_TIMESYNC_PERIODIC",
|
||||
.num = 23,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define to_qaic_drm_device(dev) container_of(dev, struct qaic_drm_device, drm)
|
||||
#define to_drm(qddev) (&(qddev)->drm)
|
||||
#define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */
|
||||
#define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev)
|
||||
|
||||
enum __packed dev_states {
|
||||
/* Device is offline or will be very soon */
|
||||
|
@ -191,8 +192,6 @@ struct qaic_bo {
|
|||
u32 nr_slice;
|
||||
/* Number of slice that have been transferred by DMA engine */
|
||||
u32 nr_slice_xfer_done;
|
||||
/* true = BO is queued for execution, true = BO is not queued */
|
||||
bool queued;
|
||||
/*
|
||||
* If true then user has attached slicing information to this BO by
|
||||
* calling DRM_IOCTL_QAIC_ATTACH_SLICE_BO ioctl.
|
||||
|
|
|
@ -141,6 +141,11 @@ struct dbc_rsp {
|
|||
__le16 status;
|
||||
} __packed;
|
||||
|
||||
static inline bool bo_queued(struct qaic_bo *bo)
|
||||
{
|
||||
return !list_empty(&bo->xfer_list);
|
||||
}
|
||||
|
||||
inline int get_dbc_req_elem_size(void)
|
||||
{
|
||||
return sizeof(struct dbc_req);
|
||||
|
@ -569,6 +574,9 @@ static void qaic_free_sgt(struct sg_table *sgt)
|
|||
{
|
||||
struct scatterlist *sg;
|
||||
|
||||
if (!sgt)
|
||||
return;
|
||||
|
||||
for (sg = sgt->sgl; sg; sg = sg_next(sg))
|
||||
if (sg_page(sg))
|
||||
__free_pages(sg_page(sg), get_order(sg->length));
|
||||
|
@ -648,6 +656,7 @@ static void qaic_init_bo(struct qaic_bo *bo, bool reinit)
|
|||
}
|
||||
complete_all(&bo->xfer_done);
|
||||
INIT_LIST_HEAD(&bo->slices);
|
||||
INIT_LIST_HEAD(&bo->xfer_list);
|
||||
}
|
||||
|
||||
static struct qaic_bo *qaic_alloc_init_bo(void)
|
||||
|
@ -709,9 +718,13 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
|
|||
if (ret)
|
||||
goto free_bo;
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
if (ret)
|
||||
goto free_bo;
|
||||
|
||||
ret = drm_gem_handle_create(file_priv, obj, &args->handle);
|
||||
if (ret)
|
||||
goto free_sgt;
|
||||
goto free_bo;
|
||||
|
||||
bo->handle = args->handle;
|
||||
drm_gem_object_put(obj);
|
||||
|
@ -720,10 +733,8 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
|
|||
|
||||
return 0;
|
||||
|
||||
free_sgt:
|
||||
qaic_free_sgt(bo->sgt);
|
||||
free_bo:
|
||||
kfree(bo);
|
||||
drm_gem_object_put(obj);
|
||||
unlock_dev_srcu:
|
||||
srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
|
||||
unlock_usr_srcu:
|
||||
|
@ -738,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file
|
|||
struct drm_gem_object *obj;
|
||||
struct qaic_device *qdev;
|
||||
struct qaic_user *usr;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
usr = file_priv->driver_priv;
|
||||
usr_rcu_id = srcu_read_lock(&usr->qddev_lock);
|
||||
|
@ -760,9 +771,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file
|
|||
goto unlock_dev_srcu;
|
||||
}
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
if (ret == 0)
|
||||
args->offset = drm_vma_node_offset_addr(&obj->vma_node);
|
||||
args->offset = drm_vma_node_offset_addr(&obj->vma_node);
|
||||
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
|
@ -828,9 +837,6 @@ static int qaic_prepare_import_bo(struct qaic_bo *bo, struct qaic_attach_slice_h
|
|||
struct sg_table *sgt;
|
||||
int ret;
|
||||
|
||||
if (obj->import_attach->dmabuf->size < hdr->size)
|
||||
return -EINVAL;
|
||||
|
||||
sgt = dma_buf_map_attachment(obj->import_attach, hdr->dir);
|
||||
if (IS_ERR(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
|
@ -847,9 +853,6 @@ static int qaic_prepare_export_bo(struct qaic_device *qdev, struct qaic_bo *bo,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (bo->base.size < hdr->size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_map_sgtable(&qdev->pdev->dev, bo->sgt, hdr->dir, 0);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
@ -950,9 +953,6 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
|
|||
if (arg_size / args->hdr.count != sizeof(*slice_ent))
|
||||
return -EINVAL;
|
||||
|
||||
if (args->hdr.size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -992,16 +992,16 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
|
|||
goto free_slice_ent;
|
||||
}
|
||||
|
||||
ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, args->hdr.size);
|
||||
if (ret)
|
||||
goto free_slice_ent;
|
||||
|
||||
obj = drm_gem_object_lookup(file_priv, args->hdr.handle);
|
||||
if (!obj) {
|
||||
ret = -ENOENT;
|
||||
goto free_slice_ent;
|
||||
}
|
||||
|
||||
ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, obj->size);
|
||||
if (ret)
|
||||
goto put_bo;
|
||||
|
||||
bo = to_qaic_bo(obj);
|
||||
ret = mutex_lock_interruptible(&bo->lock);
|
||||
if (ret)
|
||||
|
@ -1173,7 +1173,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil
|
|||
struct bo_slice *slice;
|
||||
unsigned long flags;
|
||||
struct qaic_bo *bo;
|
||||
bool queued;
|
||||
int i, j;
|
||||
int ret;
|
||||
|
||||
|
@ -1205,9 +1204,7 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil
|
|||
}
|
||||
|
||||
spin_lock_irqsave(&dbc->xfer_lock, flags);
|
||||
queued = bo->queued;
|
||||
bo->queued = true;
|
||||
if (queued) {
|
||||
if (bo_queued(bo)) {
|
||||
spin_unlock_irqrestore(&dbc->xfer_lock, flags);
|
||||
ret = -EINVAL;
|
||||
goto unlock_bo;
|
||||
|
@ -1230,7 +1227,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil
|
|||
else
|
||||
ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail);
|
||||
if (ret) {
|
||||
bo->queued = false;
|
||||
spin_unlock_irqrestore(&dbc->xfer_lock, flags);
|
||||
goto unlock_bo;
|
||||
}
|
||||
|
@ -1253,8 +1249,7 @@ failed_to_send_bo:
|
|||
spin_lock_irqsave(&dbc->xfer_lock, flags);
|
||||
bo = list_last_entry(&dbc->xfer_list, struct qaic_bo, xfer_list);
|
||||
obj = &bo->base;
|
||||
bo->queued = false;
|
||||
list_del(&bo->xfer_list);
|
||||
list_del_init(&bo->xfer_list);
|
||||
spin_unlock_irqrestore(&dbc->xfer_lock, flags);
|
||||
dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir);
|
||||
drm_gem_object_put(obj);
|
||||
|
@ -1615,8 +1610,7 @@ read_fifo:
|
|||
*/
|
||||
dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir);
|
||||
bo->nr_slice_xfer_done = 0;
|
||||
bo->queued = false;
|
||||
list_del(&bo->xfer_list);
|
||||
list_del_init(&bo->xfer_list);
|
||||
bo->perf_stats.req_processed_ts = ktime_get_ns();
|
||||
complete_all(&bo->xfer_done);
|
||||
drm_gem_object_put(&bo->base);
|
||||
|
@ -1875,7 +1869,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
|
|||
|
||||
/* Check if BO is committed to H/W for DMA */
|
||||
spin_lock_irqsave(&dbc->xfer_lock, flags);
|
||||
if (bo->queued) {
|
||||
if (bo_queued(bo)) {
|
||||
spin_unlock_irqrestore(&dbc->xfer_lock, flags);
|
||||
ret = -EBUSY;
|
||||
goto unlock_ch_srcu;
|
||||
|
@ -1905,8 +1899,7 @@ static void empty_xfer_list(struct qaic_device *qdev, struct dma_bridge_chan *db
|
|||
spin_lock_irqsave(&dbc->xfer_lock, flags);
|
||||
while (!list_empty(&dbc->xfer_list)) {
|
||||
bo = list_first_entry(&dbc->xfer_list, typeof(*bo), xfer_list);
|
||||
bo->queued = false;
|
||||
list_del(&bo->xfer_list);
|
||||
list_del_init(&bo->xfer_list);
|
||||
spin_unlock_irqrestore(&dbc->xfer_lock, flags);
|
||||
bo->nr_slice_xfer_done = 0;
|
||||
bo->req_id = 0;
|
||||
|
|
|
@ -44,6 +44,53 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode");
|
|||
static bool link_up;
|
||||
static DEFINE_IDA(qaic_usrs);
|
||||
|
||||
static void qaicm_wq_release(struct drm_device *dev, void *res)
|
||||
{
|
||||
struct workqueue_struct *wq = res;
|
||||
|
||||
destroy_workqueue(wq);
|
||||
}
|
||||
|
||||
static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt)
|
||||
{
|
||||
struct workqueue_struct *wq;
|
||||
int ret;
|
||||
|
||||
wq = alloc_workqueue(fmt, WQ_UNBOUND, 0);
|
||||
if (!wq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return wq;
|
||||
}
|
||||
|
||||
static void qaicm_srcu_release(struct drm_device *dev, void *res)
|
||||
{
|
||||
struct srcu_struct *lock = res;
|
||||
|
||||
cleanup_srcu_struct(lock);
|
||||
}
|
||||
|
||||
static int qaicm_srcu_init(struct drm_device *dev, struct srcu_struct *lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = init_srcu_struct(lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return drmm_add_action_or_reset(dev, qaicm_srcu_release, lock);
|
||||
}
|
||||
|
||||
static void qaicm_pci_release(struct drm_device *dev, void *res)
|
||||
{
|
||||
struct qaic_device *qdev = to_qaic_device(dev);
|
||||
|
||||
pci_set_drvdata(qdev->pdev, NULL);
|
||||
}
|
||||
|
||||
static void free_usr(struct kref *kref)
|
||||
{
|
||||
struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count);
|
||||
|
@ -299,74 +346,73 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev)
|
|||
release_dbc(qdev, i);
|
||||
}
|
||||
|
||||
static void cleanup_qdev(struct qaic_device *qdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < qdev->num_dbc; ++i)
|
||||
cleanup_srcu_struct(&qdev->dbc[i].ch_lock);
|
||||
cleanup_srcu_struct(&qdev->dev_lock);
|
||||
pci_set_drvdata(qdev->pdev, NULL);
|
||||
destroy_workqueue(qdev->cntl_wq);
|
||||
destroy_workqueue(qdev->qts_wq);
|
||||
}
|
||||
|
||||
static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qaic_drm_device *qddev;
|
||||
struct qaic_device *qdev;
|
||||
int i;
|
||||
struct drm_device *drm;
|
||||
int i, ret;
|
||||
|
||||
qdev = devm_kzalloc(&pdev->dev, sizeof(*qdev), GFP_KERNEL);
|
||||
qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL);
|
||||
if (!qdev)
|
||||
return NULL;
|
||||
|
||||
qdev->dev_state = QAIC_OFFLINE;
|
||||
if (id->device == PCI_DEV_AIC100) {
|
||||
qdev->num_dbc = 16;
|
||||
qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL);
|
||||
qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL);
|
||||
if (!qdev->dbc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdev->cntl_wq = alloc_workqueue("qaic_cntl", WQ_UNBOUND, 0);
|
||||
if (!qdev->cntl_wq)
|
||||
qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm);
|
||||
if (IS_ERR(qddev))
|
||||
return NULL;
|
||||
|
||||
qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0);
|
||||
if (!qdev->qts_wq) {
|
||||
destroy_workqueue(qdev->cntl_wq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drm = to_drm(qddev);
|
||||
pci_set_drvdata(pdev, qdev);
|
||||
qdev->pdev = pdev;
|
||||
|
||||
mutex_init(&qdev->cntl_mutex);
|
||||
ret = drmm_mutex_init(drm, &qddev->users_mutex);
|
||||
if (ret)
|
||||
return NULL;
|
||||
ret = drmm_add_action_or_reset(drm, qaicm_pci_release, NULL);
|
||||
if (ret)
|
||||
return NULL;
|
||||
ret = drmm_mutex_init(drm, &qdev->cntl_mutex);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
qdev->cntl_wq = qaicm_wq_init(drm, "qaic_cntl");
|
||||
if (IS_ERR(qdev->cntl_wq))
|
||||
return NULL;
|
||||
qdev->qts_wq = qaicm_wq_init(drm, "qaic_ts");
|
||||
if (IS_ERR(qdev->qts_wq))
|
||||
return NULL;
|
||||
|
||||
ret = qaicm_srcu_init(drm, &qdev->dev_lock);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
qdev->qddev = qddev;
|
||||
qdev->pdev = pdev;
|
||||
qddev->qdev = qdev;
|
||||
|
||||
INIT_LIST_HEAD(&qdev->cntl_xfer_list);
|
||||
init_srcu_struct(&qdev->dev_lock);
|
||||
INIT_LIST_HEAD(&qddev->users);
|
||||
|
||||
for (i = 0; i < qdev->num_dbc; ++i) {
|
||||
spin_lock_init(&qdev->dbc[i].xfer_lock);
|
||||
qdev->dbc[i].qdev = qdev;
|
||||
qdev->dbc[i].id = i;
|
||||
INIT_LIST_HEAD(&qdev->dbc[i].xfer_list);
|
||||
init_srcu_struct(&qdev->dbc[i].ch_lock);
|
||||
ret = qaicm_srcu_init(drm, &qdev->dbc[i].ch_lock);
|
||||
if (ret)
|
||||
return NULL;
|
||||
init_waitqueue_head(&qdev->dbc[i].dbc_release);
|
||||
INIT_LIST_HEAD(&qdev->dbc[i].bo_lists);
|
||||
}
|
||||
|
||||
qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm);
|
||||
if (IS_ERR(qddev)) {
|
||||
cleanup_qdev(qdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drmm_mutex_init(to_drm(qddev), &qddev->users_mutex);
|
||||
INIT_LIST_HEAD(&qddev->users);
|
||||
qddev->qdev = qdev;
|
||||
qdev->qddev = qddev;
|
||||
|
||||
return qdev;
|
||||
}
|
||||
|
||||
|
@ -472,35 +518,28 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
ret = init_pci(qdev, pdev);
|
||||
if (ret)
|
||||
goto cleanup_qdev;
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < qdev->num_dbc; ++i)
|
||||
qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i);
|
||||
|
||||
mhi_irq = init_msi(qdev, pdev);
|
||||
if (mhi_irq < 0) {
|
||||
ret = mhi_irq;
|
||||
goto cleanup_qdev;
|
||||
}
|
||||
if (mhi_irq < 0)
|
||||
return mhi_irq;
|
||||
|
||||
ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION);
|
||||
if (ret)
|
||||
goto cleanup_qdev;
|
||||
return ret;
|
||||
|
||||
qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq,
|
||||
qdev->single_msi);
|
||||
if (IS_ERR(qdev->mhi_cntrl)) {
|
||||
ret = PTR_ERR(qdev->mhi_cntrl);
|
||||
goto cleanup_drm_dev;
|
||||
qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_drm_dev:
|
||||
qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION);
|
||||
cleanup_qdev:
|
||||
cleanup_qdev(qdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qaic_pci_remove(struct pci_dev *pdev)
|
||||
|
@ -511,9 +550,8 @@ static void qaic_pci_remove(struct pci_dev *pdev)
|
|||
return;
|
||||
|
||||
qaic_dev_reset_clean_local_state(qdev);
|
||||
qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION);
|
||||
qaic_mhi_free_controller(qdev->mhi_cntrl, link_up);
|
||||
cleanup_qdev(qdev);
|
||||
qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION);
|
||||
}
|
||||
|
||||
static void qaic_pci_shutdown(struct pci_dev *pdev)
|
||||
|
|
|
@ -42,7 +42,7 @@ config DRM_MIPI_DSI
|
|||
config DRM_DEBUG_MM
|
||||
bool "Insert extra checks and debug info into the DRM range managers"
|
||||
default n
|
||||
depends on DRM=y
|
||||
depends on DRM
|
||||
depends on STACKTRACE_SUPPORT
|
||||
select STACKDEPOT
|
||||
help
|
||||
|
@ -289,19 +289,7 @@ config DRM_VGEM
|
|||
as used by Mesa's software renderer for enhanced performance.
|
||||
If M is selected the module will be called vgem.
|
||||
|
||||
config DRM_VKMS
|
||||
tristate "Virtual KMS (EXPERIMENTAL)"
|
||||
depends on DRM && MMU
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_SHMEM_HELPER
|
||||
select CRC32
|
||||
default n
|
||||
help
|
||||
Virtual Kernel Mode-Setting (VKMS) is used for testing or for
|
||||
running GPU in a headless machines. Choose this option to get
|
||||
a VKMS.
|
||||
|
||||
If M is selected the module will be called vkms.
|
||||
source "drivers/gpu/drm/vkms/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/exynos/Kconfig"
|
||||
|
||||
|
|
|
@ -2240,11 +2240,13 @@ static void it6505_link_training_work(struct work_struct *work)
|
|||
ret = it6505_link_start_auto_train(it6505);
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "auto train %s, auto_train_retry: %d",
|
||||
ret ? "pass" : "failed", it6505->auto_train_retry);
|
||||
it6505->auto_train_retry--;
|
||||
|
||||
if (ret) {
|
||||
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
|
||||
it6505_link_train_ok(it6505);
|
||||
return;
|
||||
} else {
|
||||
it6505->auto_train_retry--;
|
||||
}
|
||||
|
||||
it6505_dump(it6505);
|
||||
|
|
|
@ -1992,11 +1992,11 @@ int samsung_dsim_probe(struct platform_device *pdev)
|
|||
else
|
||||
dsi->bridge.timings = &samsung_dsim_bridge_timings_de_high;
|
||||
|
||||
if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host)
|
||||
if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) {
|
||||
ret = dsi->plat_data->host_ops->register_host(dsi);
|
||||
|
||||
if (ret)
|
||||
goto err_disable_runtime;
|
||||
if (ret)
|
||||
goto err_disable_runtime;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -41,8 +41,24 @@
|
|||
|
||||
/* Registers */
|
||||
|
||||
/* DSI D-PHY Layer registers */
|
||||
#define D0W_DPHYCONTTX 0x0004
|
||||
#define CLW_DPHYCONTTX 0x0020
|
||||
#define D0W_DPHYCONTRX 0x0024
|
||||
#define D1W_DPHYCONTRX 0x0028
|
||||
#define D2W_DPHYCONTRX 0x002c
|
||||
#define D3W_DPHYCONTRX 0x0030
|
||||
#define COM_DPHYCONTRX 0x0038
|
||||
#define CLW_CNTRL 0x0040
|
||||
#define D0W_CNTRL 0x0044
|
||||
#define D1W_CNTRL 0x0048
|
||||
#define D2W_CNTRL 0x004c
|
||||
#define D3W_CNTRL 0x0050
|
||||
#define TESTMODE_CNTRL 0x0054
|
||||
|
||||
/* PPI layer registers */
|
||||
#define PPI_STARTPPI 0x0104 /* START control bit */
|
||||
#define PPI_BUSYPPI 0x0108 /* PPI busy status */
|
||||
#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
|
||||
#define LPX_PERIOD 3
|
||||
#define PPI_LANEENABLE 0x0134
|
||||
|
@ -59,6 +75,7 @@
|
|||
|
||||
/* DSI layer registers */
|
||||
#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
|
||||
#define DSI_BUSYDSI 0x0208 /* DSI busy status */
|
||||
#define DSI_LANEENABLE 0x0210 /* Enables each lane */
|
||||
#define DSI_RX_START BIT(0)
|
||||
|
||||
|
@ -69,6 +86,20 @@
|
|||
#define LANEENABLE_L2EN BIT(1)
|
||||
#define LANEENABLE_L3EN BIT(2)
|
||||
|
||||
#define DSI_LANESTATUS0 0x0214 /* DSI lane status 0 */
|
||||
#define DSI_LANESTATUS1 0x0218 /* DSI lane status 1 */
|
||||
#define DSI_INTSTATUS 0x0220 /* Interrupt Status */
|
||||
#define DSI_INTMASK 0x0224 /* Interrupt Mask */
|
||||
#define DSI_INTCLR 0x0228 /* Interrupt Clear */
|
||||
#define DSI_LPTXTO 0x0230 /* LPTX Time Out Counter */
|
||||
|
||||
/* DSI General Registers */
|
||||
#define DSIERRCNT 0x0300 /* DSI Error Count Register */
|
||||
|
||||
/* DSI Application Layer Registers */
|
||||
#define APLCTRL 0x0400 /* Application layer Control Register */
|
||||
#define RDPKTLN 0x0404 /* DSI Read packet Length Register */
|
||||
|
||||
/* Display Parallel Input Interface */
|
||||
#define DPIPXLFMT 0x0440
|
||||
#define VS_POL_ACTIVE_LOW (1 << 10)
|
||||
|
@ -114,35 +145,39 @@
|
|||
#define VFUEN BIT(0) /* Video Frame Timing Upload */
|
||||
|
||||
/* System */
|
||||
#define TC_IDREG 0x0500
|
||||
#define SYSSTAT 0x0508
|
||||
#define SYSCTRL 0x0510
|
||||
#define DP0_AUDSRC_NO_INPUT (0 << 3)
|
||||
#define DP0_AUDSRC_I2S_RX (1 << 3)
|
||||
#define DP0_VIDSRC_NO_INPUT (0 << 0)
|
||||
#define DP0_VIDSRC_DSI_RX (1 << 0)
|
||||
#define DP0_VIDSRC_DPI_RX (2 << 0)
|
||||
#define DP0_VIDSRC_COLOR_BAR (3 << 0)
|
||||
#define SYSRSTENB 0x050c
|
||||
#define TC_IDREG 0x0500 /* Chip ID and Revision ID */
|
||||
#define SYSBOOT 0x0504 /* System BootStrap Status Register */
|
||||
#define SYSSTAT 0x0508 /* System Status Register */
|
||||
#define SYSRSTENB 0x050c /* System Reset/Enable Register */
|
||||
#define ENBI2C (1 << 0)
|
||||
#define ENBLCD0 (1 << 2)
|
||||
#define ENBBM (1 << 3)
|
||||
#define ENBDSIRX (1 << 4)
|
||||
#define ENBREG (1 << 5)
|
||||
#define ENBHDCP (1 << 8)
|
||||
#define GPIOM 0x0540
|
||||
#define GPIOC 0x0544
|
||||
#define GPIOO 0x0548
|
||||
#define GPIOI 0x054c
|
||||
#define INTCTL_G 0x0560
|
||||
#define INTSTS_G 0x0564
|
||||
#define SYSCTRL 0x0510 /* System Control Register */
|
||||
#define DP0_AUDSRC_NO_INPUT (0 << 3)
|
||||
#define DP0_AUDSRC_I2S_RX (1 << 3)
|
||||
#define DP0_VIDSRC_NO_INPUT (0 << 0)
|
||||
#define DP0_VIDSRC_DSI_RX (1 << 0)
|
||||
#define DP0_VIDSRC_DPI_RX (2 << 0)
|
||||
#define DP0_VIDSRC_COLOR_BAR (3 << 0)
|
||||
#define GPIOM 0x0540 /* GPIO Mode Control Register */
|
||||
#define GPIOC 0x0544 /* GPIO Direction Control Register */
|
||||
#define GPIOO 0x0548 /* GPIO Output Register */
|
||||
#define GPIOI 0x054c /* GPIO Input Register */
|
||||
#define INTCTL_G 0x0560 /* General Interrupts Control Register */
|
||||
#define INTSTS_G 0x0564 /* General Interrupts Status Register */
|
||||
|
||||
#define INT_SYSERR BIT(16)
|
||||
#define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10))
|
||||
#define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11))
|
||||
|
||||
#define INT_GP0_LCNT 0x0584
|
||||
#define INT_GP1_LCNT 0x0588
|
||||
#define TEST_INT_C 0x0570 /* Test Interrupts Control Register */
|
||||
#define TEST_INT_S 0x0574 /* Test Interrupts Status Register */
|
||||
|
||||
#define INT_GP0_LCNT 0x0584 /* Interrupt GPIO0 Low Count Value Register */
|
||||
#define INT_GP1_LCNT 0x0588 /* Interrupt GPIO1 Low Count Value Register */
|
||||
|
||||
/* Control */
|
||||
#define DP0CTL 0x0600
|
||||
|
@ -152,9 +187,12 @@
|
|||
#define DP_EN BIT(0) /* Enable DPTX function */
|
||||
|
||||
/* Clocks */
|
||||
#define DP0_VIDMNGEN0 0x0610
|
||||
#define DP0_VIDMNGEN1 0x0614
|
||||
#define DP0_VMNGENSTATUS 0x0618
|
||||
#define DP0_VIDMNGEN0 0x0610 /* DP0 Video Force M Value Register */
|
||||
#define DP0_VIDMNGEN1 0x0614 /* DP0 Video Force N Value Register */
|
||||
#define DP0_VMNGENSTATUS 0x0618 /* DP0 Video Current M Value Register */
|
||||
#define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */
|
||||
#define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */
|
||||
#define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */
|
||||
|
||||
/* Main Channel */
|
||||
#define DP0_SECSAMPLE 0x0640
|
||||
|
@ -224,8 +262,22 @@
|
|||
#define DP0_SNKLTCHGREQ 0x06d4
|
||||
#define DP0_LTLOOPCTRL 0x06d8
|
||||
#define DP0_SNKLTCTRL 0x06e4
|
||||
#define DP0_TPATDAT0 0x06e8 /* DP0 Test Pattern bits 29 to 0 */
|
||||
#define DP0_TPATDAT1 0x06ec /* DP0 Test Pattern bits 59 to 30 */
|
||||
#define DP0_TPATDAT2 0x06f0 /* DP0 Test Pattern bits 89 to 60 */
|
||||
#define DP0_TPATDAT3 0x06f4 /* DP0 Test Pattern bits 119 to 90 */
|
||||
|
||||
#define DP1_SRCCTRL 0x07a0
|
||||
#define AUDCFG0 0x0700 /* DP0 Audio Config0 Register */
|
||||
#define AUDCFG1 0x0704 /* DP0 Audio Config1 Register */
|
||||
#define AUDIFDATA0 0x0708 /* DP0 Audio Info Frame Bytes 3 to 0 */
|
||||
#define AUDIFDATA1 0x070c /* DP0 Audio Info Frame Bytes 7 to 4 */
|
||||
#define AUDIFDATA2 0x0710 /* DP0 Audio Info Frame Bytes 11 to 8 */
|
||||
#define AUDIFDATA3 0x0714 /* DP0 Audio Info Frame Bytes 15 to 12 */
|
||||
#define AUDIFDATA4 0x0718 /* DP0 Audio Info Frame Bytes 19 to 16 */
|
||||
#define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */
|
||||
#define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */
|
||||
|
||||
#define DP1_SRCCTRL 0x07a0 /* DP1 Control Register */
|
||||
|
||||
/* PHY */
|
||||
#define DP_PHY_CTRL 0x0800
|
||||
|
@ -238,6 +290,25 @@
|
|||
#define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */
|
||||
#define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */
|
||||
#define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */
|
||||
#define DP_PHY_CFG_WR 0x0810 /* DP PHY Configuration Test Write Register */
|
||||
#define DP_PHY_CFG_RD 0x0814 /* DP PHY Configuration Test Read Register */
|
||||
#define DP0_AUX_PHY_CTRL 0x0820 /* DP0 AUX PHY Control Register */
|
||||
#define DP0_MAIN_PHY_DBG 0x0840 /* DP0 Main PHY Test Debug Register */
|
||||
|
||||
/* I2S */
|
||||
#define I2SCFG 0x0880 /* I2S Audio Config 0 Register */
|
||||
#define I2SCH0STAT0 0x0888 /* I2S Audio Channel 0 Status Bytes 3 to 0 */
|
||||
#define I2SCH0STAT1 0x088c /* I2S Audio Channel 0 Status Bytes 7 to 4 */
|
||||
#define I2SCH0STAT2 0x0890 /* I2S Audio Channel 0 Status Bytes 11 to 8 */
|
||||
#define I2SCH0STAT3 0x0894 /* I2S Audio Channel 0 Status Bytes 15 to 12 */
|
||||
#define I2SCH0STAT4 0x0898 /* I2S Audio Channel 0 Status Bytes 19 to 16 */
|
||||
#define I2SCH0STAT5 0x089c /* I2S Audio Channel 0 Status Bytes 23 to 20 */
|
||||
#define I2SCH1STAT0 0x08a0 /* I2S Audio Channel 1 Status Bytes 3 to 0 */
|
||||
#define I2SCH1STAT1 0x08a4 /* I2S Audio Channel 1 Status Bytes 7 to 4 */
|
||||
#define I2SCH1STAT2 0x08a8 /* I2S Audio Channel 1 Status Bytes 11 to 8 */
|
||||
#define I2SCH1STAT3 0x08ac /* I2S Audio Channel 1 Status Bytes 15 to 12 */
|
||||
#define I2SCH1STAT4 0x08b0 /* I2S Audio Channel 1 Status Bytes 19 to 16 */
|
||||
#define I2SCH1STAT5 0x08b4 /* I2S Audio Channel 1 Status Bytes 23 to 20 */
|
||||
|
||||
/* PLL */
|
||||
#define DP0_PLLCTRL 0x0900
|
||||
|
@ -1833,16 +1904,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg)
|
|||
case 0x1f4:
|
||||
/* DSI Protocol Layer */
|
||||
case DSI_STARTDSI:
|
||||
case 0x208:
|
||||
case DSI_BUSYDSI:
|
||||
case DSI_LANEENABLE:
|
||||
case 0x214:
|
||||
case 0x218:
|
||||
case 0x220:
|
||||
case DSI_LANESTATUS0:
|
||||
case DSI_LANESTATUS1:
|
||||
case DSI_INTSTATUS:
|
||||
case 0x224:
|
||||
case 0x228:
|
||||
case 0x230:
|
||||
/* DSI General */
|
||||
case 0x300:
|
||||
case DSIERRCNT:
|
||||
/* DSI Application Layer */
|
||||
case 0x400:
|
||||
case 0x404:
|
||||
|
@ -1978,13 +2049,20 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg)
|
|||
}
|
||||
|
||||
static const struct regmap_range tc_volatile_ranges[] = {
|
||||
regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI),
|
||||
regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI),
|
||||
regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS),
|
||||
regmap_reg_range(DSIERRCNT, DSIERRCNT),
|
||||
regmap_reg_range(VFUEN0, VFUEN0),
|
||||
regmap_reg_range(SYSSTAT, SYSSTAT),
|
||||
regmap_reg_range(GPIOI, GPIOI),
|
||||
regmap_reg_range(INTSTS_G, INTSTS_G),
|
||||
regmap_reg_range(DP0_VMNGENSTATUS, DP0_VMNGENSTATUS),
|
||||
regmap_reg_range(DP0_AMNGENSTATUS, DP0_AMNGENSTATUS),
|
||||
regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS),
|
||||
regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ),
|
||||
regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL),
|
||||
regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL),
|
||||
regmap_reg_range(VFUEN0, VFUEN0),
|
||||
regmap_reg_range(INTSTS_G, INTSTS_G),
|
||||
regmap_reg_range(GPIOI, GPIOI),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table tc_volatile_table = {
|
||||
|
@ -1992,12 +2070,28 @@ static const struct regmap_access_table tc_volatile_table = {
|
|||
.n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges),
|
||||
};
|
||||
|
||||
static bool tc_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg != TC_IDREG) &&
|
||||
(reg != DP0_LTSTAT) &&
|
||||
(reg != DP0_SNKLTCHGREQ);
|
||||
}
|
||||
static const struct regmap_range tc_precious_ranges[] = {
|
||||
regmap_reg_range(SYSSTAT, SYSSTAT),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table tc_precious_table = {
|
||||
.yes_ranges = tc_precious_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(tc_precious_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range tc_non_writeable_ranges[] = {
|
||||
regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI),
|
||||
regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI),
|
||||
regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS),
|
||||
regmap_reg_range(TC_IDREG, SYSSTAT),
|
||||
regmap_reg_range(GPIOI, GPIOI),
|
||||
regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table tc_writeable_table = {
|
||||
.no_ranges = tc_non_writeable_ranges,
|
||||
.n_no_ranges = ARRAY_SIZE(tc_non_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config tc_regmap_config = {
|
||||
.name = "tc358767",
|
||||
|
@ -2008,7 +2102,8 @@ static const struct regmap_config tc_regmap_config = {
|
|||
.cache_type = REGCACHE_MAPLE,
|
||||
.readable_reg = tc_readable_reg,
|
||||
.volatile_table = &tc_volatile_table,
|
||||
.writeable_reg = tc_writeable_reg,
|
||||
.precious_table = &tc_precious_table,
|
||||
.wr_table = &tc_writeable_table,
|
||||
.reg_format_endian = REGMAP_ENDIAN_BIG,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
};
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
#include "drm_crtc_internal.h"
|
||||
#include "drm_internal.h"
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
/***************************************************
|
||||
* Initialization, etc.
|
||||
**************************************************/
|
||||
|
@ -647,5 +645,3 @@ void drm_debugfs_encoder_remove(struct drm_encoder *encoder)
|
|||
debugfs_remove_recursive(encoder->debugfs_entry);
|
||||
encoder->debugfs_entry = NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
|
|
@ -3611,7 +3611,8 @@ static bool mode_in_range(const struct drm_display_mode *mode,
|
|||
if (!mode_in_vsync_range(mode, edid, t))
|
||||
return false;
|
||||
|
||||
if ((max_clock = range_pixel_clock(edid, t)))
|
||||
max_clock = range_pixel_clock(edid, t);
|
||||
if (max_clock)
|
||||
if (mode->clock > max_clock)
|
||||
return false;
|
||||
|
||||
|
@ -6990,28 +6991,6 @@ int drm_add_modes_noedid(struct drm_connector *connector,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_add_modes_noedid);
|
||||
|
||||
/**
|
||||
* drm_set_preferred_mode - Sets the preferred mode of a connector
|
||||
* @connector: connector whose mode list should be processed
|
||||
* @hpref: horizontal resolution of preferred mode
|
||||
* @vpref: vertical resolution of preferred mode
|
||||
*
|
||||
* Marks a mode as preferred if it matches the resolution specified by @hpref
|
||||
* and @vpref.
|
||||
*/
|
||||
void drm_set_preferred_mode(struct drm_connector *connector,
|
||||
int hpref, int vpref)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
if (mode->hdisplay == hpref &&
|
||||
mode->vdisplay == vpref)
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_set_preferred_mode);
|
||||
|
||||
static bool is_hdmi2_sink(const struct drm_connector *connector)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -229,7 +229,7 @@ typedef struct drm_update_draw32 {
|
|||
unsigned int num;
|
||||
/* 64-bit version has a 32-bit pad here */
|
||||
u64 data; /**< Pointer */
|
||||
} __attribute__((packed)) drm_update_draw32_t;
|
||||
} __packed drm_update_draw32_t;
|
||||
|
||||
static int compat_drm_update_draw(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
|
@ -296,7 +296,7 @@ typedef struct drm_mode_fb_cmd232 {
|
|||
u32 pitches[4];
|
||||
u32 offsets[4];
|
||||
u64 modifier[4];
|
||||
} __attribute__((packed)) drm_mode_fb_cmd232_t;
|
||||
} __packed drm_mode_fb_cmd232_t;
|
||||
|
||||
static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
|
|
|
@ -2752,3 +2752,25 @@ bool drm_mode_is_420(const struct drm_display_info *display,
|
|||
drm_mode_is_420_also(display, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_is_420);
|
||||
|
||||
/**
|
||||
* drm_set_preferred_mode - Sets the preferred mode of a connector
|
||||
* @connector: connector whose mode list should be processed
|
||||
* @hpref: horizontal resolution of preferred mode
|
||||
* @vpref: vertical resolution of preferred mode
|
||||
*
|
||||
* Marks a mode as preferred if it matches the resolution specified by @hpref
|
||||
* and @vpref.
|
||||
*/
|
||||
void drm_set_preferred_mode(struct drm_connector *connector,
|
||||
int hpref, int vpref)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
if (mode->hdisplay == hpref &&
|
||||
mode->vdisplay == vpref)
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_set_preferred_mode);
|
||||
|
|
|
@ -1100,42 +1100,6 @@ enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_crtc_helper_mode_valid_fixed);
|
||||
|
||||
/**
|
||||
* drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID
|
||||
* property from the connector's
|
||||
* DDC channel
|
||||
* @connector: The connector
|
||||
*
|
||||
* Returns:
|
||||
* The number of detected display modes.
|
||||
*
|
||||
* Uses a connector's DDC channel to retrieve EDID data and update the
|
||||
* connector's EDID property and display modes. Drivers can use this
|
||||
* function to implement struct &drm_connector_helper_funcs.get_modes
|
||||
* for connectors with a DDC channel.
|
||||
*/
|
||||
int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector)
|
||||
{
|
||||
struct edid *edid;
|
||||
int count = 0;
|
||||
|
||||
if (!connector->ddc)
|
||||
return 0;
|
||||
|
||||
edid = drm_get_edid(connector, connector->ddc);
|
||||
|
||||
// clears property if EDID is NULL
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
|
||||
if (edid) {
|
||||
count = drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc);
|
||||
|
||||
/**
|
||||
* drm_connector_helper_get_modes_fixed - Duplicates a display mode for a connector
|
||||
* @connector: the connector
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
||||
struct hibmc_connector {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/io.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
|
|
@ -146,14 +146,13 @@ int mgag200_device_preinit(struct mga_device *mdev)
|
|||
}
|
||||
mdev->vram_res = res;
|
||||
|
||||
/* Don't fail on errors, but performance might be reduced. */
|
||||
devm_arch_io_reserve_memtype_wc(dev->dev, res->start, resource_size(res));
|
||||
devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res));
|
||||
|
||||
mdev->vram = devm_ioremap(dev->dev, res->start, resource_size(res));
|
||||
mdev->vram = devm_ioremap_wc(dev->dev, res->start, resource_size(res));
|
||||
if (!mdev->vram)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't fail on errors, but performance might be reduced. */
|
||||
devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "mgag200_drv.h"
|
||||
|
||||
|
@ -717,17 +717,23 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st
|
|||
int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct mga_device *mdev = to_mga_device(connector->dev);
|
||||
int ret;
|
||||
const struct drm_edid *drm_edid;
|
||||
int count;
|
||||
|
||||
/*
|
||||
* Protect access to I/O registers from concurrent modesetting
|
||||
* by acquiring the I/O-register lock.
|
||||
*/
|
||||
mutex_lock(&mdev->rmmio_lock);
|
||||
ret = drm_connector_helper_get_modes_from_ddc(connector);
|
||||
|
||||
drm_edid = drm_edid_read(connector);
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
count = drm_edid_connector_add_modes(connector);
|
||||
drm_edid_free(drm_edid);
|
||||
|
||||
mutex_unlock(&mdev->rmmio_lock);
|
||||
|
||||
return ret;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -449,7 +449,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
|
|||
regp->Attribute[NV_CIO_AR_CSEL_INDEX] = 0x00;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Sets up registers for the given mode/adjusted_mode pair.
|
||||
*
|
||||
* The clocks, CRTCs and outputs attached to this CRTC must be off.
|
||||
|
@ -625,7 +625,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Sets up registers for the given mode/adjusted_mode pair.
|
||||
*
|
||||
* The clocks, CRTCs and outputs attached to this CRTC must be off.
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include "nouveau_connector.h"
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
|
@ -44,6 +43,7 @@
|
|||
|
||||
struct nvkm_i2c_port;
|
||||
struct dcb_output;
|
||||
struct edid;
|
||||
|
||||
#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
|
||||
struct nouveau_backlight {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* \file mga_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the MGA DRM.
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "nouveau_ioctl.h"
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
|
|
|
@ -452,13 +452,12 @@ nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid)
|
|||
if (ret)
|
||||
goto done;
|
||||
|
||||
*pedid = kmalloc(args->size, GFP_KERNEL);
|
||||
*pedid = kmemdup(args->data, args->size, GFP_KERNEL);
|
||||
if (!*pedid) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(*pedid, args->data, args->size);
|
||||
ret = args->size;
|
||||
done:
|
||||
kfree(args);
|
||||
|
|
|
@ -1040,7 +1040,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Wait until GR goes idle. GR is considered idle if it is disabled by the
|
||||
* MC (0x200) register, or GR is not busy and a context switch is not in
|
||||
* progress.
|
||||
|
|
|
@ -575,7 +575,7 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds)
|
|||
* init opcode handlers
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
/*
|
||||
* init_reserved - stub for various unknown/unused single-byte opcodes
|
||||
*
|
||||
*/
|
||||
|
@ -602,7 +602,7 @@ init_reserved(struct nvbios_init *init)
|
|||
init->offset += length;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_DONE - opcode 0x71
|
||||
*
|
||||
*/
|
||||
|
@ -613,7 +613,7 @@ init_done(struct nvbios_init *init)
|
|||
init->offset = 0x0000;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_RESTRICT_PROG - opcode 0x32
|
||||
*
|
||||
*/
|
||||
|
@ -650,7 +650,7 @@ init_io_restrict_prog(struct nvbios_init *init)
|
|||
trace("}]\n");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_REPEAT - opcode 0x33
|
||||
*
|
||||
*/
|
||||
|
@ -676,7 +676,7 @@ init_repeat(struct nvbios_init *init)
|
|||
init->repeat = repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_RESTRICT_PLL - opcode 0x34
|
||||
*
|
||||
*/
|
||||
|
@ -716,7 +716,7 @@ init_io_restrict_pll(struct nvbios_init *init)
|
|||
trace("}]\n");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_END_REPEAT - opcode 0x36
|
||||
*
|
||||
*/
|
||||
|
@ -732,7 +732,7 @@ init_end_repeat(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_COPY - opcode 0x37
|
||||
*
|
||||
*/
|
||||
|
@ -759,7 +759,7 @@ init_copy(struct nvbios_init *init)
|
|||
init_wrvgai(init, port, index, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_NOT - opcode 0x38
|
||||
*
|
||||
*/
|
||||
|
@ -771,7 +771,7 @@ init_not(struct nvbios_init *init)
|
|||
init_exec_inv(init);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_FLAG_CONDITION - opcode 0x39
|
||||
*
|
||||
*/
|
||||
|
@ -788,7 +788,7 @@ init_io_flag_condition(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_GENERIC_CONDITION - opcode 0x3a
|
||||
*
|
||||
*/
|
||||
|
@ -840,7 +840,7 @@ init_generic_condition(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_MASK_OR - opcode 0x3b
|
||||
*
|
||||
*/
|
||||
|
@ -859,7 +859,7 @@ init_io_mask_or(struct nvbios_init *init)
|
|||
init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_OR - opcode 0x3c
|
||||
*
|
||||
*/
|
||||
|
@ -878,7 +878,7 @@ init_io_or(struct nvbios_init *init)
|
|||
init_wrvgai(init, 0x03d4, index, data | (1 << or));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ANDN_REG - opcode 0x47
|
||||
*
|
||||
*/
|
||||
|
@ -895,7 +895,7 @@ init_andn_reg(struct nvbios_init *init)
|
|||
init_mask(init, reg, mask, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_OR_REG - opcode 0x48
|
||||
*
|
||||
*/
|
||||
|
@ -912,7 +912,7 @@ init_or_reg(struct nvbios_init *init)
|
|||
init_mask(init, reg, 0, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
|
||||
*
|
||||
*/
|
||||
|
@ -942,7 +942,7 @@ init_idx_addr_latched(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_RESTRICT_PLL2 - opcode 0x4a
|
||||
*
|
||||
*/
|
||||
|
@ -977,7 +977,7 @@ init_io_restrict_pll2(struct nvbios_init *init)
|
|||
trace("}]\n");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_PLL2 - opcode 0x4b
|
||||
*
|
||||
*/
|
||||
|
@ -994,7 +994,7 @@ init_pll2(struct nvbios_init *init)
|
|||
init_prog_pll(init, reg, freq);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_I2C_BYTE - opcode 0x4c
|
||||
*
|
||||
*/
|
||||
|
@ -1025,7 +1025,7 @@ init_i2c_byte(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_I2C_BYTE - opcode 0x4d
|
||||
*
|
||||
*/
|
||||
|
@ -1051,7 +1051,7 @@ init_zm_i2c_byte(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_I2C - opcode 0x4e
|
||||
*
|
||||
*/
|
||||
|
@ -1085,7 +1085,7 @@ init_zm_i2c(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_TMDS - opcode 0x4f
|
||||
*
|
||||
*/
|
||||
|
@ -1111,7 +1111,7 @@ init_tmds(struct nvbios_init *init)
|
|||
init_wr32(init, reg + 0, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_TMDS_GROUP - opcode 0x50
|
||||
*
|
||||
*/
|
||||
|
@ -1138,7 +1138,7 @@ init_zm_tmds_group(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
|
||||
*
|
||||
*/
|
||||
|
@ -1168,7 +1168,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init)
|
|||
init_wrvgai(init, 0x03d4, addr0, save0);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CR - opcode 0x52
|
||||
*
|
||||
*/
|
||||
|
@ -1188,7 +1188,7 @@ init_cr(struct nvbios_init *init)
|
|||
init_wrvgai(init, 0x03d4, addr, val | data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_CR - opcode 0x53
|
||||
*
|
||||
*/
|
||||
|
@ -1205,7 +1205,7 @@ init_zm_cr(struct nvbios_init *init)
|
|||
init_wrvgai(init, 0x03d4, addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_CR_GROUP - opcode 0x54
|
||||
*
|
||||
*/
|
||||
|
@ -1229,7 +1229,7 @@ init_zm_cr_group(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CONDITION_TIME - opcode 0x56
|
||||
*
|
||||
*/
|
||||
|
@ -1256,7 +1256,7 @@ init_condition_time(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_LTIME - opcode 0x57
|
||||
*
|
||||
*/
|
||||
|
@ -1273,7 +1273,7 @@ init_ltime(struct nvbios_init *init)
|
|||
mdelay(msec);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_REG_SEQUENCE - opcode 0x58
|
||||
*
|
||||
*/
|
||||
|
@ -1298,7 +1298,7 @@ init_zm_reg_sequence(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_PLL_INDIRECT - opcode 0x59
|
||||
*
|
||||
*/
|
||||
|
@ -1317,7 +1317,7 @@ init_pll_indirect(struct nvbios_init *init)
|
|||
init_prog_pll(init, reg, freq);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_REG_INDIRECT - opcode 0x5a
|
||||
*
|
||||
*/
|
||||
|
@ -1336,7 +1336,7 @@ init_zm_reg_indirect(struct nvbios_init *init)
|
|||
init_wr32(init, addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_SUB_DIRECT - opcode 0x5b
|
||||
*
|
||||
*/
|
||||
|
@ -1362,7 +1362,7 @@ init_sub_direct(struct nvbios_init *init)
|
|||
init->offset += 3;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_JUMP - opcode 0x5c
|
||||
*
|
||||
*/
|
||||
|
@ -1380,7 +1380,7 @@ init_jump(struct nvbios_init *init)
|
|||
init->offset += 3;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_I2C_IF - opcode 0x5e
|
||||
*
|
||||
*/
|
||||
|
@ -1407,7 +1407,7 @@ init_i2c_if(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_COPY_NV_REG - opcode 0x5f
|
||||
*
|
||||
*/
|
||||
|
@ -1433,7 +1433,7 @@ init_copy_nv_reg(struct nvbios_init *init)
|
|||
init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_INDEX_IO - opcode 0x62
|
||||
*
|
||||
*/
|
||||
|
@ -1451,7 +1451,7 @@ init_zm_index_io(struct nvbios_init *init)
|
|||
init_wrvgai(init, port, index, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_COMPUTE_MEM - opcode 0x63
|
||||
*
|
||||
*/
|
||||
|
@ -1469,7 +1469,7 @@ init_compute_mem(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RESET - opcode 0x65
|
||||
*
|
||||
*/
|
||||
|
@ -1496,7 +1496,7 @@ init_reset(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CONFIGURE_MEM - opcode 0x66
|
||||
*
|
||||
*/
|
||||
|
@ -1555,7 +1555,7 @@ init_configure_mem(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CONFIGURE_CLK - opcode 0x67
|
||||
*
|
||||
*/
|
||||
|
@ -1589,7 +1589,7 @@ init_configure_clk(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CONFIGURE_PREINIT - opcode 0x68
|
||||
*
|
||||
*/
|
||||
|
@ -1615,7 +1615,7 @@ init_configure_preinit(struct nvbios_init *init)
|
|||
init_exec_force(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO - opcode 0x69
|
||||
*
|
||||
*/
|
||||
|
@ -1655,7 +1655,7 @@ init_io(struct nvbios_init *init)
|
|||
init_wrport(init, port, data | value);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_SUB - opcode 0x6b
|
||||
*
|
||||
*/
|
||||
|
@ -1682,7 +1682,7 @@ init_sub(struct nvbios_init *init)
|
|||
init->offset += 2;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RAM_CONDITION - opcode 0x6d
|
||||
*
|
||||
*/
|
||||
|
@ -1701,7 +1701,7 @@ init_ram_condition(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_NV_REG - opcode 0x6e
|
||||
*
|
||||
*/
|
||||
|
@ -1719,7 +1719,7 @@ init_nv_reg(struct nvbios_init *init)
|
|||
init_mask(init, reg, ~mask, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_MACRO - opcode 0x6f
|
||||
*
|
||||
*/
|
||||
|
@ -1743,7 +1743,7 @@ init_macro(struct nvbios_init *init)
|
|||
init->offset += 2;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RESUME - opcode 0x72
|
||||
*
|
||||
*/
|
||||
|
@ -1755,7 +1755,7 @@ init_resume(struct nvbios_init *init)
|
|||
init_exec_set(init, true);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_STRAP_CONDITION - opcode 0x73
|
||||
*
|
||||
*/
|
||||
|
@ -1773,7 +1773,7 @@ init_strap_condition(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_TIME - opcode 0x74
|
||||
*
|
||||
*/
|
||||
|
@ -1794,7 +1794,7 @@ init_time(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_CONDITION - opcode 0x75
|
||||
*
|
||||
*/
|
||||
|
@ -1811,7 +1811,7 @@ init_condition(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_IO_CONDITION - opcode 0x76
|
||||
*
|
||||
*/
|
||||
|
@ -1828,7 +1828,7 @@ init_io_condition(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_REG16 - opcode 0x77
|
||||
*
|
||||
*/
|
||||
|
@ -1845,7 +1845,7 @@ init_zm_reg16(struct nvbios_init *init)
|
|||
init_wr32(init, addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_INDEX_IO - opcode 0x78
|
||||
*
|
||||
*/
|
||||
|
@ -1867,7 +1867,7 @@ init_index_io(struct nvbios_init *init)
|
|||
init_wrvgai(init, port, index, data | value);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_PLL - opcode 0x79
|
||||
*
|
||||
*/
|
||||
|
@ -1884,7 +1884,7 @@ init_pll(struct nvbios_init *init)
|
|||
init_prog_pll(init, reg, freq);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_REG - opcode 0x7a
|
||||
*
|
||||
*/
|
||||
|
@ -1904,7 +1904,7 @@ init_zm_reg(struct nvbios_init *init)
|
|||
init_wr32(init, addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RAM_RESTRICT_PLL - opcde 0x87
|
||||
*
|
||||
*/
|
||||
|
@ -1934,7 +1934,7 @@ init_ram_restrict_pll(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RESET_BEGUN - opcode 0x8c
|
||||
*
|
||||
*/
|
||||
|
@ -1945,7 +1945,7 @@ init_reset_begun(struct nvbios_init *init)
|
|||
init->offset += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RESET_END - opcode 0x8d
|
||||
*
|
||||
*/
|
||||
|
@ -1956,7 +1956,7 @@ init_reset_end(struct nvbios_init *init)
|
|||
init->offset += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_GPIO - opcode 0x8e
|
||||
*
|
||||
*/
|
||||
|
@ -1972,7 +1972,7 @@ init_gpio(struct nvbios_init *init)
|
|||
nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
|
||||
*
|
||||
*/
|
||||
|
@ -2010,7 +2010,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_COPY_ZM_REG - opcode 0x90
|
||||
*
|
||||
*/
|
||||
|
@ -2027,7 +2027,7 @@ init_copy_zm_reg(struct nvbios_init *init)
|
|||
init_wr32(init, dreg, init_rd32(init, sreg));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_REG_GROUP - opcode 0x91
|
||||
*
|
||||
*/
|
||||
|
@ -2049,7 +2049,7 @@ init_zm_reg_group(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_XLAT - opcode 0x96
|
||||
*
|
||||
*/
|
||||
|
@ -2077,7 +2077,7 @@ init_xlat(struct nvbios_init *init)
|
|||
init_mask(init, daddr, ~dmask, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_ZM_MASK_ADD - opcode 0x97
|
||||
*
|
||||
*/
|
||||
|
@ -2098,7 +2098,7 @@ init_zm_mask_add(struct nvbios_init *init)
|
|||
init_wr32(init, addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_AUXCH - opcode 0x98
|
||||
*
|
||||
*/
|
||||
|
@ -2122,7 +2122,7 @@ init_auxch(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_AUXCH - opcode 0x99
|
||||
*
|
||||
*/
|
||||
|
@ -2144,7 +2144,7 @@ init_zm_auxch(struct nvbios_init *init)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_I2C_LONG_IF - opcode 0x9a
|
||||
*
|
||||
*/
|
||||
|
@ -2183,7 +2183,7 @@ init_i2c_long_if(struct nvbios_init *init)
|
|||
init_exec_set(init, false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* INIT_GPIO_NE - opcode 0xa9
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -45,7 +45,7 @@ static const struct cvb_coef gk20a_cvb_coef[] = {
|
|||
/* 852 */ { 1608418, -21643, -269, 0, 763, -48},
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
|
||||
*/
|
||||
static inline int
|
||||
|
@ -58,7 +58,7 @@ gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef)
|
|||
return mv;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cvb_t_mv =
|
||||
* ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
|
||||
* ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
|
||||
|
|
|
@ -70,6 +70,21 @@ struct panel_delay {
|
|||
*/
|
||||
unsigned int hpd_absent;
|
||||
|
||||
/**
|
||||
* @powered_on_to_enable: Time between panel powered on and enable.
|
||||
*
|
||||
* The minimum time, in milliseconds, that needs to have passed
|
||||
* between when panel powered on and enable may begin.
|
||||
*
|
||||
* This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the
|
||||
* power supply enabled until we can turn the backlight on and see
|
||||
* valid data.
|
||||
*
|
||||
* This doesn't normally need to be set if timings are already met by
|
||||
* prepare_to_enable or enable.
|
||||
*/
|
||||
unsigned int powered_on_to_enable;
|
||||
|
||||
/**
|
||||
* @prepare_to_enable: Time between prepare and enable.
|
||||
*
|
||||
|
@ -216,6 +231,7 @@ struct panel_edp {
|
|||
bool prepared;
|
||||
|
||||
ktime_t prepared_time;
|
||||
ktime_t powered_on_time;
|
||||
ktime_t unprepared_time;
|
||||
|
||||
const struct panel_desc *desc;
|
||||
|
@ -413,8 +429,7 @@ static int panel_edp_unprepare(struct drm_panel *panel)
|
|||
if (!p->prepared)
|
||||
return 0;
|
||||
|
||||
pm_runtime_mark_last_busy(panel->dev);
|
||||
ret = pm_runtime_put_autosuspend(panel->dev);
|
||||
ret = pm_runtime_put_sync_suspend(panel->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
p->prepared = false;
|
||||
|
@ -455,6 +470,8 @@ static int panel_edp_prepare_once(struct panel_edp *p)
|
|||
|
||||
gpiod_set_value_cansleep(p->enable_gpio, 1);
|
||||
|
||||
p->powered_on_time = ktime_get_boottime();
|
||||
|
||||
delay = p->desc->delay.hpd_reliable;
|
||||
if (p->no_hpd)
|
||||
delay = max(delay, p->desc->delay.hpd_absent);
|
||||
|
@ -579,6 +596,8 @@ static int panel_edp_enable(struct drm_panel *panel)
|
|||
|
||||
panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
|
||||
|
||||
panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable);
|
||||
|
||||
p->enabled = true;
|
||||
|
||||
return 0;
|
||||
|
@ -1837,6 +1856,13 @@ static const struct panel_delay delay_200_500_p2e80 = {
|
|||
.prepare_to_enable = 80,
|
||||
};
|
||||
|
||||
static const struct panel_delay delay_200_500_e50_p2e80 = {
|
||||
.hpd_absent = 200,
|
||||
.unprepare = 500,
|
||||
.enable = 50,
|
||||
.prepare_to_enable = 80,
|
||||
};
|
||||
|
||||
static const struct panel_delay delay_200_500_p2e100 = {
|
||||
.hpd_absent = 200,
|
||||
.unprepare = 500,
|
||||
|
@ -1874,6 +1900,13 @@ static const struct panel_delay delay_200_500_e200 = {
|
|||
.enable = 200,
|
||||
};
|
||||
|
||||
static const struct panel_delay delay_200_500_e200_d200 = {
|
||||
.hpd_absent = 200,
|
||||
.unprepare = 500,
|
||||
.enable = 200,
|
||||
.disable = 200,
|
||||
};
|
||||
|
||||
static const struct panel_delay delay_200_500_e200_d10 = {
|
||||
.hpd_absent = 200,
|
||||
.unprepare = 500,
|
||||
|
@ -1887,6 +1920,13 @@ static const struct panel_delay delay_200_150_e200 = {
|
|||
.enable = 200,
|
||||
};
|
||||
|
||||
static const struct panel_delay delay_200_500_e50_po2e200 = {
|
||||
.hpd_absent = 200,
|
||||
.unprepare = 500,
|
||||
.enable = 50,
|
||||
.powered_on_to_enable = 200,
|
||||
};
|
||||
|
||||
#define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
|
@ -1912,7 +1952,9 @@ static const struct panel_delay delay_200_150_e200 = {
|
|||
* Sort first by vendor, then by product ID.
|
||||
*/
|
||||
static const struct edp_panel_entry edp_panels[] = {
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"),
|
||||
|
@ -1923,54 +1965,91 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"),
|
||||
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0",
|
||||
&auo_b116xa3_mode),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"),
|
||||
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1",
|
||||
&auo_b116xa3_mode),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"),
|
||||
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f8, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0813, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0843, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x096e, &delay_200_500_e50_po2e200, "NV116WHM-T07 V8.0"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0993, &delay_200_500_e80, "NV116WHM-T14 V8.0"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"),
|
||||
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1141, &delay_200_500_e80_d50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x114a, &delay_200_500_e80_d50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"),
|
||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"),
|
||||
|
||||
EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50, "MNC207QS1-1"),
|
||||
|
||||
EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"),
|
||||
|
||||
EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"),
|
||||
|
@ -1979,11 +2058,25 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"),
|
||||
EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"),
|
||||
|
||||
EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
|
||||
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"),
|
||||
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"),
|
||||
|
||||
EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, &delay_200_500_e50, "KD116N9-30NH-F3"),
|
||||
EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"),
|
||||
EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"),
|
||||
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0000, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x048d, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0537, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"),
|
||||
|
||||
EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"),
|
||||
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"),
|
||||
|
|
|
@ -646,26 +646,17 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
|
|||
return -EINVAL;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
dev_err(dev, "cannot get reset gpio\n");
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
if (IS_ERR(ctx->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n");
|
||||
|
||||
ctx->vci = devm_regulator_get(dev, "vci");
|
||||
if (IS_ERR(ctx->vci)) {
|
||||
ret = PTR_ERR(ctx->vci);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to request vci regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(ctx->vci))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n");
|
||||
|
||||
ctx->iovcc = devm_regulator_get(dev, "iovcc");
|
||||
if (IS_ERR(ctx->iovcc)) {
|
||||
ret = PTR_ERR(ctx->iovcc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(ctx->iovcc))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
|
||||
"Failed to request iovcc regulator\n");
|
||||
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#define NT35510_CMD_CORRECT_GAMMA BIT(0)
|
||||
#define NT35510_CMD_CONTROL_DISPLAY BIT(1)
|
||||
|
||||
#define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */
|
||||
#define MCS_CMD_READ_ID1 0xDA
|
||||
#define MCS_CMD_READ_ID2 0xDB
|
||||
|
@ -112,18 +115,33 @@
|
|||
/* AVDD and AVEE setting 3 bytes */
|
||||
#define NT35510_P1_AVDD_LEN 3
|
||||
#define NT35510_P1_AVEE_LEN 3
|
||||
#define NT35510_P1_VCL_LEN 3
|
||||
#define NT35510_P1_VGH_LEN 3
|
||||
#define NT35510_P1_VGL_LEN 3
|
||||
#define NT35510_P1_VGP_LEN 3
|
||||
#define NT35510_P1_VGN_LEN 3
|
||||
#define NT35510_P1_VCMOFF_LEN 2
|
||||
/* BT1CTR thru BT5CTR setting 3 bytes */
|
||||
#define NT35510_P1_BT1CTR_LEN 3
|
||||
#define NT35510_P1_BT2CTR_LEN 3
|
||||
#define NT35510_P1_BT3CTR_LEN 3
|
||||
#define NT35510_P1_BT4CTR_LEN 3
|
||||
#define NT35510_P1_BT5CTR_LEN 3
|
||||
/* 52 gamma parameters times two per color: positive and negative */
|
||||
#define NT35510_P1_GAMMA_LEN 52
|
||||
|
||||
#define NT35510_WRCTRLD_BCTRL BIT(5)
|
||||
#define NT35510_WRCTRLD_A BIT(4)
|
||||
#define NT35510_WRCTRLD_DD BIT(3)
|
||||
#define NT35510_WRCTRLD_BL BIT(2)
|
||||
#define NT35510_WRCTRLD_DB BIT(1)
|
||||
#define NT35510_WRCTRLD_G BIT(0)
|
||||
|
||||
#define NT35510_WRCABC_OFF 0
|
||||
#define NT35510_WRCABC_UI_MODE 1
|
||||
#define NT35510_WRCABC_STILL_MODE 2
|
||||
#define NT35510_WRCABC_MOVING_MODE 3
|
||||
|
||||
/**
|
||||
* struct nt35510_config - the display-specific NT35510 configuration
|
||||
*
|
||||
|
@ -171,6 +189,14 @@ struct nt35510_config {
|
|||
* timing in the display controller.
|
||||
*/
|
||||
const struct drm_display_mode mode;
|
||||
/**
|
||||
* @mode_flags: DSI operation mode related flags
|
||||
*/
|
||||
unsigned long mode_flags;
|
||||
/**
|
||||
* @cmds: enable DSI commands
|
||||
*/
|
||||
u32 cmds;
|
||||
/**
|
||||
* @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V
|
||||
* in 0.1V steps the default is 0x05 which means 6.0V
|
||||
|
@ -220,6 +246,25 @@ struct nt35510_config {
|
|||
* The defaults are 4 and 3 yielding 0x34
|
||||
*/
|
||||
u8 bt2ctr[NT35510_P1_BT2CTR_LEN];
|
||||
/**
|
||||
* @vcl: setting for VCL ranging from 0x00 = -2.5V to 0x11 = -4.0V
|
||||
* in 1V steps, the default is 0x00 which means -2.5V
|
||||
*/
|
||||
u8 vcl[NT35510_P1_VCL_LEN];
|
||||
/**
|
||||
* @bt3ctr: setting for boost power control for the VCL step-up
|
||||
* circuit (3)
|
||||
* bits 0..2 in the lower nibble controls CLCK, the booster clock
|
||||
* frequency, the values are the same as for PCK in @bt1ctr.
|
||||
* bits 4..5 in the upper nibble controls BTCL, the boosting
|
||||
* amplification for the step-up circuit.
|
||||
* 0 = Disable
|
||||
* 1 = -0.5 x VDDB
|
||||
* 2 = -1 x VDDB
|
||||
* 3 = -2 x VDDB
|
||||
* The defaults are 4 and 2 yielding 0x24
|
||||
*/
|
||||
u8 bt3ctr[NT35510_P1_BT3CTR_LEN];
|
||||
/**
|
||||
* @vgh: setting for VGH ranging from 0x00 = 7.0V to 0x0B = 18.0V
|
||||
* in 1V steps, the default is 0x08 which means 15V
|
||||
|
@ -273,6 +318,113 @@ struct nt35510_config {
|
|||
* same layout of bytes as @vgp.
|
||||
*/
|
||||
u8 vgn[NT35510_P1_VGN_LEN];
|
||||
/**
|
||||
* @vcmoff: setting the DC VCOM offset voltage
|
||||
* The first byte contains bit 8 of VCM in bit 0 and VCMOFFSEL in bit 4.
|
||||
* The second byte contains bits 0..7 of VCM.
|
||||
* VCMOFFSEL the common voltage offset mode.
|
||||
* VCMOFFSEL 0x00 = VCOM .. 0x01 Gamma.
|
||||
* The default is 0x00.
|
||||
* VCM the VCOM output voltage (VCMOFFSEL = 0) or the internal register
|
||||
* offset for gamma voltage (VCMOFFSEL = 1).
|
||||
* VCM 0x00 = 0V/0 .. 0x118 = 3.5V/280 in steps of 12.5mV/1step
|
||||
* The default is 0x00 = 0V/0.
|
||||
*/
|
||||
u8 vcmoff[NT35510_P1_VCMOFF_LEN];
|
||||
/**
|
||||
* @dopctr: setting optional control for display
|
||||
* ERR bits 0..1 in the first byte is the ERR pin output signal setting.
|
||||
* 0 = Disable, ERR pin output low
|
||||
* 1 = ERR pin output CRC error only
|
||||
* 2 = ERR pin output ECC error only
|
||||
* 3 = ERR pin output CRC and ECC error
|
||||
* The default is 0.
|
||||
* N565 bit 2 in the first byte is the 16-bit/pixel format selection.
|
||||
* 0 = R[4:0] + G[5:3] & G[2:0] + B[4:0]
|
||||
* 1 = G[2:0] + R[4:0] & B[4:0] + G[5:3]
|
||||
* The default is 0.
|
||||
* DIS_EoTP_HS bit 3 in the first byte is "DSI protocol violation" error
|
||||
* reporting.
|
||||
* 0 = reporting when error
|
||||
* 1 = not reporting when error
|
||||
* DSIM bit 4 in the first byte is the video mode data type enable
|
||||
* 0 = Video mode data type disable
|
||||
* 1 = Video mode data type enable
|
||||
* The default is 0.
|
||||
* DSIG bit 5 int the first byte is the generic r/w data type enable
|
||||
* 0 = Generic r/w disable
|
||||
* 1 = Generic r/w enable
|
||||
* The default is 0.
|
||||
* DSITE bit 6 in the first byte is TE line enable
|
||||
* 0 = TE line is disabled
|
||||
* 1 = TE line is enabled
|
||||
* The default is 0.
|
||||
* RAMKP bit 7 in the first byte is the frame memory keep/loss in
|
||||
* sleep-in mode
|
||||
* 0 = contents loss in sleep-in
|
||||
* 1 = contents keep in sleep-in
|
||||
* The default is 0.
|
||||
* CRL bit 1 in the second byte is the source driver data shift
|
||||
* direction selection. This bit is XOR operation with bit RSMX
|
||||
* of 3600h command.
|
||||
* 0 (RMSX = 0) = S1 -> S1440
|
||||
* 0 (RMSX = 1) = S1440 -> S1
|
||||
* 1 (RMSX = 0) = S1440 -> S1
|
||||
* 1 (RMSX = 1) = S1 -> S1440
|
||||
* The default is 0.
|
||||
* CTB bit 2 in the second byte is the vertical scanning direction
|
||||
* selection for gate control signals. This bit is XOR operation
|
||||
* with bit ML of 3600h command.
|
||||
* 0 (ML = 0) = Forward (top -> bottom)
|
||||
* 0 (ML = 1) = Reverse (bottom -> top)
|
||||
* 1 (ML = 0) = Reverse (bottom -> top)
|
||||
* 1 (ML = 1) = Forward (top -> bottom)
|
||||
* The default is 0.
|
||||
* CRGB bit 3 in the second byte is RGB-BGR order selection. This
|
||||
* bit is XOR operation with bit RGB of 3600h command.
|
||||
* 0 (RGB = 0) = RGB/Normal
|
||||
* 0 (RGB = 1) = BGR/RB swap
|
||||
* 1 (RGB = 0) = BGR/RB swap
|
||||
* 1 (RGB = 1) = RGB/Normal
|
||||
* The default is 0.
|
||||
* TE_PWR_SEL bit 4 in the second byte is the TE output voltage
|
||||
* level selection (only valid when DSTB_SEL = 0 or DSTB_SEL = 1,
|
||||
* VSEL = High and VDDI = 1.665~3.3V).
|
||||
* 0 = TE output voltage level is VDDI
|
||||
* 1 = TE output voltage level is VDDA
|
||||
* The default is 0.
|
||||
*/
|
||||
u8 dopctr[NT35510_P0_DOPCTR_LEN];
|
||||
/**
|
||||
* @madctl: Memory data access control
|
||||
* RSMY bit 0 is flip vertical. Flips the display image top to down.
|
||||
* RSMX bit 1 is flip horizontal. Flips the display image left to right.
|
||||
* MH bit 2 is the horizontal refresh order.
|
||||
* RGB bit 3 is the RGB-BGR order.
|
||||
* 0 = RGB color sequence
|
||||
* 1 = BGR color sequence
|
||||
* ML bit 4 is the vertical refresh order.
|
||||
* MV bit 5 is the row/column exchange.
|
||||
* MX bit 6 is the column address order.
|
||||
* MY bit 7 is the row address order.
|
||||
*/
|
||||
u8 madctl;
|
||||
/**
|
||||
* @sdhdtctr: source output data hold time
|
||||
* 0x00..0x3F = 0..31.5us in steps of 0.5us
|
||||
* The default is 0x05 = 2.5us.
|
||||
*/
|
||||
u8 sdhdtctr;
|
||||
/**
|
||||
* @gseqctr: EQ control for gate signals
|
||||
* GFEQ_XX[3:0]: time setting of EQ step for falling edge in steps
|
||||
* of 0.5us.
|
||||
* The default is 0x07 = 3.5us
|
||||
* GREQ_XX[7:4]: time setting of EQ step for rising edge in steps
|
||||
* of 0.5us.
|
||||
* The default is 0x07 = 3.5us
|
||||
*/
|
||||
u8 gseqctr[NT35510_P0_GSEQCTR_LEN];
|
||||
/**
|
||||
* @sdeqctr: Source driver control settings, first byte is
|
||||
* 0 for mode 1 and 1 for mode 2. Mode 1 uses two steps and
|
||||
|
@ -343,6 +495,43 @@ struct nt35510_config {
|
|||
* @gamma_corr_neg_b: Blue gamma correction parameters, negative
|
||||
*/
|
||||
u8 gamma_corr_neg_b[NT35510_P1_GAMMA_LEN];
|
||||
/**
|
||||
* @wrdisbv: write display brightness
|
||||
* 0x00 value means the lowest brightness and 0xff value means
|
||||
* the highest brightness.
|
||||
* The default is 0x00.
|
||||
*/
|
||||
u8 wrdisbv;
|
||||
/**
|
||||
* @wrctrld: write control display
|
||||
* G bit 0 selects gamma curve: 0 = Manual, 1 = Automatic
|
||||
* DB bit 1 selects display brightness: 0 = Manual, 1 = Automatic
|
||||
* BL bit 2 controls backlight control: 0 = Off, 1 = On
|
||||
* DD bit 3 controls display dimming: 0 = Off, 1 = On
|
||||
* A bit 4 controls LABC block: 0 = Off, 1 = On
|
||||
* BCTRL bit 5 controls brightness block: 0 = Off, 1 = On
|
||||
*/
|
||||
u8 wrctrld;
|
||||
/**
|
||||
* @wrcabc: write content adaptive brightness control
|
||||
* There is possible to use 4 different modes for content adaptive
|
||||
* image functionality:
|
||||
* 0: Off
|
||||
* 1: User Interface Image (UI-Mode)
|
||||
* 2: Still Picture Image (Still-Mode)
|
||||
* 3: Moving Picture Image (Moving-Mode)
|
||||
* The default is 0
|
||||
*/
|
||||
u8 wrcabc;
|
||||
/**
|
||||
* @wrcabcmb: write CABC minimum brightness
|
||||
* Set the minimum brightness value of the display for CABC
|
||||
* function.
|
||||
* 0x00 value means the lowest brightness for CABC and 0xff
|
||||
* value means the highest brightness for CABC.
|
||||
* The default is 0x00.
|
||||
*/
|
||||
u8 wrcabcmb;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -486,6 +675,16 @@ static int nt35510_setup_power(struct nt35510 *nt)
|
|||
nt->conf->bt2ctr);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCL,
|
||||
NT35510_P1_VCL_LEN,
|
||||
nt->conf->vcl);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_BT3CTR,
|
||||
NT35510_P1_BT3CTR_LEN,
|
||||
nt->conf->bt3ctr);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGH,
|
||||
NT35510_P1_VGH_LEN,
|
||||
nt->conf->vgh);
|
||||
|
@ -522,6 +721,12 @@ static int nt35510_setup_power(struct nt35510 *nt)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCMOFF,
|
||||
NT35510_P1_VCMOFF_LEN,
|
||||
nt->conf->vcmoff);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Typically 10 ms */
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
|
@ -536,46 +741,28 @@ static int nt35510_setup_display(struct nt35510 *nt)
|
|||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev);
|
||||
const struct nt35510_config *conf = nt->conf;
|
||||
u8 dopctr[NT35510_P0_DOPCTR_LEN];
|
||||
u8 gseqctr[NT35510_P0_GSEQCTR_LEN];
|
||||
u8 dpfrctr[NT35510_P0_DPFRCTR1_LEN];
|
||||
/* FIXME: set up any rotation (assume none for now) */
|
||||
u8 addr_mode = NT35510_ROTATE_0_SETTING;
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/* Enable TE, EoTP and RGB pixel format */
|
||||
dopctr[0] = NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP |
|
||||
NT35510_DOPCTR_0_N565;
|
||||
dopctr[1] = NT35510_DOPCTR_1_CTB;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P0_DOPCTR,
|
||||
NT35510_P0_DOPCTR_LEN,
|
||||
dopctr);
|
||||
conf->dopctr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &addr_mode,
|
||||
sizeof(addr_mode));
|
||||
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &conf->madctl,
|
||||
sizeof(conf->madctl));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Source data hold time, default 0x05 = 2.5us
|
||||
* 0x00..0x3F = 0 .. 31.5us in steps of 0.5us
|
||||
* 0x0A = 5us
|
||||
*/
|
||||
val = 0x0A;
|
||||
ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &val,
|
||||
sizeof(val));
|
||||
ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &conf->sdhdtctr,
|
||||
sizeof(conf->sdhdtctr));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* EQ control for gate signals, 0x00 = 0 us */
|
||||
gseqctr[0] = 0x00;
|
||||
gseqctr[1] = 0x00;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P0_GSEQCTR,
|
||||
NT35510_P0_GSEQCTR_LEN,
|
||||
gseqctr);
|
||||
conf->gseqctr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -719,36 +906,38 @@ static int nt35510_power_on(struct nt35510 *nt)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_r);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_g);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_b);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_r);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_g);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_b);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (nt->conf->cmds & NT35510_CMD_CORRECT_GAMMA) {
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_r);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_g);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_pos_b);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_r);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_g);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG,
|
||||
NT35510_P1_GAMMA_LEN,
|
||||
nt->conf->gamma_corr_neg_b);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set up stuff in manufacturer control, page 0 */
|
||||
ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR,
|
||||
|
@ -827,6 +1016,26 @@ static int nt35510_prepare(struct drm_panel *panel)
|
|||
/* Up to 120 ms */
|
||||
usleep_range(120000, 150000);
|
||||
|
||||
if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) {
|
||||
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
|
||||
&nt->conf->wrctrld,
|
||||
sizeof(nt->conf->wrctrld));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
|
||||
&nt->conf->wrcabc,
|
||||
sizeof(nt->conf->wrcabc));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS,
|
||||
&nt->conf->wrcabcmb,
|
||||
sizeof(nt->conf->wrcabcmb));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret) {
|
||||
dev_err(nt->dev, "failed to turn display on (%d)\n", ret);
|
||||
|
@ -896,7 +1105,6 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
|
|||
*/
|
||||
dsi->hs_rate = 349440000;
|
||||
dsi->lp_rate = 9600000;
|
||||
dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
|
||||
|
||||
/*
|
||||
* Every new incarnation of this display must have a unique
|
||||
|
@ -908,6 +1116,8 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
dsi->mode_flags = nt->conf->mode_flags;
|
||||
|
||||
nt->supplies[0].supply = "vdd"; /* 2.3-4.8 V */
|
||||
nt->supplies[1].supply = "vddi"; /* 1.65-3.3V */
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->supplies),
|
||||
|
@ -923,7 +1133,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
|
||||
nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(nt->reset_gpio)) {
|
||||
dev_err(dev, "error getting RESET GPIO\n");
|
||||
return PTR_ERR(nt->reset_gpio);
|
||||
|
@ -952,7 +1162,10 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
|
|||
return PTR_ERR(bl);
|
||||
}
|
||||
bl->props.max_brightness = 255;
|
||||
bl->props.brightness = 255;
|
||||
if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY)
|
||||
bl->props.brightness = nt->conf->wrdisbv;
|
||||
else
|
||||
bl->props.brightness = 255;
|
||||
bl->props.power = FB_BLANK_POWERDOWN;
|
||||
nt->panel.backlight = bl;
|
||||
}
|
||||
|
@ -1030,6 +1243,8 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = {
|
|||
.vtotal = 800 + 2 + 0 + 5, /* VBP = 5 */
|
||||
.flags = 0,
|
||||
},
|
||||
.mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS,
|
||||
.cmds = NT35510_CMD_CORRECT_GAMMA,
|
||||
/* 0x09: AVDD = 5.6V */
|
||||
.avdd = { 0x09, 0x09, 0x09 },
|
||||
/* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */
|
||||
|
@ -1038,6 +1253,10 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = {
|
|||
.avee = { 0x09, 0x09, 0x09 },
|
||||
/* 0x24: NCK = Hsync/2, BTN = -2 x VDDB */
|
||||
.bt2ctr = { 0x24, 0x24, 0x24 },
|
||||
/* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -2.5V */
|
||||
.vcl = { 0x00, 0x00, 0x00 },
|
||||
/* 0x24: CLCK = Hsync/2, BTN = -1 x VDDB */
|
||||
.bt3ctr = { 0x24, 0x24, 0x24 },
|
||||
/* 0x05 = 12V */
|
||||
.vgh = { 0x05, 0x05, 0x05 },
|
||||
/* 0x24: NCKA = Hsync/2, VGH = 2 x AVDD - AVEE */
|
||||
|
@ -1050,6 +1269,16 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = {
|
|||
.vgp = { 0x00, 0xA3, 0x00 },
|
||||
/* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */
|
||||
.vgn = { 0x00, 0xA3, 0x00 },
|
||||
/* VCMOFFSEL = VCOM voltage offset mode, VCM = 0V */
|
||||
.vcmoff = { 0x00, 0x00 },
|
||||
/* Enable TE, EoTP and RGB pixel format */
|
||||
.dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP |
|
||||
NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB },
|
||||
.madctl = NT35510_ROTATE_0_SETTING,
|
||||
/* 0x0A: SDT = 5 us */
|
||||
.sdhdtctr = 0x0A,
|
||||
/* EQ control for gate signals, 0x00 = 0 us */
|
||||
.gseqctr = { 0x00, 0x00 },
|
||||
/* SDEQCTR: source driver EQ mode 2, 2.5 us rise time on each step */
|
||||
.sdeqctr = { 0x01, 0x05, 0x05, 0x05 },
|
||||
/* SDVPCTR: Normal operation off color during v porch */
|
||||
|
@ -1073,7 +1302,88 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = {
|
|||
.gamma_corr_neg_b = { NT35510_GAMMA_NEG_DEFAULT },
|
||||
};
|
||||
|
||||
static const struct nt35510_config nt35510_frida_frd400b25025 = {
|
||||
.width_mm = 52,
|
||||
.height_mm = 86,
|
||||
.mode = {
|
||||
.clock = 23000,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 34, /* HFP = 34 */
|
||||
.hsync_end = 480 + 34 + 2, /* HSync = 2 */
|
||||
.htotal = 480 + 34 + 2 + 34, /* HBP = 34 */
|
||||
.vdisplay = 800,
|
||||
.vsync_start = 800 + 15, /* VFP = 15 */
|
||||
.vsync_end = 800 + 15 + 12, /* VSync = 12 */
|
||||
.vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */
|
||||
.flags = 0,
|
||||
},
|
||||
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_LPM,
|
||||
.cmds = NT35510_CMD_CONTROL_DISPLAY,
|
||||
/* 0x03: AVDD = 6.2V */
|
||||
.avdd = { 0x03, 0x03, 0x03 },
|
||||
/* 0x46: PCK = 2 x Hsync, BTP = 2.5 x VDDB */
|
||||
.bt1ctr = { 0x46, 0x46, 0x46 },
|
||||
/* 0x03: AVEE = -6.2V */
|
||||
.avee = { 0x03, 0x03, 0x03 },
|
||||
/* 0x36: PCK = 2 x Hsync, BTP = 2 x VDDB */
|
||||
.bt2ctr = { 0x36, 0x36, 0x36 },
|
||||
/* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -3.5V */
|
||||
.vcl = { 0x00, 0x00, 0x02 },
|
||||
/* 0x26: CLCK = 2 x Hsync, BTN = -1 x VDDB */
|
||||
.bt3ctr = { 0x26, 0x26, 0x26 },
|
||||
/* 0x09 = 16V */
|
||||
.vgh = { 0x09, 0x09, 0x09 },
|
||||
/* 0x36: HCK = 2 x Hsync, VGH = 2 x AVDD - AVEE */
|
||||
.bt4ctr = { 0x36, 0x36, 0x36 },
|
||||
/* 0x08 = -10V */
|
||||
.vgl = { 0x08, 0x08, 0x08 },
|
||||
/* 0x26: LCK = 2 x Hsync, VGL = AVDD + VCL - AVDD */
|
||||
.bt5ctr = { 0x26, 0x26, 0x26 },
|
||||
/* VGMP: 0x080 = 4.6V, VGSP = 0V */
|
||||
.vgp = { 0x00, 0x80, 0x00 },
|
||||
/* VGMP: 0x080 = 4.6V, VGSP = 0V */
|
||||
.vgn = { 0x00, 0x80, 0x00 },
|
||||
/* VCMOFFSEL = VCOM voltage offset mode, VCM = -1V */
|
||||
.vcmoff = { 0x00, 0x50 },
|
||||
.dopctr = { NT35510_DOPCTR_0_RAMKP | NT35510_DOPCTR_0_DSITE |
|
||||
NT35510_DOPCTR_0_DSIG | NT35510_DOPCTR_0_DSIM |
|
||||
NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, 0 },
|
||||
.madctl = NT35510_ROTATE_180_SETTING,
|
||||
/* 0x03: SDT = 1.5 us */
|
||||
.sdhdtctr = 0x03,
|
||||
/* EQ control for gate signals, 0x00 = 0 us */
|
||||
.gseqctr = { 0x00, 0x00 },
|
||||
/* SDEQCTR: source driver EQ mode 2, 1 us rise time on each step */
|
||||
.sdeqctr = { 0x01, 0x02, 0x02, 0x02 },
|
||||
/* SDVPCTR: Normal operation off color during v porch */
|
||||
.sdvpctr = 0x01,
|
||||
/* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */
|
||||
.t1 = 0x0184,
|
||||
/* VBP: vertical back porch toward the panel */
|
||||
.vbp = 0x1C,
|
||||
/* VFP: vertical front porch toward the panel */
|
||||
.vfp = 0x1C,
|
||||
/* PSEL: divide pixel clock 23MHz with 1 (no clock downscaling) */
|
||||
.psel = 0,
|
||||
/* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */
|
||||
.dpmctr12 = { 0x03, 0x00, 0x00, },
|
||||
/* write display brightness */
|
||||
.wrdisbv = 0x7f,
|
||||
/* write control display */
|
||||
.wrctrld = NT35510_WRCTRLD_BCTRL | NT35510_WRCTRLD_DD |
|
||||
NT35510_WRCTRLD_BL,
|
||||
/* write content adaptive brightness control */
|
||||
.wrcabc = NT35510_WRCABC_STILL_MODE,
|
||||
/* write CABC minimum brightness */
|
||||
.wrcabcmb = 0xff,
|
||||
};
|
||||
|
||||
static const struct of_device_id nt35510_of_match[] = {
|
||||
{
|
||||
.compatible = "frida,frd400b25025",
|
||||
.data = &nt35510_frida_frd400b25025,
|
||||
},
|
||||
{
|
||||
.compatible = "hydis,hva40wv1",
|
||||
.data = &nt35510_hydis_hva40wv1,
|
||||
|
|
|
@ -343,6 +343,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
|
|||
return ret;
|
||||
}
|
||||
|
||||
rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder,
|
||||
dev->of_node, 0, 0);
|
||||
|
||||
dp->plat_data.encoder = &dp->encoder.encoder;
|
||||
|
||||
ret = analogix_dp_bind(dp->adp, drm_dev);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -26,12 +25,17 @@
|
|||
|
||||
#include "inno_hdmi.h"
|
||||
|
||||
struct hdmi_data_info {
|
||||
int vic;
|
||||
bool sink_has_audio;
|
||||
unsigned int enc_in_format;
|
||||
unsigned int enc_out_format;
|
||||
unsigned int colorimetry;
|
||||
#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
|
||||
|
||||
struct inno_hdmi_phy_config {
|
||||
unsigned long pixelclock;
|
||||
u8 pre_emphasis;
|
||||
u8 voltage_level_control;
|
||||
};
|
||||
|
||||
struct inno_hdmi_variant {
|
||||
struct inno_hdmi_phy_config *phy_configs;
|
||||
struct inno_hdmi_phy_config *default_phy_config;
|
||||
};
|
||||
|
||||
struct inno_hdmi_i2c {
|
||||
|
@ -46,10 +50,9 @@ struct inno_hdmi_i2c {
|
|||
|
||||
struct inno_hdmi {
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
|
||||
int irq;
|
||||
struct clk *pclk;
|
||||
struct clk *refclk;
|
||||
void __iomem *regs;
|
||||
|
||||
struct drm_connector connector;
|
||||
|
@ -58,10 +61,14 @@ struct inno_hdmi {
|
|||
struct inno_hdmi_i2c *i2c;
|
||||
struct i2c_adapter *ddc;
|
||||
|
||||
unsigned int tmds_rate;
|
||||
const struct inno_hdmi_variant *variant;
|
||||
};
|
||||
|
||||
struct hdmi_data_info hdmi_data;
|
||||
struct drm_display_mode previous_mode;
|
||||
struct inno_hdmi_connector_state {
|
||||
struct drm_connector_state base;
|
||||
unsigned int enc_out_format;
|
||||
unsigned int colorimetry;
|
||||
bool rgb_limited_range;
|
||||
};
|
||||
|
||||
static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
|
||||
|
@ -76,50 +83,16 @@ static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector)
|
|||
return container_of(connector, struct inno_hdmi, connector);
|
||||
}
|
||||
|
||||
#define to_inno_hdmi_conn_state(conn_state) \
|
||||
container_of_const(conn_state, struct inno_hdmi_connector_state, base)
|
||||
|
||||
enum {
|
||||
CSC_ITU601_16_235_TO_RGB_0_255_8BIT,
|
||||
CSC_ITU601_0_255_TO_RGB_0_255_8BIT,
|
||||
CSC_ITU709_16_235_TO_RGB_0_255_8BIT,
|
||||
CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
|
||||
CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
|
||||
CSC_RGB_0_255_TO_RGB_16_235_8BIT,
|
||||
};
|
||||
|
||||
static const char coeff_csc[][24] = {
|
||||
/*
|
||||
* YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]):
|
||||
* R = 1.164*Y + 1.596*V - 204
|
||||
* G = 1.164*Y - 0.391*U - 0.813*V + 154
|
||||
* B = 1.164*Y + 2.018*U - 258
|
||||
*/
|
||||
{
|
||||
0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc,
|
||||
0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a,
|
||||
0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02
|
||||
},
|
||||
/*
|
||||
* YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]):
|
||||
* R = Y + 1.402*V - 248
|
||||
* G = Y - 0.344*U - 0.714*V + 135
|
||||
* B = Y + 1.772*U - 227
|
||||
*/
|
||||
{
|
||||
0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8,
|
||||
0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87,
|
||||
0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3
|
||||
},
|
||||
/*
|
||||
* YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]):
|
||||
* R = 1.164*Y + 1.793*V - 248
|
||||
* G = 1.164*Y - 0.213*U - 0.534*V + 77
|
||||
* B = 1.164*Y + 2.115*U - 289
|
||||
*/
|
||||
{
|
||||
0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8,
|
||||
0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d,
|
||||
0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21
|
||||
},
|
||||
|
||||
/*
|
||||
* RGB2YUV:601 SD mode:
|
||||
* Cb = -0.291G - 0.148R + 0.439B + 128
|
||||
|
@ -155,6 +128,36 @@ static const char coeff_csc[][24] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
|
||||
{ 74250000, 0x3f, 0xbb },
|
||||
{ 165000000, 0x6f, 0xbb },
|
||||
{ ~0UL, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = {
|
||||
{ 74250000, 0x3f, 0xaa },
|
||||
{ 165000000, 0x5f, 0xaa },
|
||||
{ ~0UL, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
|
||||
unsigned long pixelclk)
|
||||
{
|
||||
const struct inno_hdmi_phy_config *phy_configs =
|
||||
hdmi->variant->phy_configs;
|
||||
int i;
|
||||
|
||||
for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
|
||||
if (pixelclk <= phy_configs[i].pixelclock)
|
||||
return i;
|
||||
}
|
||||
|
||||
DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
|
||||
pixelclk);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
|
||||
{
|
||||
return readl_relaxed(hdmi->regs + (offset) * 0x04);
|
||||
|
@ -174,11 +177,11 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset,
|
|||
hdmi_writeb(hdmi, offset, temp);
|
||||
}
|
||||
|
||||
static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi)
|
||||
static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate)
|
||||
{
|
||||
int ddc_bus_freq;
|
||||
unsigned long long ddc_bus_freq = rate >> 2;
|
||||
|
||||
ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE;
|
||||
do_div(ddc_bus_freq, HDMI_SCL_RATE);
|
||||
|
||||
hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
|
||||
hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
|
||||
|
@ -196,38 +199,44 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
|
|||
hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
|
||||
}
|
||||
|
||||
static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
|
||||
static void inno_hdmi_standby(struct inno_hdmi *hdmi)
|
||||
{
|
||||
switch (mode) {
|
||||
case NORMAL:
|
||||
inno_hdmi_sys_power(hdmi, false);
|
||||
inno_hdmi_sys_power(hdmi, false);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
|
||||
};
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
|
||||
static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
|
||||
unsigned long mpixelclock)
|
||||
{
|
||||
struct inno_hdmi_phy_config *phy_config;
|
||||
int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
|
||||
|
||||
inno_hdmi_sys_power(hdmi, true);
|
||||
break;
|
||||
|
||||
case LOWER_PWR:
|
||||
inno_hdmi_sys_power(hdmi, false);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode);
|
||||
if (ret < 0) {
|
||||
phy_config = hdmi->variant->default_phy_config;
|
||||
DRM_DEV_ERROR(hdmi->dev,
|
||||
"Using default phy configuration for TMDS rate %lu",
|
||||
mpixelclock);
|
||||
} else {
|
||||
phy_config = &hdmi->variant->phy_configs[ret];
|
||||
}
|
||||
}
|
||||
|
||||
inno_hdmi_sys_power(hdmi, false);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
|
||||
|
||||
inno_hdmi_sys_power(hdmi, true);
|
||||
};
|
||||
|
||||
static void inno_hdmi_reset(struct inno_hdmi *hdmi)
|
||||
{
|
||||
|
@ -244,75 +253,96 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi)
|
|||
val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
|
||||
hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
|
||||
|
||||
inno_hdmi_set_pwr_mode(hdmi, NORMAL);
|
||||
inno_hdmi_standby(hdmi);
|
||||
}
|
||||
|
||||
static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc,
|
||||
union hdmi_infoframe *frame, u32 frame_index,
|
||||
u32 mask, u32 disable, u32 enable)
|
||||
static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi,
|
||||
enum hdmi_infoframe_type type)
|
||||
{
|
||||
if (mask)
|
||||
hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable);
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index);
|
||||
|
||||
if (setup_rc >= 0) {
|
||||
u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
|
||||
ssize_t rc, i;
|
||||
|
||||
rc = hdmi_infoframe_pack(frame, packed_frame,
|
||||
sizeof(packed_frame));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < rc; i++)
|
||||
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
|
||||
packed_frame[i]);
|
||||
|
||||
if (mask)
|
||||
hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable);
|
||||
if (type != HDMI_INFOFRAME_TYPE_AVI) {
|
||||
drm_err(connector->dev,
|
||||
"Unsupported infoframe type: %u\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
return setup_rc;
|
||||
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
|
||||
}
|
||||
|
||||
static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi,
|
||||
union hdmi_infoframe *frame, enum hdmi_infoframe_type type)
|
||||
{
|
||||
union hdmi_infoframe frame;
|
||||
int rc;
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
|
||||
ssize_t rc, i;
|
||||
|
||||
rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
|
||||
&hdmi->connector,
|
||||
mode);
|
||||
if (type != HDMI_INFOFRAME_TYPE_AVI) {
|
||||
drm_err(connector->dev,
|
||||
"Unsupported infoframe type: %u\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI,
|
||||
m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1));
|
||||
inno_hdmi_disable_frame(hdmi, type);
|
||||
|
||||
rc = hdmi_infoframe_pack(frame, packed_frame,
|
||||
sizeof(packed_frame));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < rc; i++)
|
||||
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
|
||||
packed_frame[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
struct drm_connector_state *conn_state = connector->state;
|
||||
struct inno_hdmi_connector_state *inno_conn_state =
|
||||
to_inno_hdmi_conn_state(conn_state);
|
||||
union hdmi_infoframe frame;
|
||||
int rc;
|
||||
|
||||
rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
&hdmi->connector,
|
||||
mode);
|
||||
if (rc) {
|
||||
inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
|
||||
if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444)
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
|
||||
else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
|
||||
else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422)
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
|
||||
else
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
|
||||
|
||||
return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
|
||||
if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
||||
connector, mode,
|
||||
inno_conn_state->rgb_limited_range ?
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||
HDMI_QUANTIZATION_RANGE_FULL);
|
||||
} else {
|
||||
frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
|
||||
frame.avi.ycc_quantization_range =
|
||||
HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
|
||||
}
|
||||
|
||||
return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI);
|
||||
}
|
||||
|
||||
static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
|
||||
{
|
||||
struct hdmi_data_info *data = &hdmi->hdmi_data;
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
struct drm_connector_state *conn_state = connector->state;
|
||||
struct inno_hdmi_connector_state *inno_conn_state =
|
||||
to_inno_hdmi_conn_state(conn_state);
|
||||
int c0_c2_change = 0;
|
||||
int csc_enable = 0;
|
||||
int csc_mode = 0;
|
||||
|
@ -330,9 +360,14 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
|
|||
v_VIDEO_INPUT_CSP(0);
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
|
||||
|
||||
if (data->enc_in_format == data->enc_out_format) {
|
||||
if ((data->enc_in_format == HDMI_COLORSPACE_RGB) ||
|
||||
(data->enc_in_format >= HDMI_COLORSPACE_YUV444)) {
|
||||
if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) {
|
||||
if (inno_conn_state->rgb_limited_range) {
|
||||
csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
|
||||
auto_csc = AUTO_CSC_DISABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_ENABLE;
|
||||
|
||||
} else {
|
||||
value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
|
||||
|
||||
|
@ -342,35 +377,21 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
|
|||
v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) {
|
||||
if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
|
||||
(data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
|
||||
csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
|
||||
auto_csc = AUTO_CSC_DISABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_ENABLE;
|
||||
} else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
|
||||
(data->enc_out_format == HDMI_COLORSPACE_RGB)) {
|
||||
csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
|
||||
auto_csc = AUTO_CSC_ENABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_DISABLE;
|
||||
}
|
||||
} else {
|
||||
if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
|
||||
(data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
|
||||
csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
|
||||
auto_csc = AUTO_CSC_DISABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_ENABLE;
|
||||
} else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
|
||||
(data->enc_out_format == HDMI_COLORSPACE_RGB)) {
|
||||
csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT;
|
||||
auto_csc = AUTO_CSC_ENABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_DISABLE;
|
||||
if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) {
|
||||
if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
|
||||
csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
|
||||
auto_csc = AUTO_CSC_DISABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_ENABLE;
|
||||
}
|
||||
} else {
|
||||
if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) {
|
||||
csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
|
||||
auto_csc = AUTO_CSC_DISABLE;
|
||||
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
||||
csc_enable = v_CSC_ENABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,7 +432,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
|
|||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
|
||||
|
||||
value = mode->hsync_start - mode->hdisplay;
|
||||
value = mode->htotal - mode->hsync_start;
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
|
||||
|
||||
|
@ -426,7 +447,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
|
|||
value = mode->vtotal - mode->vdisplay;
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
|
||||
|
||||
value = mode->vsync_start - mode->vdisplay;
|
||||
value = mode->vtotal - mode->vsync_start;
|
||||
hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
|
||||
|
||||
value = mode->vsync_end - mode->vsync_start;
|
||||
|
@ -443,19 +464,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
|
|||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_display_info *display = &hdmi->connector.display_info;
|
||||
|
||||
hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
|
||||
|
||||
hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB;
|
||||
hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
|
||||
|
||||
if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) ||
|
||||
(hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) ||
|
||||
(hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) ||
|
||||
(hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18))
|
||||
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
|
||||
else
|
||||
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
|
||||
unsigned long mpixelclock = mode->clock * 1000;
|
||||
|
||||
/* Mute video and audio output */
|
||||
hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
|
||||
|
@ -469,10 +478,8 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
|
|||
|
||||
inno_hdmi_config_video_csc(hdmi);
|
||||
|
||||
if (display->is_hdmi) {
|
||||
if (display->is_hdmi)
|
||||
inno_hdmi_config_video_avi(hdmi, mode);
|
||||
inno_hdmi_config_video_vsi(hdmi, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* When IP controller have configured to an accurate video
|
||||
|
@ -480,47 +487,73 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
|
|||
* DCLK_LCDC, so we need to init the TMDS rate to mode pixel
|
||||
* clock rate, and reconfigure the DDC clock.
|
||||
*/
|
||||
hdmi->tmds_rate = mode->clock * 1000;
|
||||
inno_hdmi_i2c_init(hdmi);
|
||||
inno_hdmi_i2c_init(hdmi, mpixelclock);
|
||||
|
||||
/* Unmute video and audio output */
|
||||
hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
|
||||
v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
|
||||
|
||||
inno_hdmi_power_up(hdmi, mpixelclock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
unsigned long mpixelclk, max_tolerance;
|
||||
long rounded_refclk;
|
||||
|
||||
/* No support for double-clock modes */
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
return MODE_BAD;
|
||||
|
||||
mpixelclk = mode->clock * 1000;
|
||||
|
||||
if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if (hdmi->refclk) {
|
||||
rounded_refclk = clk_round_rate(hdmi->refclk, mpixelclk);
|
||||
if (rounded_refclk < 0)
|
||||
return MODE_BAD;
|
||||
|
||||
/* Vesa DMT standard mentions +/- 0.5% max tolerance */
|
||||
max_tolerance = mpixelclk / 200;
|
||||
if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance)
|
||||
return MODE_NOCLOCK;
|
||||
}
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void inno_hdmi_encoder_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
|
||||
struct drm_connector_state *conn_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
|
||||
if (WARN_ON(!conn_state))
|
||||
return;
|
||||
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
|
||||
if (WARN_ON(!crtc_state))
|
||||
return;
|
||||
|
||||
inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
|
||||
}
|
||||
|
||||
static void inno_hdmi_encoder_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
|
||||
|
||||
inno_hdmi_setup(hdmi, adj_mode);
|
||||
|
||||
/* Store the display mode for plugin/DPMS poweron events */
|
||||
drm_mode_copy(&hdmi->previous_mode, adj_mode);
|
||||
}
|
||||
|
||||
static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
|
||||
|
||||
inno_hdmi_set_pwr_mode(hdmi, NORMAL);
|
||||
}
|
||||
|
||||
static void inno_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
|
||||
|
||||
inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
|
||||
}
|
||||
|
||||
static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
return true;
|
||||
inno_hdmi_standby(hdmi);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -529,19 +562,35 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
|||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
|
||||
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
||||
u8 vic = drm_match_cea_mode(mode);
|
||||
struct inno_hdmi_connector_state *inno_conn_state =
|
||||
to_inno_hdmi_conn_state(conn_state);
|
||||
|
||||
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
s->output_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
|
||||
return 0;
|
||||
if (vic == 6 || vic == 7 ||
|
||||
vic == 21 || vic == 22 ||
|
||||
vic == 2 || vic == 3 ||
|
||||
vic == 17 || vic == 18)
|
||||
inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601;
|
||||
else
|
||||
inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
|
||||
|
||||
inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
|
||||
inno_conn_state->rgb_limited_range =
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
|
||||
|
||||
return inno_hdmi_display_mode_valid(hdmi,
|
||||
&crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = {
|
||||
.enable = inno_hdmi_encoder_enable,
|
||||
.disable = inno_hdmi_encoder_disable,
|
||||
.mode_fixup = inno_hdmi_encoder_mode_fixup,
|
||||
.mode_set = inno_hdmi_encoder_mode_set,
|
||||
.atomic_check = inno_hdmi_encoder_atomic_check,
|
||||
.atomic_check = inno_hdmi_encoder_atomic_check,
|
||||
.atomic_enable = inno_hdmi_encoder_enable,
|
||||
.atomic_disable = inno_hdmi_encoder_disable,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
|
@ -564,7 +613,6 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
|
|||
|
||||
edid = drm_get_edid(connector, hdmi->ddc);
|
||||
if (edid) {
|
||||
hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
|
@ -577,14 +625,9 @@ static enum drm_mode_status
|
|||
inno_hdmi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
|
||||
|
||||
static int
|
||||
inno_hdmi_probe_single_connector_modes(struct drm_connector *connector,
|
||||
uint32_t maxX, uint32_t maxY)
|
||||
{
|
||||
return drm_helper_probe_single_connector_modes(connector, 1920, 1080);
|
||||
return inno_hdmi_display_mode_valid(hdmi, mode);
|
||||
}
|
||||
|
||||
static void inno_hdmi_connector_destroy(struct drm_connector *connector)
|
||||
|
@ -593,13 +636,64 @@ static void inno_hdmi_connector_destroy(struct drm_connector *connector)
|
|||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static void
|
||||
inno_hdmi_connector_destroy_state(struct drm_connector *connector,
|
||||
struct drm_connector_state *state)
|
||||
{
|
||||
struct inno_hdmi_connector_state *inno_conn_state =
|
||||
to_inno_hdmi_conn_state(state);
|
||||
|
||||
__drm_atomic_helper_connector_destroy_state(&inno_conn_state->base);
|
||||
kfree(inno_conn_state);
|
||||
}
|
||||
|
||||
static void inno_hdmi_connector_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct inno_hdmi_connector_state *inno_conn_state;
|
||||
|
||||
if (connector->state) {
|
||||
inno_hdmi_connector_destroy_state(connector, connector->state);
|
||||
connector->state = NULL;
|
||||
}
|
||||
|
||||
inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL);
|
||||
if (!inno_conn_state)
|
||||
return;
|
||||
|
||||
__drm_atomic_helper_connector_reset(connector, &inno_conn_state->base);
|
||||
|
||||
inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709;
|
||||
inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB;
|
||||
inno_conn_state->rgb_limited_range = false;
|
||||
}
|
||||
|
||||
static struct drm_connector_state *
|
||||
inno_hdmi_connector_duplicate_state(struct drm_connector *connector)
|
||||
{
|
||||
struct inno_hdmi_connector_state *inno_conn_state;
|
||||
|
||||
if (WARN_ON(!connector->state))
|
||||
return NULL;
|
||||
|
||||
inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state),
|
||||
sizeof(*inno_conn_state), GFP_KERNEL);
|
||||
|
||||
if (!inno_conn_state)
|
||||
return NULL;
|
||||
|
||||
__drm_atomic_helper_connector_duplicate_state(connector,
|
||||
&inno_conn_state->base);
|
||||
|
||||
return &inno_conn_state->base;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs inno_hdmi_connector_funcs = {
|
||||
.fill_modes = inno_hdmi_probe_single_connector_modes,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = inno_hdmi_connector_detect,
|
||||
.destroy = inno_hdmi_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
.reset = inno_hdmi_connector_reset,
|
||||
.atomic_duplicate_state = inno_hdmi_connector_duplicate_state,
|
||||
.atomic_destroy_state = inno_hdmi_connector_destroy_state,
|
||||
};
|
||||
|
||||
static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
|
||||
|
@ -819,6 +913,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm = data;
|
||||
struct inno_hdmi *hdmi;
|
||||
const struct inno_hdmi_variant *variant;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
|
@ -827,7 +922,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
return -ENOMEM;
|
||||
|
||||
hdmi->dev = dev;
|
||||
hdmi->drm_dev = drm;
|
||||
|
||||
variant = of_device_get_match_data(hdmi->dev);
|
||||
if (!variant)
|
||||
return -EINVAL;
|
||||
|
||||
hdmi->variant = variant;
|
||||
|
||||
hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hdmi->regs))
|
||||
|
@ -846,6 +946,20 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
return ret;
|
||||
}
|
||||
|
||||
hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref");
|
||||
if (IS_ERR(hdmi->refclk)) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n");
|
||||
ret = PTR_ERR(hdmi->refclk);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->refclk);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(hdmi->dev,
|
||||
"Cannot enable HDMI reference clock: %d\n", ret);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
|
@ -862,13 +976,16 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
}
|
||||
|
||||
/*
|
||||
* When IP controller haven't configured to an accurate video
|
||||
* timing, then the TMDS clock source would be switched to
|
||||
* PCLK_HDMI, so we need to init the TMDS rate to PCLK rate,
|
||||
* and reconfigure the DDC clock.
|
||||
* When the controller isn't configured to an accurate
|
||||
* video timing and there is no reference clock available,
|
||||
* then the TMDS clock source would be switched to PCLK_HDMI,
|
||||
* so we need to init the TMDS rate to PCLK rate, and
|
||||
* reconfigure the DDC clock.
|
||||
*/
|
||||
hdmi->tmds_rate = clk_get_rate(hdmi->pclk);
|
||||
inno_hdmi_i2c_init(hdmi);
|
||||
if (hdmi->refclk)
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk));
|
||||
else
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk));
|
||||
|
||||
ret = inno_hdmi_register(drm, hdmi);
|
||||
if (ret)
|
||||
|
@ -892,6 +1009,8 @@ err_cleanup_hdmi:
|
|||
err_put_adapter:
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(hdmi->refclk);
|
||||
err_disable_pclk:
|
||||
clk_disable_unprepare(hdmi->pclk);
|
||||
return ret;
|
||||
}
|
||||
|
@ -905,6 +1024,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
|
|||
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
|
||||
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
clk_disable_unprepare(hdmi->refclk);
|
||||
clk_disable_unprepare(hdmi->pclk);
|
||||
}
|
||||
|
||||
|
@ -923,8 +1043,22 @@ static void inno_hdmi_remove(struct platform_device *pdev)
|
|||
component_del(&pdev->dev, &inno_hdmi_ops);
|
||||
}
|
||||
|
||||
static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = {
|
||||
.phy_configs = rk3036_hdmi_phy_configs,
|
||||
.default_phy_config = &rk3036_hdmi_phy_configs[1],
|
||||
};
|
||||
|
||||
static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = {
|
||||
.phy_configs = rk3128_hdmi_phy_configs,
|
||||
.default_phy_config = &rk3128_hdmi_phy_configs[1],
|
||||
};
|
||||
|
||||
static const struct of_device_id inno_hdmi_dt_ids[] = {
|
||||
{ .compatible = "rockchip,rk3036-inno-hdmi",
|
||||
.data = &rk3036_inno_hdmi_variant,
|
||||
},
|
||||
{ .compatible = "rockchip,rk3128-inno-hdmi",
|
||||
.data = &rk3128_inno_hdmi_variant,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
enum PWR_MODE {
|
||||
NORMAL,
|
||||
LOWER_PWR,
|
||||
};
|
||||
|
||||
#define HDMI_SCL_RATE (100*1000)
|
||||
#define DDC_BUS_FREQ_L 0x4b
|
||||
#define DDC_BUS_FREQ_H 0x4c
|
||||
|
|
|
@ -576,8 +576,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||
ret = -EINVAL;
|
||||
goto err_put_port;
|
||||
} else if (ret) {
|
||||
DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
dev_err_probe(dev, ret, "failed to find panel and bridge node\n");
|
||||
goto err_put_port;
|
||||
}
|
||||
if (lvds->panel)
|
||||
|
|
|
@ -227,11 +227,22 @@ static const struct vop_win_data rk3126_vop_win_data[] = {
|
|||
.type = DRM_PLANE_TYPE_CURSOR },
|
||||
};
|
||||
|
||||
static const struct vop_output rk3126_output = {
|
||||
.pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
|
||||
.hdmi_pin_pol = VOP_REG(RK3126_INT_SCALER, 0x7, 4),
|
||||
.hdmi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 22),
|
||||
.hdmi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 23),
|
||||
.rgb_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 24),
|
||||
.rgb_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 25),
|
||||
.mipi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 28),
|
||||
.mipi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 29),
|
||||
};
|
||||
|
||||
static const struct vop_data rk3126_vop = {
|
||||
.intr = &rk3036_intr,
|
||||
.common = &rk3036_common,
|
||||
.modeset = &rk3036_modeset,
|
||||
.output = &rk3036_output,
|
||||
.output = &rk3126_output,
|
||||
.win = rk3126_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3126_vop_win_data),
|
||||
.max_output = { 1920, 1080 },
|
||||
|
|
|
@ -872,6 +872,9 @@
|
|||
/* rk3036 register definition end */
|
||||
|
||||
/* rk3126 register definition */
|
||||
#define RK3126_INT_SCALER 0x0c
|
||||
|
||||
/* win1 register */
|
||||
#define RK3126_WIN1_MST 0x4c
|
||||
#define RK3126_WIN1_DSP_INFO 0x50
|
||||
#define RK3126_WIN1_DSP_ST 0x54
|
||||
|
|
|
@ -1248,7 +1248,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
|
|||
long timeout, struct workqueue_struct *timeout_wq,
|
||||
atomic_t *score, const char *name, struct device *dev)
|
||||
{
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
sched->ops = ops;
|
||||
sched->credit_limit = credit_limit;
|
||||
|
@ -1284,11 +1284,11 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
|
|||
|
||||
sched->own_submit_wq = true;
|
||||
}
|
||||
ret = -ENOMEM;
|
||||
|
||||
sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!sched->sched_rq)
|
||||
goto Out_free;
|
||||
goto Out_check_own;
|
||||
sched->num_rqs = num_rqs;
|
||||
for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
|
||||
sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL);
|
||||
|
@ -1313,13 +1313,14 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
|
|||
Out_unroll:
|
||||
for (--i ; i >= DRM_SCHED_PRIORITY_KERNEL; i--)
|
||||
kfree(sched->sched_rq[i]);
|
||||
Out_free:
|
||||
|
||||
kfree(sched->sched_rq);
|
||||
sched->sched_rq = NULL;
|
||||
Out_check_own:
|
||||
if (sched->own_submit_wq)
|
||||
destroy_workqueue(sched->submit_wq);
|
||||
drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__);
|
||||
return ret;
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sched_init);
|
||||
|
||||
|
|
|
@ -142,6 +142,11 @@ static const struct of_device_id ssd130x_of_match[] = {
|
|||
.compatible = "solomon,ssd1327",
|
||||
.data = &ssd130x_variants[SSD1327_ID],
|
||||
},
|
||||
/* ssd133x family */
|
||||
{
|
||||
.compatible = "solomon,ssd1331",
|
||||
.data = &ssd130x_variants[SSD1331_ID],
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ssd130x_of_match);
|
||||
|
@ -166,6 +171,8 @@ static const struct spi_device_id ssd130x_spi_table[] = {
|
|||
{ "ssd1322", SSD1322_ID },
|
||||
{ "ssd1325", SSD1325_ID },
|
||||
{ "ssd1327", SSD1327_ID },
|
||||
/* ssd133x family */
|
||||
{ "ssd1331", SSD1331_ID },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ssd130x_spi_table);
|
||||
|
|
|
@ -119,6 +119,26 @@
|
|||
#define SSD130X_SET_VCOMH_VOLTAGE 0xbe
|
||||
#define SSD132X_SET_FUNCTION_SELECT_B 0xd5
|
||||
|
||||
/* ssd133x commands */
|
||||
#define SSD133X_SET_COL_RANGE 0x15
|
||||
#define SSD133X_SET_ROW_RANGE 0x75
|
||||
#define SSD133X_CONTRAST_A 0x81
|
||||
#define SSD133X_CONTRAST_B 0x82
|
||||
#define SSD133X_CONTRAST_C 0x83
|
||||
#define SSD133X_SET_MASTER_CURRENT 0x87
|
||||
#define SSD132X_SET_PRECHARGE_A 0x8a
|
||||
#define SSD132X_SET_PRECHARGE_B 0x8b
|
||||
#define SSD132X_SET_PRECHARGE_C 0x8c
|
||||
#define SSD133X_SET_DISPLAY_START 0xa1
|
||||
#define SSD133X_SET_DISPLAY_OFFSET 0xa2
|
||||
#define SSD133X_SET_DISPLAY_NORMAL 0xa4
|
||||
#define SSD133X_SET_MASTER_CONFIG 0xad
|
||||
#define SSD133X_POWER_SAVE_MODE 0xb0
|
||||
#define SSD133X_PHASES_PERIOD 0xb1
|
||||
#define SSD133X_SET_CLOCK_FREQ 0xb3
|
||||
#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb
|
||||
#define SSD133X_SET_VCOMH_VOLTAGE 0xbe
|
||||
|
||||
#define MAX_CONTRAST 255
|
||||
|
||||
const struct ssd130x_deviceinfo ssd130x_variants[] = {
|
||||
|
@ -180,6 +200,12 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = {
|
|||
.default_width = 128,
|
||||
.default_height = 128,
|
||||
.family_id = SSD132X_FAMILY,
|
||||
},
|
||||
/* ssd133x family */
|
||||
[SSD1331_ID] = {
|
||||
.default_width = 96,
|
||||
.default_height = 64,
|
||||
.family_id = SSD133X_FAMILY,
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);
|
||||
|
@ -589,6 +615,117 @@ static int ssd132x_init(struct ssd130x_device *ssd130x)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ssd133x_init(struct ssd130x_device *ssd130x)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Set color A contrast */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set color B contrast */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_B, 0x50);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set color C contrast */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_C, 0x7d);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set master current */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CURRENT, 0x06);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set column start and end */
|
||||
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set row start and end */
|
||||
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Horizontal Address Increment
|
||||
* Normal order SA,SB,SC (e.g. RGB)
|
||||
* COM Split Odd Even
|
||||
* 256 color format
|
||||
*/
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x20);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set display start and offset */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_START, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_OFFSET, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set display mode normal */
|
||||
ret = ssd130x_write_cmd(ssd130x, 1, SSD133X_SET_DISPLAY_NORMAL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set multiplex ratio value */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set master configuration */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CONFIG, 0x8e);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set power mode */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_POWER_SAVE_MODE, 0x0b);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set Phase 1 and 2 period */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_PHASES_PERIOD, 0x31);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set clock divider */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_CLOCK_FREQ, 0xf0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set pre-charge A */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_A, 0x64);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set pre-charge B */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_B, 0x78);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set pre-charge C */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_C, 0x64);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set pre-charge level */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_PRECHARGE_VOLTAGE, 0x3a);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set VCOMH voltage */
|
||||
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_VCOMH_VOLTAGE, 0x3e);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
||||
struct drm_rect *rect, u8 *buf,
|
||||
u8 *data_array)
|
||||
|
@ -753,6 +890,47 @@ static int ssd132x_update_rect(struct ssd130x_device *ssd130x,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ssd133x_update_rect(struct ssd130x_device *ssd130x,
|
||||
struct drm_rect *rect, u8 *data_array,
|
||||
unsigned int pitch)
|
||||
{
|
||||
unsigned int x = rect->x1;
|
||||
unsigned int y = rect->y1;
|
||||
unsigned int columns = drm_rect_width(rect);
|
||||
unsigned int rows = drm_rect_height(rect);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The screen is divided in Segment and Common outputs, where
|
||||
* COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are
|
||||
* the columns.
|
||||
*
|
||||
* Each Segment has a 8-bit pixel and each Common output has a
|
||||
* row of pixels. When using the (default) horizontal address
|
||||
* increment mode, each byte of data sent to the controller has
|
||||
* a Segment (e.g: SEG0).
|
||||
*
|
||||
* When using the 256 color depth format, each pixel contains 3
|
||||
* sub-pixels for color A, B and C. These have 3 bit, 3 bit and
|
||||
* 2 bits respectively.
|
||||
*/
|
||||
|
||||
/* Set column start and end */
|
||||
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, x, columns - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set row start and end */
|
||||
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, y, rows - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Write out update in one go since horizontal addressing mode is used */
|
||||
ret = ssd130x_write_data(ssd130x, data_array, pitch * rows);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
||||
{
|
||||
unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT);
|
||||
|
@ -805,6 +983,22 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
|||
ssd130x_write_data(ssd130x, data_array, columns * height);
|
||||
}
|
||||
|
||||
static void ssd133x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
||||
{
|
||||
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||
unsigned int pitch;
|
||||
|
||||
if (!fi)
|
||||
return;
|
||||
|
||||
pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
|
||||
|
||||
memset(data_array, 0, pitch * ssd130x->height);
|
||||
|
||||
/* Write out update in one go since horizontal addressing mode is used */
|
||||
ssd130x_write_data(ssd130x, data_array, pitch * ssd130x->height);
|
||||
}
|
||||
|
||||
static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb,
|
||||
const struct iosys_map *vmap,
|
||||
struct drm_rect *rect,
|
||||
|
@ -866,6 +1060,36 @@ static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ssd133x_fb_blit_rect(struct drm_framebuffer *fb,
|
||||
const struct iosys_map *vmap,
|
||||
struct drm_rect *rect, u8 *data_array,
|
||||
struct drm_format_conv_state *fmtcnv_state)
|
||||
{
|
||||
struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
|
||||
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||
unsigned int dst_pitch;
|
||||
struct iosys_map dst;
|
||||
int ret = 0;
|
||||
|
||||
if (!fi)
|
||||
return -EINVAL;
|
||||
|
||||
dst_pitch = drm_format_info_min_pitch(fi, 0, drm_rect_width(rect));
|
||||
|
||||
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iosys_map_set_vaddr(&dst, data_array);
|
||||
drm_fb_xrgb8888_to_rgb332(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
|
||||
|
||||
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
|
||||
|
||||
ssd133x_update_rect(ssd130x, rect, data_array, dst_pitch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
|
@ -964,6 +1188,29 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ssd133x_primary_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_crtc *crtc = plane_state->crtc;
|
||||
struct drm_crtc_state *crtc_state = NULL;
|
||||
int ret;
|
||||
|
||||
if (crtc)
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (!plane_state->visible)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
|
@ -1034,6 +1281,39 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane,
|
|||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
||||
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
|
||||
struct ssd130x_crtc_state *ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_device *drm = plane->dev;
|
||||
struct drm_rect dst_clip;
|
||||
struct drm_rect damage;
|
||||
int idx;
|
||||
|
||||
if (!drm_dev_enter(drm, &idx))
|
||||
return;
|
||||
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &damage) {
|
||||
dst_clip = plane_state->dst;
|
||||
|
||||
if (!drm_rect_intersect(&dst_clip, &damage))
|
||||
continue;
|
||||
|
||||
ssd133x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,
|
||||
ssd130x_crtc_state->data_array,
|
||||
&shadow_plane_state->fmtcnv_state);
|
||||
}
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
|
@ -1082,6 +1362,30 @@ static void ssd132x_primary_plane_atomic_disable(struct drm_plane *plane,
|
|||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static void ssd133x_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *drm = plane->dev;
|
||||
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct ssd130x_crtc_state *ssd130x_crtc_state;
|
||||
int idx;
|
||||
|
||||
if (!plane_state->crtc)
|
||||
return;
|
||||
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
|
||||
ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);
|
||||
|
||||
if (!drm_dev_enter(drm, &idx))
|
||||
return;
|
||||
|
||||
ssd133x_clear_screen(ssd130x, ssd130x_crtc_state->data_array);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
/* Called during init to allocate the plane's atomic state. */
|
||||
static void ssd130x_primary_plane_reset(struct drm_plane *plane)
|
||||
{
|
||||
|
@ -1144,6 +1448,12 @@ static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs[]
|
|||
.atomic_check = ssd132x_primary_plane_atomic_check,
|
||||
.atomic_update = ssd132x_primary_plane_atomic_update,
|
||||
.atomic_disable = ssd132x_primary_plane_atomic_disable,
|
||||
},
|
||||
[SSD133X_FAMILY] = {
|
||||
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
|
||||
.atomic_check = ssd133x_primary_plane_atomic_check,
|
||||
.atomic_update = ssd133x_primary_plane_atomic_update,
|
||||
.atomic_disable = ssd133x_primary_plane_atomic_disable,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1214,6 +1524,33 @@ static int ssd132x_crtc_atomic_check(struct drm_crtc *crtc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ssd133x_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *drm = crtc->dev;
|
||||
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state);
|
||||
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||
unsigned int pitch;
|
||||
int ret;
|
||||
|
||||
if (!fi)
|
||||
return -EINVAL;
|
||||
|
||||
ret = drm_crtc_helper_atomic_check(crtc, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
|
||||
|
||||
ssd130x_state->data_array = kmalloc(pitch * ssd130x->height, GFP_KERNEL);
|
||||
if (!ssd130x_state->data_array)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called during init to allocate the CRTC's atomic state. */
|
||||
static void ssd130x_crtc_reset(struct drm_crtc *crtc)
|
||||
{
|
||||
|
@ -1275,6 +1612,10 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs[] = {
|
|||
.mode_valid = ssd130x_crtc_mode_valid,
|
||||
.atomic_check = ssd132x_crtc_atomic_check,
|
||||
},
|
||||
[SSD133X_FAMILY] = {
|
||||
.mode_valid = ssd130x_crtc_mode_valid,
|
||||
.atomic_check = ssd133x_crtc_atomic_check,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs ssd130x_crtc_funcs = {
|
||||
|
@ -1337,6 +1678,31 @@ power_off:
|
|||
ssd130x_power_off(ssd130x);
|
||||
}
|
||||
|
||||
static void ssd133x_encoder_atomic_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *drm = encoder->dev;
|
||||
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||
int ret;
|
||||
|
||||
ret = ssd130x_power_on(ssd130x);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ret = ssd133x_init(ssd130x);
|
||||
if (ret)
|
||||
goto power_off;
|
||||
|
||||
ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON);
|
||||
|
||||
backlight_enable(ssd130x->bl_dev);
|
||||
|
||||
return;
|
||||
|
||||
power_off:
|
||||
ssd130x_power_off(ssd130x);
|
||||
}
|
||||
|
||||
static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
|
@ -1358,6 +1724,10 @@ static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs[] = {
|
|||
[SSD132X_FAMILY] = {
|
||||
.atomic_enable = ssd132x_encoder_atomic_enable,
|
||||
.atomic_disable = ssd130x_encoder_atomic_disable,
|
||||
},
|
||||
[SSD133X_FAMILY] = {
|
||||
.atomic_enable = ssd133x_encoder_atomic_enable,
|
||||
.atomic_disable = ssd130x_encoder_atomic_disable,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
|
||||
enum ssd130x_family_ids {
|
||||
SSD130X_FAMILY,
|
||||
SSD132X_FAMILY
|
||||
SSD132X_FAMILY,
|
||||
SSD133X_FAMILY
|
||||
};
|
||||
|
||||
enum ssd130x_variants {
|
||||
|
@ -39,6 +40,8 @@ enum ssd130x_variants {
|
|||
SSD1322_ID,
|
||||
SSD1325_ID,
|
||||
SSD1327_ID,
|
||||
/* ssd133x family */
|
||||
SSD1331_ID,
|
||||
NR_SSD130X_VARIANTS
|
||||
};
|
||||
|
||||
|
|
|
@ -522,7 +522,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
|
|||
if (err < 0) {
|
||||
dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n",
|
||||
dpaux->irq, err);
|
||||
return err;
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
disable_irq(dpaux->irq);
|
||||
|
@ -542,7 +542,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
|
|||
*/
|
||||
err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto err_pm_disable;
|
||||
|
||||
#ifdef CONFIG_GENERIC_PINCONF
|
||||
dpaux->desc.name = dev_name(&pdev->dev);
|
||||
|
@ -555,7 +555,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
|
|||
dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux);
|
||||
if (IS_ERR(dpaux->pinctrl)) {
|
||||
dev_err(&pdev->dev, "failed to register pincontrol\n");
|
||||
return PTR_ERR(dpaux->pinctrl);
|
||||
err = PTR_ERR(dpaux->pinctrl);
|
||||
goto err_pm_disable;
|
||||
}
|
||||
#endif
|
||||
/* enable and clear all interrupts */
|
||||
|
@ -571,10 +572,15 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
|
|||
err = devm_of_dp_aux_populate_ep_devices(&dpaux->aux);
|
||||
if (err < 0) {
|
||||
dev_err(dpaux->dev, "failed to populate AUX bus: %d\n", err);
|
||||
return err;
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_dpaux_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_fixed.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
@ -26,6 +25,7 @@
|
|||
/* XXX move to include/uapi/drm/drm_fourcc.h? */
|
||||
#define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT_ULL(22)
|
||||
|
||||
struct edid;
|
||||
struct reset_control;
|
||||
|
||||
struct tegra_drm {
|
||||
|
|
|
@ -1544,9 +1544,11 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
|
|||
np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
|
||||
if (np) {
|
||||
struct platform_device *gangster = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!gangster)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dsi->slave = platform_get_drvdata(gangster);
|
||||
of_node_put(np);
|
||||
|
||||
if (!dsi->slave) {
|
||||
put_device(&gangster->dev);
|
||||
|
@ -1594,44 +1596,58 @@ static int tegra_dsi_probe(struct platform_device *pdev)
|
|||
|
||||
if (!pdev->dev.pm_domain) {
|
||||
dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
|
||||
if (IS_ERR(dsi->rst))
|
||||
return PTR_ERR(dsi->rst);
|
||||
if (IS_ERR(dsi->rst)) {
|
||||
err = PTR_ERR(dsi->rst);
|
||||
goto remove;
|
||||
}
|
||||
}
|
||||
|
||||
dsi->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(dsi->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk),
|
||||
"cannot get DSI clock\n");
|
||||
if (IS_ERR(dsi->clk)) {
|
||||
err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk),
|
||||
"cannot get DSI clock\n");
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
|
||||
if (IS_ERR(dsi->clk_lp))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
|
||||
"cannot get low-power clock\n");
|
||||
if (IS_ERR(dsi->clk_lp)) {
|
||||
err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
|
||||
"cannot get low-power clock\n");
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
|
||||
if (IS_ERR(dsi->clk_parent))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent),
|
||||
"cannot get parent clock\n");
|
||||
if (IS_ERR(dsi->clk_parent)) {
|
||||
err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent),
|
||||
"cannot get parent clock\n");
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
|
||||
if (IS_ERR(dsi->vdd))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd),
|
||||
"cannot get VDD supply\n");
|
||||
if (IS_ERR(dsi->vdd)) {
|
||||
err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd),
|
||||
"cannot get VDD supply\n");
|
||||
goto remove;
|
||||
}
|
||||
|
||||
err = tegra_dsi_setup_clocks(dsi);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "cannot setup clocks\n");
|
||||
return err;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(dsi->regs))
|
||||
return PTR_ERR(dsi->regs);
|
||||
if (IS_ERR(dsi->regs)) {
|
||||
err = PTR_ERR(dsi->regs);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node);
|
||||
if (IS_ERR(dsi->mipi))
|
||||
return PTR_ERR(dsi->mipi);
|
||||
if (IS_ERR(dsi->mipi)) {
|
||||
err = PTR_ERR(dsi->mipi);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dsi->host.ops = &tegra_dsi_host_ops;
|
||||
dsi->host.dev = &pdev->dev;
|
||||
|
@ -1659,9 +1675,12 @@ static int tegra_dsi_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
unregister:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
mipi_dsi_host_unregister(&dsi->host);
|
||||
mipi_free:
|
||||
tegra_mipi_free(dsi->mipi);
|
||||
remove:
|
||||
tegra_output_remove(&dsi->output);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1856,12 +1856,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
|
||||
hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hdmi->regs))
|
||||
return PTR_ERR(hdmi->regs);
|
||||
if (IS_ERR(hdmi->regs)) {
|
||||
err = PTR_ERR(hdmi->regs);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
err = platform_get_irq(pdev, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto remove;
|
||||
|
||||
hdmi->irq = err;
|
||||
|
||||
|
@ -1870,18 +1872,18 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
|
|||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
|
||||
hdmi->irq, err);
|
||||
return err;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
err = devm_pm_runtime_enable(&pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
goto remove;
|
||||
|
||||
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
goto remove;
|
||||
|
||||
INIT_LIST_HEAD(&hdmi->client.list);
|
||||
hdmi->client.ops = &hdmi_client_ops;
|
||||
|
@ -1891,10 +1893,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
|
|||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove:
|
||||
tegra_output_remove(&hdmi->output);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_hdmi_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
@ -142,8 +143,10 @@ int tegra_output_probe(struct tegra_output *output)
|
|||
GPIOD_IN,
|
||||
"HDMI hotplug detect");
|
||||
if (IS_ERR(output->hpd_gpio)) {
|
||||
if (PTR_ERR(output->hpd_gpio) != -ENOENT)
|
||||
return PTR_ERR(output->hpd_gpio);
|
||||
if (PTR_ERR(output->hpd_gpio) != -ENOENT) {
|
||||
err = PTR_ERR(output->hpd_gpio);
|
||||
goto put_i2c;
|
||||
}
|
||||
|
||||
output->hpd_gpio = NULL;
|
||||
}
|
||||
|
@ -152,7 +155,7 @@ int tegra_output_probe(struct tegra_output *output)
|
|||
err = gpiod_to_irq(output->hpd_gpio);
|
||||
if (err < 0) {
|
||||
dev_err(output->dev, "gpiod_to_irq(): %d\n", err);
|
||||
return err;
|
||||
goto put_i2c;
|
||||
}
|
||||
|
||||
output->hpd_irq = err;
|
||||
|
@ -165,7 +168,7 @@ int tegra_output_probe(struct tegra_output *output)
|
|||
if (err < 0) {
|
||||
dev_err(output->dev, "failed to request IRQ#%u: %d\n",
|
||||
output->hpd_irq, err);
|
||||
return err;
|
||||
goto put_i2c;
|
||||
}
|
||||
|
||||
output->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
@ -179,6 +182,12 @@ int tegra_output_probe(struct tegra_output *output)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
put_i2c:
|
||||
if (output->ddc)
|
||||
i2c_put_adapter(output->ddc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_output_remove(struct tegra_output *output)
|
||||
|
|
|
@ -225,26 +225,28 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
|
|||
rgb->clk = devm_clk_get(dc->dev, NULL);
|
||||
if (IS_ERR(rgb->clk)) {
|
||||
dev_err(dc->dev, "failed to get clock\n");
|
||||
return PTR_ERR(rgb->clk);
|
||||
err = PTR_ERR(rgb->clk);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
rgb->clk_parent = devm_clk_get(dc->dev, "parent");
|
||||
if (IS_ERR(rgb->clk_parent)) {
|
||||
dev_err(dc->dev, "failed to get parent clock\n");
|
||||
return PTR_ERR(rgb->clk_parent);
|
||||
err = PTR_ERR(rgb->clk_parent);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
err = clk_set_parent(rgb->clk, rgb->clk_parent);
|
||||
if (err < 0) {
|
||||
dev_err(dc->dev, "failed to set parent clock: %d\n", err);
|
||||
return err;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
rgb->pll_d_out0 = clk_get_sys(NULL, "pll_d_out0");
|
||||
if (IS_ERR(rgb->pll_d_out0)) {
|
||||
err = PTR_ERR(rgb->pll_d_out0);
|
||||
dev_err(dc->dev, "failed to get pll_d_out0: %d\n", err);
|
||||
return err;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
if (dc->soc->has_pll_d2_out0) {
|
||||
|
@ -252,13 +254,19 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
|
|||
if (IS_ERR(rgb->pll_d2_out0)) {
|
||||
err = PTR_ERR(rgb->pll_d2_out0);
|
||||
dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err);
|
||||
return err;
|
||||
goto put_pll;
|
||||
}
|
||||
}
|
||||
|
||||
dc->rgb = &rgb->output;
|
||||
|
||||
return 0;
|
||||
|
||||
put_pll:
|
||||
clk_put(rgb->pll_d_out0);
|
||||
remove:
|
||||
tegra_output_remove(&rgb->output);
|
||||
return err;
|
||||
}
|
||||
|
||||
void tegra_dc_rgb_remove(struct tegra_dc *dc)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <drm/display/drm_scdc_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_eld.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
|
|
@ -182,9 +182,6 @@ static void tilcdc_fini(struct drm_device *dev)
|
|||
if (priv->clk)
|
||||
clk_put(priv->clk);
|
||||
|
||||
if (priv->mmio)
|
||||
iounmap(priv->mmio);
|
||||
|
||||
if (priv->wq)
|
||||
destroy_workqueue(priv->wq);
|
||||
|
||||
|
@ -201,7 +198,6 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct device_node *node = dev->of_node;
|
||||
struct tilcdc_drm_private *priv;
|
||||
struct resource *res;
|
||||
u32 bpp = 0;
|
||||
int ret;
|
||||
|
||||
|
@ -226,17 +222,10 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
|
|||
goto init_failed;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get memory resource\n");
|
||||
ret = -EINVAL;
|
||||
goto init_failed;
|
||||
}
|
||||
|
||||
priv->mmio = ioremap(res->start, resource_size(res));
|
||||
if (!priv->mmio) {
|
||||
dev_err(dev, "failed to ioremap\n");
|
||||
ret = -ENOMEM;
|
||||
priv->mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->mmio)) {
|
||||
dev_err(dev, "failed to request / ioremap\n");
|
||||
ret = PTR_ERR(priv->mmio);
|
||||
goto init_failed;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,4 +3,7 @@
|
|||
obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \
|
||||
ttm_device_test.o \
|
||||
ttm_pool_test.o \
|
||||
ttm_resource_test.o \
|
||||
ttm_tt_test.o \
|
||||
ttm_bo_test.o \
|
||||
ttm_kunit_helpers.o
|
||||
|
|
622
drivers/gpu/drm/ttm/tests/ttm_bo_test.c
Normal file
622
drivers/gpu/drm/ttm/tests/ttm_bo_test.c
Normal file
|
@ -0,0 +1,622 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 AND MIT
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ww_mutex.h>
|
||||
|
||||
#include <drm/ttm/ttm_resource.h>
|
||||
#include <drm/ttm/ttm_placement.h>
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
|
||||
#include "ttm_kunit_helpers.h"
|
||||
|
||||
#define BO_SIZE SZ_8K
|
||||
|
||||
struct ttm_bo_test_case {
|
||||
const char *description;
|
||||
bool interruptible;
|
||||
bool no_wait;
|
||||
};
|
||||
|
||||
static const struct ttm_bo_test_case ttm_bo_reserved_cases[] = {
|
||||
{
|
||||
.description = "Cannot be interrupted and sleeps",
|
||||
.interruptible = false,
|
||||
.no_wait = false,
|
||||
},
|
||||
{
|
||||
.description = "Cannot be interrupted, locks straight away",
|
||||
.interruptible = false,
|
||||
.no_wait = true,
|
||||
},
|
||||
{
|
||||
.description = "Can be interrupted, sleeps",
|
||||
.interruptible = true,
|
||||
.no_wait = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void ttm_bo_init_case_desc(const struct ttm_bo_test_case *t,
|
||||
char *desc)
|
||||
{
|
||||
strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(ttm_bo_reserve, ttm_bo_reserved_cases, ttm_bo_init_case_desc);
|
||||
|
||||
static void ttm_bo_reserve_optimistic_no_ticket(struct kunit *test)
|
||||
{
|
||||
const struct ttm_bo_test_case *params = test->param_value;
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_bo_reserve(bo, params->interruptible, params->no_wait, NULL);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
}
|
||||
|
||||
static void ttm_bo_reserve_locked_no_sleep(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
bool interruptible = false;
|
||||
bool no_wait = true;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
/* Let's lock it beforehand */
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
|
||||
err = ttm_bo_reserve(bo, interruptible, no_wait, NULL);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, -EBUSY);
|
||||
}
|
||||
|
||||
static void ttm_bo_reserve_no_wait_ticket(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ww_acquire_ctx ctx;
|
||||
bool interruptible = false;
|
||||
bool no_wait = true;
|
||||
int err;
|
||||
|
||||
ww_acquire_init(&ctx, &reservation_ww_class);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
|
||||
KUNIT_ASSERT_EQ(test, err, -EBUSY);
|
||||
|
||||
ww_acquire_fini(&ctx);
|
||||
}
|
||||
|
||||
static void ttm_bo_reserve_double_resv(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ww_acquire_ctx ctx;
|
||||
bool interruptible = false;
|
||||
bool no_wait = false;
|
||||
int err;
|
||||
|
||||
ww_acquire_init(&ctx, &reservation_ww_class);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
|
||||
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
ww_acquire_fini(&ctx);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, -EALREADY);
|
||||
}
|
||||
|
||||
/*
|
||||
* A test case heavily inspired by ww_test_edeadlk_normal(). It injects
|
||||
* a deadlock by manipulating the sequence number of the context that holds
|
||||
* dma_resv lock of bo2 so the other context is "wounded" and has to back off
|
||||
* (indicated by -EDEADLK). The subtest checks if ttm_bo_reserve() properly
|
||||
* propagates that error.
|
||||
*/
|
||||
static void ttm_bo_reserve_deadlock(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo1, *bo2;
|
||||
struct ww_acquire_ctx ctx1, ctx2;
|
||||
bool interruptible = false;
|
||||
bool no_wait = false;
|
||||
int err;
|
||||
|
||||
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
ww_acquire_init(&ctx1, &reservation_ww_class);
|
||||
mutex_lock(&bo2->base.resv->lock.base);
|
||||
|
||||
/* The deadlock will be caught by WW mutex, don't warn about it */
|
||||
lock_release(&bo2->base.resv->lock.base.dep_map, 1);
|
||||
|
||||
bo2->base.resv->lock.ctx = &ctx2;
|
||||
ctx2 = ctx1;
|
||||
ctx2.stamp--; /* Make the context holding the lock younger */
|
||||
|
||||
err = ttm_bo_reserve(bo1, interruptible, no_wait, &ctx1);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
err = ttm_bo_reserve(bo2, interruptible, no_wait, &ctx1);
|
||||
KUNIT_ASSERT_EQ(test, err, -EDEADLK);
|
||||
|
||||
dma_resv_unlock(bo1->base.resv);
|
||||
ww_acquire_fini(&ctx1);
|
||||
}
|
||||
|
||||
#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST)
|
||||
struct signal_timer {
|
||||
struct timer_list timer;
|
||||
struct ww_acquire_ctx *ctx;
|
||||
};
|
||||
|
||||
static void signal_for_ttm_bo_reserve(struct timer_list *t)
|
||||
{
|
||||
struct signal_timer *s_timer = from_timer(s_timer, t, timer);
|
||||
struct task_struct *task = s_timer->ctx->task;
|
||||
|
||||
do_send_sig_info(SIGTERM, SEND_SIG_PRIV, task, PIDTYPE_PID);
|
||||
}
|
||||
|
||||
static int threaded_ttm_bo_reserve(void *arg)
|
||||
{
|
||||
struct ttm_buffer_object *bo = arg;
|
||||
struct signal_timer s_timer;
|
||||
struct ww_acquire_ctx ctx;
|
||||
bool interruptible = true;
|
||||
bool no_wait = false;
|
||||
int err;
|
||||
|
||||
ww_acquire_init(&ctx, &reservation_ww_class);
|
||||
|
||||
/* Prepare a signal that will interrupt the reservation attempt */
|
||||
timer_setup_on_stack(&s_timer.timer, &signal_for_ttm_bo_reserve, 0);
|
||||
s_timer.ctx = &ctx;
|
||||
|
||||
mod_timer(&s_timer.timer, msecs_to_jiffies(100));
|
||||
|
||||
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
|
||||
|
||||
timer_delete_sync(&s_timer.timer);
|
||||
destroy_timer_on_stack(&s_timer.timer);
|
||||
|
||||
ww_acquire_fini(&ctx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ttm_bo_reserve_interrupted(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct task_struct *task;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
task = kthread_create(threaded_ttm_bo_reserve, bo, "ttm-bo-reserve");
|
||||
|
||||
if (IS_ERR(task))
|
||||
KUNIT_FAIL(test, "Couldn't create ttm bo reserve task\n");
|
||||
|
||||
/* Take a lock so the threaded reserve has to wait */
|
||||
mutex_lock(&bo->base.resv->lock.base);
|
||||
|
||||
wake_up_process(task);
|
||||
msleep(20);
|
||||
err = kthread_stop(task);
|
||||
|
||||
mutex_unlock(&bo->base.resv->lock.base);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, -ERESTARTSYS);
|
||||
}
|
||||
#endif /* IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) */
|
||||
|
||||
static void ttm_bo_unreserve_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_resource *res1, *res2;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource_manager *man;
|
||||
unsigned int bo_prio = TTM_MAX_BO_PRIORITY - 1;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
int err;
|
||||
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo->priority = bo_prio;
|
||||
|
||||
err = ttm_resource_alloc(bo, place, &res1);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
bo->resource = res1;
|
||||
|
||||
/* Add a dummy resource to populate LRU */
|
||||
ttm_resource_alloc(bo, place, &res2);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_unreserve(bo);
|
||||
|
||||
man = ttm_manager_type(priv->ttm_dev, mem_type);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
list_is_last(&res1->lru, &man->lru[bo->priority]), 1);
|
||||
|
||||
ttm_resource_free(bo, &res2);
|
||||
ttm_resource_free(bo, &res1);
|
||||
}
|
||||
|
||||
static void ttm_bo_unreserve_pinned(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_resource *res1, *res2;
|
||||
struct ttm_place *place;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
int err;
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_pin(bo);
|
||||
|
||||
err = ttm_resource_alloc(bo, place, &res1);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo->resource = res1;
|
||||
|
||||
/* Add a dummy resource to the pinned list */
|
||||
err = ttm_resource_alloc(bo, place, &res2);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
list_is_last(&res2->lru, &priv->ttm_dev->pinned), 1);
|
||||
|
||||
ttm_bo_unreserve(bo);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
list_is_last(&res1->lru, &priv->ttm_dev->pinned), 1);
|
||||
|
||||
ttm_resource_free(bo, &res1);
|
||||
ttm_resource_free(bo, &res2);
|
||||
}
|
||||
|
||||
static void ttm_bo_unreserve_bulk(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_lru_bulk_move lru_bulk_move;
|
||||
struct ttm_lru_bulk_move_pos *pos;
|
||||
struct ttm_buffer_object *bo1, *bo2;
|
||||
struct ttm_resource *res1, *res2;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_place *place;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
unsigned int bo_priority = 0;
|
||||
int err;
|
||||
|
||||
ttm_lru_bulk_move_init(&lru_bulk_move);
|
||||
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
dma_resv_lock(bo1->base.resv, NULL);
|
||||
ttm_bo_set_bulk_move(bo1, &lru_bulk_move);
|
||||
dma_resv_unlock(bo1->base.resv);
|
||||
|
||||
err = ttm_resource_alloc(bo1, place, &res1);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo1->resource = res1;
|
||||
|
||||
dma_resv_lock(bo2->base.resv, NULL);
|
||||
ttm_bo_set_bulk_move(bo2, &lru_bulk_move);
|
||||
dma_resv_unlock(bo2->base.resv);
|
||||
|
||||
err = ttm_resource_alloc(bo2, place, &res2);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo2->resource = res2;
|
||||
|
||||
ttm_bo_reserve(bo1, false, false, NULL);
|
||||
ttm_bo_unreserve(bo1);
|
||||
|
||||
pos = &lru_bulk_move.pos[mem_type][bo_priority];
|
||||
KUNIT_ASSERT_PTR_EQ(test, res1, pos->last);
|
||||
|
||||
ttm_resource_free(bo1, &res1);
|
||||
ttm_resource_free(bo2, &res2);
|
||||
}
|
||||
|
||||
static void ttm_bo_put_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_place *place;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
int err;
|
||||
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo->type = ttm_bo_type_device;
|
||||
|
||||
err = ttm_resource_alloc(bo, place, &res);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo->resource = res;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
KUNIT_EXPECT_EQ(test, err, 0);
|
||||
|
||||
ttm_bo_put(bo);
|
||||
}
|
||||
|
||||
static const char *mock_name(struct dma_fence *f)
|
||||
{
|
||||
return "kunit-ttm-bo-put";
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops mock_fence_ops = {
|
||||
.get_driver_name = mock_name,
|
||||
.get_timeline_name = mock_name,
|
||||
};
|
||||
|
||||
static void ttm_bo_put_shared_resv(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct dma_resv *external_resv;
|
||||
struct dma_fence *fence;
|
||||
/* A dummy DMA fence lock */
|
||||
spinlock_t fence_lock;
|
||||
struct ttm_device *ttm_dev;
|
||||
int err;
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
external_resv = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, external_resv);
|
||||
|
||||
dma_resv_init(external_resv);
|
||||
|
||||
fence = kunit_kzalloc(test, sizeof(*fence), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, fence);
|
||||
|
||||
spin_lock_init(&fence_lock);
|
||||
dma_fence_init(fence, &mock_fence_ops, &fence_lock, 0, 0);
|
||||
|
||||
dma_resv_lock(external_resv, NULL);
|
||||
dma_resv_reserve_fences(external_resv, 1);
|
||||
dma_resv_add_fence(external_resv, fence, DMA_RESV_USAGE_BOOKKEEP);
|
||||
dma_resv_unlock(external_resv);
|
||||
|
||||
dma_fence_signal(fence);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo->type = ttm_bo_type_device;
|
||||
bo->base.resv = external_resv;
|
||||
|
||||
ttm_bo_put(bo);
|
||||
}
|
||||
|
||||
static void ttm_bo_pin_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_device *ttm_dev;
|
||||
unsigned int no_pins = 3;
|
||||
int err;
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
for (int i = 0; i < no_pins; i++) {
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_pin(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
}
|
||||
|
||||
KUNIT_ASSERT_EQ(test, bo->pin_count, no_pins);
|
||||
}
|
||||
|
||||
static void ttm_bo_pin_unpin_resource(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_lru_bulk_move lru_bulk_move;
|
||||
struct ttm_lru_bulk_move_pos *pos;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_place *place;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
unsigned int bo_priority = 0;
|
||||
int err;
|
||||
|
||||
ttm_lru_bulk_move_init(&lru_bulk_move);
|
||||
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_resource_alloc(bo, place, &res);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo->resource = res;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_set_bulk_move(bo, &lru_bulk_move);
|
||||
ttm_bo_pin(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
pos = &lru_bulk_move.pos[mem_type][bo_priority];
|
||||
|
||||
KUNIT_ASSERT_EQ(test, bo->pin_count, 1);
|
||||
KUNIT_ASSERT_NULL(test, pos->first);
|
||||
KUNIT_ASSERT_NULL(test, pos->last);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_unpin(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_PTR_EQ(test, res, pos->last);
|
||||
KUNIT_ASSERT_EQ(test, bo->pin_count, 0);
|
||||
|
||||
ttm_resource_free(bo, &res);
|
||||
}
|
||||
|
||||
static void ttm_bo_multiple_pin_one_unpin(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv = test->priv;
|
||||
struct ttm_lru_bulk_move lru_bulk_move;
|
||||
struct ttm_lru_bulk_move_pos *pos;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_device *ttm_dev;
|
||||
struct ttm_place *place;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
unsigned int bo_priority = 0;
|
||||
int err;
|
||||
|
||||
ttm_lru_bulk_move_init(&lru_bulk_move);
|
||||
|
||||
place = ttm_place_kunit_init(test, mem_type, 0);
|
||||
|
||||
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
|
||||
|
||||
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
priv->ttm_dev = ttm_dev;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_resource_alloc(bo, place, &res);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo->resource = res;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_set_bulk_move(bo, &lru_bulk_move);
|
||||
|
||||
/* Multiple pins */
|
||||
ttm_bo_pin(bo);
|
||||
ttm_bo_pin(bo);
|
||||
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
pos = &lru_bulk_move.pos[mem_type][bo_priority];
|
||||
|
||||
KUNIT_ASSERT_EQ(test, bo->pin_count, 2);
|
||||
KUNIT_ASSERT_NULL(test, pos->first);
|
||||
KUNIT_ASSERT_NULL(test, pos->last);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_unpin(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, bo->pin_count, 1);
|
||||
KUNIT_ASSERT_NULL(test, pos->first);
|
||||
KUNIT_ASSERT_NULL(test, pos->last);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_unpin(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
ttm_resource_free(bo, &res);
|
||||
}
|
||||
|
||||
static struct kunit_case ttm_bo_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(ttm_bo_reserve_optimistic_no_ticket,
|
||||
ttm_bo_reserve_gen_params),
|
||||
KUNIT_CASE(ttm_bo_reserve_locked_no_sleep),
|
||||
KUNIT_CASE(ttm_bo_reserve_no_wait_ticket),
|
||||
KUNIT_CASE(ttm_bo_reserve_double_resv),
|
||||
#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST)
|
||||
KUNIT_CASE(ttm_bo_reserve_interrupted),
|
||||
#endif
|
||||
KUNIT_CASE(ttm_bo_reserve_deadlock),
|
||||
KUNIT_CASE(ttm_bo_unreserve_basic),
|
||||
KUNIT_CASE(ttm_bo_unreserve_pinned),
|
||||
KUNIT_CASE(ttm_bo_unreserve_bulk),
|
||||
KUNIT_CASE(ttm_bo_put_basic),
|
||||
KUNIT_CASE(ttm_bo_put_shared_resv),
|
||||
KUNIT_CASE(ttm_bo_pin_basic),
|
||||
KUNIT_CASE(ttm_bo_pin_unpin_resource),
|
||||
KUNIT_CASE(ttm_bo_multiple_pin_one_unpin),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite ttm_bo_test_suite = {
|
||||
.name = "ttm_bo",
|
||||
.init = ttm_test_devices_init,
|
||||
.exit = ttm_test_devices_fini,
|
||||
.test_cases = ttm_bo_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suites(&ttm_bo_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -2,9 +2,33 @@
|
|||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
|
||||
#include "ttm_kunit_helpers.h"
|
||||
|
||||
static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo,
|
||||
uint32_t page_flags)
|
||||
{
|
||||
struct ttm_tt *tt;
|
||||
|
||||
tt = kzalloc(sizeof(*tt), GFP_KERNEL);
|
||||
ttm_tt_init(tt, bo, page_flags, ttm_cached, 0);
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
|
||||
{
|
||||
kfree(ttm);
|
||||
}
|
||||
|
||||
static void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo)
|
||||
{
|
||||
}
|
||||
|
||||
struct ttm_device_funcs ttm_dev_funcs = {
|
||||
.ttm_tt_create = ttm_tt_simple_create,
|
||||
.ttm_tt_destroy = ttm_tt_simple_destroy,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ttm_dev_funcs);
|
||||
|
||||
|
@ -29,19 +53,41 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
|
|||
struct ttm_test_devices *devs,
|
||||
size_t size)
|
||||
{
|
||||
struct drm_gem_object gem_obj = { .size = size };
|
||||
struct drm_gem_object gem_obj = { };
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = kunit_kzalloc(test, sizeof(*bo), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, bo);
|
||||
|
||||
bo->base = gem_obj;
|
||||
err = drm_gem_object_init(devs->drm, &bo->base, size);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
bo->bdev = devs->ttm_dev;
|
||||
bo->destroy = dummy_ttm_bo_destroy;
|
||||
|
||||
kref_init(&bo->kref);
|
||||
|
||||
return bo;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ttm_bo_kunit_init);
|
||||
|
||||
struct ttm_place *ttm_place_kunit_init(struct kunit *test,
|
||||
uint32_t mem_type, uint32_t flags)
|
||||
{
|
||||
struct ttm_place *place;
|
||||
|
||||
place = kunit_kzalloc(test, sizeof(*place), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, place);
|
||||
|
||||
place->mem_type = mem_type;
|
||||
place->flags = flags;
|
||||
|
||||
return place;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ttm_place_kunit_init);
|
||||
|
||||
struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *devs;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/ttm/ttm_device.h>
|
||||
#include <drm/ttm/ttm_bo.h>
|
||||
#include <drm/ttm/ttm_placement.h>
|
||||
|
||||
#include <drm/drm_kunit_helpers.h>
|
||||
#include <kunit/test.h>
|
||||
|
@ -28,6 +29,8 @@ int ttm_device_kunit_init(struct ttm_test_devices *priv,
|
|||
struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
|
||||
struct ttm_test_devices *devs,
|
||||
size_t size);
|
||||
struct ttm_place *ttm_place_kunit_init(struct kunit *test,
|
||||
uint32_t mem_type, uint32_t flags);
|
||||
|
||||
struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test);
|
||||
struct ttm_test_devices *ttm_test_devices_all(struct kunit *test);
|
||||
|
|
|
@ -78,10 +78,9 @@ static struct ttm_pool *ttm_pool_pre_populated(struct kunit *test,
|
|||
struct ttm_test_devices *devs = priv->devs;
|
||||
struct ttm_pool *pool;
|
||||
struct ttm_tt *tt;
|
||||
unsigned long order = __fls(size / PAGE_SIZE);
|
||||
int err;
|
||||
|
||||
tt = ttm_tt_kunit_init(test, order, caching, size);
|
||||
tt = ttm_tt_kunit_init(test, 0, caching, size);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
pool = kunit_kzalloc(test, sizeof(*pool), GFP_KERNEL);
|
||||
|
|
335
drivers/gpu/drm/ttm/tests/ttm_resource_test.c
Normal file
335
drivers/gpu/drm/ttm/tests/ttm_resource_test.c
Normal file
|
@ -0,0 +1,335 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 AND MIT
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
#include <drm/ttm/ttm_resource.h>
|
||||
|
||||
#include "ttm_kunit_helpers.h"
|
||||
|
||||
#define RES_SIZE SZ_4K
|
||||
#define TTM_PRIV_DUMMY_REG (TTM_NUM_MEM_TYPES - 1)
|
||||
|
||||
struct ttm_resource_test_case {
|
||||
const char *description;
|
||||
uint32_t mem_type;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct ttm_resource_test_priv {
|
||||
struct ttm_test_devices *devs;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
};
|
||||
|
||||
static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { };
|
||||
|
||||
static int ttm_resource_test_init(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, priv);
|
||||
|
||||
priv->devs = ttm_test_devices_all(test);
|
||||
KUNIT_ASSERT_NOT_NULL(test, priv->devs);
|
||||
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ttm_resource_test_fini(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
|
||||
ttm_test_devices_put(test, priv->devs);
|
||||
}
|
||||
|
||||
static void ttm_init_test_mocks(struct kunit *test,
|
||||
struct ttm_resource_test_priv *priv,
|
||||
uint32_t mem_type, uint32_t flags)
|
||||
{
|
||||
size_t size = RES_SIZE;
|
||||
|
||||
/* Make sure we have what we need for a good BO mock */
|
||||
KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev);
|
||||
|
||||
priv->bo = ttm_bo_kunit_init(test, priv->devs, size);
|
||||
priv->place = ttm_place_kunit_init(test, mem_type, flags);
|
||||
}
|
||||
|
||||
static void ttm_init_test_manager(struct kunit *test,
|
||||
struct ttm_resource_test_priv *priv,
|
||||
uint32_t mem_type)
|
||||
{
|
||||
struct ttm_device *ttm_dev = priv->devs->ttm_dev;
|
||||
struct ttm_resource_manager *man;
|
||||
size_t size = SZ_16K;
|
||||
|
||||
man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, man);
|
||||
|
||||
man->use_tt = false;
|
||||
man->func = &ttm_resource_manager_mock_funcs;
|
||||
|
||||
ttm_resource_manager_init(man, ttm_dev, size);
|
||||
ttm_set_driver_manager(ttm_dev, mem_type, man);
|
||||
ttm_resource_manager_set_used(man, true);
|
||||
}
|
||||
|
||||
static const struct ttm_resource_test_case ttm_resource_cases[] = {
|
||||
{
|
||||
.description = "Init resource in TTM_PL_SYSTEM",
|
||||
.mem_type = TTM_PL_SYSTEM,
|
||||
},
|
||||
{
|
||||
.description = "Init resource in TTM_PL_VRAM",
|
||||
.mem_type = TTM_PL_VRAM,
|
||||
},
|
||||
{
|
||||
.description = "Init resource in a private placement",
|
||||
.mem_type = TTM_PRIV_DUMMY_REG,
|
||||
},
|
||||
{
|
||||
.description = "Init resource in TTM_PL_SYSTEM, set placement flags",
|
||||
.mem_type = TTM_PL_SYSTEM,
|
||||
.flags = TTM_PL_FLAG_TOPDOWN,
|
||||
},
|
||||
};
|
||||
|
||||
static void ttm_resource_case_desc(const struct ttm_resource_test_case *t, char *desc)
|
||||
{
|
||||
strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc);
|
||||
|
||||
static void ttm_resource_init_basic(struct kunit *test)
|
||||
{
|
||||
const struct ttm_resource_test_case *params = test->param_value;
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource_manager *man;
|
||||
uint64_t expected_usage;
|
||||
|
||||
ttm_init_test_mocks(test, priv, params->mem_type, params->flags);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
if (params->mem_type > TTM_PL_SYSTEM)
|
||||
ttm_init_test_manager(test, priv, params->mem_type);
|
||||
|
||||
res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, res);
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type);
|
||||
expected_usage = man->usage + RES_SIZE;
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority]));
|
||||
|
||||
ttm_resource_init(bo, place, res);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, res->start, 0);
|
||||
KUNIT_ASSERT_EQ(test, res->size, RES_SIZE);
|
||||
KUNIT_ASSERT_EQ(test, res->mem_type, place->mem_type);
|
||||
KUNIT_ASSERT_EQ(test, res->placement, place->flags);
|
||||
KUNIT_ASSERT_PTR_EQ(test, res->bo, bo);
|
||||
|
||||
KUNIT_ASSERT_NULL(test, res->bus.addr);
|
||||
KUNIT_ASSERT_EQ(test, res->bus.offset, 0);
|
||||
KUNIT_ASSERT_FALSE(test, res->bus.is_iomem);
|
||||
KUNIT_ASSERT_EQ(test, res->bus.caching, ttm_cached);
|
||||
KUNIT_ASSERT_EQ(test, man->usage, expected_usage);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority]));
|
||||
|
||||
ttm_resource_fini(man, res);
|
||||
}
|
||||
|
||||
static void ttm_resource_init_pinned(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource_manager *man;
|
||||
|
||||
ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type);
|
||||
|
||||
res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, res);
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned));
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
ttm_bo_pin(bo);
|
||||
ttm_resource_init(bo, place, res);
|
||||
KUNIT_ASSERT_TRUE(test, list_is_singular(&bo->bdev->pinned));
|
||||
|
||||
ttm_bo_unpin(bo);
|
||||
ttm_resource_fini(man, res);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned));
|
||||
}
|
||||
|
||||
static void ttm_resource_fini_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource_manager *man;
|
||||
|
||||
ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type);
|
||||
|
||||
res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, res);
|
||||
|
||||
ttm_resource_init(bo, place, res);
|
||||
ttm_resource_fini(man, res);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&res->lru));
|
||||
KUNIT_ASSERT_EQ(test, man->usage, 0);
|
||||
}
|
||||
|
||||
static void ttm_resource_manager_init_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource_manager *man;
|
||||
size_t size = SZ_16K;
|
||||
|
||||
man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, man);
|
||||
|
||||
ttm_resource_manager_init(man, priv->devs->ttm_dev, size);
|
||||
|
||||
KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev);
|
||||
KUNIT_ASSERT_EQ(test, man->size, size);
|
||||
KUNIT_ASSERT_EQ(test, man->usage, 0);
|
||||
KUNIT_ASSERT_NULL(test, man->move);
|
||||
KUNIT_ASSERT_NOT_NULL(test, &man->move_lock);
|
||||
|
||||
for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i]));
|
||||
}
|
||||
|
||||
static void ttm_resource_manager_usage_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource *res;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource_manager *man;
|
||||
uint64_t actual_usage;
|
||||
|
||||
ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, res);
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type);
|
||||
|
||||
ttm_resource_init(bo, place, res);
|
||||
actual_usage = ttm_resource_manager_usage(man);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE);
|
||||
|
||||
ttm_resource_fini(man, res);
|
||||
}
|
||||
|
||||
static void ttm_resource_manager_set_used_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource_manager *man;
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, TTM_PL_SYSTEM);
|
||||
KUNIT_ASSERT_TRUE(test, man->use_type);
|
||||
|
||||
ttm_resource_manager_set_used(man, false);
|
||||
KUNIT_ASSERT_FALSE(test, man->use_type);
|
||||
}
|
||||
|
||||
static void ttm_sys_man_alloc_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource_manager *man;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource *res;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
int ret;
|
||||
|
||||
ttm_init_test_mocks(test, priv, mem_type, 0);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, mem_type);
|
||||
ret = man->func->alloc(man, bo, place, &res);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
KUNIT_ASSERT_EQ(test, res->size, RES_SIZE);
|
||||
KUNIT_ASSERT_EQ(test, res->mem_type, mem_type);
|
||||
KUNIT_ASSERT_PTR_EQ(test, res->bo, bo);
|
||||
|
||||
ttm_resource_fini(man, res);
|
||||
}
|
||||
|
||||
static void ttm_sys_man_free_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_resource_test_priv *priv = test->priv;
|
||||
struct ttm_resource_manager *man;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_place *place;
|
||||
struct ttm_resource *res;
|
||||
uint32_t mem_type = TTM_PL_SYSTEM;
|
||||
|
||||
ttm_init_test_mocks(test, priv, mem_type, 0);
|
||||
bo = priv->bo;
|
||||
place = priv->place;
|
||||
|
||||
res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, res);
|
||||
|
||||
ttm_resource_alloc(bo, place, &res);
|
||||
|
||||
man = ttm_manager_type(priv->devs->ttm_dev, mem_type);
|
||||
man->func->free(man, res);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority]));
|
||||
KUNIT_ASSERT_EQ(test, man->usage, 0);
|
||||
}
|
||||
|
||||
static struct kunit_case ttm_resource_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params),
|
||||
KUNIT_CASE(ttm_resource_init_pinned),
|
||||
KUNIT_CASE(ttm_resource_fini_basic),
|
||||
KUNIT_CASE(ttm_resource_manager_init_basic),
|
||||
KUNIT_CASE(ttm_resource_manager_usage_basic),
|
||||
KUNIT_CASE(ttm_resource_manager_set_used_basic),
|
||||
KUNIT_CASE(ttm_sys_man_alloc_basic),
|
||||
KUNIT_CASE(ttm_sys_man_free_basic),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite ttm_resource_test_suite = {
|
||||
.name = "ttm_resource",
|
||||
.init = ttm_resource_test_init,
|
||||
.exit = ttm_resource_test_fini,
|
||||
.test_cases = ttm_resource_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suites(&ttm_resource_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
295
drivers/gpu/drm/ttm/tests/ttm_tt_test.c
Normal file
295
drivers/gpu/drm/ttm/tests/ttm_tt_test.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 AND MIT
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
|
||||
#include "ttm_kunit_helpers.h"
|
||||
|
||||
#define BO_SIZE SZ_4K
|
||||
|
||||
struct ttm_tt_test_case {
|
||||
const char *description;
|
||||
uint32_t size;
|
||||
uint32_t extra_pages_num;
|
||||
};
|
||||
|
||||
static int ttm_tt_test_init(struct kunit *test)
|
||||
{
|
||||
struct ttm_test_devices *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, priv);
|
||||
|
||||
priv = ttm_test_devices_all(test);
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = {
|
||||
{
|
||||
.description = "Page-aligned size",
|
||||
.size = SZ_4K,
|
||||
},
|
||||
{
|
||||
.description = "Extra pages requested",
|
||||
.size = SZ_4K,
|
||||
.extra_pages_num = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static void ttm_tt_init_case_desc(const struct ttm_tt_test_case *t,
|
||||
char *desc)
|
||||
{
|
||||
strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases,
|
||||
ttm_tt_init_case_desc);
|
||||
|
||||
static void ttm_tt_init_basic(struct kunit *test)
|
||||
{
|
||||
const struct ttm_tt_test_case *params = test->param_value;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
uint32_t page_flags = TTM_TT_FLAG_ZERO_ALLOC;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
uint32_t extra_pages = params->extra_pages_num;
|
||||
int num_pages = params->size >> PAGE_SHIFT;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, params->size);
|
||||
|
||||
err = ttm_tt_init(tt, bo, page_flags, caching, extra_pages);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages + extra_pages);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, tt->page_flags, page_flags);
|
||||
KUNIT_ASSERT_EQ(test, tt->caching, caching);
|
||||
|
||||
KUNIT_ASSERT_NULL(test, tt->dma_address);
|
||||
KUNIT_ASSERT_NULL(test, tt->swap_storage);
|
||||
}
|
||||
|
||||
static void ttm_tt_init_misaligned(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
uint32_t size = SZ_8K;
|
||||
int num_pages = (size + SZ_4K) >> PAGE_SHIFT;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, size);
|
||||
|
||||
/* Make the object size misaligned */
|
||||
bo->base.size += 1;
|
||||
|
||||
err = ttm_tt_init(tt, bo, 0, caching, 0);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages);
|
||||
}
|
||||
|
||||
static void ttm_tt_fini_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_tt_init(tt, bo, 0, caching, 0);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt->pages);
|
||||
|
||||
ttm_tt_fini(tt);
|
||||
KUNIT_ASSERT_NULL(test, tt->pages);
|
||||
}
|
||||
|
||||
static void ttm_tt_fini_sg(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_sg_tt_init(tt, bo, 0, caching);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt->dma_address);
|
||||
|
||||
ttm_tt_fini(tt);
|
||||
KUNIT_ASSERT_NULL(test, tt->dma_address);
|
||||
}
|
||||
|
||||
static void ttm_tt_fini_shmem(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
struct file *shmem;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_tt_init(tt, bo, 0, caching, 0);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
|
||||
shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
|
||||
tt->swap_storage = shmem;
|
||||
|
||||
ttm_tt_fini(tt);
|
||||
KUNIT_ASSERT_NULL(test, tt->swap_storage);
|
||||
}
|
||||
|
||||
static void ttm_tt_create_basic(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo->type = ttm_bo_type_device;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, err, 0);
|
||||
KUNIT_EXPECT_NOT_NULL(test, bo->ttm);
|
||||
|
||||
/* Free manually, as it was allocated outside of KUnit */
|
||||
kfree(bo->ttm);
|
||||
}
|
||||
|
||||
static void ttm_tt_create_invalid_bo_type(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
bo->type = ttm_bo_type_sg + 1;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, err, -EINVAL);
|
||||
KUNIT_EXPECT_NULL(test, bo->ttm);
|
||||
}
|
||||
|
||||
static void ttm_tt_create_ttm_exists(struct kunit *test)
|
||||
{
|
||||
struct ttm_buffer_object *bo;
|
||||
struct ttm_tt *tt;
|
||||
enum ttm_caching caching = ttm_cached;
|
||||
int err;
|
||||
|
||||
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, tt);
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
err = ttm_tt_init(tt, bo, 0, caching, 0);
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
bo->ttm = tt;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
/* Expect to keep the previous TTM */
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
KUNIT_ASSERT_PTR_EQ(test, tt, bo->ttm);
|
||||
}
|
||||
|
||||
static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo,
|
||||
uint32_t page_flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ttm_device_funcs ttm_dev_empty_funcs = {
|
||||
.ttm_tt_create = ttm_tt_null_create,
|
||||
};
|
||||
|
||||
static void ttm_tt_create_failed(struct kunit *test)
|
||||
{
|
||||
const struct ttm_test_devices *devs = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
/* Update ttm_device_funcs so we don't alloc ttm_tt */
|
||||
devs->ttm_dev->funcs = &ttm_dev_empty_funcs;
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, -ENOMEM);
|
||||
}
|
||||
|
||||
static void ttm_tt_destroy_basic(struct kunit *test)
|
||||
{
|
||||
const struct ttm_test_devices *devs = test->priv;
|
||||
struct ttm_buffer_object *bo;
|
||||
int err;
|
||||
|
||||
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
|
||||
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
err = ttm_tt_create(bo, false);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, 0);
|
||||
KUNIT_ASSERT_NOT_NULL(test, bo->ttm);
|
||||
|
||||
ttm_tt_destroy(devs->ttm_dev, bo->ttm);
|
||||
}
|
||||
|
||||
static struct kunit_case ttm_tt_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params),
|
||||
KUNIT_CASE(ttm_tt_init_misaligned),
|
||||
KUNIT_CASE(ttm_tt_fini_basic),
|
||||
KUNIT_CASE(ttm_tt_fini_sg),
|
||||
KUNIT_CASE(ttm_tt_fini_shmem),
|
||||
KUNIT_CASE(ttm_tt_create_basic),
|
||||
KUNIT_CASE(ttm_tt_create_invalid_bo_type),
|
||||
KUNIT_CASE(ttm_tt_create_ttm_exists),
|
||||
KUNIT_CASE(ttm_tt_create_failed),
|
||||
KUNIT_CASE(ttm_tt_destroy_basic),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite ttm_tt_test_suite = {
|
||||
.name = "ttm_tt",
|
||||
.init = ttm_tt_test_init,
|
||||
.exit = ttm_test_devices_fini,
|
||||
.test_cases = ttm_tt_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suites(&ttm_tt_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -30,6 +30,8 @@
|
|||
#include <drm/ttm/ttm_placement.h>
|
||||
#include <drm/ttm/ttm_resource.h>
|
||||
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
/**
|
||||
* ttm_lru_bulk_move_init - initialize a bulk move structure
|
||||
* @bulk: the structure to init
|
||||
|
@ -240,6 +242,7 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo,
|
|||
spin_unlock(&bo->bdev->lru_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_resource_alloc);
|
||||
|
||||
void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/file.h>
|
||||
#include <linux/module.h>
|
||||
#include <drm/drm_cache.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/ttm/ttm_bo.h>
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
|
||||
|
@ -91,6 +92,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_create);
|
||||
|
||||
/*
|
||||
* Allocates storage for pointers to the pages that back the ttm.
|
||||
|
@ -129,6 +131,7 @@ void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
|
|||
{
|
||||
bdev->funcs->ttm_tt_destroy(bdev, ttm);
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_destroy);
|
||||
|
||||
static void ttm_tt_init_fields(struct ttm_tt *ttm,
|
||||
struct ttm_buffer_object *bo,
|
||||
|
|
|
@ -260,11 +260,26 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int v3d_debugfs_mm(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
struct drm_debugfs_entry *entry = m->private;
|
||||
struct drm_device *dev = entry->dev;
|
||||
struct v3d_dev *v3d = to_v3d_dev(dev);
|
||||
|
||||
spin_lock(&v3d->mm_lock);
|
||||
drm_mm_print(&v3d->mm, &p);
|
||||
spin_unlock(&v3d->mm_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_debugfs_info v3d_debugfs_list[] = {
|
||||
{"v3d_ident", v3d_v3d_debugfs_ident, 0},
|
||||
{"v3d_regs", v3d_v3d_debugfs_regs, 0},
|
||||
{"measure_clock", v3d_measure_clock, 0},
|
||||
{"bo_stats", v3d_debugfs_bo_stats, 0},
|
||||
{"v3d_mm", v3d_debugfs_mm, 0},
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -1497,16 +1497,16 @@ static int vc4_prepare_fb(struct drm_plane *plane,
|
|||
struct drm_plane_state *state)
|
||||
{
|
||||
struct vc4_bo *bo;
|
||||
int ret;
|
||||
|
||||
if (!state->fb)
|
||||
return 0;
|
||||
|
||||
bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);
|
||||
|
||||
drm_gem_plane_helper_prepare_fb(plane, state);
|
||||
|
||||
if (plane->state->fb == state->fb)
|
||||
return 0;
|
||||
ret = drm_gem_plane_helper_prepare_fb(plane, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return vc4_bo_inc_usecnt(bo);
|
||||
}
|
||||
|
@ -1516,7 +1516,7 @@ static void vc4_cleanup_fb(struct drm_plane *plane,
|
|||
{
|
||||
struct vc4_bo *bo;
|
||||
|
||||
if (plane->state->fb == state->fb || !state->fb)
|
||||
if (!state->fb)
|
||||
return;
|
||||
|
||||
bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);
|
||||
|
|
|
@ -99,8 +99,8 @@ virtio_gpu_parse_deps(struct virtio_gpu_submit *submit)
|
|||
return 0;
|
||||
|
||||
/*
|
||||
* kvalloc at first tries to allocate memory using kmalloc and
|
||||
* falls back to vmalloc only on failure. It also uses __GFP_NOWARN
|
||||
* kvmalloc() at first tries to allocate memory using kmalloc() and
|
||||
* falls back to vmalloc() only on failure. It also uses __GFP_NOWARN
|
||||
* internally for allocations larger than a page size, preventing
|
||||
* storm of KMSG warnings.
|
||||
*/
|
||||
|
@ -529,7 +529,7 @@ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
|
|||
virtio_gpu_submit(&submit);
|
||||
|
||||
/*
|
||||
* Set up usr-out data after submitting the job to optimize
|
||||
* Set up user-out data after submitting the job to optimize
|
||||
* the job submission path.
|
||||
*/
|
||||
virtio_gpu_install_out_fence_fd(&submit);
|
||||
|
|
15
drivers/gpu/drm/vkms/Kconfig
Normal file
15
drivers/gpu/drm/vkms/Kconfig
Normal file
|
@ -0,0 +1,15 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config DRM_VKMS
|
||||
tristate "Virtual KMS (EXPERIMENTAL)"
|
||||
depends on DRM && MMU
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_SHMEM_HELPER
|
||||
select CRC32
|
||||
default n
|
||||
help
|
||||
Virtual Kernel Mode-Setting (VKMS) is used for testing or for
|
||||
running GPU in a headless machines. Choose this option to get
|
||||
a VKMS.
|
||||
|
||||
If M is selected the module will be called vkms.
|
|
@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan
|
|||
enum lut_channel channel)
|
||||
{
|
||||
s64 lut_index = get_lut_index(lut, channel_value);
|
||||
u16 *floor_lut_value, *ceil_lut_value;
|
||||
u16 floor_channel_value, ceil_channel_value;
|
||||
|
||||
/*
|
||||
* This checks if `struct drm_color_lut` has any gap added by the compiler
|
||||
|
@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan
|
|||
*/
|
||||
static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4);
|
||||
|
||||
u16 *floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)];
|
||||
u16 *ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)];
|
||||
floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)];
|
||||
if (drm_fixp2int(lut_index) == (lut->lut_length - 1))
|
||||
/* We're at the end of the LUT array, use same value for ceil and floor */
|
||||
ceil_lut_value = floor_lut_value;
|
||||
else
|
||||
ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)];
|
||||
|
||||
u16 floor_channel_value = floor_lut_value[channel];
|
||||
u16 ceil_channel_value = ceil_lut_value[channel];
|
||||
floor_channel_value = floor_lut_value[channel];
|
||||
ceil_channel_value = ceil_lut_value[channel];
|
||||
|
||||
return lerp_u16(floor_channel_value, ceil_channel_value,
|
||||
lut_index & DRM_FIXED_DECIMAL_MASK);
|
||||
|
|
|
@ -621,10 +621,10 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context)
|
|||
* @sw_context: Pointer to the software context.
|
||||
* @res_type: Resource type.
|
||||
* @dirty: Whether to change dirty status.
|
||||
* @converter: User-space visisble type specific information.
|
||||
* @converter: User-space visible type specific information.
|
||||
* @id_loc: Pointer to the location in the command buffer currently being parsed
|
||||
* from where the user-space resource id handle is located.
|
||||
* @p_res: Pointer to pointer to resource validalidation node. Populated on
|
||||
* @p_res: Pointer to pointer to resource validation node. Populated on
|
||||
* exit.
|
||||
*/
|
||||
static int
|
||||
|
|
|
@ -64,8 +64,11 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
|
|||
ttm_resource_init(bo, place, *res);
|
||||
|
||||
id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
if (id < 0) {
|
||||
ttm_resource_fini(man, *res);
|
||||
kfree(*res);
|
||||
return id;
|
||||
}
|
||||
|
||||
spin_lock(&gman->lock);
|
||||
|
||||
|
|
|
@ -694,6 +694,10 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
|||
int ret = 0;
|
||||
|
||||
if (vps->surf) {
|
||||
if (vps->surf_mapped) {
|
||||
vmw_bo_unmap(vps->surf->res.guest_memory_bo);
|
||||
vps->surf_mapped = false;
|
||||
}
|
||||
vmw_surface_unreference(&vps->surf);
|
||||
vps->surf = NULL;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ enum stdu_content_type {
|
|||
* struct vmw_stdu_dirty - closure structure for the update functions
|
||||
*
|
||||
* @base: The base type we derive from. Used by vmw_kms_helper_dirty().
|
||||
* @transfer: Transfer direction for DMA command.
|
||||
* @left: Left side of bounding box.
|
||||
* @right: Right side of bounding box.
|
||||
* @top: Top side of bounding box.
|
||||
|
@ -100,7 +99,7 @@ struct vmw_stdu_update_gb_image {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct vmw_screen_target_display_unit
|
||||
* struct vmw_screen_target_display_unit - conglomerated STDU structure
|
||||
*
|
||||
* @base: VMW specific DU structure
|
||||
* @display_srf: surface to be displayed. The dimension of this will always
|
||||
|
@ -208,6 +207,8 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv,
|
|||
* @res: Buffer to bind to the screen target. Set to NULL to blank screen.
|
||||
*
|
||||
* Binding a surface to a Screen Target the same as flipping
|
||||
*
|
||||
* Returns: %0 on success or -errno code on failure
|
||||
*/
|
||||
static int vmw_stdu_bind_st(struct vmw_private *dev_priv,
|
||||
struct vmw_screen_target_display_unit *stdu,
|
||||
|
@ -314,6 +315,9 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv,
|
|||
*
|
||||
* @dev_priv: VMW DRM device
|
||||
* @stdu: display unit to destroy
|
||||
*
|
||||
* Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
|
||||
* interrupted.
|
||||
*/
|
||||
static int vmw_stdu_destroy_st(struct vmw_private *dev_priv,
|
||||
struct vmw_screen_target_display_unit *stdu)
|
||||
|
@ -536,7 +540,8 @@ static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty)
|
|||
* If DMA-ing till the screen target system, the function will also notify
|
||||
* the screen target system that a bounding box of the cliprects has been
|
||||
* updated.
|
||||
* Returns 0 on success, negative error code on failure. -ERESTARTSYS if
|
||||
*
|
||||
* Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
|
||||
* interrupted.
|
||||
*/
|
||||
int vmw_kms_stdu_readback(struct vmw_private *dev_priv,
|
||||
|
@ -703,7 +708,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty)
|
|||
* case the device has already synchronized.
|
||||
* @crtc: If crtc is passed, perform surface dirty on that crtc only.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure. -ERESTARTSYS if
|
||||
* Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
|
||||
* interrupted.
|
||||
*/
|
||||
int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
|
||||
|
@ -887,7 +892,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
|
|||
* backed by a buffer object. The display surface is pinned here, and it'll
|
||||
* be unpinned in .cleanup_fb()
|
||||
*
|
||||
* Returns 0 on success
|
||||
* Returns: %0 on success
|
||||
*/
|
||||
static int
|
||||
vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||
|
@ -1465,6 +1470,8 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
|
|||
* This function is called once per CRTC, and allocates one Screen Target
|
||||
* display unit to represent that CRTC. Since the SVGA device does not separate
|
||||
* out encoder and connector, they are represented as part of the STDU as well.
|
||||
*
|
||||
* Returns: %0 on success or -errno code on failure
|
||||
*/
|
||||
static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
* struct vmw_user_surface - User-space visible surface resource
|
||||
*
|
||||
* @prime: The TTM prime object.
|
||||
* @base: The TTM base object handling user-space visibility.
|
||||
* @srf: The surface metadata.
|
||||
* @master: Master of the creating client. Used for security check.
|
||||
*/
|
||||
|
|
|
@ -108,7 +108,7 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
|
|||
*/
|
||||
#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
|
||||
defined CONFIG_ACPI_BGRT
|
||||
static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
|
||||
static void efifb_copy_bmp(u8 *src, u32 *dst, int width, const struct screen_info *si)
|
||||
{
|
||||
u8 r, g, b;
|
||||
|
||||
|
@ -130,7 +130,7 @@ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
|
|||
* resolution still fits, it will be displayed very close to the right edge of
|
||||
* the display looking quite bad. This function checks for this.
|
||||
*/
|
||||
static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
|
||||
static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width)
|
||||
{
|
||||
/*
|
||||
* All x86 firmwares horizontally center the image (the yoffset
|
||||
|
@ -141,16 +141,15 @@ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
|
|||
return bgrt_tab.image_offset_x == expected_xoffset;
|
||||
}
|
||||
#else
|
||||
static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
|
||||
static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void efifb_show_boot_graphics(struct fb_info *info)
|
||||
static void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si)
|
||||
{
|
||||
u32 bmp_width, bmp_height, bmp_pitch, dst_x, y, src_y;
|
||||
struct screen_info *si = &screen_info;
|
||||
struct bmp_file_header *file_header;
|
||||
struct bmp_dib_header *dib_header;
|
||||
void *bgrt_image = NULL;
|
||||
|
@ -247,7 +246,8 @@ error:
|
|||
pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
|
||||
}
|
||||
#else
|
||||
static inline void efifb_show_boot_graphics(struct fb_info *info) {}
|
||||
static inline void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -282,7 +282,7 @@ static const struct fb_ops efifb_ops = {
|
|||
.fb_setcolreg = efifb_setcolreg,
|
||||
};
|
||||
|
||||
static int efifb_setup(char *options)
|
||||
static int efifb_setup(struct screen_info *si, char *options)
|
||||
{
|
||||
char *this_opt;
|
||||
|
||||
|
@ -290,16 +290,16 @@ static int efifb_setup(char *options)
|
|||
while ((this_opt = strsep(&options, ",")) != NULL) {
|
||||
if (!*this_opt) continue;
|
||||
|
||||
efifb_setup_from_dmi(&screen_info, this_opt);
|
||||
efifb_setup_from_dmi(si, this_opt);
|
||||
|
||||
if (!strncmp(this_opt, "base:", 5))
|
||||
screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
|
||||
si->lfb_base = simple_strtoul(this_opt+5, NULL, 0);
|
||||
else if (!strncmp(this_opt, "stride:", 7))
|
||||
screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
|
||||
si->lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
|
||||
else if (!strncmp(this_opt, "height:", 7))
|
||||
screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
|
||||
si->lfb_height = simple_strtoul(this_opt+7, NULL, 0);
|
||||
else if (!strncmp(this_opt, "width:", 6))
|
||||
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
|
||||
si->lfb_width = simple_strtoul(this_opt+6, NULL, 0);
|
||||
else if (!strcmp(this_opt, "nowc"))
|
||||
mem_flags &= ~EFI_MEMORY_WC;
|
||||
else if (!strcmp(this_opt, "nobgrt"))
|
||||
|
@ -310,15 +310,15 @@ static int efifb_setup(char *options)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool fb_base_is_valid(void)
|
||||
static inline bool fb_base_is_valid(struct screen_info *si)
|
||||
{
|
||||
if (screen_info.lfb_base)
|
||||
if (si->lfb_base)
|
||||
return true;
|
||||
|
||||
if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
|
||||
if (!(si->capabilities & VIDEO_CAPABILITY_64BIT_BASE))
|
||||
return false;
|
||||
|
||||
if (screen_info.ext_lfb_base)
|
||||
if (si->ext_lfb_base)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -329,7 +329,10 @@ static ssize_t name##_show(struct device *dev, \
|
|||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, fmt "\n", (screen_info.lfb_##name)); \
|
||||
struct screen_info *si = dev_get_platdata(dev); \
|
||||
if (!si) \
|
||||
return -ENODEV; \
|
||||
return sprintf(buf, fmt "\n", (si->lfb_##name)); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(name)
|
||||
|
||||
|
@ -356,6 +359,7 @@ static u64 bar_offset;
|
|||
|
||||
static int efifb_probe(struct platform_device *dev)
|
||||
{
|
||||
struct screen_info *si;
|
||||
struct fb_info *info;
|
||||
struct efifb_par *par;
|
||||
int err, orientation;
|
||||
|
@ -365,48 +369,60 @@ static int efifb_probe(struct platform_device *dev)
|
|||
char *option = NULL;
|
||||
efi_memory_desc_t md;
|
||||
|
||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
|
||||
/*
|
||||
* If we fail probing the device, the kernel might try a different
|
||||
* driver. We get a copy of the attached screen_info, so that we can
|
||||
* modify its values without affecting later drivers.
|
||||
*/
|
||||
si = dev_get_platdata(&dev->dev);
|
||||
if (!si)
|
||||
return -ENODEV;
|
||||
si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
|
||||
if (!si)
|
||||
return -ENOMEM;
|
||||
|
||||
if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (fb_get_options("efifb", &option))
|
||||
return -ENODEV;
|
||||
efifb_setup(option);
|
||||
efifb_setup(si, option);
|
||||
|
||||
/* We don't get linelength from UGA Draw Protocol, only from
|
||||
* EFI Graphics Protocol. So if it's not in DMI, and it's not
|
||||
* passed in from the user, we really can't use the framebuffer.
|
||||
*/
|
||||
if (!screen_info.lfb_linelength)
|
||||
if (!si->lfb_linelength)
|
||||
return -ENODEV;
|
||||
|
||||
if (!screen_info.lfb_depth)
|
||||
screen_info.lfb_depth = 32;
|
||||
if (!screen_info.pages)
|
||||
screen_info.pages = 1;
|
||||
if (!fb_base_is_valid()) {
|
||||
if (!si->lfb_depth)
|
||||
si->lfb_depth = 32;
|
||||
if (!si->pages)
|
||||
si->pages = 1;
|
||||
if (!fb_base_is_valid(si)) {
|
||||
printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
printk(KERN_INFO "efifb: probing for efifb\n");
|
||||
|
||||
/* just assume they're all unset if any are */
|
||||
if (!screen_info.blue_size) {
|
||||
screen_info.blue_size = 8;
|
||||
screen_info.blue_pos = 0;
|
||||
screen_info.green_size = 8;
|
||||
screen_info.green_pos = 8;
|
||||
screen_info.red_size = 8;
|
||||
screen_info.red_pos = 16;
|
||||
screen_info.rsvd_size = 8;
|
||||
screen_info.rsvd_pos = 24;
|
||||
if (!si->blue_size) {
|
||||
si->blue_size = 8;
|
||||
si->blue_pos = 0;
|
||||
si->green_size = 8;
|
||||
si->green_pos = 8;
|
||||
si->red_size = 8;
|
||||
si->red_pos = 16;
|
||||
si->rsvd_size = 8;
|
||||
si->rsvd_pos = 24;
|
||||
}
|
||||
|
||||
efifb_fix.smem_start = screen_info.lfb_base;
|
||||
efifb_fix.smem_start = si->lfb_base;
|
||||
|
||||
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
|
||||
if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
|
||||
u64 ext_lfb_base;
|
||||
|
||||
ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
|
||||
ext_lfb_base = (u64)(unsigned long)si->ext_lfb_base << 32;
|
||||
efifb_fix.smem_start |= ext_lfb_base;
|
||||
}
|
||||
|
||||
|
@ -417,10 +433,10 @@ static int efifb_probe(struct platform_device *dev)
|
|||
efifb_fix.smem_start = bar_resource->start + bar_offset;
|
||||
}
|
||||
|
||||
efifb_defined.bits_per_pixel = screen_info.lfb_depth;
|
||||
efifb_defined.xres = screen_info.lfb_width;
|
||||
efifb_defined.yres = screen_info.lfb_height;
|
||||
efifb_fix.line_length = screen_info.lfb_linelength;
|
||||
efifb_defined.bits_per_pixel = si->lfb_depth;
|
||||
efifb_defined.xres = si->lfb_width;
|
||||
efifb_defined.yres = si->lfb_height;
|
||||
efifb_fix.line_length = si->lfb_linelength;
|
||||
|
||||
/* size_vmode -- that is the amount of memory needed for the
|
||||
* used video mode, i.e. the minimum amount of
|
||||
|
@ -430,7 +446,7 @@ static int efifb_probe(struct platform_device *dev)
|
|||
/* size_total -- all video memory we have. Used for
|
||||
* entries, ressource allocation and bounds
|
||||
* checking. */
|
||||
size_total = screen_info.lfb_size;
|
||||
size_total = si->lfb_size;
|
||||
if (size_total < size_vmode)
|
||||
size_total = size_vmode;
|
||||
|
||||
|
@ -505,14 +521,14 @@ static int efifb_probe(struct platform_device *dev)
|
|||
goto err_release_fb;
|
||||
}
|
||||
|
||||
efifb_show_boot_graphics(info);
|
||||
efifb_show_boot_graphics(info, si);
|
||||
|
||||
pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
|
||||
efifb_fix.smem_start, size_remap/1024, size_total/1024);
|
||||
pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
|
||||
efifb_defined.xres, efifb_defined.yres,
|
||||
efifb_defined.bits_per_pixel, efifb_fix.line_length,
|
||||
screen_info.pages);
|
||||
si->pages);
|
||||
|
||||
efifb_defined.xres_virtual = efifb_defined.xres;
|
||||
efifb_defined.yres_virtual = efifb_fix.smem_len /
|
||||
|
@ -526,26 +542,26 @@ static int efifb_probe(struct platform_device *dev)
|
|||
efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8;
|
||||
efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8;
|
||||
|
||||
efifb_defined.red.offset = screen_info.red_pos;
|
||||
efifb_defined.red.length = screen_info.red_size;
|
||||
efifb_defined.green.offset = screen_info.green_pos;
|
||||
efifb_defined.green.length = screen_info.green_size;
|
||||
efifb_defined.blue.offset = screen_info.blue_pos;
|
||||
efifb_defined.blue.length = screen_info.blue_size;
|
||||
efifb_defined.transp.offset = screen_info.rsvd_pos;
|
||||
efifb_defined.transp.length = screen_info.rsvd_size;
|
||||
efifb_defined.red.offset = si->red_pos;
|
||||
efifb_defined.red.length = si->red_size;
|
||||
efifb_defined.green.offset = si->green_pos;
|
||||
efifb_defined.green.length = si->green_size;
|
||||
efifb_defined.blue.offset = si->blue_pos;
|
||||
efifb_defined.blue.length = si->blue_size;
|
||||
efifb_defined.transp.offset = si->rsvd_pos;
|
||||
efifb_defined.transp.length = si->rsvd_size;
|
||||
|
||||
pr_info("efifb: %s: "
|
||||
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
|
||||
"Truecolor",
|
||||
screen_info.rsvd_size,
|
||||
screen_info.red_size,
|
||||
screen_info.green_size,
|
||||
screen_info.blue_size,
|
||||
screen_info.rsvd_pos,
|
||||
screen_info.red_pos,
|
||||
screen_info.green_pos,
|
||||
screen_info.blue_pos);
|
||||
si->rsvd_size,
|
||||
si->red_size,
|
||||
si->green_size,
|
||||
si->blue_size,
|
||||
si->rsvd_pos,
|
||||
si->red_pos,
|
||||
si->green_pos,
|
||||
si->blue_pos);
|
||||
|
||||
efifb_fix.ypanstep = 0;
|
||||
efifb_fix.ywrapstep = 0;
|
||||
|
|
|
@ -470,7 +470,7 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
|
|||
if (err == -ENOENT)
|
||||
return 0;
|
||||
|
||||
dev_info(dev, "failed to parse power-domains: %d\n", err);
|
||||
dev_err(dev, "failed to parse power-domains: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ static int vesafb_setup(char *options)
|
|||
|
||||
static int vesafb_probe(struct platform_device *dev)
|
||||
{
|
||||
struct screen_info *si;
|
||||
struct fb_info *info;
|
||||
struct vesafb_par *par;
|
||||
int i, err;
|
||||
|
@ -251,21 +252,33 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
unsigned int size_total;
|
||||
char *option = NULL;
|
||||
|
||||
/*
|
||||
* If we fail probing the device, the kernel might try a different
|
||||
* driver. We get a copy of the attached screen_info, so that we can
|
||||
* modify its values without affecting later drivers.
|
||||
*/
|
||||
si = dev_get_platdata(&dev->dev);
|
||||
if (!si)
|
||||
return -ENODEV;
|
||||
si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
|
||||
if (!si)
|
||||
return -ENOMEM;
|
||||
|
||||
/* ignore error return of fb_get_options */
|
||||
fb_get_options("vesafb", &option);
|
||||
vesafb_setup(option);
|
||||
|
||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
|
||||
if (si->orig_video_isVGA != VIDEO_TYPE_VLFB)
|
||||
return -ENODEV;
|
||||
|
||||
vga_compat = (screen_info.capabilities & 2) ? 0 : 1;
|
||||
vesafb_fix.smem_start = screen_info.lfb_base;
|
||||
vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
|
||||
vga_compat = (si->capabilities & 2) ? 0 : 1;
|
||||
vesafb_fix.smem_start = si->lfb_base;
|
||||
vesafb_defined.bits_per_pixel = si->lfb_depth;
|
||||
if (15 == vesafb_defined.bits_per_pixel)
|
||||
vesafb_defined.bits_per_pixel = 16;
|
||||
vesafb_defined.xres = screen_info.lfb_width;
|
||||
vesafb_defined.yres = screen_info.lfb_height;
|
||||
vesafb_fix.line_length = screen_info.lfb_linelength;
|
||||
vesafb_defined.xres = si->lfb_width;
|
||||
vesafb_defined.yres = si->lfb_height;
|
||||
vesafb_fix.line_length = si->lfb_linelength;
|
||||
vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ?
|
||||
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
|
||||
|
||||
|
@ -277,7 +290,7 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
/* size_total -- all video memory we have. Used for mtrr
|
||||
* entries, resource allocation and bounds
|
||||
* checking. */
|
||||
size_total = screen_info.lfb_size * 65536;
|
||||
size_total = si->lfb_size * 65536;
|
||||
if (vram_total)
|
||||
size_total = vram_total * 1024 * 1024;
|
||||
if (size_total < size_vmode)
|
||||
|
@ -297,7 +310,7 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
vesafb_fix.smem_len = size_remap;
|
||||
|
||||
#ifndef __i386__
|
||||
screen_info.vesapm_seg = 0;
|
||||
si->vesapm_seg = 0;
|
||||
#endif
|
||||
|
||||
if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) {
|
||||
|
@ -317,23 +330,26 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
par = info->par;
|
||||
info->pseudo_palette = par->pseudo_palette;
|
||||
|
||||
par->base = screen_info.lfb_base;
|
||||
par->base = si->lfb_base;
|
||||
par->size = size_total;
|
||||
|
||||
printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
|
||||
vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
|
||||
vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
|
||||
vesafb_fix.line_length, si->pages);
|
||||
|
||||
if (screen_info.vesapm_seg) {
|
||||
if (si->vesapm_seg) {
|
||||
printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n",
|
||||
screen_info.vesapm_seg,screen_info.vesapm_off);
|
||||
si->vesapm_seg, si->vesapm_off);
|
||||
}
|
||||
|
||||
if (screen_info.vesapm_seg < 0xc000)
|
||||
if (si->vesapm_seg < 0xc000)
|
||||
ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
|
||||
|
||||
if (ypan || pmi_setpal) {
|
||||
unsigned long pmi_phys;
|
||||
unsigned short *pmi_base;
|
||||
pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
|
||||
pmi_phys = ((unsigned long)si->vesapm_seg << 4) + si->vesapm_off;
|
||||
pmi_base = (unsigned short *)phys_to_virt(pmi_phys);
|
||||
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
|
||||
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
|
||||
printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
|
||||
|
@ -377,14 +393,14 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8;
|
||||
vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8;
|
||||
|
||||
vesafb_defined.red.offset = screen_info.red_pos;
|
||||
vesafb_defined.red.length = screen_info.red_size;
|
||||
vesafb_defined.green.offset = screen_info.green_pos;
|
||||
vesafb_defined.green.length = screen_info.green_size;
|
||||
vesafb_defined.blue.offset = screen_info.blue_pos;
|
||||
vesafb_defined.blue.length = screen_info.blue_size;
|
||||
vesafb_defined.transp.offset = screen_info.rsvd_pos;
|
||||
vesafb_defined.transp.length = screen_info.rsvd_size;
|
||||
vesafb_defined.red.offset = si->red_pos;
|
||||
vesafb_defined.red.length = si->red_size;
|
||||
vesafb_defined.green.offset = si->green_pos;
|
||||
vesafb_defined.green.length = si->green_size;
|
||||
vesafb_defined.blue.offset = si->blue_pos;
|
||||
vesafb_defined.blue.length = si->blue_size;
|
||||
vesafb_defined.transp.offset = si->rsvd_pos;
|
||||
vesafb_defined.transp.length = si->rsvd_size;
|
||||
|
||||
if (vesafb_defined.bits_per_pixel <= 8) {
|
||||
depth = vesafb_defined.green.length;
|
||||
|
@ -399,14 +415,14 @@ static int vesafb_probe(struct platform_device *dev)
|
|||
(vesafb_defined.bits_per_pixel > 8) ?
|
||||
"Truecolor" : (vga_compat || pmi_setpal) ?
|
||||
"Pseudocolor" : "Static Pseudocolor",
|
||||
screen_info.rsvd_size,
|
||||
screen_info.red_size,
|
||||
screen_info.green_size,
|
||||
screen_info.blue_size,
|
||||
screen_info.rsvd_pos,
|
||||
screen_info.red_pos,
|
||||
screen_info.green_pos,
|
||||
screen_info.blue_pos);
|
||||
si->rsvd_size,
|
||||
si->red_size,
|
||||
si->green_size,
|
||||
si->blue_size,
|
||||
si->rsvd_pos,
|
||||
si->red_pos,
|
||||
si->green_pos,
|
||||
si->blue_pos);
|
||||
|
||||
vesafb_fix.ypanstep = ypan ? 1 : 0;
|
||||
vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0;
|
||||
|
|
|
@ -346,25 +346,29 @@ struct __drm_private_objs_state {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct drm_atomic_state - the global state object for atomic updates
|
||||
* @ref: count of all references to this state (will not be freed until zero)
|
||||
* @dev: parent DRM device
|
||||
* @async_update: hint for asynchronous plane update
|
||||
* @planes: pointer to array of structures with per-plane data
|
||||
* @crtcs: pointer to array of CRTC pointers
|
||||
* @num_connector: size of the @connectors and @connector_states arrays
|
||||
* @connectors: pointer to array of structures with per-connector data
|
||||
* @num_private_objs: size of the @private_objs array
|
||||
* @private_objs: pointer to array of private object pointers
|
||||
* @acquire_ctx: acquire context for this atomic modeset state update
|
||||
* struct drm_atomic_state - Atomic commit structure
|
||||
*
|
||||
* This structure is the kernel counterpart of @drm_mode_atomic and represents
|
||||
* an atomic commit that transitions from an old to a new display state. It
|
||||
* contains all the objects affected by the atomic commit and both the new
|
||||
* state structures and pointers to the old state structures for
|
||||
* these.
|
||||
*
|
||||
* States are added to an atomic update by calling drm_atomic_get_crtc_state(),
|
||||
* drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for
|
||||
* private state structures, drm_atomic_get_private_obj_state().
|
||||
*/
|
||||
struct drm_atomic_state {
|
||||
/**
|
||||
* @ref:
|
||||
*
|
||||
* Count of all references to this update (will not be freed until zero).
|
||||
*/
|
||||
struct kref ref;
|
||||
|
||||
/**
|
||||
* @dev: Parent DRM Device.
|
||||
*/
|
||||
struct drm_device *dev;
|
||||
|
||||
/**
|
||||
|
@ -388,7 +392,12 @@ struct drm_atomic_state {
|
|||
* flag are not allowed.
|
||||
*/
|
||||
bool legacy_cursor_update : 1;
|
||||
|
||||
/**
|
||||
* @async_update: hint for asynchronous plane update
|
||||
*/
|
||||
bool async_update : 1;
|
||||
|
||||
/**
|
||||
* @duplicated:
|
||||
*
|
||||
|
@ -398,13 +407,52 @@ struct drm_atomic_state {
|
|||
* states.
|
||||
*/
|
||||
bool duplicated : 1;
|
||||
|
||||
/**
|
||||
* @planes:
|
||||
*
|
||||
* Pointer to array of @drm_plane and @drm_plane_state part of this
|
||||
* update.
|
||||
*/
|
||||
struct __drm_planes_state *planes;
|
||||
|
||||
/**
|
||||
* @crtcs:
|
||||
*
|
||||
* Pointer to array of @drm_crtc and @drm_crtc_state part of this
|
||||
* update.
|
||||
*/
|
||||
struct __drm_crtcs_state *crtcs;
|
||||
|
||||
/**
|
||||
* @num_connector: size of the @connectors array
|
||||
*/
|
||||
int num_connector;
|
||||
|
||||
/**
|
||||
* @connectors:
|
||||
*
|
||||
* Pointer to array of @drm_connector and @drm_connector_state part of
|
||||
* this update.
|
||||
*/
|
||||
struct __drm_connnectors_state *connectors;
|
||||
|
||||
/**
|
||||
* @num_private_objs: size of the @private_objs array
|
||||
*/
|
||||
int num_private_objs;
|
||||
|
||||
/**
|
||||
* @private_objs:
|
||||
*
|
||||
* Pointer to array of @drm_private_obj and @drm_private_obj_state part
|
||||
* of this update.
|
||||
*/
|
||||
struct __drm_private_objs_state *private_objs;
|
||||
|
||||
/**
|
||||
* @acquire_ctx: acquire context for this atomic modeset state update
|
||||
*/
|
||||
struct drm_modeset_acquire_ctx *acquire_ctx;
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,11 +24,14 @@
|
|||
#define __DRM_EDID_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <drm/drm_mode.h>
|
||||
|
||||
enum hdmi_quantization_range;
|
||||
struct drm_connector;
|
||||
struct drm_device;
|
||||
struct drm_display_mode;
|
||||
struct drm_edid;
|
||||
struct hdmi_avi_infoframe;
|
||||
struct hdmi_vendor_infoframe;
|
||||
struct i2c_adapter;
|
||||
|
||||
#define EDID_LENGTH 128
|
||||
|
@ -46,7 +49,7 @@ struct est_timings {
|
|||
u8 t1;
|
||||
u8 t2;
|
||||
u8 mfg_rsvd;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
|
||||
#define EDID_TIMING_ASPECT_SHIFT 6
|
||||
|
@ -59,7 +62,7 @@ struct est_timings {
|
|||
struct std_timing {
|
||||
u8 hsize; /* need to multiply by 8 then add 248 */
|
||||
u8 vfreq_aspect;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
|
||||
#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
|
||||
|
@ -85,12 +88,12 @@ struct detailed_pixel_timing {
|
|||
u8 hborder;
|
||||
u8 vborder;
|
||||
u8 misc;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* If it's not pixel timing, it'll be one of the below */
|
||||
struct detailed_data_string {
|
||||
u8 str[13];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define DRM_EDID_RANGE_OFFSET_MIN_VFREQ (1 << 0) /* 1.4 */
|
||||
#define DRM_EDID_RANGE_OFFSET_MAX_VFREQ (1 << 1) /* 1.4 */
|
||||
|
@ -120,7 +123,7 @@ struct detailed_data_monitor_range {
|
|||
__le16 m;
|
||||
u8 k;
|
||||
u8 j; /* need to divide by 2 */
|
||||
} __attribute__((packed)) gtf2;
|
||||
} __packed gtf2;
|
||||
struct {
|
||||
u8 version;
|
||||
u8 data1; /* high 6 bits: extra clock resolution */
|
||||
|
@ -129,27 +132,27 @@ struct detailed_data_monitor_range {
|
|||
u8 flags; /* preferred aspect and blanking support */
|
||||
u8 supported_scalings;
|
||||
u8 preferred_refresh;
|
||||
} __attribute__((packed)) cvt;
|
||||
} __attribute__((packed)) formula;
|
||||
} __attribute__((packed));
|
||||
} __packed cvt;
|
||||
} __packed formula;
|
||||
} __packed;
|
||||
|
||||
struct detailed_data_wpindex {
|
||||
u8 white_yx_lo; /* Lower 2 bits each */
|
||||
u8 white_x_hi;
|
||||
u8 white_y_hi;
|
||||
u8 gamma; /* need to divide by 100 then add 1 */
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct detailed_data_color_point {
|
||||
u8 windex1;
|
||||
u8 wpindex1[3];
|
||||
u8 windex2;
|
||||
u8 wpindex2[3];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cvt_timing {
|
||||
u8 code[3];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct detailed_non_pixel {
|
||||
u8 pad1;
|
||||
|
@ -163,8 +166,8 @@ struct detailed_non_pixel {
|
|||
struct detailed_data_wpindex color;
|
||||
struct std_timing timings[6];
|
||||
struct cvt_timing cvt[4];
|
||||
} __attribute__((packed)) data;
|
||||
} __attribute__((packed));
|
||||
} __packed data;
|
||||
} __packed;
|
||||
|
||||
#define EDID_DETAIL_EST_TIMINGS 0xf7
|
||||
#define EDID_DETAIL_CVT_3BYTE 0xf8
|
||||
|
@ -181,8 +184,8 @@ struct detailed_timing {
|
|||
union {
|
||||
struct detailed_pixel_timing pixel_data;
|
||||
struct detailed_non_pixel other_data;
|
||||
} __attribute__((packed)) data;
|
||||
} __attribute__((packed));
|
||||
} __packed data;
|
||||
} __packed;
|
||||
|
||||
#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0)
|
||||
#define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 1)
|
||||
|
@ -307,7 +310,7 @@ struct edid {
|
|||
u8 extensions;
|
||||
/* Checksum */
|
||||
u8 checksum;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
|
||||
|
||||
|
@ -319,11 +322,6 @@ struct cea_sad {
|
|||
u8 byte2; /* meaning depends on format */
|
||||
};
|
||||
|
||||
struct drm_encoder;
|
||||
struct drm_connector;
|
||||
struct drm_connector_state;
|
||||
struct drm_display_mode;
|
||||
|
||||
int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads);
|
||||
int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb);
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
|
@ -426,8 +424,6 @@ enum hdmi_quantization_range
|
|||
drm_default_rgb_quant_range(const struct drm_display_mode *mode);
|
||||
int drm_add_modes_noedid(struct drm_connector *connector,
|
||||
int hdisplay, int vdisplay);
|
||||
void drm_set_preferred_mode(struct drm_connector *connector,
|
||||
int hpref, int vpref);
|
||||
|
||||
int drm_edid_header_is_valid(const void *edid);
|
||||
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
|
||||
|
|
|
@ -95,7 +95,7 @@ static inline int drm_fixp2int_round(s64 a)
|
|||
|
||||
static inline int drm_fixp2int_ceil(s64 a)
|
||||
{
|
||||
if (a > 0)
|
||||
if (a >= 0)
|
||||
return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
|
||||
else
|
||||
return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
|
||||
|
|
|
@ -467,6 +467,8 @@ bool drm_mode_is_420_also(const struct drm_display_info *display,
|
|||
const struct drm_display_mode *mode);
|
||||
bool drm_mode_is_420(const struct drm_display_info *display,
|
||||
const struct drm_display_mode *mode);
|
||||
void drm_set_preferred_mode(struct drm_connector *connector,
|
||||
int hpref, int vpref);
|
||||
|
||||
struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
|
||||
enum drm_connector_tv_mode mode,
|
||||
|
|
|
@ -32,7 +32,6 @@ enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
|
|||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *fixed_mode);
|
||||
|
||||
int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector);
|
||||
int drm_connector_helper_get_modes_fixed(struct drm_connector *connector,
|
||||
const struct drm_display_mode *fixed_mode);
|
||||
int drm_connector_helper_get_modes(struct drm_connector *connector);
|
||||
|
|
|
@ -238,34 +238,32 @@ struct drm_nouveau_vm_init {
|
|||
struct drm_nouveau_vm_bind_op {
|
||||
/**
|
||||
* @op: the operation type
|
||||
*
|
||||
* Supported values:
|
||||
*
|
||||
* %DRM_NOUVEAU_VM_BIND_OP_MAP - Map a GEM object to the GPU's VA
|
||||
* space. Optionally, the &DRM_NOUVEAU_VM_BIND_SPARSE flag can be
|
||||
* passed to instruct the kernel to create sparse mappings for the
|
||||
* given range.
|
||||
*
|
||||
* %DRM_NOUVEAU_VM_BIND_OP_UNMAP - Unmap an existing mapping in the
|
||||
* GPU's VA space. If the region the mapping is located in is a
|
||||
* sparse region, new sparse mappings are created where the unmapped
|
||||
* (memory backed) mapping was mapped previously. To remove a sparse
|
||||
* region the &DRM_NOUVEAU_VM_BIND_SPARSE must be set.
|
||||
*/
|
||||
__u32 op;
|
||||
/**
|
||||
* @DRM_NOUVEAU_VM_BIND_OP_MAP:
|
||||
*
|
||||
* Map a GEM object to the GPU's VA space. Optionally, the
|
||||
* &DRM_NOUVEAU_VM_BIND_SPARSE flag can be passed to instruct the kernel to
|
||||
* create sparse mappings for the given range.
|
||||
*/
|
||||
#define DRM_NOUVEAU_VM_BIND_OP_MAP 0x0
|
||||
/**
|
||||
* @DRM_NOUVEAU_VM_BIND_OP_UNMAP:
|
||||
*
|
||||
* Unmap an existing mapping in the GPU's VA space. If the region the mapping
|
||||
* is located in is a sparse region, new sparse mappings are created where the
|
||||
* unmapped (memory backed) mapping was mapped previously. To remove a sparse
|
||||
* region the &DRM_NOUVEAU_VM_BIND_SPARSE must be set.
|
||||
*/
|
||||
#define DRM_NOUVEAU_VM_BIND_OP_UNMAP 0x1
|
||||
/**
|
||||
* @flags: the flags for a &drm_nouveau_vm_bind_op
|
||||
*
|
||||
* Supported values:
|
||||
*
|
||||
* %DRM_NOUVEAU_VM_BIND_SPARSE - Indicates that an allocated VA
|
||||
* space region should be sparse.
|
||||
*/
|
||||
__u32 flags;
|
||||
/**
|
||||
* @DRM_NOUVEAU_VM_BIND_SPARSE:
|
||||
*
|
||||
* Indicates that an allocated VA space region should be sparse.
|
||||
*/
|
||||
#define DRM_NOUVEAU_VM_BIND_SPARSE (1 << 8)
|
||||
/**
|
||||
* @handle: the handle of the DRM GEM object to map
|
||||
|
@ -301,17 +299,17 @@ struct drm_nouveau_vm_bind {
|
|||
__u32 op_count;
|
||||
/**
|
||||
* @flags: the flags for a &drm_nouveau_vm_bind ioctl
|
||||
*
|
||||
* Supported values:
|
||||
*
|
||||
* %DRM_NOUVEAU_VM_BIND_RUN_ASYNC - Indicates that the given VM_BIND
|
||||
* operation should be executed asynchronously by the kernel.
|
||||
*
|
||||
* If this flag is not supplied the kernel executes the associated
|
||||
* operations synchronously and doesn't accept any &drm_nouveau_sync
|
||||
* objects.
|
||||
*/
|
||||
__u32 flags;
|
||||
/**
|
||||
* @DRM_NOUVEAU_VM_BIND_RUN_ASYNC:
|
||||
*
|
||||
* Indicates that the given VM_BIND operation should be executed asynchronously
|
||||
* by the kernel.
|
||||
*
|
||||
* If this flag is not supplied the kernel executes the associated operations
|
||||
* synchronously and doesn't accept any &drm_nouveau_sync objects.
|
||||
*/
|
||||
#define DRM_NOUVEAU_VM_BIND_RUN_ASYNC 0x1
|
||||
/**
|
||||
* @wait_count: the number of wait &drm_nouveau_syncs
|
||||
|
|
|
@ -242,18 +242,7 @@ struct qaic_attach_slice_entry {
|
|||
* @dbc_id: In. Associate the sliced BO with this DBC.
|
||||
* @handle: In. GEM handle of the BO to slice.
|
||||
* @dir: In. Direction of data flow. 1 = DMA_TO_DEVICE, 2 = DMA_FROM_DEVICE
|
||||
* @size: In. Total length of BO being used. This should not exceed base
|
||||
* size of BO (struct drm_gem_object.base)
|
||||
* For BOs being allocated using DRM_IOCTL_QAIC_CREATE_BO, size of
|
||||
* BO requested is PAGE_SIZE aligned then allocated hence allocated
|
||||
* BO size maybe bigger. This size should not exceed the new
|
||||
* PAGE_SIZE aligned BO size.
|
||||
* @dev_addr: In. Device address this slice pushes to or pulls from.
|
||||
* @db_addr: In. Address of the doorbell to ring.
|
||||
* @db_data: In. Data to write to the doorbell.
|
||||
* @db_len: In. Size of the doorbell data in bits - 32, 16, or 8. 0 is for
|
||||
* inactive doorbells.
|
||||
* @offset: In. Start of this slice as an offset from the start of the BO.
|
||||
* @size: Deprecated. This value is ignored and size of @handle is used instead.
|
||||
*/
|
||||
struct qaic_attach_slice_hdr {
|
||||
__u32 count;
|
||||
|
|
|
@ -309,6 +309,8 @@ struct virtio_gpu_cmd_submit {
|
|||
|
||||
#define VIRTIO_GPU_CAPSET_VIRGL 1
|
||||
#define VIRTIO_GPU_CAPSET_VIRGL2 2
|
||||
/* 3 is reserved for gfxstream */
|
||||
#define VIRTIO_GPU_CAPSET_VENUS 4
|
||||
|
||||
/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
|
||||
struct virtio_gpu_get_capset_info {
|
||||
|
|
Loading…
Reference in New Issue
Block a user